diff --git a/.github/workflows/clang-diff-format.yml b/.github/workflows/clang-diff-format.yml index 130563872ebe..5f43bb4f792c 100644 --- a/.github/workflows/clang-diff-format.yml +++ b/.github/workflows/clang-diff-format.yml @@ -11,7 +11,7 @@ jobs: - name: Checkout uses: actions/checkout@v3 - name: Fetch git - run: git fetch + run: git fetch --no-tags -fu origin develop:develop - name: Run Clang-Format-Diff.py run: | git diff -U0 origin/develop -- $(git ls-files -- $(cat test/util/data/non-backported.txt)) | ./contrib/devtools/clang-format-diff.py -p1 > diff_output.txt diff --git a/.github/workflows/guix-build.yml b/.github/workflows/guix-build.yml index 880e39d164a1..7d996a432e55 100644 --- a/.github/workflows/guix-build.yml +++ b/.github/workflows/guix-build.yml @@ -7,11 +7,15 @@ permissions: on: pull_request_target: + types: [labeled] push: jobs: build-image: runs-on: ubuntu-24.04-arm + if: | + (github.event_name == 'push' && (startsWith(github.ref, 'refs/tags/') || vars.RUN_GUIX_ON_ALL_PUSH == 'true')) || + contains(github.event.pull_request.labels.*.name, 'guix-build') outputs: image-tag: ${{ steps.prepare.outputs.image-tag }} repo-name: ${{ steps.prepare.outputs.repo-name }} @@ -19,7 +23,7 @@ jobs: - name: Checkout uses: actions/checkout@v4 with: - ref: ${{ github.event.pull_request.head.sha }} + ref: ${{ github.event.pull_request.head.sha || github.sha }} path: dash fetch-depth: 0 @@ -65,7 +69,6 @@ jobs: needs: build-image # runs-on: [ "self-hosted", "linux", "x64", "ubuntu-core" ] runs-on: ubuntu-24.04-arm -# if: ${{ contains(github.event.pull_request.labels.*.name, 'guix-build') }} strategy: matrix: build_target: [x86_64-linux-gnu, arm-linux-gnueabihf, aarch64-linux-gnu, riscv64-linux-gnu, powerpc64-linux-gnu, x86_64-w64-mingw32, x86_64-apple-darwin, arm64-apple-darwin] @@ -79,7 +82,7 @@ jobs: - name: Checkout uses: actions/checkout@v4 with: - ref: ${{ github.event.pull_request.head.sha }} + ref: ${{ github.event.pull_request.head.sha || github.sha }} path: dash fetch-depth: 0 diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 585d263c8e2d..78b825aa8254 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -25,7 +25,7 @@ jobs: - name: Initial setup run: | git config --global --add safe.directory "$PWD" - git fetch -fu origin develop:develop + git fetch --no-tags -fu origin develop:develop shell: bash - name: Run linters diff --git a/.github/workflows/merge-check.yml b/.github/workflows/merge-check.yml index f70500e8ca22..7fc2e22a8705 100644 --- a/.github/workflows/merge-check.yml +++ b/.github/workflows/merge-check.yml @@ -28,9 +28,9 @@ jobs: if [[ "${{ github.ref_name }}" == "master" ]]; then echo "Already on master, no need to check --ff-only" else - git fetch origin master:master + git fetch --no-tags origin master:master if [[ "${{ github.event_name }}" == "pull_request"* ]]; then - git fetch origin ${{ github.event.pull_request.base.ref }}:base_branch + git fetch --no-tags origin ${{ github.event.pull_request.base.ref }}:base_branch git checkout base_branch git pull --rebase=false origin pull/${{ github.event.pull_request.number }}/head git checkout master diff --git a/.github/workflows/test-src.yml b/.github/workflows/test-src.yml index 62e47d0152ee..c0a9e5e58289 100644 --- a/.github/workflows/test-src.yml +++ b/.github/workflows/test-src.yml @@ -18,6 +18,7 @@ on: env: INTEGRATION_TESTS_ARGS: "--extended --exclude feature_pruning,feature_dbcrash" + 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 jobs: test-src: diff --git a/.python-version b/.python-version index 43077b246094..1445aee866ce 100644 --- a/.python-version +++ b/.python-version @@ -1 +1 @@ -3.9.18 +3.10.14 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4f14019e9658..25d0874c0af9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -10,10 +10,9 @@ First, in terms of structure, there is no particular concept of "Dash Core developers" in the sense of privileged people. Open source often naturally revolves around a meritocracy where contributors earn trust from the developer community over time. Nevertheless, some hierarchy is necessary for practical -purposes. As such, there are repository "maintainers" who are responsible for -merging pull requests, as well as a "lead maintainer" who is responsible for the -[release cycle](/doc/release-process.md) as well as overall merging, moderation -and appointment of maintainers. +purposes. As such, there are repository maintainers who are responsible for +merging pull requests, the [release cycle](/doc/release-process.md), and +moderation. Getting Started --------------- @@ -272,7 +271,7 @@ projects such as libsecp256k1), and is not to be confused with overall Dash Network Protocol consensus changes. Whether a pull request is merged into Dash Core rests with the project merge -maintainers and ultimately the project lead. +maintainers. Maintainers will take into consideration if a patch is in line with the general principles of the project; meets the minimum standards for inclusion; and will diff --git a/Makefile.am b/Makefile.am index ad1c903f1acb..7bd3cc67bb71 100644 --- a/Makefile.am +++ b/Makefile.am @@ -22,6 +22,7 @@ endif 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_WALLET_BIN=$(top_builddir)/src/$(BITCOIN_WALLET_TOOL_NAME)$(EXEEXT) @@ -41,7 +42,6 @@ OSX_PLIST=$(top_builddir)/share/qt/Info.plist #not installed DIST_CONTRIB = \ $(top_srcdir)/contrib/debian/copyright \ - $(top_srcdir)/contrib/install_db4.sh \ $(top_srcdir)/test/sanitizer_suppressions/lsan \ $(top_srcdir)/test/sanitizer_suppressions/tsan \ $(top_srcdir)/test/sanitizer_suppressions/ubsan \ @@ -77,6 +77,7 @@ $(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 @@ -318,14 +319,14 @@ clean-local: clean-docs test-security-check: if TARGET_DARWIN - $(AM_V_at) CC='$(CC)' CFLAGS='$(CFLAGS)' CPPFLAGS='$(CPPFLAGS)' LDFLAGS='$(LDFLAGS)' $(PYTHON) $(top_srcdir)/contrib/devtools/test-security-check.py TestSecurityChecks.test_MACHO - $(AM_V_at) CC='$(CC)' CFLAGS='$(CFLAGS)' CPPFLAGS='$(CPPFLAGS)' LDFLAGS='$(LDFLAGS)' $(PYTHON) $(top_srcdir)/contrib/devtools/test-symbol-check.py TestSymbolChecks.test_MACHO + $(AM_V_at) CXX='$(CXX)' CXXFLAGS='$(CXXFLAGS)' CPPFLAGS='$(CPPFLAGS)' LDFLAGS='$(LDFLAGS)' $(PYTHON) $(top_srcdir)/contrib/devtools/test-security-check.py TestSecurityChecks.test_MACHO + $(AM_V_at) CXX='$(CXX)' CXXFLAGS='$(CXXFLAGS)' CPPFLAGS='$(CPPFLAGS)' LDFLAGS='$(LDFLAGS)' $(PYTHON) $(top_srcdir)/contrib/devtools/test-symbol-check.py TestSymbolChecks.test_MACHO endif if TARGET_WINDOWS - $(AM_V_at) CC='$(CC)' CFLAGS='$(CFLAGS)' CPPFLAGS='$(CPPFLAGS)' LDFLAGS='$(LDFLAGS)' $(PYTHON) $(top_srcdir)/contrib/devtools/test-security-check.py TestSecurityChecks.test_PE - $(AM_V_at) CC='$(CC)' CFLAGS='$(CFLAGS)' CPPFLAGS='$(CPPFLAGS)' LDFLAGS='$(LDFLAGS)' $(PYTHON) $(top_srcdir)/contrib/devtools/test-symbol-check.py TestSymbolChecks.test_PE + $(AM_V_at) CXX='$(CXX)' CXXFLAGS='$(CXXFLAGS)' CPPFLAGS='$(CPPFLAGS)' LDFLAGS='$(LDFLAGS)' $(PYTHON) $(top_srcdir)/contrib/devtools/test-security-check.py TestSecurityChecks.test_PE + $(AM_V_at) CXX='$(CXX)' CXXFLAGS='$(CXXFLAGS)' CPPFLAGS='$(CPPFLAGS)' LDFLAGS='$(LDFLAGS)' $(PYTHON) $(top_srcdir)/contrib/devtools/test-symbol-check.py TestSymbolChecks.test_PE endif if TARGET_LINUX - $(AM_V_at) CC='$(CC)' CFLAGS='$(CFLAGS)' CPPFLAGS='$(CPPFLAGS)' LDFLAGS='$(LDFLAGS)' $(PYTHON) $(top_srcdir)/contrib/devtools/test-security-check.py TestSecurityChecks.test_ELF - $(AM_V_at) CC='$(CC)' CFLAGS='$(CFLAGS)' CPPFLAGS='$(CPPFLAGS)' LDFLAGS='$(LDFLAGS)' $(PYTHON) $(top_srcdir)/contrib/devtools/test-symbol-check.py TestSymbolChecks.test_ELF + $(AM_V_at) CXX='$(CXX)' CXXFLAGS='$(CXXFLAGS)' CPPFLAGS='$(CPPFLAGS)' LDFLAGS='$(LDFLAGS)' $(PYTHON) $(top_srcdir)/contrib/devtools/test-security-check.py TestSecurityChecks.test_ELF + $(AM_V_at) CXX='$(CXX)' CXXFLAGS='$(CXXFLAGS)' CPPFLAGS='$(CPPFLAGS)' LDFLAGS='$(LDFLAGS)' $(PYTHON) $(top_srcdir)/contrib/devtools/test-symbol-check.py TestSymbolChecks.test_ELF endif diff --git a/README.md b/README.md index 11875daf7a11..edb28d9739c8 100644 --- a/README.md +++ b/README.md @@ -10,15 +10,19 @@ https://www.dash.org For an immediately usable, binary version of the Dash Core software, see https://www.dash.org/downloads/. -Further information about Dash Core is available in [./doc/](/doc). +Dash Core connects to the Dash peer-to-peer network to download and fully +validate blocks and transactions. It also includes a wallet and graphical user +interface, which can be optionally built. + +Further information about Dash Core is available in the [doc folder](/doc). What is Dash? ------------- -Dash is an experimental digital currency that enables instant, private -payments to anyone, anywhere in the world. Dash uses peer-to-peer technology -to operate with no central authority: managing transactions and issuing money -are carried out collectively by the network. Dash Core is the name of the open +Dash is a digital currency that enables instant, private payments to anyone, +anywhere in the world. Dash uses peer-to-peer technology to operate with +no central authority: managing transactions and issuing money are carried out +collectively by the network. Dash Core is the name of the open source software which enables the use of this currency. diff --git a/SECURITY.md b/SECURITY.md index 7c31430d3bc2..dce97e5ea2ec 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -4,8 +4,8 @@ | Version | Supported | | ------- | ------------------ | -| 22.x | :white_check_mark: | -| < 22 | :x: | +| 23.x | :white_check_mark: | +| < 23 | :x: | ## Reporting a Vulnerability diff --git a/build-aux/m4/bitcoin_qt.m4 b/build-aux/m4/bitcoin_qt.m4 index b646a3e2a9d3..7a970cf911e5 100644 --- a/build-aux/m4/bitcoin_qt.m4 +++ b/build-aux/m4/bitcoin_qt.m4 @@ -148,7 +148,7 @@ AC_DEFUN([BITCOIN_QT_CONFIGURE],[ _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 + elif test "$TARGET_OS" = "linux" -o "$TARGET_OS" = "freebsd"; 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 diff --git a/ci/dash/build_src.sh b/ci/dash/build_src.sh index ad1201e4599d..7014d51328d0 100755 --- a/ci/dash/build_src.sh +++ b/ci/dash/build_src.sh @@ -33,7 +33,7 @@ if [ -n "$CONFIG_SHELL" ]; then export CONFIG_SHELL="$CONFIG_SHELL" fi -BITCOIN_CONFIG_ALL="--disable-dependency-tracking --prefix=$DEPENDS_DIR/$HOST --bindir=$BASE_OUTDIR/bin --libdir=$BASE_OUTDIR/lib" +BITCOIN_CONFIG_ALL="--enable-external-signer --disable-dependency-tracking --prefix=$DEPENDS_DIR/$HOST --bindir=$BASE_OUTDIR/bin --libdir=$BASE_OUTDIR/lib" if [ -z "$NO_WERROR" ]; then BITCOIN_CONFIG_ALL="${BITCOIN_CONFIG_ALL} --enable-werror" fi diff --git a/ci/dash/lint-tidy.sh b/ci/dash/lint-tidy.sh index d417d0009b90..c4d9ab5ed431 100755 --- a/ci/dash/lint-tidy.sh +++ b/ci/dash/lint-tidy.sh @@ -21,10 +21,19 @@ fi cd "${BASE_ROOT_DIR}/build-ci/dashcore-${BUILD_TARGET}" iwyu_tool.py \ "src/compat" \ + "src/dbwrapper.cpp" \ "src/init" \ + "src/node/chainstate.cpp" \ + "src/node/minisketchwrapper.cpp" \ + "src/policy/feerate.cpp" \ + "src/policy/packages.cpp" \ + "src/policy/settings.cpp" \ + "src/primitives/transaction.cpp" \ + "src/random.cpp" \ "src/rpc/fees.cpp" \ "src/rpc/signmessage.cpp" \ "src/test/fuzz/txorphan.cpp" \ + "src/threadinterrupt.cpp" \ "src/util/bip32.cpp" \ "src/util/bytevectorhash.cpp" \ "src/util/check.cpp" \ @@ -35,6 +44,7 @@ iwyu_tool.py \ "src/util/moneystr.cpp" \ "src/util/serfloat.cpp" \ "src/util/spanparsing.cpp" \ + "src/util/string.cpp" \ "src/util/strencodings.cpp" \ "src/util/syserror.cpp" \ "src/util/url.cpp" \ diff --git a/ci/dash/test_integrationtests.sh b/ci/dash/test_integrationtests.sh index 6fcca71fcf50..b4b0304b2ad8 100755 --- a/ci/dash/test_integrationtests.sh +++ b/ci/dash/test_integrationtests.sh @@ -20,10 +20,10 @@ fi export LD_LIBRARY_PATH=$DEPENDS_DIR/$HOST/lib -if [ -n "$PREVIOUS_RELEASES_TO_DOWNLOAD" ]; then - echo "Downloading previous releases: $PREVIOUS_RELEASES_TO_DOWNLOAD" +if [ "$DOWNLOAD_PREVIOUS_RELEASES" = "true" ]; then + echo "Downloading previous releases..." # shellcheck disable=SC2086 - ./test/get_previous_releases.py -b -t "$PREVIOUS_RELEASES_DIR" ${PREVIOUS_RELEASES_TO_DOWNLOAD} + ./test/get_previous_releases.py -b -t "$PREVIOUS_RELEASES_DIR" fi cd "build-ci/dashcore-$BUILD_TARGET" diff --git a/ci/lint/04_install.sh b/ci/lint/04_install.sh index 431672ba1fb3..0453e9167488 100755 --- a/ci/lint/04_install.sh +++ b/ci/lint/04_install.sh @@ -33,12 +33,12 @@ if [ -z "${SKIP_PYTHON_INSTALL}" ]; then python3 --version fi -${CI_RETRY_EXE} pip3 install codespell==2.0.0 -${CI_RETRY_EXE} pip3 install flake8==3.8.3 +${CI_RETRY_EXE} pip3 install codespell==2.1.0 +${CI_RETRY_EXE} pip3 install flake8==4.0.1 ${CI_RETRY_EXE} pip3 install lief==0.13.1 -${CI_RETRY_EXE} pip3 install mypy==0.910 -${CI_RETRY_EXE} pip3 install pyzmq==22.3.0 -${CI_RETRY_EXE} pip3 install vulture==2.3 +${CI_RETRY_EXE} pip3 install mypy==0.981 +${CI_RETRY_EXE} pip3 install pyzmq==24.0.1 +${CI_RETRY_EXE} pip3 install vulture==2.6 SHELLCHECK_VERSION=v0.8.0 curl -sL "https://github.com/koalaman/shellcheck/releases/download/${SHELLCHECK_VERSION}/shellcheck-${SHELLCHECK_VERSION}.linux.x86_64.tar.xz" | \ diff --git a/ci/test/00_setup_env_arm.sh b/ci/test/00_setup_env_arm.sh index af66a99b5111..edbc9334928f 100755 --- a/ci/test/00_setup_env_arm.sh +++ b/ci/test/00_setup_env_arm.sh @@ -25,4 +25,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 --with-boost-process" +export BITCOIN_CONFIG="--enable-reduce-exports CXXFLAGS=-Wno-psabi" diff --git a/ci/test/00_setup_env_mac.sh b/ci/test/00_setup_env_mac.sh index aba312bf78af..ca04e916fc2a 100755 --- a/ci/test/00_setup_env_mac.sh +++ b/ci/test/00_setup_env_mac.sh @@ -14,4 +14,4 @@ export XCODE_BUILD_ID=15A240d export RUN_UNIT_TESTS=false export RUN_FUNCTIONAL_TESTS=false export GOAL="all deploy" -export BITCOIN_CONFIG="--with-gui --enable-reduce-exports --disable-miner --with-boost-process" +export BITCOIN_CONFIG="--with-gui --enable-reduce-exports --disable-miner" diff --git a/ci/test/00_setup_env_mac_native_x86_64.sh b/ci/test/00_setup_env_mac_native_x86_64.sh index 252b95c2178f..b20efb2bde37 100755 --- a/ci/test/00_setup_env_mac_native_x86_64.sh +++ b/ci/test/00_setup_env_mac_native_x86_64.sh @@ -10,7 +10,7 @@ export CONTAINER_NAME=ci_macos export HOST=x86_64-apple-darwin export PIP_PACKAGES="zmq lief" export GOAL="install" -export BITCOIN_CONFIG="--with-gui --enable-reduce-exports --disable-miner --with-boost-process" +export BITCOIN_CONFIG="--with-gui --enable-reduce-exports --disable-miner" export CI_OS_NAME="macos" export NO_DEPENDS=1 export OSX_SDK="" diff --git a/ci/test/00_setup_env_native_asan.sh b/ci/test/00_setup_env_native_asan.sh index 5f1507e5b7e2..ac78c511139e 100755 --- a/ci/test/00_setup_env_native_asan.sh +++ b/ci/test/00_setup_env_native_asan.sh @@ -12,4 +12,4 @@ export TEST_RUNNER_EXTRA="--timeout-factor=4" # Increase timeout because saniti export FUNCTIONAL_TESTS_CONFIG="--exclude wallet_multiwallet.py" # Temporarily suppress ASan heap-use-after-free (see issue #14163) export RUN_BENCH=true export GOAL="install" -export BITCOIN_CONFIG="--enable-zmq --with-incompatible-bdb --with-gui=qt5 CPPFLAGS=-DDEBUG_LOCKORDER --with-sanitizers=address,integer,undefined CC=clang CXX=clang++ --with-boost-process" +export BITCOIN_CONFIG="--enable-zmq --with-incompatible-bdb --with-gui=qt5 CPPFLAGS=-DDEBUG_LOCKORDER --with-sanitizers=address,integer,undefined CC=clang CXX=clang++" diff --git a/ci/test/00_setup_env_native_fuzz.sh b/ci/test/00_setup_env_native_fuzz.sh index 18929cc2b2f0..71356f213582 100755 --- a/ci/test/00_setup_env_native_fuzz.sh +++ b/ci/test/00_setup_env_native_fuzz.sh @@ -15,4 +15,4 @@ export RUN_UNIT_TESTS=false export RUN_FUNCTIONAL_TESTS=false export RUN_FUZZ_TESTS=true export GOAL="install" -export BITCOIN_CONFIG="--enable-zmq --disable-ccache --enable-fuzz --with-sanitizers=fuzzer,address,undefined,integer CC='clang-18 -ftrivial-auto-var-init=pattern' CXX='clang++-18 -ftrivial-auto-var-init=pattern' --with-boost-process" +export BITCOIN_CONFIG="--enable-zmq --disable-ccache --enable-fuzz --with-sanitizers=fuzzer,address,undefined,integer CC='clang-19 -ftrivial-auto-var-init=pattern' CXX='clang++-19 -ftrivial-auto-var-init=pattern'" 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 f379d8ee7edc..59d921d54fc9 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,5 @@ export RUN_FUZZ_TESTS=true export FUZZ_TESTS_CONFIG="--valgrind" export GOAL="install" # Temporarily pin dwarf 4, until valgrind can understand clang's dwarf 5 -export BITCOIN_CONFIG="--enable-fuzz --with-sanitizers=fuzzer CC=clang-18 CXX=clang++-18 CFLAGS='-gdwarf-4' CXXFLAGS='-gdwarf-4'" +export BITCOIN_CONFIG="--enable-fuzz --with-sanitizers=fuzzer CC=clang-19 CXX=clang++-19 CFLAGS='-gdwarf-4' CXXFLAGS='-gdwarf-4'" export CCACHE_MAXSIZE=200M diff --git a/ci/test/00_setup_env_native_multiprocess.sh b/ci/test/00_setup_env_native_multiprocess.sh index 7ab95903d131..4583a86737a0 100755 --- a/ci/test/00_setup_env_native_multiprocess.sh +++ b/ci/test/00_setup_env_native_multiprocess.sh @@ -9,11 +9,11 @@ export LC_ALL=C.UTF-8 export CONTAINER_NAME=ci_native_multiprocess export HOST=x86_64-pc-linux-gnu export PACKAGES="cmake python3 llvm clang" -export DEP_OPTS="MULTIPROCESS=1 CC=clang-18 CXX=clang++-18" +export DEP_OPTS="MULTIPROCESS=1 CC=clang-19 CXX=clang++-19" export RUN_TIDY=true export GOAL="install" export TEST_RUNNER_EXTRA="--v2transport" -export BITCOIN_CONFIG="--with-boost-process --enable-debug CC=clang-18 CXX=clang++-18" # Use clang to avoid OOM +export BITCOIN_CONFIG="--enable-debug CC=clang-19 CXX=clang++-19" # Use clang to avoid OOM # Additional flags for RUN_TIDY export BITCOIN_CONFIG="${BITCOIN_CONFIG} --disable-hardening CFLAGS='-O0 -g0' CXXFLAGS='-O0 -g0 -Wno-error=documentation'" export BITCOIND=dash-node # Used in functional tests diff --git a/ci/test/00_setup_env_native_nowallet.sh b/ci/test/00_setup_env_native_nowallet.sh index 3637d3b8d0da..3e083c3d4d62 100755 --- a/ci/test/00_setup_env_native_nowallet.sh +++ b/ci/test/00_setup_env_native_nowallet.sh @@ -11,4 +11,4 @@ export HOST=x86_64-pc-linux-gnu export PACKAGES="python3-zmq" export DEP_OPTS="NO_WALLET=1 CC=gcc-14 CXX=g++-14" export GOAL="install" -export BITCOIN_CONFIG="--enable-reduce-exports --with-boost-process CC=gcc-14 CXX=g++-14" +export BITCOIN_CONFIG="--enable-reduce-exports CC=gcc-14 CXX=g++-14" diff --git a/ci/test/00_setup_env_native_qt5.sh b/ci/test/00_setup_env_native_qt5.sh index 78aeef1f0aec..1b41c7d4644e 100755 --- a/ci/test/00_setup_env_native_qt5.sh +++ b/ci/test/00_setup_env_native_qt5.sh @@ -14,5 +14,5 @@ export TEST_RUNNER_EXTRA="--previous-releases --coverage --extended --exclude fe export RUN_UNIT_TESTS_SEQUENTIAL="true" export RUN_UNIT_TESTS="false" export GOAL="install" -export PREVIOUS_RELEASES_TO_DOWNLOAD="v0.12.1.5 v0.15.0.0 v0.16.1.1 v0.17.0.3 v18.2.2 v19.3.0 v20.1.1 v21.1.1" -export BITCOIN_CONFIG="--enable-zmq --with-libs=no --enable-reduce-exports --disable-fuzz-binary LDFLAGS=-static-libstdc++ --with-boost-process" +export DOWNLOAD_PREVIOUS_RELEASES="true" +export BITCOIN_CONFIG="--enable-zmq --with-libs=no --enable-reduce-exports LDFLAGS=-static-libstdc++" diff --git a/ci/test/00_setup_env_native_tsan.sh b/ci/test/00_setup_env_native_tsan.sh index 3820e469aa5f..798ded8afd16 100755 --- a/ci/test/00_setup_env_native_tsan.sh +++ b/ci/test/00_setup_env_native_tsan.sh @@ -7,11 +7,11 @@ export LC_ALL=C.UTF-8 export CONTAINER_NAME=ci_native_tsan -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 PACKAGES="clang-19 llvm-19 libclang-rt-19-dev libc++abi-19-dev libc++-19-dev python3-zmq" +export DEP_OPTS="CC=clang-19 CXX='clang++-19 -stdlib=libc++'" export TEST_RUNNER_EXTRA="--extended --exclude feature_pruning,feature_dbcrash,wallet_multiwallet.py" # Temporarily suppress ASan heap-use-after-free (see issue #14163) export TEST_RUNNER_EXTRA="${TEST_RUNNER_EXTRA} --timeout-factor=4" # Increase timeout because sanitizers slow down export GOAL="install" -export BITCOIN_CONFIG="--enable-zmq --with-sanitizers=thread CC=clang-18 CXX=clang++-18 CXXFLAGS='-g' --with-boost-process" +export BITCOIN_CONFIG="--enable-zmq --with-sanitizers=thread CC=clang-19 CXX=clang++-19 CXXFLAGS='-g'" export CPPFLAGS="-DARENA_DEBUG -DDEBUG_LOCKORDER -DDEBUG_LOCKCONTENTION" export PYZMQ=true diff --git a/ci/test/00_setup_env_native_ubsan.sh b/ci/test/00_setup_env_native_ubsan.sh index 9fb440dfd41e..f562bce0edbf 100755 --- a/ci/test/00_setup_env_native_ubsan.sh +++ b/ci/test/00_setup_env_native_ubsan.sh @@ -8,8 +8,8 @@ export LC_ALL=C.UTF-8 export CONTAINER_NAME=ci_native_ubsan -export PACKAGES="clang-18 llvm-18 python3-zmq qtbase5-dev qttools5-dev-tools libevent-dev bsdmainutils libboost-dev libdb5.3++-dev libminiupnpc-dev libzmq3-dev libqrencode-dev" +export PACKAGES="clang-19 llvm-19 python3-zmq qtbase5-dev qttools5-dev-tools libevent-dev bsdmainutils libboost-dev libdb5.3++-dev libminiupnpc-dev libzmq3-dev libqrencode-dev" export DEP_OPTS="NO_UPNP=1 DEBUG=1" export GOAL="install" -export BITCOIN_CONFIG="--enable-zmq --enable-reduce-exports --enable-crash-hooks --with-sanitizers=undefined CC=clang-18 CXX=clang++-18" +export BITCOIN_CONFIG="--enable-zmq --enable-reduce-exports --enable-crash-hooks --with-sanitizers=undefined CC=clang-19 CXX=clang++-19" export PYZMQ=true diff --git a/ci/test/00_setup_env_native_valgrind.sh b/ci/test/00_setup_env_native_valgrind.sh index d7bf8b2f3550..478a347d8c9d 100755 --- a/ci/test/00_setup_env_native_valgrind.sh +++ b/ci/test/00_setup_env_native_valgrind.sh @@ -12,4 +12,4 @@ export NO_DEPENDS=1 export TEST_RUNNER_EXTRA="--exclude rpc_bind,feature_bind_extra --timeout-factor=4" # Excluded for now, see https://github.com/bitcoin/bitcoin/issues/17765#issuecomment-602068547 export GOAL="install" # Temporarily pin dwarf 4, until valgrind can understand clang's dwarf 5 -export BITCOIN_CONFIG="--enable-zmq --with-incompatible-bdb --with-gui=no CC=clang-18 CXX=clang++-18 CFLAGS='-gdwarf-4' CXXFLAGS='-gdwarf-4'" # TODO enable GUI +export BITCOIN_CONFIG="--enable-zmq --with-incompatible-bdb --with-gui=no CC=clang-19 CXX=clang++-19 CFLAGS='-gdwarf-4' CXXFLAGS='-gdwarf-4'" # TODO enable GUI diff --git a/ci/test/00_setup_env_s390x.sh b/ci/test/00_setup_env_s390x.sh index 5d95535daf92..2bb4d5e57562 100755 --- a/ci/test/00_setup_env_s390x.sh +++ b/ci/test/00_setup_env_s390x.sh @@ -22,4 +22,4 @@ export RUN_UNIT_TESTS=true 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 --with-boost-process" +export BITCOIN_CONFIG="--enable-reduce-exports" diff --git a/ci/test/00_setup_env_win64.sh b/ci/test/00_setup_env_win64.sh index fa39b532213e..2010c111818d 100755 --- a/ci/test/00_setup_env_win64.sh +++ b/ci/test/00_setup_env_win64.sh @@ -16,5 +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-gui --enable-reduce-exports --disable-miner --without-boost-process CXXFLAGS='-Wno-return-type -Wno-error=maybe-uninitialized -Wno-error=array-bounds'" +export BITCOIN_CONFIG="--enable-gui --enable-reduce-exports --disable-miner CXXFLAGS='-Wno-return-type -Wno-error=maybe-uninitialized -Wno-error=array-bounds'" export DIRECT_WINE_EXEC_TESTS=true diff --git a/ci/test/05_before_script.sh b/ci/test/05_before_script.sh index fa847fb0802b..e8043f65dfd7 100755 --- a/ci/test/05_before_script.sh +++ b/ci/test/05_before_script.sh @@ -30,6 +30,6 @@ if [ -z "$NO_DEPENDS" ]; then fi CI_EXEC "$SHELL_OPTS" make "$MAKEJOBS" -C depends HOST="$HOST" "$DEP_OPTS" LOG=1 fi -if [ -n "$PREVIOUS_RELEASES_TO_DOWNLOAD" ]; then - CI_EXEC test/get_previous_releases.py -b -t "$PREVIOUS_RELEASES_DIR" "${PREVIOUS_RELEASES_TO_DOWNLOAD}" +if [ "$DOWNLOAD_PREVIOUS_RELEASES" = "true" ]; then + CI_EXEC test/get_previous_releases.py -b -t "$PREVIOUS_RELEASES_DIR" fi diff --git a/configure.ac b/configure.ac index e9b2ccc15bdb..d88e4cdd5d4b 100644 --- a/configure.ac +++ b/configure.ac @@ -31,6 +31,7 @@ fi BITCOIN_DAEMON_NAME=dashd BITCOIN_GUI_NAME=dash-qt +BITCOIN_TEST_NAME=test_dash BITCOIN_CLI_NAME=dash-cli BITCOIN_TX_NAME=dash-tx BITCOIN_WALLET_TOOL_NAME=dash-wallet @@ -236,12 +237,6 @@ AC_ARG_ENABLE([lcov-branch-coverage], [use_lcov_branch=yes], [use_lcov_branch=no]) -AC_ARG_ENABLE([threadlocal], - [AS_HELP_STRING([--enable-threadlocal], - [enable features that depend on the c++ thread_local keyword (currently just thread names in debug logs). (default is to enable if there is platform support)])], - [use_thread_local=$enableval], - [use_thread_local=auto]) - AC_ARG_ENABLE([zmq], [AS_HELP_STRING([--disable-zmq], [disable ZMQ notifications])], @@ -324,10 +319,10 @@ AC_ARG_ENABLE([werror], [enable_werror=$enableval], [enable_werror=no]) -AC_ARG_WITH([boost-process], - [AS_HELP_STRING([--with-boost-process],[Opt in to using Boost Process (default is no)])], - [boost_process=$withval], - [boost_process=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++]) @@ -359,7 +354,7 @@ if test "$enable_debug" = "yes"; then dnl them, to prevent autoconfs "-g -O2" being added. Otherwise we'd end up dnl with "-O0 -g3 -g -O2". if test "$CXXFLAGS_overridden" = "no"; then - CXXFLAGS="" + CXXFLAGS="" fi dnl Disable all optimizations @@ -375,6 +370,7 @@ if test "$enable_debug" = "yes"; then AX_CHECK_PREPROC_FLAG([-DDEBUG_CORE], [DEBUG_CPPFLAGS="$DEBUG_CPPFLAGS -DDEBUG_CORE"], [], [$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]) else @@ -393,29 +389,6 @@ else fi fi -if test "$enable_stacktraces" != no; then - AC_CHECK_HEADERS([execinfo.h], [], [enable_stacktraces=no]) -fi - -AM_CONDITIONAL([ENABLE_STACKTRACES], [test "$enable_stacktraces" = "yes"]) -if test "$enable_stacktraces" = "yes"; then - AC_DEFINE(ENABLE_STACKTRACES, 1, [Define this symbol if stacktraces should be enabled]) -else - enable_crashhooks=no -fi - -AM_CONDITIONAL([ENABLE_CRASH_HOOKS], [test "$enable_crashhooks" = "yes"]) -if test "$enable_crashhooks" = "yes"; then - AC_DEFINE(ENABLE_CRASH_HOOKS, 1, [Define this symbol if crash hooks should be enabled]) -fi - -AX_CHECK_LINK_FLAG([-Wl,-wrap=__cxa_allocate_exception], [LINK_WRAP_SUPPORTED=yes],,,) -AM_CONDITIONAL([CRASH_HOOKS_WRAPPED_CXX_ABI],[test $LINK_WRAP_SUPPORTED = "yes"]) - -if test "$LINK_WRAP_SUPPORTED" = "yes"; then - AC_DEFINE(CRASH_HOOKS_WRAPPED_CXX_ABI, 1, [Define this symbol to use wrapped CXX ABIs for exception stacktraces]) -fi - # Needed for MinGW targets when debug symbols are enabled as compiled objects get very large AX_CHECK_COMPILE_FLAG([-Wa,-mbig-obj], [DEBUG_CXXFLAGS="$DEBUG_CXXFLAGS -Wa,-mbig-obj"],,,) @@ -453,6 +426,15 @@ if test "$enable_werror" = "yes"; then fi ERROR_CXXFLAGS=$CXXFLAG_WERROR + dnl -Wdeprecated-literal-operator cause problems with clang 20. Do not treat these warnings as errors. + dnl TODO: remove it once we update hana + AX_CHECK_COMPILE_FLAG([-Wdeprecated-literal-operator], [NOWARN_CXXFLAGS="$NOWARN_CXXFLAGS -Wno-error=deprecated-literal-operator"], [], [$CXXFLAG_WERROR], [AC_LANG_SOURCE([ + #if !defined(__clang__) || defined(__INTEL_COMPILER) + #error Non-clang compiler detected, not setting flag + #endif + int main(void) { return 0; } + ])]) + dnl -Wattributes cause problems with some versions of GCC. Do not treat these warnings as errors. AX_CHECK_COMPILE_FLAG([-Wattributes], [NOWARN_CXXFLAGS="$NOWARN_CXXFLAGS -Wno-error=attributes"], [], [$CXXFLAG_WERROR], [AC_LANG_SOURCE([ #if defined(__clang__) || defined(__INTEL_COMPILER) || !defined(__GNUC__) @@ -882,11 +864,17 @@ case $host in export PKG_CONFIG_PATH="$($BREW --prefix qt@5 2>/dev/null)/lib/pkgconfig:$PKG_CONFIG_PATH" fi - gmp_prefix=$($BREW --prefix gmp 2>/dev/null) - if test "$gmp_prefix" != ""; then - CORE_CPPFLAGS="$CORE_CPPFLAGS -I$gmp_prefix/include" - CORE_LDFLAGS="$CORE_LDFLAGS -L$gmp_prefix/lib" - fi + gmp_prefix=$($BREW --prefix gmp 2>/dev/null) + if test "$gmp_prefix" != ""; then + if test "$suppress_external_warnings" != "no"; then + GMP_CPPFLAGS="-isystem $gmp_prefix/include" + else + GMP_CPPFLAGS="-I$gmp_prefix/include" + fi + GMP_LDFLAGS="-L$gmp_prefix/lib" + CORE_CPPFLAGS="$CORE_CPPFLAGS $GMP_CPPFLAGS" + CORE_LDFLAGS="$CORE_LDFLAGS $GMP_LDFLAGS" + fi case $host in *aarch64*) @@ -958,6 +946,9 @@ case $host in *linux*) TARGET_OS=linux ;; + *freebsd*) + TARGET_OS=freebsd + ;; esac if test "$use_extended_functional_tests" != "no"; then @@ -1110,12 +1101,11 @@ if test "$use_hardening" != "no"; then 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 - case $host in - *mingw*) - AC_CHECK_LIB([ssp], [main], [], [AC_MSG_ERROR([libssp missing])]) - ;; - esac +dnl Add build-id for perf and debug symbol matching (Linux only) +if test "$TARGET_OS" = "linux"; then + AX_CHECK_LINK_FLAG([-Wl,--build-id=sha1], [CORE_LDFLAGS="$CORE_LDFLAGS -Wl,--build-id=sha1"], [], [$LDFLAG_WERROR]) fi dnl These flags are specific to ld64, and may cause issues with other linkers. @@ -1201,43 +1191,91 @@ AC_COMPILE_IFELSE([AC_LANG_SOURCE([ [AC_MSG_RESULT([no])] ) -if test "$use_thread_local" = "yes" || test "$use_thread_local" = "auto"; then - TEMP_LDFLAGS="$LDFLAGS" - LDFLAGS="$TEMP_LDFLAGS $PTHREAD_CFLAGS" - AC_MSG_CHECKING([for thread_local support]) - AC_LINK_IFELSE([AC_LANG_SOURCE([ - #include - static thread_local int foo = 0; - static void run_thread() { foo++;} - int main(){ - for(int i = 0; i < 10; i++) { std::thread(run_thread).detach();} - return foo; - } - ])], - [ - case $host in - *mingw*) - dnl mingw32's implementation of thread_local has also been shown to behave - dnl erroneously under concurrent usage; see: - dnl https://gist.github.com/jamesob/fe9a872051a88b2025b1aa37bfa98605 - AC_MSG_RESULT([no]) - ;; - *freebsd*) - dnl FreeBSD's implementation of thread_local is also buggy (per - dnl https://groups.google.com/d/msg/bsdmailinglist/22ncTZAbDp4/Dii_pII5AwAJ) - AC_MSG_RESULT([no]) - ;; - *) - AC_DEFINE([HAVE_THREAD_LOCAL], [1], [Define if thread_local is supported.]) - AC_MSG_RESULT([yes]) - ;; - esac - ], - [ - AC_MSG_RESULT([no]) - ] - ) - LDFLAGS="$TEMP_LDFLAGS" +BACKTRACE_FLAGS= +BACKTRACE_LDFLAGS= +BACKTRACE_LIBS= +if test "$enable_stacktraces" != "no"; then + AC_CHECK_HEADERS([backtrace.h], [ + if test "$TARGET_OS" = "windows"; then + BACKTRACE_LIBS="$BACKTRACE_LIBS -ldbghelp" + else + AC_CHECK_HEADERS([execinfo.h], [ + case $host in + *bsd*) + AC_SEARCH_LIBS([backtrace], [execinfo], [ + BACKTRACE_LIBS="$BACKTRACE_LIBS -lexecinfo" + ], [ + if test "$enable_stacktraces" = "yes"; then + AC_MSG_ERROR([--enable-stacktraces was specified but cannot locate libexecinfo]) + fi + AC_MSG_WARN([cannot locate libexecinfo, stacktraces will be disabled]) + enable_stacktraces=no + ]) + ;; + esac + AX_CHECK_LINK_FLAG([-Wl,-export-dynamic], [BACKTRACE_LDFLAGS="$BACKTRACE_LDFLAGS -Wl,-export-dynamic"], [ + AX_CHECK_LINK_FLAG([-rdynamic], [BACKTRACE_LDFLAGS="$BACKTRACE_LDFLAGS -rdynamic"], [ + if test "$enable_stacktraces" = "yes"; then + AC_MSG_ERROR([--enable-stacktraces was specified but cannot set requisite linker flags]) + fi + AC_MSG_WARN([cannot set requisite linker flags, stacktraces will be disabled]) + enable_stacktraces=no + ], [$LDFLAG_WERROR]) + ], [$LDFLAG_WERROR]) + ], [ + if test "$enable_stacktraces" = "yes"; then + AC_MSG_ERROR([--enable-stacktraces was specified but execinfo.h was not found]) + fi + AC_MSG_WARN([execinfo.h was not found, stacktraces will be disabled]) + enable_stacktraces=no + ]) + fi + BACKTRACE_LIBS="$BACKTRACE_LIBS -lbacktrace" + dnl More modern compilers may emit DWARF 5 binaries by default, use DWARF 4 out of precaution + if test "$TARGET_OS" != "windows"; then + AX_CHECK_COMPILE_FLAG([-gdwarf-4], [BACKTRACE_FLAGS="$BACKTRACE_FLAGS -gdwarf-4"], [ + if test "$enable_stacktraces" = "yes"; then + AC_MSG_ERROR([--enable-stacktraces was specified but cannot set -gdwarf-4]) + fi + AC_MSG_WARN([cannot set -gdwarf-4, stacktraces will be disabled]) + enable_stacktraces=no + ], [$CXXFLAG_WERROR]) + fi + if test "$TARGET_OS" = "darwin"; then + AX_CHECK_COMPILE_FLAG([-fno-standalone-debug], [BACKTRACE_FLAGS="$BACKTRACE_FLAGS -fno-standalone-debug"], [ + if test "$enable_stacktraces" = "yes"; then + AC_MSG_ERROR([--enable-stacktraces was specified but cannot set -fno-standalone-debug]) + fi + AC_MSG_WARN([cannot set -fno-standalone-debug, stacktraces will be disabled]) + enable_stacktraces=no + ], [$CXXFLAG_WERROR]) + fi + ], [ + if test "$enable_stacktraces" = "yes"; then + AC_MSG_ERROR([--enable-stacktraces was specified but backtrace.h was not found]) + fi + AC_MSG_WARN([backtrace.h was not found, stacktraces will be disabled]) + enable_stacktraces=no + ]) +fi + +AM_CONDITIONAL([ENABLE_STACKTRACES], [test "$enable_stacktraces" = "yes"]) +if test "$enable_stacktraces" = "yes"; then + AC_DEFINE(ENABLE_STACKTRACES, 1, [Define this symbol if stacktraces should be enabled]) +else + enable_crashhooks=no +fi + +AM_CONDITIONAL([ENABLE_CRASH_HOOKS], [test "$enable_crashhooks" = "yes"]) +if test "$enable_crashhooks" = "yes"; then + AC_DEFINE(ENABLE_CRASH_HOOKS, 1, [Define this symbol if crash hooks should be enabled]) +fi + +AX_CHECK_LINK_FLAG([-Wl,-wrap=__cxa_allocate_exception], [LINK_WRAP_SUPPORTED=yes],,,) +AM_CONDITIONAL([CRASH_HOOKS_WRAPPED_CXX_ABI],[test "$LINK_WRAP_SUPPORTED" = "yes"]) + +if test "$LINK_WRAP_SUPPORTED" = "yes"; then + AC_DEFINE(CRASH_HOOKS_WRAPPED_CXX_ABI, 1, [Define this symbol to use wrapped CXX ABIs for exception stacktraces]) fi dnl Check for different ways of gathering OS randomness @@ -1281,15 +1319,6 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include [ AC_MSG_RESULT([no])] ) -dnl ensure backtrace() is found, check -lexecinfo if necessary -if test "$TARGET_OS" != "windows"; then - if test "$enable_stacktraces" != "no"; then - AC_SEARCH_LIBS([backtrace], [execinfo], [], [ - AC_MSG_ERROR([Unable to find backtrace()]) - ]) - fi -fi - AC_MSG_CHECKING([for fdatasync]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[ fdatasync(0); ]])], @@ -1408,6 +1437,7 @@ if test "$enable_fuzz" = "yes"; then bitcoin_enable_qt_dbus=no use_bench=no use_tests=no + use_external_signer=no use_upnp=no use_natpmp=no use_zmq=no @@ -1499,6 +1529,12 @@ if test "$use_usdt" != "no"; then 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" @@ -1508,14 +1544,15 @@ if test "$use_upnp" != "no"; then [AC_CHECK_LIB([miniupnpc], [upnpDiscover], [MINIUPNPC_LIBS="$MINIUPNPC_LIBS -lminiupnpc"], [have_miniupnpc=no], [$MINIUPNPC_LIBS])], [have_miniupnpc=no] ) - dnl The minimum supported miniUPnPc API version is set to 10. This keeps compatibility - dnl with Ubuntu 16.04 LTS and Debian 8 libminiupnpc-dev packages. + + dnl The minimum supported miniUPnPc API version is set to 17. This excludes + dnl versions with known vulnerabilities. if test "$have_miniupnpc" != "no"; then AC_MSG_CHECKING([whether miniUPnPc API version is supported]) AC_PREPROC_IFELSE([AC_LANG_PROGRAM([[ @%:@include ]], [[ - #if MINIUPNPC_API_VERSION >= 10 + #if MINIUPNPC_API_VERSION >= 17 // Everything is okay #else # error miniUPnPc API version is too old @@ -1524,7 +1561,7 @@ if test "$use_upnp" != "no"; then AC_MSG_RESULT([yes]) ],[ AC_MSG_RESULT([no]) - AC_MSG_WARN([miniUPnPc API version < 10 is unsupported, disabling UPnP support.]) + AC_MSG_WARN([miniUPnPc API version < 17 is unsupported, disabling UPnP support.]) have_miniupnpc=no ]) fi @@ -1542,18 +1579,18 @@ if test "$use_natpmp" != "no"; then fi if test "$build_bitcoin_wallet$build_bitcoin_cli$build_bitcoin_tx$build_bitcoind$bitcoin_enable_qt$use_tests$use_bench$enable_fuzz_binary" = "nononononononono"; then - use_boost=no + use_boost=no else - use_boost=yes + 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([[only libdashconsensus can be built without boost]]) -fi + 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([[only libdashconsensus can be built without boost]]) + fi dnl we don't use multi_index serialization BOOST_CPPFLAGS="$BOOST_CPPFLAGS -DBOOST_MULTI_INDEX_DISABLE_SERIALIZATION" @@ -1562,27 +1599,28 @@ fi BOOST_CPPFLAGS="$BOOST_CPPFLAGS -DBOOST_MULTI_INDEX_ENABLE_SAFE_MODE" fi -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 ]])]) - -dnl Opt-in to Boost Process -if test "$boost_process" != "no"; then -AC_MSG_CHECKING(for Boost Process) -AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], - [[ boost::process::child* child = new boost::process::child; delete child; ]])], - [ AC_MSG_RESULT(yes); AC_DEFINE([HAVE_BOOST_PROCESS],,[define if Boost::Process is available])], - [ AC_MSG_ERROR([Boost::Process is not available!])] -) -fi + 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 ]])]) 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 @@ -1658,8 +1696,14 @@ if test "$use_zmq" = "yes"; then fi dnl check if libgmp is present +TEMP_CPPFLAGS="$CPPFLAGS" +TEMP_LDFLAGS="$LDFLAGS" +CPPFLAGS="$CPPFLAGS $GMP_CPPFLAGS" +LDFLAGS="$LDFLAGS $GMP_LDFLAGS" AC_CHECK_HEADER([gmp.h],, AC_MSG_ERROR(libgmp headers missing)) AC_CHECK_LIB([gmp], [__gmpz_init],GMP_LIBS=-lgmp, AC_MSG_ERROR(libgmp missing)) +CPPFLAGS="$TEMP_CPPFLAGS" +LDFLAGS="$TEMP_LDFLAGS" AM_CONDITIONAL([ENABLE_ZMQ], [test "$use_zmq" = "yes"]) @@ -1929,6 +1973,7 @@ 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_WALLET_TOOL_NAME) @@ -1969,11 +2014,15 @@ 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(BACKTRACE_FLAGS) +AC_SUBST(BACKTRACE_LDFLAGS) +AC_SUBST(BACKTRACE_LIBS) AC_SUBST(GMP_LIBS) AC_SUBST(NATPMP_CPPFLAGS) AC_SUBST(NATPMP_LIBS) @@ -1996,6 +2045,9 @@ 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. @@ -2030,7 +2082,7 @@ esac echo echo "Options used to compile and link:" -echo " boost process = $with_boost_process" +echo " external signer = $use_external_signer" echo " multiprocess = $build_multiprocess" echo " with libs = $build_bitcoin_libs" echo " with wallet = $enable_wallet" @@ -2040,36 +2092,36 @@ if test "$enable_wallet" != "no"; then fi echo " with gui / qt = $bitcoin_enable_qt" if test $bitcoin_enable_qt != "no"; then - echo " with qr = $use_qr" + echo " with qr = $use_qr" fi -echo " with zmq = $use_zmq" +echo " with zmq = $use_zmq" if test $enable_fuzz = "no"; then - echo " with test = $use_tests" + echo " with test = $use_tests" else - echo " with test = not building test_dash because fuzzing is enabled" + echo " with test = not building test_dash 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 " stacktraces enabled = $enable_stacktraces" -echo " crash hooks enabled = $enable_crashhooks" -echo " miner enabled = $enable_miner" -echo " gprof enabled = $enable_gprof" -echo " werror = $enable_werror" +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 " stacktraces = $enable_stacktraces" +echo " crash hooks = $enable_crashhooks" +echo " miner enabled = $enable_miner" +echo " gprof enabled = $enable_gprof" +echo " werror = $enable_werror" echo -echo " target os = $host_os" -echo " build os = $build_os" +echo " target os = $host_os" +echo " build os = $build_os" echo -echo " CC = $CC" -echo " CFLAGS = $DEBUG_CFLAGS $PTHREAD_CFLAGS $CFLAGS" -echo " CPPFLAGS = $DEBUG_CPPFLAGS $HARDENED_CPPFLAGS $CORE_CPPFLAGS $CPPFLAGS" -echo " CXX = $CXX" -echo " CXXFLAGS = $DEBUG_CXXFLAGS $HARDENED_CXXFLAGS $WARN_CXXFLAGS $NOWARN_CXXFLAGS $ERROR_CXXFLAGS $GPROF_CXXFLAGS $CORE_CXXFLAGS $CXXFLAGS" -echo " LDFLAGS = $PTHREAD_LIBS $HARDENED_LDFLAGS $GPROF_LDFLAGS $CORE_LDFLAGS $LDFLAGS" -echo " AR = $AR" -echo " ARFLAGS = $ARFLAGS" +echo " CC = $CC" +echo " CFLAGS = $DEBUG_CFLAGS $PTHREAD_CFLAGS $BACKTRACE_FLAGS $CFLAGS" +echo " CPPFLAGS = $DEBUG_CPPFLAGS $HARDENED_CPPFLAGS $CORE_CPPFLAGS $CPPFLAGS" +echo " CXX = $CXX" +echo " CXXFLAGS = $DEBUG_CXXFLAGS $HARDENED_CXXFLAGS $WARN_CXXFLAGS $NOWARN_CXXFLAGS $ERROR_CXXFLAGS $GPROF_CXXFLAGS $CORE_CXXFLAGS $BACKTRACE_FLAGS $CXXFLAGS" +echo " LDFLAGS = $PTHREAD_LIBS $HARDENED_LDFLAGS $GPROF_LDFLAGS $CORE_LDFLAGS $BACKTRACE_LDFLAGS $LDFLAGS" +echo " AR = $AR" +echo " ARFLAGS = $ARFLAGS" echo diff --git a/contrib/containers/ci/ci-slim.Dockerfile b/contrib/containers/ci/ci-slim.Dockerfile index 2bfb3baea243..4abab253573f 100644 --- a/contrib/containers/ci/ci-slim.Dockerfile +++ b/contrib/containers/ci/ci-slim.Dockerfile @@ -31,7 +31,7 @@ ENV DEBIAN_FRONTEND="noninteractive" TZ="Europe/London" # Build and base stuff ENV APT_ARGS="-y --no-install-recommends --no-upgrade" -# Packages needed to build Python and extract artifacts +# Packages needed for builds and tests RUN set -ex; \ apt-get update && apt-get install ${APT_ARGS} \ build-essential \ @@ -40,60 +40,77 @@ RUN set -ex; \ g++ \ git \ libbz2-dev \ - libffi-dev \ liblzma-dev \ - libncurses5-dev \ - libncursesw5-dev \ libreadline-dev \ libsqlite3-dev \ libssl-dev \ make \ - tk-dev \ xz-utils \ zlib1g-dev \ zstd \ && rm -rf /var/lib/apt/lists/* -# Install Python and set it as default -ENV PYENV_ROOT="/usr/local/pyenv" -ENV PATH="${PYENV_ROOT}/shims:${PYENV_ROOT}/bin:${PATH}" +# Install uv by copying from the official Docker image +COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/ + +# Install Python to a system-wide location and set it as default # PYTHON_VERSION should match the value in .python-version -ARG PYTHON_VERSION=3.9.18 +ARG PYTHON_VERSION=3.10.14 +ENV UV_PYTHON_INSTALL_DIR=/usr/local/python +RUN uv python install ${PYTHON_VERSION} + +# Create symlinks to make python available system-wide RUN set -ex; \ - curl https://pyenv.run | bash \ - && pyenv update \ - && pyenv install ${PYTHON_VERSION} \ - && pyenv global ${PYTHON_VERSION} \ - && pyenv rehash + PYTHON_PATH=$(uv python find ${PYTHON_VERSION}); \ + PYTHON_DIR=$(dirname $PYTHON_PATH); \ + ln -sf $PYTHON_DIR/python3 /usr/local/bin/python3; \ + ln -sf $PYTHON_DIR/python3 /usr/local/bin/python; \ + ln -sf $PYTHON_DIR/pip3 /usr/local/bin/pip3 2>/dev/null || true; \ + ln -sf $PYTHON_DIR/pip /usr/local/bin/pip 2>/dev/null || true + +# Use system Python for installations +ENV UV_SYSTEM_PYTHON=1 # Install Python packages -RUN set -ex; \ - pip3 install --no-cache-dir \ - codespell==1.17.1 \ - flake8==3.8.3 \ +RUN uv pip install --system --break-system-packages \ + codespell==2.1.0 \ + flake8==4.0.1 \ jinja2 \ lief==0.13.2 \ multiprocess \ - mypy==0.910 \ - pyzmq==22.3.0 \ - vulture==2.3 + mypy==0.981 \ + pyzmq==24.0.1 \ + vulture==2.6 # Install packages relied on by tests ARG DASH_HASH_VERSION=1.4.0 RUN set -ex; \ cd /tmp; \ git clone --depth 1 --no-tags --branch=${DASH_HASH_VERSION} https://github.com/dashpay/dash_hash; \ - cd dash_hash && pip3 install -r requirements.txt .; \ + cd dash_hash && uv pip install --system --break-system-packages -r requirements.txt .; \ cd .. && rm -rf dash_hash -ARG SHELLCHECK_VERSION=v0.7.1 +# Symlink all Python package executables to /usr/local/bin +RUN set -ex; \ + PYTHON_PATH=$(uv python find ${PYTHON_VERSION}); \ + PYTHON_BIN=$(dirname $PYTHON_PATH); \ + for exe in $PYTHON_BIN/*; do \ + if [ -x "$exe" ] && [ -f "$exe" ]; then \ + basename_exe=$(basename $exe); \ + if [ "$basename_exe" != "python" ] && [ "$basename_exe" != "python3" ] && [ "$basename_exe" != "pip" ] && [ "$basename_exe" != "pip3" ]; then \ + ln -sf "$exe" "/usr/local/bin/$basename_exe"; \ + fi; \ + fi; \ + done + +ARG SHELLCHECK_VERSION=v0.8.0 RUN set -ex; \ curl -fL "https://github.com/koalaman/shellcheck/releases/download/${SHELLCHECK_VERSION}/shellcheck-${SHELLCHECK_VERSION}.linux.x86_64.tar.xz" -o /tmp/shellcheck.tar.xz; \ mkdir -p /opt/shellcheck && tar -xf /tmp/shellcheck.tar.xz -C /opt/shellcheck --strip-components=1 && rm /tmp/shellcheck.tar.xz ENV PATH="/opt/shellcheck:${PATH}" # Packages needed to be able to run sanitizer builds -ARG LLVM_VERSION=18 +ARG LLVM_VERSION=19 RUN set -ex; \ . /etc/os-release; \ curl -fsSL https://apt.llvm.org/llvm-snapshot.gpg.key > /etc/apt/trusted.gpg.d/apt.llvm.org.asc; \ @@ -106,7 +123,7 @@ RUN set -ex; \ ARG USER_ID=1000 \ GROUP_ID=1000 RUN set -ex; \ - groupmod -g ${GROUP_ID} -n dash ubuntu; \ + (getent group ${GROUP_ID} && usermod -g ${GROUP_ID} ubuntu) || groupmod -g ${GROUP_ID} -n dash ubuntu; \ usermod -u ${USER_ID} -md /home/dash -l dash ubuntu; \ chown ${USER_ID}:${GROUP_ID} -R /home/dash; \ mkdir -p /src/dash && \ diff --git a/contrib/containers/develop/docker-compose.yml b/contrib/containers/develop/docker-compose.yml index 9238c97183e7..c6f2cea70424 100644 --- a/contrib/containers/develop/docker-compose.yml +++ b/contrib/containers/develop/docker-compose.yml @@ -4,6 +4,9 @@ services: build: context: '..' dockerfile: './develop/Dockerfile' + args: + USER_ID: 1000 # set this to $(id -u) of the host + GROUP_ID: 1000 # set this to $(id -g) of the host ports: - "9998:9998" # Mainnet Ports - "9999:9999" @@ -13,19 +16,8 @@ services: - seccomp:unconfined stdin_open: true # Equivalent to -i tty: true # Equivalent to -t - -# A note about volumes: -# -# If Docker is interacting with your operating system directly -# without an intermediate VM, then you do not need to change anything -# -# But if not, then you'll need to mount your system's root directory -# (i.e. /) into the boot2docker instance if you want to mirror the exact -# filesystem structure of your host. -# volumes: - type: bind -# source: /host/$PWD # Workaround needed on non-Linux hosts source: ../../.. target: /src/dash diff --git a/contrib/containers/guix/Dockerfile b/contrib/containers/guix/Dockerfile index 89d052403e4c..6e83ca53b7b9 100644 --- a/contrib/containers/guix/Dockerfile +++ b/contrib/containers/guix/Dockerfile @@ -9,7 +9,6 @@ SHELL ["/bin/bash", "-c"] RUN apt-get update && \ apt-get install -y --no-install-recommends --no-upgrade \ build-essential \ - bzip2 \ ca-certificates \ curl \ git \ @@ -52,8 +51,9 @@ RUN guix_file_name=guix-binary-${guix_version}.$(uname -m)-linux.tar.xz RUN touch /etc/nsswitch.conf -RUN guix archive --authorize < /usr/local/guix/current/share/guix/ci.guix.gnu.org.pub && \ - guix archive --authorize < /usr/local/guix/current/share/guix/bordeaux.guix.gnu.org.pub +RUN guix archive --authorize < /usr/local/guix/current/share/guix/berlin.guix.gnu.org.pub && \ + guix archive --authorize < /usr/local/guix/current/share/guix/bordeaux.guix.gnu.org.pub && \ + guix archive --authorize < /usr/local/guix/current/share/guix/ci.guix.gnu.org.pub # Build Environment Setup # https://guix.gnu.org/manual/en/html_node/Build-Environment-Setup.html @@ -73,6 +73,9 @@ RUN groupmod -g ${GROUP_ID} ubuntu; \ echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers # Copy required files to container +COPY --chown=${USER_ID}:${GROUP_ID} \ + --chmod=u=rwX,go=rX \ + --from=docker_root ./channels.scm /home/ubuntu/.config/guix/channels.scm COPY --from=docker_root ./motd.txt /etc/motd COPY --from=docker_root ./scripts/entrypoint /usr/local/bin/entrypoint COPY --from=docker_root ./scripts/guix-check /usr/local/bin/guix-check diff --git a/contrib/containers/guix/channels.scm b/contrib/containers/guix/channels.scm new file mode 100644 index 000000000000..98f965d70968 --- /dev/null +++ b/contrib/containers/guix/channels.scm @@ -0,0 +1,11 @@ +(list (channel + (name 'guix) + (url "https://codeberg.org/guix/guix") + (branch "master") + (commit + "56344729cd07c76d5133047f2866237bbb08dced") + (introduction + (make-channel-introduction + "9edb3f66fd807b096b48283debdcddccfea34bad" + (openpgp-fingerprint + "2A39 3FFF 68F4 EF7A 3D29 12AF 6F51 20A0 22FB B2D5"))))) diff --git a/contrib/containers/guix/scripts/entrypoint b/contrib/containers/guix/scripts/entrypoint index f84cf4227093..019928d49f2c 100755 --- a/contrib/containers/guix/scripts/entrypoint +++ b/contrib/containers/guix/scripts/entrypoint @@ -5,10 +5,21 @@ set -eo pipefail # Read instructions cat /etc/motd +SERVERS=( + # Official substitution servers + https://berlin.guix.gnu.org + https://bordeaux.guix.gnu.org + https://ci.guix.gnu.org + + # Mirrors of Bordeaux substitution server + https://bordeaux-singapore-mirror.cbaines.net + https://bordeaux-us-east-mirror.cbaines.net + https://hydra-guix-129.guix.gnu.org +) + # Start the Guix daemon -sudo env PATH=${PATH} guix-daemon \ - --build-users-group='guixbuild' \ - --substitute-urls='https://bordeaux.guix.gnu.org https://ci.guix.gnu.org' < /dev/null 2>&1 | +sudo env PATH=${PATH} \ + guix-daemon --build-users-group='guixbuild' --substitute-urls="$(IFS=' '; echo "${SERVERS[*]}")" < /dev/null 2>&1 | sudo tee /var/log/guix.log > /dev/null & # Hand over control diff --git a/contrib/containers/guix/scripts/guix-check b/contrib/containers/guix/scripts/guix-check index 12c9983753e2..04363162c12b 100755 --- a/contrib/containers/guix/scripts/guix-check +++ b/contrib/containers/guix/scripts/guix-check @@ -13,13 +13,9 @@ cd "$WORKSPACE_PATH" source "contrib/guix/libexec/prelude.bash" -printf "\nBinaries:\n\n" -( \ -SRC_PATH_PREFIX="${VERSION_BASE}/distsrc-" && \ -sha256sum ${SRC_PATH_PREFIX}*/src/dash{d,-cli,-tx,-wallet}{,.exe} && \ -sha256sum ${SRC_PATH_PREFIX}*/src/qt/dash-qt{,.exe} && \ -sha256sum ${SRC_PATH_PREFIX}*/src/test/test_dash{,.exe} \ -) | sort -k 2 - -printf "\nArchives:\n\n" -find "${OUTDIR_BASE}" -type f | grep -v SHA256 | xargs sha256sum | sort -k 2 +GUIX_SIGS_REPO="$(mktemp -d)" +trap 'rm -rf -- "$GUIX_SIGS_REPO"' EXIT +SIGNER=dummy +env GUIX_SIGS_REPO="${GUIX_SIGS_REPO}" NO_SIGN=1 SIGNER=${SIGNER} ./contrib/guix/guix-attest +SHASUM_LOC="${GUIX_SIGS_REPO}/${VERSION}/${SIGNER}" +cat "${SHASUM_LOC}/all.sha256sums" 2>/dev/null || cat "${SHASUM_LOC}/noncodesigned.SHA256SUMS" diff --git a/contrib/containers/guix/scripts/guix-start b/contrib/containers/guix/scripts/guix-start index 50264c42d0ee..42300bc453b6 100755 --- a/contrib/containers/guix/scripts/guix-start +++ b/contrib/containers/guix/scripts/guix-start @@ -9,10 +9,12 @@ if [[ ! -d "${WORKSPACE_PATH}" || ! "${WORKSPACE_PATH}" = /* || ! -f "${WORKSPAC exit 1 fi -export SDK_PATH="${SDK_PATH:-${WORKSPACE_PATH}/depends/SDKs}" -export SDK_SRCS="${SDK_PATH:-${WORKSPACE_PATH}/depends/sdk-sources}" +if [[ -z "${HOSTS}" || "${HOSTS}" == *"darwin"* ]]; then + export SDK_PATH="${SDK_PATH:-${WORKSPACE_PATH}/depends/SDKs}" + export SDK_SOURCES="${SDK_SOURCES:-${WORKSPACE_PATH}/depends/sdk-sources}" -./contrib/containers/guix/scripts/setup-sdk + ./contrib/containers/guix/scripts/setup-sdk +fi # Add safe.directory option only when WORKSPACE_PATH was specified via cmd-line arguments (happens in CI) if [[ -n "${1}" ]]; then diff --git a/contrib/containers/guix/scripts/setup-sdk b/contrib/containers/guix/scripts/setup-sdk index 4550aeed6424..9781ce07285d 100755 --- a/contrib/containers/guix/scripts/setup-sdk +++ b/contrib/containers/guix/scripts/setup-sdk @@ -9,16 +9,16 @@ set -eo pipefail SDK_URL="${SDK_URL:-https://bitcoincore.org/depends-sources/sdks}" SDK_PATH="${SDK_PATH:-depends/SDKs}" -SDK_SRCS="${SDK_SOURCES:-depends/sdk-sources}" +SDK_SOURCES="${SDK_SOURCES:-depends/sdk-sources}" XCODE_VERSION="${XCODE_VERSION:-15.0}" XCODE_RELEASE="${XCODE_RELEASE:-15A240d}" XCODE_ARCHIVE="Xcode-${XCODE_VERSION}-${XCODE_RELEASE}-extracted-SDK-with-libcxx-headers" -XCODE_AR_PATH="${SDK_SRCS}/${XCODE_ARCHIVE}.tar.gz" +XCODE_AR_PATH="${SDK_SOURCES}/${XCODE_ARCHIVE}.tar.gz" if [ ! -d "${SDK_PATH}/${XCODE_ARCHIVE}" ]; then if [ ! -f "${XCODE_AR_PATH}" ]; then echo "Downloading macOS SDK..." - mkdir -p "${SDK_SRCS}" + mkdir -p "${SDK_SOURCES}" curl --location --fail "${SDK_URL}/${XCODE_ARCHIVE}.tar.gz" -o "${XCODE_AR_PATH}" fi echo "Extracting macOS SDK..." diff --git a/contrib/debian/examples/dash.conf b/contrib/debian/examples/dash.conf index 3bb5690ca496..22965bc6c000 100644 --- a/contrib/debian/examples/dash.conf +++ b/contrib/debian/examples/dash.conf @@ -1,185 +1 @@ -## -## dash.conf configuration file. Lines beginning with # are comments. -## - -# Network-related settings: - -# Note that if you use testnet or regtest, particularly with the options -# addnode, connect, port, bind, rpcport, rpcbind or wallet, you will also -# want to read "[Sections]" further down. - -# Run on the test network instead of the real dash network. -#testnet=0 - -# Run a regression test network -#regtest=0 - -# Connect via a SOCKS5 proxy -#proxy=127.0.0.1:9050 - -# Bind to given address and always listen on it. Use [host]:port notation for IPv6 -#bind= - -# Bind to given address and add permission flags to peers connecting to it. Use [host]:port notation for IPv6 -#whitebind=perm@ - -############################################################## -## Quick Primer on addnode vs connect ## -## Let's say for instance you use addnode=4.2.2.4 ## -## addnode will connect you to and tell you about the ## -## nodes connected to 4.2.2.4. In addition it will tell ## -## the other nodes connected to it that you exist so ## -## they can connect to you. ## -## connect will not do the above when you 'connect' to it. ## -## It will *only* connect you to 4.2.2.4 and no one else.## -## ## -## So if you're behind a firewall, or have other problems ## -## finding nodes, add some using 'addnode'. ## -## ## -## If you want to stay private, use 'connect' to only ## -## connect to "trusted" nodes. ## -## ## -## If you run multiple nodes on a LAN, there's no need for ## -## all of them to open lots of connections. Instead ## -## 'connect' them all to one node that is port forwarded ## -## and has lots of connections. ## -## Thanks goes to [Noodle] on Freenode. ## -############################################################## - -# Use as many addnode= settings as you like to connect to specific peers -#addnode=69.164.218.197 -#addnode=10.0.0.2:9999 - -# Alternatively use as many connect= settings as you like to connect ONLY to specific peers -#connect=69.164.218.197 -#connect=10.0.0.1:9999 - -# Listening mode, enabled by default except when 'connect' is being used -#listen=1 - -# Port on which to listen for connections (default: 9999, testnet: 19999, regtest: 19899) -#port= - -# Maximum number of inbound + outbound connections (default: 125). This option -# applies only if inbound connections are enabled; otherwise, the number of connections -# will not be more than 11: 8 full-relay connections, 2 block-relay-only ones, and -# occasionally 1 short-lived feeler or extra outbound block-relay-only connection. -# These limits do not apply to connections added manually with the -addnode -# configuration option or the addnode RPC, which have a separate limit of 8 connections. -#maxconnections= - -# Maximum upload bandwidth target in MiB per day (e.g. 'maxuploadtarget=1024' is 1 GiB per day). -# This limits the upload bandwidth for those with bandwidth limits. 0 = no limit (default: 0). -# -maxuploadtarget does not apply to peers with 'download' permission. -# For more information on reducing bandwidth utilization, see: doc/reduce-traffic.md. -#maxuploadtarget= - -# -# JSON-RPC options (for controlling a running Dash/dashd process) -# - -# server=1 tells Dash-Qt and dashd to accept JSON-RPC commands -#server=0 - -# Bind to given address to listen for JSON-RPC connections. -# Refer to the manpage or dashd -help for further details. -#rpcbind= - -# If no rpcpassword is set, rpc cookie auth is sought. The default `-rpccookiefile` name -# is .cookie and found in the `-datadir` being used for dashd. This option is typically used -# when the server and client are run as the same user. -# -# If not, you must set rpcuser and rpcpassword to secure the JSON-RPC API. -# -# The config option `rpcauth` can be added to server startup argument. It is set at initialization time -# using the output from the script in share/rpcauth/rpcauth.py after providing a username: -# -# ./share/rpcauth/rpcauth.py alice -# String to be appended to dash.conf: -# rpcauth=alice:f7efda5c189b999524f151318c0c86$d5b51b3beffbc02b724e5d095828e0bc8b2456e9ac8757ae3211a5d9b16a22ae -# Your password: -# DONT_USE_THIS_YOU_WILL_GET_ROBBED_8ak1gI25KFTvjovL3gAM967mies3E= -# -# On client-side, you add the normal user/password pair to send commands: -#rpcuser=alice -#rpcpassword=DONT_USE_THIS_YOU_WILL_GET_ROBBED_8ak1gI25KFTvjovL3gAM967mies3E= -# -# You can even add multiple entries of these to the server conf file, and client can use any of them: -# rpcauth=bob:b2dd077cb54591a2f3139e69a897ac$4e71f08d48b4347cf8eff3815c0e25ae2e9a4340474079f55705f40574f4ec99 - -# How many seconds Dash Core will wait for a complete RPC HTTP request. -# after the HTTP connection is established. -#rpcclienttimeout=30 - -# By default, only RPC connections from localhost are allowed. -# Specify as many rpcallowip= settings as you like to allow connections from other hosts, -# either as a single IPv4/IPv6 or with a subnet specification. - -# NOTE: opening up the RPC port to hosts outside your local trusted network is NOT RECOMMENDED, -# because the rpcpassword is transmitted over the network unencrypted. - -# server=1 tells Dash-Qt to accept JSON-RPC commands. -# it is also read by dashd to determine if RPC should be enabled -#rpcallowip=10.1.1.34/255.255.255.0 -#rpcallowip=1.2.3.4/24 -#rpcallowip=2001:db8:85a3:0:0:8a2e:370:7334/96 - -# Listen for RPC connections on this TCP port: -#rpcport=9998 - -# You can use Dash or dashd to send commands to Dash/dashd -# running on another host using this option: -#rpcconnect=127.0.0.1 - -# Wallet options - -# Specify where to find wallet, lockfile and logs. If not present, those files will be -# created as new. -#wallet= - -# Create transactions that have enough fees so they are likely to begin confirmation within n blocks (default: 6). -# This setting is over-ridden by the -paytxfee option. -#txconfirmtarget=n - -# Pay a transaction fee every time you send dash. -#paytxfee=0.000x - -# Miscellaneous options - -# Pre-generate this many public/private key pairs, so wallet backups will be valid for -# both prior transactions and several dozen future transactions. -#keypool=100 - -# Maintain coinstats index used by the gettxoutsetinfo RPC (default: 0). -#coinstatsindex=1 - -# Enable pruning to reduce storage requirements by deleting old blocks. -# This mode is incompatible with -txindex, -coinstatsindex and -rescan. -# 0 = default (no pruning). -# 1 = allows manual pruning via RPC. -# >=945 = target to stay under in MiB. -#prune=945 - -# User interface options - -# Start Dash minimized -#min=1 - -# Minimize to the system tray -#minimizetotray=1 - -# [Sections] -# Most options apply to mainnet, testnet and regtest. -# If you want to confine an option to just one network, you should add it in the -# relevant section below. -# EXCEPTIONS: The options addnode, connect, port, bind, rpcport, rpcbind and wallet -# only apply to mainnet unless they appear in the appropriate section below. - -# Options only for mainnet -[main] - -# Options only for testnet -[test] - -# Options only for regtest -[regtest] +# This is a placeholder file. Please follow the instructions in `contrib/devtools/README.md` to generate a dash.conf file. diff --git a/contrib/devtools/README.md b/contrib/devtools/README.md index 4aadde68ab4b..31cc1f032c77 100644 --- a/contrib/devtools/README.md +++ b/contrib/devtools/README.md @@ -90,6 +90,21 @@ example: BUILDDIR=$PWD/build contrib/devtools/gen-manpages.py ``` +gen-dash-conf.sh +=================== + +Generates a dash.conf file in `contrib/debian/examples/` by parsing the output from `dashd --help`. This script is run during the +release process to include a dash.conf with the release binaries and can also be run by users to generate a file locally. +When generating a file as part of the release process, make sure to commit the changes after running the script. + +With in-tree builds this tool can be run from any directory within the +repository. To use this tool with out-of-tree builds set `BUILDDIR`. For +example: + +```bash +BUILDDIR=$PWD/build contrib/devtools/gen-dash-conf.sh +``` + github-merge.py =============== diff --git a/contrib/devtools/copyright_header.py b/contrib/devtools/copyright_header.py index c18c156d5f5e..a1b13e97c5dd 100755 --- a/contrib/devtools/copyright_header.py +++ b/contrib/devtools/copyright_header.py @@ -330,15 +330,13 @@ def get_most_recent_git_change_year(filename): ################################################################################ def read_file_lines(filename): - f = open(filename, 'r', encoding="utf8") - file_lines = f.readlines() - f.close() + with open(filename, 'r', encoding="utf8") as f: + file_lines = f.readlines() return file_lines def write_file_lines(filename, file_lines): - f = open(filename, 'w', encoding="utf8") - f.write(''.join(file_lines)) - f.close() + with open(filename, 'w', encoding="utf8") as f: + f.write(''.join(file_lines)) ################################################################################ # update header years execution diff --git a/contrib/devtools/gen-dash-conf.sh b/contrib/devtools/gen-dash-conf.sh new file mode 100755 index 000000000000..ebc93daf75a8 --- /dev/null +++ b/contrib/devtools/gen-dash-conf.sh @@ -0,0 +1,80 @@ +#!/usr/bin/env bash +# 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. + +export LC_ALL=C +TOPDIR=${TOPDIR:-$(git rev-parse --show-toplevel)} +BUILDDIR=${BUILDDIR:-$TOPDIR} +BINDIR=${BINDIR:-$BUILDDIR/src} +DASHD=${DASHD:-$BINDIR/dashd} +SHARE_EXAMPLES_DIR=${SHARE_EXAMPLES_DIR:-$TOPDIR/contrib/debian/examples/} +EXAMPLE_CONF_FILE=${EXAMPLE_CONF_FILE:-$SHARE_EXAMPLES_DIR/dash.conf} + +[ ! -x "$DASHD" ] && echo "$DASHD not found or not executable." && exit 1 + +DIRTY="" +VERSION_OUTPUT=$($DASHD --version) +if [[ $VERSION_OUTPUT == *"dirty"* ]]; then + DIRTY="${DIRTY}${DASHD}\n" +fi + +if [ -n "$DIRTY" ] +then + echo -e "WARNING: $DASHD was built from a dirty tree.\n" + echo -e "To safely generate a dash.conf file, please commit your changes to $DASHD, rebuild, then run this script again.\n" +fi + +echo 'Generating example dash.conf file in contrib/debian/examples/' + +# create the directory, if it doesn't exist +mkdir -p "${SHARE_EXAMPLES_DIR}" + +# create the header text +cat > "${EXAMPLE_CONF_FILE}" << 'EOF' +## +## dash.conf configuration file. +## Generated by contrib/devtools/gen-dash-conf.sh. +## +## Lines beginning with # are comments. +## All possible configuration options are provided. To use, copy this file +## to your data directory (default or specified by -datadir), uncomment +## options you would like to change, and save the file. +## + + +### Options +EOF + +# parse the output from dashd --help +# adding newlines is a bit funky to ensure portability for BSD +# see here for more details: https://stackoverflow.com/a/24575385 +${DASHD} --help \ + | sed '1,/Print this help message and exit/d' \ + | sed -E 's/^[[:space:]]{2}\-/#/' \ + | sed -E 's/^[[:space:]]{7}/# /' \ + | sed -E '/[=[:space:]]/!s/#.*$/&=1/' \ + | awk '/^#[a-z]/{x=$0;next}{if (NF==0) print x"\n",x="";else print}' \ + | sed 's,\(^[[:upper:]].*\)\:$,\ +### \1,' \ + | sed 's/[[:space:]]*$//' >> "${EXAMPLE_CONF_FILE}" + +# create the footer text +cat >> "${EXAMPLE_CONF_FILE}" << 'EOF' + +# [Sections] +# Most options will apply to all networks. To confine an option to a specific +# network, add it under the relevant section below. +# +# Note: If not specified under a network section, the options addnode, connect, +# port, bind, rpcport, rpcbind, and wallet will only apply to mainnet. + +# Options for mainnet +[main] + +# Options for testnet +[test] + +# Options for regtest +[regtest] +EOF diff --git a/contrib/devtools/iwyu/bitcoin.core.imp b/contrib/devtools/iwyu/bitcoin.core.imp index ce7786f58c24..c4c4ba4cebd8 100644 --- a/contrib/devtools/iwyu/bitcoin.core.imp +++ b/contrib/devtools/iwyu/bitcoin.core.imp @@ -1,6 +1,3 @@ -# Fixups / upstreamed changes +# Nothing for now. [ - { include: [ "", private, "", public ] }, - { include: [ "", private, "", public ] }, - { include: [ "", private, "", public ] }, ] diff --git a/contrib/devtools/split-debug.sh.in b/contrib/devtools/split-debug.sh.in index 92b72b1446cf..7ad5f6ed5ad7 100644 --- a/contrib/devtools/split-debug.sh.in +++ b/contrib/devtools/split-debug.sh.in @@ -6,5 +6,5 @@ fi @OBJCOPY@ --enable-deterministic-archives -p --only-keep-debug $1 $3 @OBJCOPY@ --enable-deterministic-archives -p --strip-debug $1 $2 -@STRIP@ --enable-deterministic-archives -p -s $2 +@STRIP@ --enable-deterministic-archives -p --strip-debug --strip-unneeded $2 @OBJCOPY@ --enable-deterministic-archives -p --add-gnu-debuglink=$3 $2 diff --git a/contrib/devtools/symbol-check.py b/contrib/devtools/symbol-check.py index a89cd32e83d2..c296ad16fb9a 100755 --- a/contrib/devtools/symbol-check.py +++ b/contrib/devtools/symbol-check.py @@ -163,7 +163,8 @@ 'msvcrt.dll', # C standard library for MSVC 'SHELL32.dll', # shell API 'WS2_32.dll', # sockets -'bcrypt.dll', +'bcrypt.dll', # crypto API +'dbghelp.dll', # debugging routines # bitcoin-qt only 'dwmapi.dll', # desktop window manager 'GDI32.dll', # graphics device interface @@ -252,7 +253,7 @@ def check_MACHO_sdk(binary) -> bool: return False def check_MACHO_lld(binary) -> bool: - if binary.build_version.tools[0].version == [18, 1, 8]: + if binary.build_version.tools[0].version == [19, 1, 4]: return True return False @@ -285,7 +286,8 @@ def check_ELF_ABI(binary) -> bool: CHECKS = { lief.EXE_FORMATS.ELF: [ ('IMPORTED_SYMBOLS', check_imported_symbols), - ('EXPORTED_SYMBOLS', check_exported_symbols), + # Dash: We export symbols aggressively to aid in backtrace generation + # ('EXPORTED_SYMBOLS', check_exported_symbols), ('LIBRARY_DEPENDENCIES', check_ELF_libraries), ('INTERPRETER_NAME', check_ELF_interpreter), ('ABI', check_ELF_ABI), diff --git a/contrib/devtools/test-security-check.py b/contrib/devtools/test-security-check.py index 035a6e696877..d64d08fb732f 100755 --- a/contrib/devtools/test-security-check.py +++ b/contrib/devtools/test-security-check.py @@ -16,10 +16,10 @@ def write_testcode(filename): with open(filename, 'w', encoding="utf8") as f: f.write(''' - #include + #include 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; } ''') @@ -35,17 +35,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, source, executable, options): - subprocess.run([*cc,source,'-o',executable] + env_flags() + options, check=True) +def call_security_check(cxx, source, executable, options): + 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, universal_newlines=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) @@ -53,93 +53,93 @@ def get_arch(cc, source, executable): class TestSecurityChecks(unittest.TestCase): def test_ELF(self): - source = 'test1.c' + source = 'test1.cpp' executable = 'test1' - cc = determine_wellknown_cmd('CC', 'gcc') + cxx = determine_wellknown_cmd('CXX', 'g++') write_testcode(source) - arch = get_arch(cc, source, executable) + arch = get_arch(cxx, source, executable) if arch == lief.ARCHITECTURES.X86: - self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-zexecstack','-Wl,-znorelro','-no-pie','-fno-PIE', '-Wl,-z,separate-code']), + self.assertEqual(call_security_check(cxx, source, executable, ['-Wl,-zexecstack','-Wl,-znorelro','-no-pie','-fno-PIE', '-Wl,-z,separate-code']), (1, executable+': failed PIE NX RELRO CONTROL_FLOW')) - self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-Wl,-znorelro','-no-pie','-fno-PIE', '-Wl,-z,separate-code']), + self.assertEqual(call_security_check(cxx, source, executable, ['-Wl,-znoexecstack','-Wl,-znorelro','-no-pie','-fno-PIE', '-Wl,-z,separate-code']), (1, executable+': failed PIE RELRO CONTROL_FLOW')) - self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-Wl,-znorelro','-no-pie','-fno-PIE', '-Wl,-z,separate-code']), + self.assertEqual(call_security_check(cxx, source, executable, ['-Wl,-znoexecstack','-Wl,-znorelro','-no-pie','-fno-PIE', '-Wl,-z,separate-code']), (1, executable+': failed PIE RELRO CONTROL_FLOW')) - self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-Wl,-znorelro','-pie','-fPIE', '-Wl,-z,separate-code']), + self.assertEqual(call_security_check(cxx, source, executable, ['-Wl,-znoexecstack','-Wl,-znorelro','-pie','-fPIE', '-Wl,-z,separate-code']), (1, executable+': failed RELRO CONTROL_FLOW')) - self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-Wl,-zrelro','-Wl,-z,now','-pie','-fPIE', '-Wl,-z,noseparate-code']), + self.assertEqual(call_security_check(cxx, source, executable, ['-Wl,-znoexecstack','-Wl,-zrelro','-Wl,-z,now','-pie','-fPIE', '-Wl,-z,noseparate-code']), (1, executable+': failed separate_code CONTROL_FLOW')) - self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-Wl,-zrelro','-Wl,-z,now','-pie','-fPIE', '-Wl,-z,separate-code']), + self.assertEqual(call_security_check(cxx, source, executable, ['-Wl,-znoexecstack','-Wl,-zrelro','-Wl,-z,now','-pie','-fPIE', '-Wl,-z,separate-code']), (1, executable+': failed CONTROL_FLOW')) - self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-Wl,-zrelro','-Wl,-z,now','-pie','-fPIE', '-Wl,-z,separate-code', '-fcf-protection=full']), + self.assertEqual(call_security_check(cxx, source, executable, ['-Wl,-znoexecstack','-Wl,-zrelro','-Wl,-z,now','-pie','-fPIE', '-Wl,-z,separate-code', '-fcf-protection=full']), (0, '')) else: - self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-zexecstack','-Wl,-znorelro','-no-pie','-fno-PIE', '-Wl,-z,separate-code']), + self.assertEqual(call_security_check(cxx, source, executable, ['-Wl,-zexecstack','-Wl,-znorelro','-no-pie','-fno-PIE', '-Wl,-z,separate-code']), (1, executable+': failed PIE NX RELRO')) - self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-Wl,-znorelro','-no-pie','-fno-PIE', '-Wl,-z,separate-code']), + self.assertEqual(call_security_check(cxx, source, executable, ['-Wl,-znoexecstack','-Wl,-znorelro','-no-pie','-fno-PIE', '-Wl,-z,separate-code']), (1, executable+': failed PIE RELRO')) - self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-Wl,-znorelro','-no-pie','-fno-PIE', '-Wl,-z,separate-code']), + self.assertEqual(call_security_check(cxx, source, executable, ['-Wl,-znoexecstack','-Wl,-znorelro','-no-pie','-fno-PIE', '-Wl,-z,separate-code']), (1, executable+': failed PIE RELRO')) - self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-Wl,-znorelro','-pie','-fPIE', '-Wl,-z,separate-code']), + self.assertEqual(call_security_check(cxx, source, executable, ['-Wl,-znoexecstack','-Wl,-znorelro','-pie','-fPIE', '-Wl,-z,separate-code']), (1, executable+': failed RELRO')) - self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-Wl,-zrelro','-Wl,-z,now','-pie','-fPIE', '-Wl,-z,noseparate-code']), + self.assertEqual(call_security_check(cxx, source, executable, ['-Wl,-znoexecstack','-Wl,-zrelro','-Wl,-z,now','-pie','-fPIE', '-Wl,-z,noseparate-code']), (1, executable+': failed separate_code')) - self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-Wl,-zrelro','-Wl,-z,now','-pie','-fPIE', '-Wl,-z,separate-code']), + self.assertEqual(call_security_check(cxx, source, executable, ['-Wl,-znoexecstack','-Wl,-zrelro','-Wl,-z,now','-pie','-fPIE', '-Wl,-z,separate-code']), (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']), + self.assertEqual(call_security_check(cxx, 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']), + self.assertEqual(call_security_check(cxx, 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']), + self.assertEqual(call_security_check(cxx, 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']), + self.assertEqual(call_security_check(cxx, 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']), + self.assertEqual(call_security_check(cxx, 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']), + self.assertEqual(call_security_check(cxx, 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']), + self.assertEqual(call_security_check(cxx, source, executable, ['-Wl,--nxcompat','-Wl,--enable-reloc-section','-Wl,--dynamicbase','-Wl,--high-entropy-va','-pie','-fPIE', '-fcf-protection=full','-fstack-protector-all', '-lssp']), (0, '')) clean_files(source, executable) 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']), + self.assertEqual(call_security_check(cxx, 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']), + self.assertEqual(call_security_check(cxx, 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']), + self.assertEqual(call_security_check(cxx, 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']), + self.assertEqual(call_security_check(cxx, 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']), + self.assertEqual(call_security_check(cxx, source, executable, ['-fstack-protector-all', '-fcf-protection=full', '-Wl,-fixup_chains']), (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']), + self.assertEqual(call_security_check(cxx, 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']), + self.assertEqual(call_security_check(cxx, 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']), + self.assertEqual(call_security_check(cxx, 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']), + self.assertEqual(call_security_check(cxx, source, executable, ['-fstack-protector-all', '-Wl,-fixup_chains', '-mbranch-protection=bti']), (0, '')) diff --git a/contrib/devtools/test-symbol-check.py b/contrib/devtools/test-symbol-check.py index 44482bc2f1ad..92966000406b 100755 --- a/contrib/devtools/test-symbol-check.py +++ b/contrib/devtools/test-symbol-check.py @@ -12,17 +12,17 @@ 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, universal_newlines=True) os.remove(source) os.remove(executable) @@ -30,13 +30,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(''' @@ -49,31 +49,31 @@ def test_ELF(self): } ''') - 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 + #include 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(''' @@ -87,11 +87,11 @@ def test_MACHO(self): ''') - 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(''' @@ -104,10 +104,10 @@ def test_MACHO(self): } ''') - 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(''' @@ -117,13 +117,13 @@ def test_MACHO(self): } ''') - self.assertEqual(call_symbol_check(cc, source, executable, ['-Wl,-platform_version','-Wl,macos', '-Wl,11.0', '-Wl,11.4']), + self.assertEqual(call_symbol_check(cxx, source, executable, ['-Wl,-platform_version','-Wl,macos', '-Wl,11.0', '-Wl,11.4']), (1, f'{executable}: failed SDK')) def test_PE(self): - source = 'test1.c' + source = 'test1.cpp' executable = 'test1.exe' - cc = determine_wellknown_cmd('CC', 'x86_64-w64-mingw32-gcc') + cxx = determine_wellknown_cmd('CXX', 'x86_64-w64-mingw32-g++') with open(source, 'w', encoding="utf8") as f: f.write(''' @@ -136,11 +136,11 @@ def test_PE(self): } ''') - 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: @@ -151,10 +151,10 @@ def test_PE(self): } ''') - 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(''' @@ -167,7 +167,7 @@ def test_PE(self): } ''') - 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/flatpak/org.dash.dash-core.metainfo.xml b/contrib/flatpak/org.dash.dash-core.metainfo.xml new file mode 100644 index 000000000000..5302b44b2b5a --- /dev/null +++ b/contrib/flatpak/org.dash.dash-core.metainfo.xml @@ -0,0 +1,34 @@ + + + org.dash.dash-core + Dash Core + MIT + CC0-1.0 + Fully validating Dash peer-to-peer network node, wallet and GUI + https://dash.org/ + https://github.com/dashpay/dash/issues/new?title=[flatpak] + org.dash.dash-core.desktop + +

+ Dash Core connects to the Dash peer-to-peer network to download and + fully validate blocks and transactions. It also includes a wallet and + graphical user interface. +

+
+ + + https://docs.dash.org/en/stable/_images/overview.png + + + + + + + + + intense + + + Dash Core Group + +
diff --git a/contrib/guix/Dockerfile b/contrib/guix/Dockerfile deleted file mode 100644 index bffb10f75c48..000000000000 --- a/contrib/guix/Dockerfile +++ /dev/null @@ -1,63 +0,0 @@ -FROM alpine:3.17 - -RUN apk --no-cache --update add \ - bash \ - bzip2 \ - ca-certificates \ - curl \ - git \ - make \ - shadow - -ARG guix_download_path=ftp://ftp.gnu.org/gnu/guix -ARG guix_version=1.4.0 -ARG guix_checksum_aarch64=72d807392889919940b7ec9632c45a259555e6b0942ea7bfd131101e08ebfcf4 -ARG guix_checksum_x86_64=236ca7c9c5958b1f396c2924fcc5bc9d6fdebcb1b4cf3c7c6d46d4bf660ed9c9 -ARG builder_count=32 - -ENV PATH="/root/.config/guix/current/bin:$PATH" - -# Application Setup -# https://guix.gnu.org/manual/en/html_node/Application-Setup.html -ENV GUIX_LOCPATH="/root/.guix-profile/lib/locale" -ENV LC_ALL="en_US.UTF-8" - -RUN guix_file_name=guix-binary-${guix_version}.$(uname -m)-linux.tar.xz && \ - eval "guix_checksum=\${guix_checksum_$(uname -m)}" && \ - cd /tmp && \ - wget -q -O "$guix_file_name" "${guix_download_path}/${guix_file_name}" && \ - echo "${guix_checksum} ${guix_file_name}" | sha256sum -c && \ - tar xJf "$guix_file_name" && \ - mv var/guix /var/ && \ - mv gnu / && \ - mkdir -p ~root/.config/guix && \ - ln -sf /var/guix/profiles/per-user/root/current-guix ~root/.config/guix/current && \ - source ~root/.config/guix/current/etc/profile - -# Guix expects this file to exist -RUN touch /etc/nsswitch.conf - -RUN guix archive --authorize < ~root/.config/guix/current/share/guix/ci.guix.gnu.org.pub - -# Build Environment Setup -# https://guix.gnu.org/manual/en/html_node/Build-Environment-Setup.html - -RUN groupadd --system guixbuild -RUN for i in $(seq -w 1 ${builder_count}); do \ - useradd -g guixbuild -G guixbuild \ - -d /var/empty -s $(which nologin) \ - -c "Guix build user ${i}" --system \ - "guixbuilder${i}" ; \ - done - -ENTRYPOINT ["/root/.config/guix/current/bin/guix-daemon","--build-users-group=guixbuild"] - -RUN git clone https://github.com/dashpay/dash.git /dash - -RUN mkdir base_cache sources SDKs - -WORKDIR /dash - -RUN mkdir -p depends/SDKs && \ - curl -L https://bitcoincore.org/depends-sources/sdks/Xcode-15.0-15A240d-extracted-SDK-with-libcxx-headers.tar.gz | tar -xz -C depends/SDKs - diff --git a/contrib/guix/INSTALL.md b/contrib/guix/INSTALL.md index f2d635895963..b347c8350858 100644 --- a/contrib/guix/INSTALL.md +++ b/contrib/guix/INSTALL.md @@ -19,7 +19,6 @@ Otherwise, you may choose from one of the following options to install Guix: - Installs any release - Binary installation only, requires high level of trust 3. Using **Docker image** [↗︎ external instructions][install-docker] - - Maintained by pastapastapasta - Easy (automatically performs *some* setup) - Works wherever Docker images work - Installs any release @@ -59,8 +58,8 @@ so you should log out and log back in. ## Option 3: Using Docker image -Please refer to Docker's image -[here](https://github.com/dashpay/dash/tree/master/contrib/guix/Dockerfile). +Please refer to Docker image +[here](https://github.com/dashpay/dash/tree/master/contrib/containers/guix/Dockerfile). ## Option 4: Using a distribution-maintained package @@ -319,7 +318,7 @@ Source: https://logs.guix.gnu.org/guix/2020-11-12.log#232527 Start by cloning Guix: ``` -git clone https://git.savannah.gnu.org/git/guix.git +git clone https://codeberg.org/guix/guix.git cd guix ``` @@ -607,7 +606,7 @@ checklist. ``` Generation 38 Feb 22 2021 16:39:31 (current) guix f350df4 - repository URL: https://git.savannah.gnu.org/git/guix.git + repository URL: https://codeberg.org/guix/guix.git branch: version-1.2.0 commit: f350df405fbcd5b9e27e6b6aa500da7f101f41e7 ``` @@ -760,8 +759,8 @@ Please see the following links for more details: - An upstream coreutils bug has been filed: [debbugs#47940](https://debbugs.gnu.org/cgi/bugreport.cgi?bug=47940) - A Guix bug detailing the underlying problem has been filed: [guix-issues#47935](https://issues.guix.gnu.org/47935), [guix-issues#49985](https://issues.guix.gnu.org/49985#5) -- A commit to skip this test in Guix has been merged into the core-updates branch: -[savannah/guix@6ba1058](https://git.savannah.gnu.org/cgit/guix.git/commit/?id=6ba1058df0c4ce5611c2367531ae5c3cdc729ab4) +- A commit to skip this test is included since Guix 1.4.0: +[codeberg/guix@6ba1058](https://codeberg.org/guix/guix/commit/6ba1058df0c4ce5611c2367531ae5c3cdc729ab4) [install-script]: #options-1-and-2-using-the-official-shell-installer-script-or-binary-tarball diff --git a/contrib/guix/README.md b/contrib/guix/README.md index 94536700f855..5e468c783977 100644 --- a/contrib/guix/README.md +++ b/contrib/guix/README.md @@ -364,12 +364,6 @@ Where `` is likely: - `/usr/local` if you installed Guix from source and didn't supply any prefix-modifying flags to Guix's `./configure` -For dongcarl's substitute server at https://guix.carldong.io, run as root: - -```sh -wget -qO- 'https://guix.carldong.io/signing-key.pub' | guix archive --authorize -``` - #### Removing authorized keys To remove previously authorized keys, simply edit `/etc/guix/acl` and remove the @@ -381,28 +375,28 @@ Once its key is authorized, the official Guix build farm at https://ci.guix.gnu.org is automatically used unless the `--no-substitutes` flag is supplied. This default list of substitute servers is overridable both on a `guix-daemon` level and when you invoke `guix` commands. See examples below for -the various ways of adding dongcarl's substitute server after having [authorized -his signing key](#step-1-authorize-the-signing-keys). +the various ways of adding a substitute server after having [authorized +its signing key](#step-1-authorize-the-signing-keys). Change the **default list** of substitute servers by starting `guix-daemon` with the `--substitute-urls` option (you will likely need to edit your init script): ```sh -guix-daemon --substitute-urls='https://guix.carldong.io https://ci.guix.gnu.org' +guix-daemon --substitute-urls='https://bordeaux.guix.gnu.org https://ci.guix.gnu.org' ``` Override the default list of substitute servers by passing the `--substitute-urls` option for invocations of `guix` commands: ```sh -guix --substitute-urls='https://guix.carldong.io https://ci.guix.gnu.org' +guix --substitute-urls='https://bordeaux.guix.gnu.org https://ci.guix.gnu.org' ``` For scripts under `./contrib/guix`, set the `SUBSTITUTE_URLS` environment variable: ```sh -export SUBSTITUTE_URLS='https://guix.carldong.io https://ci.guix.gnu.org' +export SUBSTITUTE_URLS='https://bordeaux.guix.gnu.org https://ci.guix.gnu.org' ``` ## Option 2: Disabling substitutes on an ad-hoc basis diff --git a/contrib/guix/guix-build b/contrib/guix/guix-build index 122c8dc22df1..80b719eb29d8 100755 --- a/contrib/guix/guix-build +++ b/contrib/guix/guix-build @@ -69,6 +69,12 @@ fi mkdir -p "$VERSION_BASE" +################ +# SOURCE_DATE_EPOCH should not unintentionally be set +################ + +check_source_date_epoch + ################ # Build directories should not exist ################ diff --git a/contrib/guix/guix-codesign b/contrib/guix/guix-codesign index 3ce038186550..e17e3a07a66b 100755 --- a/contrib/guix/guix-codesign +++ b/contrib/guix/guix-codesign @@ -67,6 +67,12 @@ EOF exit 1 fi +################ +# SOURCE_DATE_EPOCH should not unintentionally be set +################ + +check_source_date_epoch + ################ # The codesignature git worktree should not be dirty ################ diff --git a/contrib/guix/libexec/build.sh b/contrib/guix/libexec/build.sh index 1bb910b7cc4a..4e378b000979 100755 --- a/contrib/guix/libexec/build.sh +++ b/contrib/guix/libexec/build.sh @@ -238,8 +238,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" @@ -343,6 +341,61 @@ mkdir -p "$DISTSRC" find "${DISTNAME}/bin" -type f -executable -print0 find "${DISTNAME}/lib" -type f -print0 } | xargs -0 -P"$JOBS" -I{} "${DISTSRC}/contrib/devtools/split-debug.sh" {} {} {}.dbg + + case "$HOST" in + *linux*) + # Compress DWARF sections in debug files and set proper permissions + find "${DISTNAME}" -name "*.dbg" -type f -print0 | xargs -0 -P"$JOBS" -I{} sh -c "${HOST}-objcopy --compress-debug-sections=zlib \"\$1\" \"\$1.tmp\" && mv \"\$1.tmp\" \"\$1\" && chmod 644 \"\$1\"" _ {} + + # Create .build-id tree for perf auto-discovery + mkdir -p "${DISTNAME}/usr/lib/debug/.build-id" + { + find "${DISTNAME}/bin" -type f -executable -print0 + find "${DISTNAME}/lib" -type f -print0 + } | while IFS= read -r -d '' elf; do + if file "$elf" | grep -q "ELF.*executable\|ELF.*shared object"; then + build_id=$("${HOST}"-readelf -n "$elf" 2>/dev/null | awk '/Build ID/ {print $3; exit}') + if [ -n "$build_id" ] && [ -f "${elf}.dbg" ]; then + dir="${DISTNAME}/usr/lib/debug/.build-id/${build_id:0:2}" + mkdir -p "$dir" + cp "${elf}.dbg" "${dir}/${build_id:2}.debug" + chmod 644 "${dir}/${build_id:2}.debug" + fi + fi + done + + # Verify build-ids and debug links + verification_output=$( + { + find "${DISTNAME}/bin" -type f -executable -print0 + find "${DISTNAME}/lib" -type f -print0 + } | { + verification_failed=0 + while IFS= read -r -d '' elf; do + if file "$elf" | grep -q "ELF.*executable\|ELF.*shared object"; then + # Check for build-id + if ! "${HOST}"-readelf -n "$elf" 2>/dev/null | grep -q "Build ID"; then + echo "ERROR: No build-id found in $elf" >&2 + verification_failed=1 + fi + + # Check for .gnu_debuglink + if ! "${HOST}"-readelf --string-dump=.gnu_debuglink "$elf" >/dev/null 2>&1; then + echo "ERROR: No .gnu_debuglink found in $elf" >&2 + verification_failed=1 + fi + fi + done + exit "$verification_failed" + } 2>&1 + ) + verification_status=$? + if [ "$verification_status" -ne 0 ]; then + echo "$verification_output" >&2 + exit 1 + fi + ;; + esac ;; esac @@ -355,6 +408,12 @@ mkdir -p "$DISTSRC" ;; esac + # copy over the example dash.conf file. if contrib/devtools/gen-dash-conf.sh + # has not been run before buildling, this file will be a stub + cp "${DISTSRC}/contrib/debian/examples/dash.conf" "${DISTNAME}/" + + cp -r "${DISTSRC}/share/rpcauth" "${DISTNAME}/share/" + # Finally, deterministically produce {non-,}debug binary tarballs ready # for release case "$HOST" in @@ -373,12 +432,14 @@ mkdir -p "$DISTSRC" || ( rm -f "${OUTDIR}/${DISTNAME}-${HOST//x86_64-w64-mingw32/win64}-debug.zip" && exit 1 ) ;; *linux*) - find "${DISTNAME}" -not -name "*.dbg" -print0 \ + # Main (non-debug) tarball: exclude separate debug files and the build-id debug tree + find "${DISTNAME}" -not -name "*.dbg" -not -path "${DISTNAME}/usr/lib/debug/*" -print0 \ | sort --zero-terminated \ | tar --create --no-recursion --mode='u+rw,go+r-w,a+X' --null --files-from=- \ | gzip -9n > "${OUTDIR}/${DISTNAME}-${HOST}.tar.gz" \ || ( rm -f "${OUTDIR}/${DISTNAME}-${HOST}.tar.gz" && exit 1 ) - find "${DISTNAME}" -name "*.dbg" -print0 \ + # Debug tarball: include .dbg files and the build-id debug tree + find "${DISTNAME}" \( -name "*.dbg" -o -path "${DISTNAME}/usr/lib/debug/*" \) -print0 \ | sort --zero-terminated \ | tar --create --no-recursion --mode='u+rw,go+r-w,a+X' --null --files-from=- \ | gzip -9n > "${OUTDIR}/${DISTNAME}-${HOST}-debug.tar.gz" \ diff --git a/contrib/guix/libexec/prelude.bash b/contrib/guix/libexec/prelude.bash index 1b40b08c5ba9..196a5e2c683a 100644 --- a/contrib/guix/libexec/prelude.bash +++ b/contrib/guix/libexec/prelude.bash @@ -21,6 +21,26 @@ check_tools() { done } +################ +# SOURCE_DATE_EPOCH should not unintentionally be set +################ + +check_source_date_epoch() { + if [ -n "$SOURCE_DATE_EPOCH" ] && [ -z "$FORCE_SOURCE_DATE_EPOCH" ]; then + cat << EOF +ERR: Environment variable SOURCE_DATE_EPOCH is set which may break reproducibility. + + Aborting... + +Hint: You may want to: + 1. Unset this variable: \`unset SOURCE_DATE_EPOCH\` before rebuilding + 2. Set the 'FORCE_SOURCE_DATE_EPOCH' environment variable if you insist on + using your own epoch +EOF + exit 1 + fi +} + check_tools cat env readlink dirname basename git ################ @@ -50,8 +70,8 @@ fi # across time. time-machine() { # shellcheck disable=SC2086 - guix time-machine --url=https://git.savannah.gnu.org/git/guix.git \ - --commit=7bf1d7aeaffba15c4f680f93ae88fbef25427252 \ + guix time-machine --url=https://codeberg.org/guix/guix.git \ + --commit=5cb84f2013c5b1e48a7d0e617032266f1e6059e2 \ --cores="$JOBS" \ --keep-failed \ --fallback \ diff --git a/contrib/guix/manifest.scm b/contrib/guix/manifest.scm index 62dd18f19b1d..35e678722a02 100644 --- a/contrib/guix/manifest.scm +++ b/contrib/guix/manifest.scm @@ -92,17 +92,7 @@ chain for " target " development.")) (home-page (package-home-page xgcc)) (license (package-license xgcc))))) -(define base-gcc - (package - (inherit gcc-12) ;; 12.3.0 - (version "12.4.0") - (source (origin - (method url-fetch) - (uri (string-append "mirror://gnu/gcc/gcc-" - version "/gcc-" version ".tar.xz")) - (sha256 - (base32 - "0xcida8l2wykvvzvpcrcn649gj0ijn64gwxbplacpg6c0hk6akvh")))))) +(define base-gcc gcc-12) ;; 12.4.0 (define base-linux-kernel-headers linux-libre-headers-6.1) @@ -431,12 +421,8 @@ inspecting signatures in Mach-O binaries.") `(append ,flags ;; https://gcc.gnu.org/install/configure.html (list "--enable-threads=posix", - building-on))) - ((#:make-flags flags) - ;; Uses the SSP functions from glibc instead of from libssp.so. - ;; Our 'symbol-check' script will complain if we link against libssp.so, - ;; and thus will ensure that this works properly. - `(cons "gcc_cv_libc_provides_ssp=yes" ,flags)))))) + "--enable-default-ssp=yes", + building-on))))))) (define-public linux-base-gcc (package @@ -465,9 +451,9 @@ inspecting signatures in Mach-O binaries.") #t)))))))) (define-public glibc-2.31 - (let ((commit "8e30f03744837a85e33d84ccd34ed3abe30d37c3")) + (let ((commit "7b27c450c34563a28e634cccb399cd415e71ebfe")) (package - (inherit glibc) ;; 2.35 + (inherit glibc) ;; 2.39 (version "2.31") (source (origin (method git-fetch) @@ -477,8 +463,9 @@ inspecting signatures in Mach-O binaries.") (file-name (git-file-name "glibc" commit)) (sha256 (base32 - "1zi0s9yy5zkisw823vivn7zlj8w6g9p3mm7lmlqiixcxdkz4dbn6")) - (patches (search-our-patches "glibc-guix-prefix.patch")))) + "017qdpr5id7ddb4lpkzj2li1abvw916m3fc6n7nw28z4h5qbv2n0")) + (patches (search-our-patches "glibc-guix-prefix.patch" + "glibc-riscv-jumptarget.patch")))) (arguments (substitute-keyword-arguments (package-arguments glibc) ((#:configure-flags flags) @@ -487,6 +474,8 @@ inspecting signatures in Mach-O binaries.") (list "--enable-stack-protector=all", "--enable-bind-now", "--disable-werror", + "--disable-timezone-tools", + "--disable-profile", building-on))) ((#:phases phases) `(modify-phases ,phases @@ -521,7 +510,6 @@ inspecting signatures in Mach-O binaries.") moreutils ;; Compression and archiving tar - bzip2 gzip xz ;; Build tools @@ -550,9 +538,9 @@ inspecting signatures in Mach-O binaries.") (list gcc-toolchain-12 "static") (make-bitcoin-cross-toolchain target))) ((string-contains target "darwin") - (list clang-toolchain-18 - lld-18 - (make-lld-wrapper lld-18 #:lld-as-ld? #t) + (list clang-toolchain-19 + lld-19 + (make-lld-wrapper lld-19 #:lld-as-ld? #t) python-signapple zip)) (else '()))))) diff --git a/contrib/guix/patches/glibc-riscv-jumptarget.patch b/contrib/guix/patches/glibc-riscv-jumptarget.patch new file mode 100644 index 000000000000..702959433d86 --- /dev/null +++ b/contrib/guix/patches/glibc-riscv-jumptarget.patch @@ -0,0 +1,57 @@ +commit 68389203832ab39dd0dbaabbc4059e7fff51c29b +Author: Fangrui Song +Date: Thu Oct 28 11:39:49 2021 -0700 + + riscv: Fix incorrect jal with HIDDEN_JUMPTARGET + + A non-local STV_DEFAULT defined symbol is by default preemptible in a + shared object. j/jal cannot target a preemptible symbol. On other + architectures, such a jump instruction either causes PLT [BZ #18822], or + if short-ranged, sometimes rejected by the linker (but not by GNU ld's + riscv port [ld PR/28509]). + + Use HIDDEN_JUMPTARGET to target a non-preemptible symbol instead. + + With this patch, ld.so and libc.so can be linked with LLD if source + files are compiled/assembled with -mno-relax/-Wa,-mno-relax. + + Acked-by: Palmer Dabbelt + Reviewed-by: Adhemerval Zanella + +Can be dropped when we are using glibc 2.35 or later. + +diff --git a/sysdeps/riscv/setjmp.S b/sysdeps/riscv/setjmp.S +index 0b92016b31..bec7ff80f4 100644 +--- a/sysdeps/riscv/setjmp.S ++++ b/sysdeps/riscv/setjmp.S +@@ -21,7 +21,7 @@ + + ENTRY (_setjmp) + li a1, 0 +- j __sigsetjmp ++ j HIDDEN_JUMPTARGET (__sigsetjmp) + END (_setjmp) + ENTRY (setjmp) + li a1, 1 +diff --git a/sysdeps/unix/sysv/linux/riscv/setcontext.S b/sysdeps/unix/sysv/linux/riscv/setcontext.S +index 9510518750..e44a68aad4 100644 +--- a/sysdeps/unix/sysv/linux/riscv/setcontext.S ++++ b/sysdeps/unix/sysv/linux/riscv/setcontext.S +@@ -95,6 +95,7 @@ LEAF (__setcontext) + 99: j __syscall_error + + END (__setcontext) ++libc_hidden_def (__setcontext) + weak_alias (__setcontext, setcontext) + + LEAF (__start_context) +@@ -108,7 +109,7 @@ LEAF (__start_context) + /* Invoke subsequent context if present, else exit(0). */ + mv a0, s2 + beqz s2, 1f +- jal __setcontext +-1: j exit ++ jal HIDDEN_JUMPTARGET (__setcontext) ++1: j HIDDEN_JUMPTARGET (exit) + + END (__start_context) diff --git a/contrib/install_db4.sh b/contrib/install_db4.sh deleted file mode 100755 index 352e7e1a0c72..000000000000 --- a/contrib/install_db4.sh +++ /dev/null @@ -1,259 +0,0 @@ -#!/bin/sh -# Copyright (c) 2017-2021 The Bitcoin Core developers -# Distributed under the MIT software license, see the accompanying -# file COPYING or http://www.opensource.org/licenses/mit-license.php. - -# Install libdb4.8 (Berkeley DB). - -export LC_ALL=C -set -e - -if [ -z "${1}" ]; then - echo "Usage: $0 [ ...]" - echo - echo "Must specify a single argument: the directory in which db4 will be built." - echo "This is probably \`pwd\` if you're at the root of the dash repository." - exit 1 -fi - -expand_path() { - cd "${1}" && pwd -P -} - -BDB_PREFIX="$(expand_path "${1}")/db4"; shift; -BDB_VERSION='db-4.8.30.NC' -BDB_HASH='12edc0df75bf9abd7f82f821795bcee50f42cb2e5f76a6a281b85732798364ef' -BDB_URL="https://download.oracle.com/berkeley-db/${BDB_VERSION}.tar.gz" - -check_exists() { - command -v "$1" >/dev/null -} - -sha256_check() { - # Args: - # - if [ "$(uname)" = "FreeBSD" ]; then - # sha256sum exists on FreeBSD, but takes different arguments than the GNU version - sha256 -c "${1}" "${2}" - elif check_exists sha256sum; then - echo "${1} ${2}" | sha256sum -c - elif check_exists sha256; then - echo "${1} ${2}" | sha256 -c - else - echo "${1} ${2}" | shasum -a 256 -c - fi -} - -http_get() { - # Args: - # - # It's acceptable that we don't require SSL here because we manually verify - # content hashes below. - # - if [ -f "${2}" ]; then - echo "File ${2} already exists; not downloading again" - elif check_exists curl; then - curl --insecure --retry 5 "${1}" -o "${2}" - elif check_exists wget; then - wget --no-check-certificate "${1}" -O "${2}" - else - echo "Simple transfer utilities 'curl' and 'wget' not found. Please install one of them and try again." - exit 1 - fi - - sha256_check "${3}" "${2}" -} - -# Ensure the commands we use exist on the system -if ! check_exists patch; then - echo "Command-line tool 'patch' not found. Install patch and try again." - exit 1 -fi - -mkdir -p "${BDB_PREFIX}" -http_get "${BDB_URL}" "${BDB_VERSION}.tar.gz" "${BDB_HASH}" -tar -xzvf ${BDB_VERSION}.tar.gz -C "$BDB_PREFIX" -cd "${BDB_PREFIX}/${BDB_VERSION}/" - -# Apply a patch necessary when building with clang and c++11 (see https://community.oracle.com/thread/3952592) -patch --ignore-whitespace -p1 << 'EOF' -commit 3311d68f11d1697565401eee6efc85c34f022ea7 -Author: fanquake -Date: Mon Aug 17 20:03:56 2020 +0800 - - Fix C++11 compatibility - -diff --git a/dbinc/atomic.h b/dbinc/atomic.h -index 0034dcc..7c11d4a 100644 ---- a/dbinc/atomic.h -+++ b/dbinc/atomic.h -@@ -70,7 +70,7 @@ typedef struct { - * These have no memory barriers; the caller must include them when necessary. - */ - #define atomic_read(p) ((p)->value) --#define atomic_init(p, val) ((p)->value = (val)) -+#define atomic_init_db(p, val) ((p)->value = (val)) - - #ifdef HAVE_ATOMIC_SUPPORT - -@@ -144,7 +144,7 @@ typedef LONG volatile *interlocked_val; - #define atomic_inc(env, p) __atomic_inc(p) - #define atomic_dec(env, p) __atomic_dec(p) - #define atomic_compare_exchange(env, p, o, n) \ -- __atomic_compare_exchange((p), (o), (n)) -+ __atomic_compare_exchange_db((p), (o), (n)) - static inline int __atomic_inc(db_atomic_t *p) - { - int temp; -@@ -176,7 +176,7 @@ static inline int __atomic_dec(db_atomic_t *p) - * http://gcc.gnu.org/onlinedocs/gcc-4.1.0/gcc/Atomic-Builtins.html - * which configure could be changed to use. - */ --static inline int __atomic_compare_exchange( -+static inline int __atomic_compare_exchange_db( - db_atomic_t *p, atomic_value_t oldval, atomic_value_t newval) - { - atomic_value_t was; -@@ -206,7 +206,7 @@ static inline int __atomic_compare_exchange( - #define atomic_dec(env, p) (--(p)->value) - #define atomic_compare_exchange(env, p, oldval, newval) \ - (DB_ASSERT(env, atomic_read(p) == (oldval)), \ -- atomic_init(p, (newval)), 1) -+ atomic_init_db(p, (newval)), 1) - #else - #define atomic_inc(env, p) __atomic_inc(env, p) - #define atomic_dec(env, p) __atomic_dec(env, p) -diff --git a/mp/mp_fget.c b/mp/mp_fget.c -index 5fdee5a..0b75f57 100644 ---- a/mp/mp_fget.c -+++ b/mp/mp_fget.c -@@ -617,7 +617,7 @@ alloc: /* Allocate a new buffer header and data space. */ - - /* Initialize enough so we can call __memp_bhfree. */ - alloc_bhp->flags = 0; -- atomic_init(&alloc_bhp->ref, 1); -+ atomic_init_db(&alloc_bhp->ref, 1); - #ifdef DIAGNOSTIC - if ((uintptr_t)alloc_bhp->buf & (sizeof(size_t) - 1)) { - __db_errx(env, -@@ -911,7 +911,7 @@ alloc: /* Allocate a new buffer header and data space. */ - MVCC_MPROTECT(bhp->buf, mfp->stat.st_pagesize, - PROT_READ); - -- atomic_init(&alloc_bhp->ref, 1); -+ atomic_init_db(&alloc_bhp->ref, 1); - MUTEX_LOCK(env, alloc_bhp->mtx_buf); - alloc_bhp->priority = bhp->priority; - alloc_bhp->pgno = bhp->pgno; -diff --git a/mp/mp_mvcc.c b/mp/mp_mvcc.c -index 34467d2..f05aa0c 100644 ---- a/mp/mp_mvcc.c -+++ b/mp/mp_mvcc.c -@@ -276,7 +276,7 @@ __memp_bh_freeze(dbmp, infop, hp, bhp, need_frozenp) - #else - memcpy(frozen_bhp, bhp, SSZA(BH, buf)); - #endif -- atomic_init(&frozen_bhp->ref, 0); -+ atomic_init_db(&frozen_bhp->ref, 0); - if (mutex != MUTEX_INVALID) - frozen_bhp->mtx_buf = mutex; - else if ((ret = __mutex_alloc(env, MTX_MPOOL_BH, -@@ -428,7 +428,7 @@ __memp_bh_thaw(dbmp, infop, hp, frozen_bhp, alloc_bhp) - #endif - alloc_bhp->mtx_buf = mutex; - MUTEX_LOCK(env, alloc_bhp->mtx_buf); -- atomic_init(&alloc_bhp->ref, 1); -+ atomic_init_db(&alloc_bhp->ref, 1); - F_CLR(alloc_bhp, BH_FROZEN); - } - -diff --git a/mp/mp_region.c b/mp/mp_region.c -index e6cece9..ddbe906 100644 ---- a/mp/mp_region.c -+++ b/mp/mp_region.c -@@ -224,7 +224,7 @@ __memp_init(env, dbmp, reginfo_off, htab_buckets, max_nreg) - MTX_MPOOL_FILE_BUCKET, 0, &htab[i].mtx_hash)) != 0) - return (ret); - SH_TAILQ_INIT(&htab[i].hash_bucket); -- atomic_init(&htab[i].hash_page_dirty, 0); -+ atomic_init_db(&htab[i].hash_page_dirty, 0); - } - - /* -@@ -269,7 +269,7 @@ __memp_init(env, dbmp, reginfo_off, htab_buckets, max_nreg) - hp->mtx_hash = (mtx_base == MUTEX_INVALID) ? MUTEX_INVALID : - mtx_base + i; - SH_TAILQ_INIT(&hp->hash_bucket); -- atomic_init(&hp->hash_page_dirty, 0); -+ atomic_init_db(&hp->hash_page_dirty, 0); - #ifdef HAVE_STATISTICS - hp->hash_io_wait = 0; - hp->hash_frozen = hp->hash_thawed = hp->hash_frozen_freed = 0; -diff --git a/mutex/mut_method.c b/mutex/mut_method.c -index 2588763..5c6d516 100644 ---- a/mutex/mut_method.c -+++ b/mutex/mut_method.c -@@ -426,7 +426,7 @@ atomic_compare_exchange(env, v, oldval, newval) - MUTEX_LOCK(env, mtx); - ret = atomic_read(v) == oldval; - if (ret) -- atomic_init(v, newval); -+ atomic_init_db(v, newval); - MUTEX_UNLOCK(env, mtx); - - return (ret); -diff --git a/mutex/mut_tas.c b/mutex/mut_tas.c -index f3922e0..e40fcdf 100644 ---- a/mutex/mut_tas.c -+++ b/mutex/mut_tas.c -@@ -46,7 +46,7 @@ __db_tas_mutex_init(env, mutex, flags) - - #ifdef HAVE_SHARED_LATCHES - if (F_ISSET(mutexp, DB_MUTEX_SHARED)) -- atomic_init(&mutexp->sharecount, 0); -+ atomic_init_db(&mutexp->sharecount, 0); - else - #endif - if (MUTEX_INIT(&mutexp->tas)) { -@@ -486,7 +486,7 @@ __db_tas_mutex_unlock(env, mutex) - F_CLR(mutexp, DB_MUTEX_LOCKED); - /* Flush flag update before zeroing count */ - MEMBAR_EXIT(); -- atomic_init(&mutexp->sharecount, 0); -+ atomic_init_db(&mutexp->sharecount, 0); - } else { - DB_ASSERT(env, sharecount > 0); - MEMBAR_EXIT(); -EOF - -# The packaged config.guess and config.sub are ancient (2009) and can cause build issues. -# Replace them with modern versions. -# See https://github.com/bitcoin/bitcoin/issues/16064 -CONFIG_GUESS_URL='https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=4550d2f15b3a7ce2451c1f29500b9339430c877f' -CONFIG_GUESS_HASH='c8f530e01840719871748a8071113435bdfdf75b74c57e78e47898edea8754ae' -CONFIG_SUB_URL='https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=4550d2f15b3a7ce2451c1f29500b9339430c877f' -CONFIG_SUB_HASH='3969f7d5f6967ccc6f792401b8ef3916a1d1b1d0f0de5a4e354c95addb8b800e' - -rm -f "dist/config.guess" -rm -f "dist/config.sub" - -http_get "${CONFIG_GUESS_URL}" dist/config.guess "${CONFIG_GUESS_HASH}" -http_get "${CONFIG_SUB_URL}" dist/config.sub "${CONFIG_SUB_HASH}" - -cd build_unix/ - -"${BDB_PREFIX}/${BDB_VERSION}/dist/configure" \ - --enable-cxx --disable-shared --disable-replication --with-pic --prefix="${BDB_PREFIX}" \ - "${@}" - -make install - -echo -echo "db4 build complete." -echo -# shellcheck disable=SC2016 -echo 'When compiling dashd, run `./configure` in the following way:' -echo -echo " export BDB_PREFIX='${BDB_PREFIX}'" -# shellcheck disable=SC2016 -echo ' ./configure BDB_LIBS="-L${BDB_PREFIX}/lib -ldb_cxx-4.8" BDB_CFLAGS="-I${BDB_PREFIX}/include" ...' diff --git a/contrib/linearize/linearize-data.py b/contrib/linearize/linearize-data.py index 04721f4ccd52..2fab116cdefb 100755 --- a/contrib/linearize/linearize-data.py +++ b/contrib/linearize/linearize-data.py @@ -20,41 +20,9 @@ settings = {} -def hex_switchEndian(s): - """ Switches the endianness of a hex string (in pairs of hex chars) """ - pairList = [s[i:i+2].encode() for i in range(0, len(s), 2)] - return b''.join(pairList[::-1]).decode() - -def uint32(x): - return x & 0xffffffff - -def bytereverse(x): - return uint32(( ((x) << 24) | (((x) << 8) & 0x00ff0000) | - (((x) >> 8) & 0x0000ff00) | ((x) >> 24) )) - -def bufreverse(in_buf): - out_words = [] - for i in range(0, len(in_buf), 4): - word = struct.unpack('@I', in_buf[i:i+4])[0] - out_words.append(struct.pack('@I', bytereverse(word))) - return b''.join(out_words) - -def wordreverse(in_buf): - out_words = [] - for i in range(0, len(in_buf), 4): - out_words.append(in_buf[i:i+4]) - out_words.reverse() - return b''.join(out_words) - -def calc_hdr_hash(blk_hdr): - return dash_hash.getPoWHash(blk_hdr) - def calc_hash_str(blk_hdr): - hash = calc_hdr_hash(blk_hdr) - hash = bufreverse(hash) - hash = wordreverse(hash) - hash_str = hash.hex() - return hash_str + blk_hdr_hash = dash_hash.getPoWHash(blk_hdr) + return blk_hdr_hash[::-1].hex() def get_blk_dt(blk_hdr): members = struct.unpack(" ../../src/test/data/key_io_valid.json ./gen_key_io_test_vectors.py invalid 50 > ../../src/test/data/key_io_invalid.json diff --git a/contrib/testgen/gen_key_io_test_vectors.py b/contrib/testgen/gen_key_io_test_vectors.py index ba045ec1c505..40c89e85f712 100755 --- a/contrib/testgen/gen_key_io_test_vectors.py +++ b/contrib/testgen/gen_key_io_test_vectors.py @@ -4,10 +4,6 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. ''' Generate valid and invalid base58 address and private key test vectors. - -Usage: - ./gen_key_io_test_vectors.py valid 50 > ../../src/test/data/key_io_valid.json - ./gen_key_io_test_vectors.py invalid 50 > ../../src/test/data/key_io_invalid.json ''' from itertools import islice @@ -76,7 +72,7 @@ def is_valid(v): def gen_valid_base58_vector(template): '''Generate valid base58 vector''' prefix = bytearray(template[0]) - payload = bytearray(os.urandom(template[1])) + payload = rand_bytes(size=template[1]) suffix = bytearray(template[2]) dst_prefix = bytearray(template[4]) dst_suffix = bytearray(template[5]) @@ -108,17 +104,17 @@ def gen_invalid_base58_vector(template): corrupt_suffix = randbool(0.2) if corrupt_prefix: - prefix = os.urandom(1) + prefix = rand_bytes(size=1) else: prefix = bytearray(template[0]) if randomize_payload_size: - payload = os.urandom(max(int(random.expovariate(0.5)), 50)) + payload = rand_bytes(size=max(int(random.expovariate(0.5)), 50)) else: - payload = os.urandom(template[1]) + payload = rand_bytes(size=template[1]) if corrupt_suffix: - suffix = os.urandom(len(template[2])) + suffix = rand_bytes(size=len(template[2])) else: suffix = bytearray(template[2]) @@ -137,6 +133,9 @@ def randbool(p = 0.5): '''Return True with P(p)''' return random.random() < p +def rand_bytes(*, size): + return bytearray(random.getrandbits(8) for _ in range(size)) + def gen_invalid_vectors(): '''Generate invalid test vectors''' # start with some manual edge-cases @@ -153,6 +152,7 @@ def gen_invalid_vectors(): if __name__ == '__main__': import json iters = {'valid':gen_valid_vectors, 'invalid':gen_invalid_vectors} + random.seed(42) try: uiter = iters[sys.argv[1]] except IndexError: diff --git a/contrib/verify-commits/README.md b/contrib/verify-commits/README.md index b8b15280bae2..020890c3660e 100644 --- a/contrib/verify-commits/README.md +++ b/contrib/verify-commits/README.md @@ -27,6 +27,10 @@ Note that the above isn't a good UI/UX yet, and needs significant improvements to make it more convenient and reduce the chance of errors; pull-reqs improving this process would be much appreciated. +Unless `--clean-merge 0` is specified, `verify-commits.py` will attempt to verify that +each merge commit applies cleanly (with some exceptions). This requires using at least +git v2.38.0. + Configuration files ------------------- diff --git a/contrib/verify-commits/gpg.sh b/contrib/verify-commits/gpg.sh index db5bfce208ef..cfd68e45b8da 100755 --- a/contrib/verify-commits/gpg.sh +++ b/contrib/verify-commits/gpg.sh @@ -5,12 +5,9 @@ export LC_ALL=C INPUT=$(cat /dev/stdin) -VALID=false -REVSIG=false -IFS=' -' if [ "$BITCOIN_VERIFY_COMMITS_ALLOW_SHA1" = 1 ]; then - GPG_RES="$(printf '%s\n' "$INPUT" | gpg --trust-model always "$@" 2>/dev/null)" + printf '%s\n' "$INPUT" | gpg --trust-model always "$@" 2>/dev/null + exit $? else # Note how we've disabled SHA1 with the --weak-digest option, disabling # signatures - including selfsigs - that use SHA1. While you might think that @@ -20,12 +17,12 @@ else # an attacker could construct a pull-req that results in a commit object that # they've created a collision for. Not the most likely attack, but preventing # it is pretty easy so we do so as a "belt-and-suspenders" measure. - GPG_RES="" for LINE in $(gpg --version); do case "$LINE" in "gpg (GnuPG) 1.4.1"*|"gpg (GnuPG) 2.0."*) echo "Please upgrade to at least gpg 2.1.10 to check for weak signatures" > /dev/stderr - GPG_RES="$(printf '%s\n' "$INPUT" | gpg --trust-model always "$@" 2>/dev/null)" + printf '%s\n' "$INPUT" | gpg --trust-model always "$@" 2>/dev/null + exit $? ;; # We assume if you're running 2.1+, you're probably running 2.1.10+ # gpg will fail otherwise @@ -33,33 +30,6 @@ else # gpg will fail otherwise esac done - [ "$GPG_RES" = "" ] && GPG_RES="$(printf '%s\n' "$INPUT" | gpg --trust-model always --weak-digest sha1 "$@" 2>/dev/null)" -fi -for LINE in $GPG_RES; do - case "$LINE" in - "[GNUPG:] VALIDSIG "*) - while read KEY; do - [ "${LINE#?GNUPG:? VALIDSIG * * * * * * * * * }" = "$KEY" ] && VALID=true - done < ./contrib/verify-commits/trusted-keys - ;; - "[GNUPG:] REVKEYSIG "*) - [ "$BITCOIN_VERIFY_COMMITS_ALLOW_REVSIG" != 1 ] && exit 1 - REVSIG=true - GOODREVSIG="[GNUPG:] GOODSIG ${LINE#* * *}" - ;; - "[GNUPG:] EXPKEYSIG "*) - [ "$BITCOIN_VERIFY_COMMITS_ALLOW_REVSIG" != 1 ] && exit 1 - REVSIG=true - GOODREVSIG="[GNUPG:] GOODSIG ${LINE#* * *}" - ;; - esac -done -if ! $VALID; then - exit 1 -fi -if $VALID && $REVSIG; then - printf '%s\n' "$INPUT" | gpg --trust-model always "$@" 2>/dev/null | grep "^\[GNUPG:\] \(NEWSIG\|SIG_ID\|VALIDSIG\)" - echo "$GOODREVSIG" -else - printf '%s\n' "$INPUT" | gpg --trust-model always "$@" 2>/dev/null + printf '%s\n' "$INPUT" | gpg --trust-model always --weak-digest sha1 "$@" 2>/dev/null + exit $? fi diff --git a/contrib/verify-commits/verify-commits.py b/contrib/verify-commits/verify-commits.py index d522d9ce43ce..4d954cea1905 100755 --- a/contrib/verify-commits/verify-commits.py +++ b/contrib/verify-commits/verify-commits.py @@ -82,13 +82,20 @@ def main(): # get directory of this program and read data files dirname = os.path.dirname(os.path.abspath(__file__)) print("Using verify-commits data from " + dirname) - verified_root = open(dirname + "/trusted-git-root", "r", encoding="utf8").read().splitlines()[0] - verified_sha512_root = open(dirname + "/trusted-sha512-root-commit", "r", encoding="utf8").read().splitlines()[0] - revsig_allowed = open(dirname + "/allow-revsig-commits", "r", encoding="utf-8").read().splitlines() - unclean_merge_allowed = open(dirname + "/allow-unclean-merge-commits", "r", encoding="utf-8").read().splitlines() - incorrect_sha512_allowed = open(dirname + "/allow-incorrect-sha512-commits", "r", encoding="utf-8").read().splitlines() - - # Set commit and branch and set variables + with open(dirname + "/trusted-git-root", "r", encoding="utf8") as f: + verified_root = f.read().splitlines()[0] + with open(dirname + "/trusted-sha512-root-commit", "r", encoding="utf8") as f: + verified_sha512_root = f.read().splitlines()[0] + with open(dirname + "/allow-revsig-commits", "r", encoding="utf8") as f: + revsig_allowed = f.read().splitlines() + with open(dirname + "/allow-unclean-merge-commits", "r", encoding="utf8") as f: + unclean_merge_allowed = f.read().splitlines() + with open(dirname + "/allow-incorrect-sha512-commits", "r", encoding="utf8") as f: + incorrect_sha512_allowed = f.read().splitlines() + with open(dirname + "/trusted-keys", "r", encoding="utf8") as f: + trusted_keys = f.read().splitlines() + + # Set commit and variables current_commit = args.commit if ' ' in current_commit: print("Commit must not contain spaces", file=sys.stderr) @@ -97,7 +104,6 @@ def main(): no_sha1 = True prev_commit = "" initial_commit = current_commit - branch = subprocess.check_output([GIT, 'show', '-s', '--format=%H', initial_commit]).decode('utf8').splitlines()[0] # Iterate through commits while True: @@ -108,17 +114,41 @@ def main(): if current_commit == verified_root: print('There is a valid path from "{}" to {} where all commits are signed!'.format(initial_commit, verified_root)) sys.exit(0) - if current_commit == verified_sha512_root: - if verify_tree: + else: + # Make sure this commit isn't older than trusted roots + check_root_older_res = subprocess.run([GIT, "merge-base", "--is-ancestor", verified_root, current_commit]) + if check_root_older_res.returncode != 0: + print(f"\"{current_commit}\" predates the trusted root, stopping!") + sys.exit(0) + + if verify_tree: + if current_commit == verified_sha512_root: print("All Tree-SHA512s matched up to {}".format(verified_sha512_root), file=sys.stderr) - verify_tree = False - no_sha1 = False + verify_tree = False + no_sha1 = False + else: + # Skip the tree check if we are older than the trusted root + check_root_older_res = subprocess.run([GIT, "merge-base", "--is-ancestor", verified_sha512_root, current_commit]) + if check_root_older_res.returncode != 0: + print(f"\"{current_commit}\" predates the trusted SHA512 root, disabling tree verification.") + verify_tree = False + no_sha1 = False + os.environ['BITCOIN_VERIFY_COMMITS_ALLOW_SHA1'] = "0" if no_sha1 else "1" - os.environ['BITCOIN_VERIFY_COMMITS_ALLOW_REVSIG'] = "1" if current_commit in revsig_allowed else "0" + allow_revsig = current_commit in revsig_allowed # Check that the commit (and parents) was signed with a trusted key - if subprocess.call([GIT, '-c', 'gpg.program={}/gpg.sh'.format(dirname), 'verify-commit', current_commit], stdout=subprocess.DEVNULL): + valid_sig = False + verify_res = subprocess.run([GIT, '-c', 'gpg.program={}/gpg.sh'.format(dirname), 'verify-commit', "--raw", current_commit], capture_output=True) + for line in verify_res.stderr.decode().splitlines(): + if line.startswith("[GNUPG:] VALIDSIG "): + key = line.split(" ")[-1] + valid_sig = key in trusted_keys + elif (line.startswith("[GNUPG:] REVKEYSIG ") or line.startswith("[GNUPG:] EXPKEYSIG ")) and not allow_revsig: + valid_sig = False + break + if not valid_sig: if prev_commit != "": print("No parent of {} was signed with a trusted key!".format(prev_commit), file=sys.stderr) print("Parents are:", file=sys.stderr) @@ -148,15 +178,24 @@ def main(): allow_unclean = current_commit in unclean_merge_allowed if len(parents) == 2 and check_merge and not allow_unclean: current_tree = subprocess.check_output([GIT, 'show', '--format=%T', current_commit]).decode('utf8').splitlines()[0] - subprocess.call([GIT, 'checkout', '--force', '--quiet', parents[0]]) - subprocess.call([GIT, 'merge', '--no-ff', '--quiet', '--no-gpg-sign', parents[1]], stdout=subprocess.DEVNULL) - recreated_tree = subprocess.check_output([GIT, 'show', '--format=format:%T', 'HEAD']).decode('utf8').splitlines()[0] + + # This merge-tree functionality requires git >= 2.38. The + # --write-tree option was added in order to opt-in to the new + # behavior. Older versions of git will not recognize the option and + # will instead exit with code 128. + try: + recreated_tree = subprocess.check_output([GIT, "merge-tree", "--write-tree", parents[0], parents[1]]).decode('utf8').splitlines()[0] + except subprocess.CalledProcessError as e: + if e.returncode == 128: + print("git v2.38+ is required for this functionality.", file=sys.stderr) + sys.exit(1) + else: + raise e + if current_tree != recreated_tree: print("Merge commit {} is not clean".format(current_commit), file=sys.stderr) - subprocess.call([GIT, 'diff', current_commit]) - subprocess.call([GIT, 'checkout', '--force', '--quiet', branch]) + subprocess.call([GIT, 'diff', recreated_tree, current_tree]) sys.exit(1) - subprocess.call([GIT, 'checkout', '--force', '--quiet', branch]) prev_commit = current_commit current_commit = parents[0] diff --git a/depends/.gitignore b/depends/.gitignore index 19c506ce5447..d65d8931eaf2 100644 --- a/depends/.gitignore +++ b/depends/.gitignore @@ -4,6 +4,7 @@ built/ sources/ config.site x86_64* +amd64* i686* mips* arm* diff --git a/depends/Makefile b/depends/Makefile index 2bbf40297530..c8510f4cc010 100644 --- a/depends/Makefile +++ b/depends/Makefile @@ -52,7 +52,6 @@ C_STANDARD ?= c11 CXX_STANDARD ?= c++20 BUILD = $(shell ./config.guess) -HOST ?= $(BUILD) PATCHES_PATH = $(BASEDIR)/patches BASEDIR = $(CURDIR) HASH_LENGTH:=11 @@ -61,11 +60,6 @@ DOWNLOAD_RETRIES:=3 HOST_ID_SALT ?= salt BUILD_ID_SALT ?= salt -host:=$(BUILD) -ifneq ($(HOST),) -host:=$(HOST) -endif - ifneq ($(DEBUG),) release_type=debug else @@ -75,9 +69,15 @@ endif base_build_dir=$(WORK_PATH)/build base_staging_dir=$(WORK_PATH)/staging base_download_dir=$(WORK_PATH)/download -canonical_host:=$(shell ./config.sub $(HOST)) build:=$(shell ./config.sub $(BUILD)) +host:=$(build) +ifneq ($(HOST),) +host:=$(HOST) +endif +HOST ?= $(BUILD) +canonical_host:=$(shell ./config.sub $(HOST)) + build_arch =$(firstword $(subst -, ,$(build))) build_vendor=$(word 2,$(subst -, ,$(build))) full_build_os:=$(subst $(build_arch)-$(build_vendor)-,,$(build)) @@ -147,8 +147,16 @@ include packages/packages.mk # 2. Before including packages/*.mk (excluding packages/packages.mk), since # they rely on the build_id variables # -build_id:=$(shell env CC='$(build_CC)' C_STANDARD='$(C_STANDARD)' CXX='$(build_CXX)' CXX_STANDARD='$(CXX_STANDARD)' AR='$(build_AR)' RANLIB='$(build_RANLIB)' STRIP='$(build_STRIP)' SHA256SUM='$(build_SHA256SUM)' DEBUG='$(DEBUG)' LTO='$(LTO)' NO_HARDEN='$(NO_HARDEN)' ./gen_id '$(BUILD_ID_SALT)' 'GUIX_ENVIRONMENT=$(realpath $(GUIX_ENVIRONMENT))') -$(host_arch)_$(host_os)_id:=$(shell env CC='$(host_CC)' C_STANDARD='$(C_STANDARD)' CXX='$(host_CXX)' CXX_STANDARD='$(CXX_STANDARD)' AR='$(host_AR)' RANLIB='$(host_RANLIB)' STRIP='$(host_STRIP)' SHA256SUM='$(build_SHA256SUM)' DEBUG='$(DEBUG)' LTO='$(LTO)' NO_HARDEN='$(NO_HARDEN)' ./gen_id '$(HOST_ID_SALT)' 'GUIX_ENVIRONMENT=$(realpath $(GUIX_ENVIRONMENT))') +build_id:=$(shell env CC='$(build_CC)' C_STANDARD='$(C_STANDARD)' CXX='$(build_CXX)' CXX_STANDARD='$(CXX_STANDARD)' \ + AR='$(build_AR)' NM='$(build_NM)' RANLIB='$(build_RANLIB)' STRIP='$(build_STRIP)' SHA256SUM='$(build_SHA256SUM)' \ + DEBUG='$(DEBUG)' NO_HARDEN='$(NO_HARDEN)' \ + ./gen_id '$(BUILD_ID_SALT)' 'GUIX_ENVIRONMENT=$(realpath $(GUIX_ENVIRONMENT))') + +$(host_arch)_$(host_os)_id:=$(shell env CC='$(host_CC)' C_STANDARD='$(C_STANDARD)' CXX='$(host_CXX)' CXX_STANDARD='$(CXX_STANDARD)' \ + CPPFLAGS='$(CPPFLAGS)' CFLAGS='$(CFLAGS)' CXXFLAGS='$(CXXFLAGS)' LDFLAGS='$(LDFLAGS)' \ + AR='$(host_AR)' NM='$(host_NM)' RANLIB='$(host_RANLIB)' STRIP='$(host_STRIP)' SHA256SUM='$(build_SHA256SUM)' \ + DEBUG='$(DEBUG)' LTO='$(LTO)' NO_HARDEN='$(NO_HARDEN)' \ + ./gen_id '$(HOST_ID_SALT)' 'GUIX_ENVIRONMENT=$(realpath $(GUIX_ENVIRONMENT))') boost_packages_$(NO_BOOST) = $(boost_packages) @@ -231,6 +239,7 @@ $(host_prefix)/share/config.site : config.site.in $(host_prefix)/.stamp_$(final_ -e 's|@STRIP@|$(host_STRIP)|' \ -e 's|@OBJDUMP@|$(host_OBJDUMP)|' \ -e 's|@DSYMUTIL@|$(host_DSYMUTIL)|' \ + -e 's|@WINDRES@|$(host_WINDRES)|' \ -e 's|@build_os@|$(build_os)|' \ -e 's|@host_os@|$(host_os)|' \ -e 's|@CFLAGS@|$(strip $(host_CFLAGS) $(host_$(release_type)_CFLAGS))|' \ diff --git a/depends/README.md b/depends/README.md index 5d800ce06abf..3e44a66b7621 100644 --- a/depends/README.md +++ b/depends/README.md @@ -1,16 +1,59 @@ -### Usage +# Depends build + +This is a system of building and caching dependencies necessary for building +Dash Core. It supports cross-compilation. For more details see [description.md](description.md), +as well as [packages.md](packages.md) for how to add packages. + +## Usage + +### Ubuntu & Debian + + apt install automake bison cmake curl libtool make patch pkg-config python3 xz-utils To build dependencies for the current arch+OS: make -To build for another arch/OS: +### macOS - make HOST=host-platform-triplet +Install Xcode Command Line Tools and Homebrew Package Manager, +see [build-osx.md](../doc/build-osx.md). -For example: + brew install cmake make ninja - make HOST=x86_64-w64-mingw32 -j4 +To build dependencies for the current arch+OS: + + gmake + +### FreeBSD + + pkg install bash + +Skip the following packages if you don't intend to use the GUI and will build with [`NO_QT=1`](#dependency-options): + + pkg install bison ninja pkgconf python3 + +To build dependencies for the current arch+OS: + + gmake + +### NetBSD + + pkgin install bash gmake + +To build dependencies for the current arch+OS: + + gmake + +### OpenBSD + + pkg_add bash gmake gtar + +To build dependencies for the current arch+OS: + + gmake + +## Configuring Dash Core **Dash Core's `configure` script by default will ignore the depends output.** In order for it to pick up libraries, tools, and settings from the depends build, @@ -23,6 +66,53 @@ created. To use it during compilation: The default install prefix when using `config.site` is `--prefix=depends/`, so depends build outputs will be installed in that location. +## Dependency Options + +The following can be set when running make: `make FOO=bar` + +- `SOURCES_PATH`: Downloaded sources will be placed here +- `BASE_CACHE`: Built packages will be placed here +- `SDK_PATH`: Path where SDKs can be found (used by macOS) +- `FALLBACK_DOWNLOAD_PATH`: If a source file can't be fetched, try here before giving up +- `C_STANDARD`: Set the C standard version used. Defaults to `c11`. +- `CXX_STANDARD`: Set the C++ standard version used. Defaults to `c++20`. +- `NO_BOOST`: Don't download/build/cache Boost +- `NO_LIBEVENT`: Don't download/build/cache Libevent +- `NO_QT`: Don't download/build/cache Qt and its dependencies +- `NO_QR`: Don't download/build/cache packages needed for enabling qrencode +- `NO_ZMQ`: Don't download/build/cache packages needed for enabling ZeroMQ +- `NO_WALLET`: Don't download/build/cache libs needed to enable the wallet +- `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 +- `ALLOW_HOST_PACKAGES`: Packages that are missed in dependencies (due to `NO_*` option or + build script logic) are searched for among the host system packages using + `pkg-config`. It allows building with packages of other (newer) versions +- `MULTIPROCESS`: build libmultiprocess (experimental, requires cmake) +- `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 +- `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 Dash Core's configure. In this case, `--disable-wallet`. + +## Cross compilation + +To build for another arch/OS: + + make HOST=host-platform-triplet + +For example: + + make HOST=x86_64-w64-mingw32 -j4 + Common `host-platform-triplet`s for cross compilation are: - `i686-pc-linux-gnu` for Linux 32 bit @@ -41,13 +131,7 @@ Common `host-platform-triplet`s for cross compilation are: - `aarch64-linux-android` for Android ARM 64 bit - `x86_64-linux-android` for Android x86 64 bit -The paths are automatically configured and no other options are needed unless targeting [Android](../doc/build-android.md). - -### Install the required dependencies: Ubuntu & Debian - -#### Common - - apt install automake bison cmake curl libtool make patch pkg-config python3 xz-utils +The paths are automatically configured and no other options are needed. #### For macOS cross compilation @@ -60,7 +144,7 @@ For more information, see [SDK Extraction](../contrib/macdeploy/README.md#sdk-ex #### 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 @@ -88,58 +172,9 @@ For linux S390X cross compilation: sudo apt-get install g++-s390x-linux-gnu binutils-s390x-linux-gnu -### Install the required dependencies: FreeBSD - - pkg install bash - -### Install the required dependencies: OpenBSD - - pkg_add bash gtar - -### Dependency Options - -The following can be set when running make: `make FOO=bar` - -- `SOURCES_PATH`: Downloaded sources will be placed here -- `BASE_CACHE`: Built packages will be placed here -- `SDK_PATH`: Path where SDKs can be found (used by macOS) -- `FALLBACK_DOWNLOAD_PATH`: If a source file can't be fetched, try here before giving up -- `C_STANDARD`: Set the C standard version used. Defaults to `c11`. -- `CXX_STANDARD`: Set the C++ standard version used. Defaults to `c++20`. -- `NO_QT`: Don't download/build/cache Qt and its dependencies -- `NO_QR`: Don't download/build/cache packages needed for enabling qrencode -- `NO_ZMQ`: Don't download/build/cache packages needed for enabling ZeroMQ -- `NO_WALLET`: Don't download/build/cache libs needed to enable the wallet -- `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 -- `ALLOW_HOST_PACKAGES`: Packages that are missed in dependencies (due to `NO_*` option or - build script logic) are searched for among the host system packages using - `pkg-config`. It allows building with packages of other (newer) versions -- `MULTIPROCESS`: build libmultiprocess (experimental, requires cmake) -- `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 -- `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 Dash Core's configure. In this case, `--disable-wallet`. - ### Additional targets download: run 'make download' to fetch all sources without building them download-osx: run 'make download-osx' to fetch all sources needed for macOS builds download-win: run 'make download-win' to fetch all sources needed for win builds download-linux: run 'make download-linux' to fetch all sources needed for linux builds - - -### Other documentation - -- [description.md](description.md): General description of the depends system -- [packages.md](packages.md): Steps for adding packages diff --git a/depends/builders/freebsd.mk b/depends/builders/freebsd.mk index 465f58e04dc7..910de28bf36f 100644 --- a/depends/builders/freebsd.mk +++ b/depends/builders/freebsd.mk @@ -1,5 +1,9 @@ build_freebsd_CC=clang build_freebsd_CXX=clang++ -build_freebsd_SHA256SUM = shasum -a 256 +build_freebsd_SHA256SUM = sha256sum build_freebsd_DOWNLOAD = curl --location --fail --connect-timeout $(DOWNLOAD_CONNECT_TIMEOUT) --retry $(DOWNLOAD_RETRIES) -o + +# freebsd host on freebsd builder: override freebsd host preferences. +freebsd_CC = clang +freebsd_CXX = clang++ diff --git a/depends/builders/openbsd.mk b/depends/builders/openbsd.mk index 9c94c4baae7a..6aeb14312587 100644 --- a/depends/builders/openbsd.mk +++ b/depends/builders/openbsd.mk @@ -1,9 +1,13 @@ build_openbsd_CC = clang build_openbsd_CXX = clang++ -build_openbsd_SHA256SUM = sha256 +build_openbsd_SHA256SUM = sha256 -r build_openbsd_DOWNLOAD = curl --location --fail --connect-timeout $(DOWNLOAD_CONNECT_TIMEOUT) --retry $(DOWNLOAD_RETRIES) -o build_openbsd_TAR = gtar # openBSD touch doesn't understand -h build_openbsd_TOUCH = touch -m -t 200001011200 + +# openbsd host on openbsd builder: override openbsd host preferences. +openbsd_CC = clang +openbsd_CXX = clang++ diff --git a/depends/config.guess b/depends/config.guess index cdfc4392047c..48a684601bd2 100755 --- a/depends/config.guess +++ b/depends/config.guess @@ -1,10 +1,10 @@ #! /bin/sh # Attempt to guess a canonical system name. -# Copyright 1992-2023 Free Software Foundation, Inc. +# Copyright 1992-2024 Free Software Foundation, Inc. # shellcheck disable=SC2006,SC2268 # see below for rationale -timestamp='2023-08-22' +timestamp='2024-07-27' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by @@ -60,7 +60,7 @@ version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. -Copyright 1992-2023 Free Software Foundation, Inc. +Copyright 1992-2024 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." @@ -123,7 +123,7 @@ set_cc_for_build() { dummy=$tmp/dummy case ${CC_FOR_BUILD-},${HOST_CC-},${CC-} in ,,) echo "int x;" > "$dummy.c" - for driver in cc gcc c89 c99 ; do + for driver in cc gcc c17 c99 c89 ; do if ($driver -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then CC_FOR_BUILD=$driver break @@ -165,6 +165,8 @@ Linux|GNU|GNU/*) LIBC=dietlibc #elif defined(__GLIBC__) LIBC=gnu + #elif defined(__LLVM_LIBC__) + LIBC=llvm #else #include /* First heuristic to detect musl libc. */ @@ -632,7 +634,8 @@ EOF sed 's/^ //' << EOF > "$dummy.c" #include - main() + int + main () { if (!__power_pc()) exit(1); @@ -716,7 +719,8 @@ EOF #include #include - int main () + int + main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); @@ -1593,6 +1597,9 @@ EOF *:Unleashed:*:*) GUESS=$UNAME_MACHINE-unknown-unleashed$UNAME_RELEASE ;; + *:Ironclad:*:*) + GUESS=$UNAME_MACHINE-unknown-ironclad + ;; esac # Do we have a guess based on uname results? @@ -1616,6 +1623,7 @@ cat > "$dummy.c" <." version="\ GNU config.sub ($timestamp) -Copyright 1992-2023 Free Software Foundation, Inc. +Copyright 1992-2024 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." @@ -120,7 +120,6 @@ case $# in esac # Split fields of configuration type -# shellcheck disable=SC2162 saved_IFS=$IFS IFS="-" read field1 field2 field3 field4 <&2 @@ -1845,7 +2237,7 @@ case $kernel-$os-$obj in echo "Invalid configuration '$1': '$os' needs 'windows'." 1>&2 exit 1 ;; - kfreebsd*-gnu*- | kopensolaris*-gnu*-) + kfreebsd*-gnu*- | knetbsd*-gnu*- | netbsd*-gnu*- | kopensolaris*-gnu*-) ;; vxworks-simlinux- | vxworks-simwindows- | vxworks-spe-) ;; @@ -1853,6 +2245,8 @@ case $kernel-$os-$obj in ;; os2-emx-) ;; + rtmk-nova-) + ;; *-eabi*- | *-gnueabi*-) ;; none--*) @@ -1879,7 +2273,7 @@ case $vendor in *-riscix*) vendor=acorn ;; - *-sunos*) + *-sunos* | *-solaris*) vendor=sun ;; *-cnk* | *-aix*) diff --git a/depends/funcs.mk b/depends/funcs.mk index 3c0dc7a7fcab..964be8ea61c5 100644 --- a/depends/funcs.mk +++ b/depends/funcs.mk @@ -34,9 +34,8 @@ define fetch_file_inner endef define fetch_file - ( test -f $$($(1)_source_dir)/$(4) || \ ( $(call fetch_file_inner,$(1),$(2),$(3),$(4),$(5)) || \ - $(call fetch_file_inner,$(1),$(FALLBACK_DOWNLOAD_PATH),$(3),$(4),$(5)))) + $(call fetch_file_inner,$(1),$(FALLBACK_DOWNLOAD_PATH),$(4),$(4),$(5))) endef define int_get_build_recipe_hash @@ -70,7 +69,7 @@ $(1)_build_log:=$(BASEDIR)/$(1)-$($(1)_version)-$($(1)_build_id).log $(1)_all_sources=$($(1)_file_name) $($(1)_extra_sources) #stamps -$(1)_fetched=$(SOURCES_PATH)/download-stamps/.stamp_fetched-$(1)-$($(1)_file_name).hash +$(1)_fetched=$(SOURCES_PATH)/download-stamps/.stamp_fetched-$(1)-$($(1)_version)-$($(1)_sha256_hash).hash $(1)_extracted=$$($(1)_extract_dir)/.stamp_extracted $(1)_preprocessed=$$($(1)_extract_dir)/.stamp_preprocessed $(1)_cleaned=$$($(1)_extract_dir)/.stamp_cleaned @@ -206,7 +205,6 @@ endif $($(1)_fetched): mkdir -p $$(@D) $(SOURCES_PATH) rm -f $$@ - touch $$@ cd $$(@D); $($(1)_fetch_cmds) cd $($(1)_source_dir); $(foreach source,$($(1)_all_sources),$(build_SHA256SUM) $(source) >> $$(@);) touch $$@ diff --git a/depends/gen_id b/depends/gen_id index 67c43616d68b..fe6d163547ae 100755 --- a/depends/gen_id +++ b/depends/gen_id @@ -1,8 +1,9 @@ #!/usr/bin/env bash # Usage: env [ CC=... ] [ C_STANDARD=...] [ CXX=... ] [CXX_STANDARD=...] \ -# [ AR=... ] [ RANLIB=... ] [ STRIP=... ] [ DEBUG=... ] \ -# [ LTO=... ] [ NO_HARDEN=... ] ./build-id [ID_SALT]... +# [ CPPFLAGS=... ] [CFLAGS=...] [CXXFLAGS=...] [LDFLAGS=...] \ +# [ AR=... ] [ NM=... ] [ RANLIB=... ] [ STRIP=... ] [ DEBUG=... ] \ +# [ LTO=... ] [ NO_HARDEN=... ] ./gen_id [ID_SALT]... # # Prints to stdout a SHA256 hash representing the current toolset, used by # depends/Makefile as a build id for caching purposes (detecting when the @@ -34,6 +35,13 @@ echo "$@" echo "END ID SALT" + echo "BEGIN FLAGS" + echo "CPPFLAGS=${CPPFLAGS}" + echo "CFLAGS=${CFLAGS}" + echo "CXXFLAGS=${CXXFLAGS}" + echo "LDFLAGS=${LDFLAGS}" + echo "END FLAGS" + # GCC only prints COLLECT_LTO_WRAPPER when invoked with just "-v", but we want # the information from "-v -E -" as well, so just include both. echo "BEGIN CC" @@ -50,11 +58,27 @@ echo "CXX_STANDARD=${CXX_STANDARD}" echo "END CXX" + # We use lld when cross-compiling for macOS, and it's version should + # be tied to LLVM. However someone compiling with GCC and -fuse-ld=lld + # would not see a cache bust if the LLVM toolchain was updated. + echo "BEGIN lld" + bash -c "ld.lld --version" + echo "END lld" + + echo "BEGIN mold" + bash -c "mold --version" + echo "END mold" + echo "BEGIN AR" bash -c "${AR} --version" env | grep '^AR_' echo "END AR" + echo "BEGIN NM" + bash -c "${NM} --version" + env | grep '^NM_' + echo "END NM" + echo "BEGIN RANLIB" bash -c "${RANLIB} --version" env | grep '^RANLIB_' diff --git a/depends/hosts/darwin.mk b/depends/hosts/darwin.mk index a50e36110dc0..845ff03d6bae 100644 --- a/depends/hosts/darwin.mk +++ b/depends/hosts/darwin.mk @@ -19,6 +19,7 @@ clangxx_prog=$(shell $(SHELL) $(.SHELLFLAGS) "command -v clang++") darwin_AR=$(shell $(SHELL) $(.SHELLFLAGS) "command -v llvm-ar") darwin_DSYMUTIL=$(shell $(SHELL) $(.SHELLFLAGS) "command -v dsymutil") darwin_NM=$(shell $(SHELL) $(.SHELLFLAGS) "command -v llvm-nm") +darwin_OBJCOPY=$(shell $(SHELL) $(.SHELLFLAGS) "command -v llvm-objcopy") 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") diff --git a/depends/hosts/default.mk b/depends/hosts/default.mk index d82c33f29ce0..54c12c818024 100644 --- a/depends/hosts/default.mk +++ b/depends/hosts/default.mk @@ -38,5 +38,5 @@ host_$1 = $$($(host_arch)_$(host_os)_$1) host_$(release_type)_$1 = $$($(host_arch)_$(host_os)_$(release_type)_$1) endef -$(foreach tool,CC CXX AR RANLIB STRIP NM OBJCOPY OBJDUMP DSYMUTIL,$(eval $(call add_host_tool_func,$(tool)))) +$(foreach tool,CC CXX AR RANLIB STRIP NM OBJCOPY OBJDUMP DSYMUTIL WINDRES,$(eval $(call add_host_tool_func,$(tool)))) $(foreach flags,CFLAGS CXXFLAGS CPPFLAGS LDFLAGS, $(eval $(call add_host_flags_func,$(flags)))) diff --git a/depends/hosts/freebsd.mk b/depends/hosts/freebsd.mk index 055097b03ddc..3b265f647dc7 100644 --- a/depends/hosts/freebsd.mk +++ b/depends/hosts/freebsd.mk @@ -4,7 +4,7 @@ freebsd_CXXFLAGS=-pipe -std=$(CXX_STANDARD) freebsd_release_CFLAGS=-O2 freebsd_release_CXXFLAGS=$(freebsd_release_CFLAGS) -freebsd_debug_CFLAGS=-O1 +freebsd_debug_CFLAGS=-O1 -g freebsd_debug_CXXFLAGS=$(freebsd_debug_CFLAGS) ifeq (86,$(findstring 86,$(build_arch))) diff --git a/depends/hosts/mingw32.mk b/depends/hosts/mingw32.mk index 4c657358f6a5..e324fd2fffe6 100644 --- a/depends/hosts/mingw32.mk +++ b/depends/hosts/mingw32.mk @@ -11,6 +11,8 @@ mingw32_NM = $(host_toolchain)gcc-nm mingw32_RANLIB = $(host_toolchain)gcc-ranlib endif +mingw32_WINDRES = $(host_toolchain)windres + mingw32_release_CFLAGS=-O2 mingw32_release_CXXFLAGS=$(mingw32_release_CFLAGS) diff --git a/depends/hosts/netbsd.mk b/depends/hosts/netbsd.mk index 6e0fa9e12fb7..842c015ca30a 100644 --- a/depends/hosts/netbsd.mk +++ b/depends/hosts/netbsd.mk @@ -10,7 +10,7 @@ endif netbsd_release_CFLAGS=-O2 netbsd_release_CXXFLAGS=$(netbsd_release_CFLAGS) -netbsd_debug_CFLAGS=-O1 +netbsd_debug_CFLAGS=-O1 -g netbsd_debug_CXXFLAGS=$(netbsd_debug_CFLAGS) ifeq (86,$(findstring 86,$(build_arch))) diff --git a/depends/hosts/openbsd.mk b/depends/hosts/openbsd.mk index bdd36dc9b35d..b6db8575ff7a 100644 --- a/depends/hosts/openbsd.mk +++ b/depends/hosts/openbsd.mk @@ -4,7 +4,7 @@ openbsd_CXXFLAGS=-pipe -std=$(CXX_STANDARD) openbsd_release_CFLAGS=-O2 openbsd_release_CXXFLAGS=$(openbsd_release_CFLAGS) -openbsd_debug_CFLAGS=-O1 +openbsd_debug_CFLAGS=-O1 -g openbsd_debug_CXXFLAGS=$(openbsd_debug_CFLAGS) ifeq (86,$(findstring 86,$(build_arch))) diff --git a/depends/packages/backtrace.mk b/depends/packages/backtrace.mk index de7f02fefc18..95717952e388 100644 --- a/depends/packages/backtrace.mk +++ b/depends/packages/backtrace.mk @@ -1,9 +1,9 @@ package=backtrace -$(package)_version=11427f31a64b11583fec94b4c2a265c7dafb1ab3 +$(package)_version=b9e40069c0b47a722286b94eb5231f7f05c08713 $(package)_download_path=https://github.com/ianlancetaylor/libbacktrace/archive $(package)_download_file=$($(package)_version).tar.gz $(package)_file_name=$(package)_$($(package)_version).tar.gz -$(package)_sha256_hash=76a8348ff04d80141aeb1c0e55879f17f241f38238def0eb1df7c6d1ac1a2c26 +$(package)_sha256_hash=81b37e762965c676b3316e90564c89f6480606add446651c785862571a1fdbca define $(package)_set_vars $(package)_config_opts=--disable-shared --enable-host-shared --prefix=$(host_prefix) diff --git a/depends/packages/boost.mk b/depends/packages/boost.mk index 5e610362278e..a47fd1c691a2 100644 --- a/depends/packages/boost.mk +++ b/depends/packages/boost.mk @@ -1,8 +1,8 @@ package=boost $(package)_version=1.81.0 $(package)_download_path=https://archives.boost.io/release/$($(package)_version)/source/ -$(package)_file_name=boost_$(subst .,_,$($(package)_version)).tar.bz2 -$(package)_sha256_hash=71feeed900fbccca04a3b4f2f84a7c217186f28a940ed8b7ed4725986baf99fa +$(package)_file_name=boost_$(subst .,_,$($(package)_version)).tar.gz +$(package)_sha256_hash=205666dea9f6a7cfed87c7a6dfbeb52a2c1b9de55712c9c1a87735d7181452b6 $(package)_patches=process_macos_sdk.patch define $(package)_preprocess_cmds diff --git a/depends/packages/capnp.mk b/depends/packages/capnp.mk index 6d792db71136..0964ede3d31b 100644 --- a/depends/packages/capnp.mk +++ b/depends/packages/capnp.mk @@ -4,11 +4,19 @@ $(package)_download_path=$(native_$(package)_download_path) $(package)_download_file=$(native_$(package)_download_file) $(package)_file_name=$(native_$(package)_file_name) $(package)_sha256_hash=$(native_$(package)_sha256_hash) +$(package)_patches=abi_placement_new.patch +$(package)_patches += fix_openbsd_build.patch define $(package)_set_vars := $(package)_config_opts := -DBUILD_TESTING=OFF $(package)_config_opts += -DWITH_OPENSSL=OFF $(package)_config_opts += -DWITH_ZLIB=OFF + $(package)_cxxflags += -fdebug-prefix-map=$($(package)_extract_dir)=/usr -fmacro-prefix-map=$($(package)_extract_dir)=/usr +endef + +define $(package)_preprocess_cmds + patch -p2 < $($(package)_patch_dir)/abi_placement_new.patch && \ + patch -p2 < $($(package)_patch_dir)/fix_openbsd_build.patch endef define $(package)_config_cmds diff --git a/depends/packages/fontconfig.mk b/depends/packages/fontconfig.mk index 444acfe36d74..6baaecc55a76 100644 --- a/depends/packages/fontconfig.mk +++ b/depends/packages/fontconfig.mk @@ -1,8 +1,8 @@ package=fontconfig $(package)_version=2.12.6 $(package)_download_path=https://www.freedesktop.org/software/fontconfig/release/ -$(package)_file_name=$(package)-$($(package)_version).tar.bz2 -$(package)_sha256_hash=cf0c30807d08f6a28ab46c61b8dbd55c97d2f292cf88f3a07d3384687f31f017 +$(package)_file_name=$(package)-$($(package)_version).tar.gz +$(package)_sha256_hash=064b9ebf060c9e77011733ac9dc0e2ce92870b574cca2405e11f5353a683c334 $(package)_dependencies=freetype expat $(package)_patches=gperf_header_regen.patch diff --git a/depends/packages/gmp.mk b/depends/packages/gmp.mk index 3d645cd02a69..03ec302caede 100644 --- a/depends/packages/gmp.mk +++ b/depends/packages/gmp.mk @@ -1,8 +1,8 @@ package=gmp $(package)_version=6.3.0 $(package)_download_path=https://ftp.gnu.org/gnu/gmp -$(package)_file_name=gmp-$($(package)_version).tar.bz2 -$(package)_sha256_hash=ac28211a7cfb609bae2e2c8d6058d66c8fe96434f740cf6fe2e47b000d1c20cb +$(package)_file_name=gmp-$($(package)_version).tar.gz +$(package)_sha256_hash=e56fd59d76810932a0555aa15a14b61c16bed66110d3c75cc2ac49ddaa9ab24c $(package)_patches=include_ldflags_in_configure.patch define $(package)_set_vars diff --git a/depends/packages/libXau.mk b/depends/packages/libXau.mk index aeb14dcd6e8e..6bafc4f41a67 100644 --- a/depends/packages/libXau.mk +++ b/depends/packages/libXau.mk @@ -1,8 +1,8 @@ package=libXau $(package)_version=1.0.9 $(package)_download_path=https://xorg.freedesktop.org/releases/individual/lib/ -$(package)_file_name=$(package)-$($(package)_version).tar.bz2 -$(package)_sha256_hash=ccf8cbf0dbf676faa2ea0a6d64bcc3b6746064722b606c8c52917ed00dcb73ec +$(package)_file_name=$(package)-$($(package)_version).tar.gz +$(package)_sha256_hash=1f123d8304b082ad63a9e89376400a3b1d4c29e67e3ea07b3f659cccca690eea $(package)_dependencies=xproto # When updating this package, check the default value of diff --git a/depends/packages/libevent.mk b/depends/packages/libevent.mk index 4c05e8a0a742..bcc7cd067030 100644 --- a/depends/packages/libevent.mk +++ b/depends/packages/libevent.mk @@ -4,27 +4,32 @@ $(package)_download_path=https://github.com/libevent/libevent/releases/download/ $(package)_file_name=$(package)-$($(package)_version).tar.gz $(package)_sha256_hash=92e6de1be9ec176428fd2367677e61ceffc2ee1cb119035037a27d346b0403bb $(package)_patches=cmake_fixups.patch -$(package)_patches+=fix_mingw_link.patch +$(package)_patches += fix_mingw_link.patch +$(package)_patches += netbsd_fixup.patch +$(package)_patches += winver_fixup.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=-DEVENT__DISABLE_BENCHMARK=ON -DEVENT__DISABLE_OPENSSL=ON + $(package)_config_opts=-DCMAKE_BUILD_TYPE=None -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)_cflags += -fdebug-prefix-map=$($(package)_extract_dir)=/usr -fmacro-prefix-map=$($(package)_extract_dir)=/usr $(package)_cppflags += -D_GNU_SOURCE $(package)_cppflags_mingw32=-D_WIN32_WINNT=0x0601 ifeq ($(NO_HARDEN),) - $(package)_cppflags+=-D_FORTIFY_SOURCE=3 + $(package)_cppflags += -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=3 endif endef define $(package)_preprocess_cmds patch -p1 < $($(package)_patch_dir)/cmake_fixups.patch && \ - patch -p1 < $($(package)_patch_dir)/fix_mingw_link.patch + patch -p1 < $($(package)_patch_dir)/fix_mingw_link.patch && \ + patch -p1 < $($(package)_patch_dir)/netbsd_fixup.patch && \ + patch -p1 < $($(package)_patch_dir)/winver_fixup.patch endef define $(package)_config_cmds diff --git a/depends/packages/libmultiprocess.mk b/depends/packages/libmultiprocess.mk index c292c49bfbab..afbd315e3880 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 += -fdebug-prefix-map=$($(package)_extract_dir)=/usr -fmacro-prefix-map=$($(package)_extract_dir)=/usr endef define $(package)_config_cmds diff --git a/depends/packages/libxcb_util.mk b/depends/packages/libxcb_util.mk index 6e4c7359b20e..dc4456f85c84 100644 --- a/depends/packages/libxcb_util.mk +++ b/depends/packages/libxcb_util.mk @@ -1,8 +1,8 @@ package=libxcb_util $(package)_version=0.4.0 $(package)_download_path=https://xcb.freedesktop.org/dist -$(package)_file_name=xcb-util-$($(package)_version).tar.bz2 -$(package)_sha256_hash=46e49469cb3b594af1d33176cd7565def2be3fa8be4371d62271fabb5eae50e9 +$(package)_file_name=xcb-util-$($(package)_version).tar.gz +$(package)_sha256_hash=0ed0934e2ef4ddff53fcc70fc64fb16fe766cd41ee00330312e20a985fd927a7 $(package)_dependencies=libxcb define $(package)_set_vars diff --git a/depends/packages/libxcb_util_image.mk b/depends/packages/libxcb_util_image.mk index d12d67e8e888..2228250fecb1 100644 --- a/depends/packages/libxcb_util_image.mk +++ b/depends/packages/libxcb_util_image.mk @@ -1,8 +1,8 @@ package=libxcb_util_image $(package)_version=0.4.0 $(package)_download_path=https://xcb.freedesktop.org/dist -$(package)_file_name=xcb-util-image-$($(package)_version).tar.bz2 -$(package)_sha256_hash=2db96a37d78831d643538dd1b595d7d712e04bdccf8896a5e18ce0f398ea2ffc +$(package)_file_name=xcb-util-image-$($(package)_version).tar.gz +$(package)_sha256_hash=cb2c86190cf6216260b7357a57d9100811bb6f78c24576a3a5bfef6ad3740a42 $(package)_dependencies=libxcb libxcb_util define $(package)_set_vars diff --git a/depends/packages/libxcb_util_keysyms.mk b/depends/packages/libxcb_util_keysyms.mk index d4f72dedbea7..56bc33d258da 100644 --- a/depends/packages/libxcb_util_keysyms.mk +++ b/depends/packages/libxcb_util_keysyms.mk @@ -1,8 +1,8 @@ package=libxcb_util_keysyms $(package)_version=0.4.0 $(package)_download_path=https://xcb.freedesktop.org/dist -$(package)_file_name=xcb-util-keysyms-$($(package)_version).tar.bz2 -$(package)_sha256_hash=0ef8490ff1dede52b7de533158547f8b454b241aa3e4dcca369507f66f216dd9 +$(package)_file_name=xcb-util-keysyms-$($(package)_version).tar.gz +$(package)_sha256_hash=0807cf078fbe38489a41d755095c58239e1b67299f14460dec2ec811e96caa96 $(package)_dependencies=libxcb xproto define $(package)_set_vars diff --git a/depends/packages/libxcb_util_render.mk b/depends/packages/libxcb_util_render.mk index 28f1fb073c68..ee2883fedaa1 100644 --- a/depends/packages/libxcb_util_render.mk +++ b/depends/packages/libxcb_util_render.mk @@ -1,8 +1,8 @@ package=libxcb_util_render $(package)_version=0.3.9 $(package)_download_path=https://xcb.freedesktop.org/dist -$(package)_file_name=xcb-util-renderutil-$($(package)_version).tar.bz2 -$(package)_sha256_hash=c6e97e48fb1286d6394dddb1c1732f00227c70bd1bedb7d1acabefdd340bea5b +$(package)_file_name=xcb-util-renderutil-$($(package)_version).tar.gz +$(package)_sha256_hash=55eee797e3214fe39d0f3f4d9448cc53cffe06706d108824ea37bb79fcedcad5 $(package)_dependencies=libxcb define $(package)_set_vars diff --git a/depends/packages/libxcb_util_wm.mk b/depends/packages/libxcb_util_wm.mk index 3b905ba4ec55..a68fd23f8a77 100644 --- a/depends/packages/libxcb_util_wm.mk +++ b/depends/packages/libxcb_util_wm.mk @@ -1,8 +1,8 @@ package=libxcb_util_wm $(package)_version=0.4.1 $(package)_download_path=https://xcb.freedesktop.org/dist -$(package)_file_name=xcb-util-wm-$($(package)_version).tar.bz2 -$(package)_sha256_hash=28bf8179640eaa89276d2b0f1ce4285103d136be6c98262b6151aaee1d3c2a3f +$(package)_file_name=xcb-util-wm-$($(package)_version).tar.gz +$(package)_sha256_hash=038b39c4bdc04a792d62d163ba7908f4bb3373057208c07110be73c1b04b8334 $(package)_dependencies=libxcb define $(package)_set_vars diff --git a/depends/packages/native_capnp.mk b/depends/packages/native_capnp.mk index 484e78d5d906..c886d8e239df 100644 --- a/depends/packages/native_capnp.mk +++ b/depends/packages/native_capnp.mk @@ -1,9 +1,10 @@ package=native_capnp -$(package)_version=1.0.1 +$(package)_version=1.1.0 $(package)_download_path=https://capnproto.org/ $(package)_download_file=capnproto-c++-$($(package)_version).tar.gz $(package)_file_name=capnproto-cxx-$($(package)_version).tar.gz -$(package)_sha256_hash=0f7f4b8a76a2cdb284fddef20de8306450df6dd031a47a15ac95bc43c3358e09 +$(package)_sha256_hash=07167580e563f5e821e3b2af1c238c16ec7181612650c5901330fa9a0da50939 +$(package)_patches=fix_openbsd_build.patch define $(package)_set_vars $(package)_config_opts := -DBUILD_TESTING=OFF @@ -11,6 +12,10 @@ define $(package)_set_vars $(package)_config_opts += -DWITH_ZLIB=OFF endef +define $(package)_preprocess_cmds + patch -p2 < $($(package)_patch_dir)/fix_openbsd_build.patch +endef + define $(package)_config_cmds $($(package)_cmake) . endef diff --git a/depends/packages/native_libmultiprocess.mk b/depends/packages/native_libmultiprocess.mk index 2e30be434cd1..8273f1508466 100644 --- a/depends/packages/native_libmultiprocess.mk +++ b/depends/packages/native_libmultiprocess.mk @@ -1,6 +1,6 @@ package=native_libmultiprocess $(package)_version=6aca5f389bacf2942394b8738bbe15d6c9edfb9b -$(package)_download_path=https://github.com/chaincodelabs/libmultiprocess/archive +$(package)_download_path=https://github.com/bitcoin-core/libmultiprocess/archive $(package)_file_name=$($(package)_version).tar.gz $(package)_sha256_hash=2efeed53542bc1d8af3291f2b6f0e5d430d86a5e04e415ce33c136f2c226a51d $(package)_dependencies=native_capnp diff --git a/depends/packages/packages.mk b/depends/packages/packages.mk index 40f9ae6ad577..7e0bb2633219 100644 --- a/depends/packages/packages.mk +++ b/depends/packages/packages.mk @@ -10,6 +10,7 @@ qrencode_darwin_packages = qrencode qrencode_mingw32_packages = qrencode qt_linux_packages:=qt expat libxcb xcb_proto libXau xproto freetype fontconfig libxkbcommon libxcb_util libxcb_util_render libxcb_util_keysyms libxcb_util_image libxcb_util_wm +qt_freebsd_packages:=$(qt_linux_packages) qt_android_packages=qt qt_darwin_packages=qt qt_mingw32_packages=qt diff --git a/depends/packages/qrencode.mk b/depends/packages/qrencode.mk index c769ae078f12..9aae62f01c1c 100644 --- a/depends/packages/qrencode.mk +++ b/depends/packages/qrencode.mk @@ -1,8 +1,9 @@ package=qrencode $(package)_version=4.1.1 -$(package)_download_path=https://fukuchi.org/works/qrencode/ -$(package)_file_name=$(package)-$($(package)_version).tar.bz2 -$(package)_sha256_hash=e455d9732f8041cf5b9c388e345a641fd15707860f928e94507b1961256a6923 +$(package)_download_path=https://github.com/fukuchi/libqrencode/archive/refs/tags/ +$(package)_download_file=v$($(package)_version).tar.gz +$(package)_file_name=$(package)-$($(package)_version).tar.gz +$(package)_sha256_hash=5385bc1b8c2f20f3b91d258bf8ccc8cf62023935df2d2676b5b67049f31a049c $(package)_patches=cmake_fixups.patch define $(package)_set_vars diff --git a/depends/packages/qt.mk b/depends/packages/qt.mk index 5e0e20aa38df..18aedcf7afcf 100644 --- a/depends/packages/qt.mk +++ b/depends/packages/qt.mk @@ -1,10 +1,11 @@ package=qt -$(package)_version=5.15.14 -$(package)_download_path=https://download.qt.io/official_releases/qt/5.15/$($(package)_version)/submodules +$(package)_version=5.15.18 +$(package)_download_path=https://download.qt.io/archive/qt/5.15/$($(package)_version)/submodules $(package)_suffix=everywhere-opensource-src-$($(package)_version).tar.xz $(package)_file_name=qtbase-$($(package)_suffix) -$(package)_sha256_hash=500d3b390048e9538c28b5f523dfea6936f9c2e10d24ab46580ff57d430b98be -$(package)_linux_dependencies=freetype fontconfig libxcb libxkbcommon libxcb_util libxcb_util_render libxcb_util_keysyms libxcb_util_image libxcb_util_wm +$(package)_sha256_hash=7b632550ea1048fc10c741e46e2e3b093e5ca94dfa6209e9e0848800e247023b +$(package)_linux_dependencies := freetype fontconfig libxcb libxkbcommon libxcb_util libxcb_util_render libxcb_util_keysyms libxcb_util_image libxcb_util_wm +$(package)_freebsd_dependencies := $($(package)_linux_dependencies) $(package)_qt_libs=corelib network widgets gui plugins testlib $(package)_linguist_tools = lrelease lupdate lconvert $(package)_patches = qt.pro @@ -19,19 +20,19 @@ $(package)_patches += no_warnings_for_symbols.patch $(package)_patches += rcc_hardcode_timestamp.patch $(package)_patches += duplicate_lcqpafonts.patch $(package)_patches += guix_cross_lib_path.patch -$(package)_patches += fix-macos-linker.patch $(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)_patches += CVE-2025-4211-qtbase-5.15.patch +$(package)_patches += CVE-2025-5455-qtbase-5.15.patch +$(package)_patches += CVE-2025-30348-qtbase-5.15.patch $(package)_qttranslations_file_name=qttranslations-$($(package)_suffix) -$(package)_qttranslations_sha256_hash=5b94d1a11b566908622fcca2f8b799744d2f8a68da20be4caa5953ed63b10489 +$(package)_qttranslations_sha256_hash=e5625757913caf66a9d702ba102ae92cb165d8dde17759b6de9fdea84a1f857f $(package)_qttools_file_name=qttools-$($(package)_suffix) -$(package)_qttools_sha256_hash=12061a85baf5f4de8fbc795e1d3872b706f340211b9e70962caeffc6f5e89563 +$(package)_qttools_sha256_hash=931e0969d9f9d8f233e5e9bf9db0cea9ce9914d49982f1795fe6191010113568 $(package)_extra_sources = $($(package)_qttranslations_file_name) $(package)_extra_sources += $($(package)_qttools_file_name) @@ -161,6 +162,7 @@ $(package)_config_opts_linux += -dbus-runtime ifneq ($(LTO),) $(package)_config_opts_linux += -ltcg endif +$(package)_config_opts_freebsd := $$($(package)_config_opts_linux) ifneq (,$(findstring clang,$($(package)_cxx))) ifneq (,$(findstring -stdlib=libc++,$($(package)_cxx))) @@ -242,7 +244,6 @@ endef define $(package)_preprocess_cmds cp $($(package)_patch_dir)/qt.pro qt.pro && \ cp $($(package)_patch_dir)/qttools_src.pro qttools/src/src.pro && \ - patch -p1 -i $($(package)_patch_dir)/fix-macos-linker.patch && \ patch -p1 -i $($(package)_patch_dir)/dont_hardcode_pwd.patch && \ patch -p1 -i $($(package)_patch_dir)/fix_qt_pkgconfig.patch && \ patch -p1 -i $($(package)_patch_dir)/fix_android_jni_static.patch && \ @@ -250,14 +251,15 @@ define $(package)_preprocess_cmds patch -p1 -i $($(package)_patch_dir)/qtbase-moc-ignore-gcc-macro.patch && \ patch -p1 -i $($(package)_patch_dir)/memory_resource.patch && \ patch -p1 -i $($(package)_patch_dir)/no_warnings_for_symbols.patch && \ - patch -p1 -i $($(package)_patch_dir)/clang_18_libpng.patch && \ patch -p1 -i $($(package)_patch_dir)/rcc_hardcode_timestamp.patch && \ patch -p1 -i $($(package)_patch_dir)/duplicate_lcqpafonts.patch && \ 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 && \ + patch -p1 -i $($(package)_patch_dir)/CVE-2025-4211-qtbase-5.15.patch && \ + patch -p1 -i $($(package)_patch_dir)/CVE-2025-5455-qtbase-5.15.patch && \ + patch -p1 -i $($(package)_patch_dir)/CVE-2025-30348-qtbase-5.15.patch && \ mkdir -p qtbase/mkspecs/macx-clang-linux &&\ cp -f qtbase/mkspecs/macx-clang/qplatformdefs.h qtbase/mkspecs/macx-clang-linux/ &&\ cp -f $($(package)_patch_dir)/mac-qmake.conf qtbase/mkspecs/macx-clang-linux/qmake.conf && \ diff --git a/depends/packages/xproto.mk b/depends/packages/xproto.mk index 7a43c52faf43..0a534556ee4a 100644 --- a/depends/packages/xproto.mk +++ b/depends/packages/xproto.mk @@ -1,8 +1,8 @@ package=xproto $(package)_version=7.0.31 $(package)_download_path=https://xorg.freedesktop.org/releases/individual/proto -$(package)_file_name=$(package)-$($(package)_version).tar.bz2 -$(package)_sha256_hash=c6f9747da0bd3a95f86b17fb8dd5e717c8f3ab7f0ece3ba1b247899ec1ef7747 +$(package)_file_name=$(package)-$($(package)_version).tar.gz +$(package)_sha256_hash=6d755eaae27b45c5cc75529a12855fed5de5969b367ed05003944cf901ed43c7 define $(package)_set_vars $(package)_config_opts=--without-fop --without-xmlto --without-xsltproc --disable-specs @@ -21,6 +21,8 @@ define $(package)_build_cmds $(MAKE) endef +# mkdir detection is broken on Alpine. Set MKDIRPROG to ensure we always +# use "mkdir -p", and avoid parallelism issues during install. define $(package)_stage_cmds - $(MAKE) DESTDIR=$($(package)_staging_dir) install + $(MAKE) MKDIRPROG="mkdir -p" DESTDIR=$($(package)_staging_dir) install endef diff --git a/depends/packages/zeromq.mk b/depends/packages/zeromq.mk index 21e162c792b5..9cb0831d22cb 100644 --- a/depends/packages/zeromq.mk +++ b/depends/packages/zeromq.mk @@ -19,9 +19,8 @@ define $(package)_set_vars $(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)_cxxflags += -fdebug-prefix-map=$($(package)_extract_dir)=/usr -fmacro-prefix-map=$($(package)_extract_dir)=/usr $(package)_config_opts_mingw32 += -DZMQ_WIN32_WINNT=0x0601 -DZMQ_HAVE_IPC=OFF - $(package)_config_opts_mingw32 += -DCMAKE_RC_COMPILER=x86_64-w64-mingw32-windres endef define $(package)_preprocess_cmds diff --git a/depends/patches/capnp/abi_placement_new.patch b/depends/patches/capnp/abi_placement_new.patch new file mode 100644 index 000000000000..9aef85db8e86 --- /dev/null +++ b/depends/patches/capnp/abi_placement_new.patch @@ -0,0 +1,71 @@ +From 74560f26f75dda4257dce541ca362a1e763b2971 Mon Sep 17 00:00:00 2001 +From: Ryan Ofsky +Date: Thu, 6 Feb 2025 08:39:05 -0500 +Subject: [PATCH 1/1] Avoid gcc/clang ABI incompatibility caused by + PlacementNew + +GCC and clang do not use same calling convention for passing empty struct +parameters. There is more information about this in +https://itanium-cxx-abi.github.io/cxx-abi/cxx-abi-dev/archives/2015-December/002869.html + +Unfortunately this can create an issue in capnproto if it is built without +optimizations in GCC, and the resulting static libraries are used in a clang +program, or vice versa. + +Depending on what order libraries are specified on the linker command line, and +whether code compiled with the other compiler is calling any header functions +that cause weak a `operator new(unsigned int, kj::_::PlacementNew, void*)` +symbol to be defined in its own objects, this can cause the linker to link a +GCC-generated `kj::ctor` with a clang-generated `operator new`, and the +resulting program to crash due to the compilers using different calling +conventions for `operator new`. + +This problem is difficult to avoid in general, but pretty easy to avoid here by +changing `operator new` parameter order so the empty struct parameter is last. + +This change should be beneficial for capnproto users that may be compiling it +without optimizations, and not necessarily using a single compiler to build all +their dependencies. + +The problem does not occur if any optimizations are enabled because `operator +new` calls are inlined in that case. +--- + c++/src/kj/common.h | 11 +++++++---- + 1 file changed, 7 insertions(+), 4 deletions(-) + +diff --git a/c++/src/kj/common.h b/c++/src/kj/common.h +index b8edde3c..28ab11d6 100644 +--- a/c++/src/kj/common.h ++++ b/c++/src/kj/common.h +@@ -1034,24 +1034,27 @@ private: + + // We want placement new, but we don't want to #include . operator new cannot be defined in + // a namespace, and defining it globally conflicts with the definition in . So we have to +-// define a dummy type and an operator new that uses it. ++// define a dummy type and an operator new that uses it. The dummy type is intentionally passed ++// as the last parameter so clang and GCC ABI calling conventions for empty struct struct parameters ++// are compatible, and there are not segfaults trying to call clang operator new/delete from GCC or ++// vice versa. + + namespace _ { // private + struct PlacementNew {}; + } // namespace _ (private) + } // namespace kj + +-inline void* operator new(size_t, kj::_::PlacementNew, void* __p) noexcept { ++inline void* operator new(size_t, void* __p, kj::_::PlacementNew) noexcept { + return __p; + } + +-inline void operator delete(void*, kj::_::PlacementNew, void* __p) noexcept {} ++inline void operator delete(void*, void* __p, kj::_::PlacementNew) noexcept {} + + namespace kj { + + template + inline void ctor(T& location, Params&&... params) { +- new (_::PlacementNew(), &location) T(kj::fwd(params)...); ++ new (&location, _::PlacementNew()) T(kj::fwd(params)...); + } + + template diff --git a/depends/patches/capnp/fix_openbsd_build.patch b/depends/patches/capnp/fix_openbsd_build.patch new file mode 100644 index 000000000000..eb143c61e4dc --- /dev/null +++ b/depends/patches/capnp/fix_openbsd_build.patch @@ -0,0 +1,71 @@ +From 0cd1792332dce6a3afae6e2bc2939da69fea65fa Mon Sep 17 00:00:00 2001 +From: Sebastian Falbesoner +Date: Sat, 31 May 2025 00:49:44 +0200 +Subject: [PATCH 1/2] In cidr.c++, include on all non-Windows + systems + +The motivation for this commit is to fix the build for OpenBSD, +but it may also solves the same potential problem for other systems +without causing any harm. + +Suggested already twice, see +https://github.com/capnproto/capnproto/pull/1846#discussion_r1399499535 +https://github.com/capnproto/capnproto/pull/1907#discussion_r1452602424 +--- + c++/src/kj/cidr.c++ | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/c++/src/kj/cidr.c++ b/c++/src/kj/cidr.c++ +index 6a1fa32e..9432b8f4 100644 +--- a/c++/src/kj/cidr.c++ ++++ b/c++/src/kj/cidr.c++ +@@ -39,9 +39,6 @@ + #else + #include + #include +-#endif +- +-#if __FreeBSD__ + #include + #endif + +-- +2.49.0 + + +From 2e76d17db3fc484061487c0779b16495939d30c3 Mon Sep 17 00:00:00 2001 +From: Sebastian Falbesoner +Date: Sat, 31 May 2025 01:06:42 +0200 +Subject: [PATCH 2/2] Don't set KJ_USE_KQUEUE on OpenBSD + +OpenBSD doesn't support user event filters yet, hence +the build fails as it misses the symbol EVFILT_USER in +the kqueue implementation in async-unix.c++. Fix that +by not setting KJ_USE_KQUEUE on OpenBSD, so the poll()- +based implementation is used instead. + +Suggested in +https://github.com/capnproto/capnproto/pull/1907/commits/829d3f03735f8f6762a50fc346db56bf02140f02#r1452600300 +--- + c++/src/kj/async-unix.h | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/c++/src/kj/async-unix.h b/c++/src/kj/async-unix.h +index 665305ea..e66ad8e4 100644 +--- a/c++/src/kj/async-unix.h ++++ b/c++/src/kj/async-unix.h +@@ -37,8 +37,9 @@ KJ_BEGIN_HEADER + #if __linux__ + // Default to epoll on Linux. + #define KJ_USE_EPOLL 1 +-#elif __APPLE__ || __FreeBSD__ || __OpenBSD__ || __NetBSD__ || __DragonFly__ +-// MacOS and BSDs prefer kqueue() for event notification. ++#elif __APPLE__ || __FreeBSD__ || __NetBSD__ || __DragonFly__ ++// MacOS and most BSDs prefer kqueue() for event notification. ++// (Note that OpenBSD's kqueue(2) doesn't support user event filters yet) + #define KJ_USE_KQUEUE 1 + #endif + #endif +-- +2.49.0 + diff --git a/depends/patches/libevent/netbsd_fixup.patch b/depends/patches/libevent/netbsd_fixup.patch new file mode 100644 index 000000000000..21d96aaf452c --- /dev/null +++ b/depends/patches/libevent/netbsd_fixup.patch @@ -0,0 +1,23 @@ +Improve portability on NetBSD + +According to GCC documentation, "the various `-std` options disable +certain keywords". +This change adheres to GCC's recommendation by replacing the `typeof` +keyword with its alternative, `__typeof__`. + +See https://github.com/libevent/libevent/commit/1759485e9a59147a47a674f5132fcfe764e7748c. + + +--- a/kqueue.c ++++ b/kqueue.c +@@ -52,8 +52,8 @@ + * intptr_t, whereas others define it as void*. There doesn't seem to be an + * easy way to tell them apart via autoconf, so we need to use OS macros. */ + #if defined(__NetBSD__) +-#define PTR_TO_UDATA(x) ((typeof(((struct kevent *)0)->udata))(x)) +-#define INT_TO_UDATA(x) ((typeof(((struct kevent *)0)->udata))(intptr_t)(x)) ++#define PTR_TO_UDATA(x) ((__typeof__(((struct kevent *)0)->udata))(x)) ++#define INT_TO_UDATA(x) ((__typeof__(((struct kevent *)0)->udata))(intptr_t)(x)) + #elif defined(EVENT__HAVE_INTTYPES_H) && !defined(__OpenBSD__) && !defined(__FreeBSD__) && !defined(__darwin__) && !defined(__APPLE__) && !defined(__CloudABI__) + #define PTR_TO_UDATA(x) ((intptr_t)(x)) + #define INT_TO_UDATA(x) ((intptr_t)(x)) diff --git a/depends/patches/libevent/winver_fixup.patch b/depends/patches/libevent/winver_fixup.patch new file mode 100644 index 000000000000..4995c356f942 --- /dev/null +++ b/depends/patches/libevent/winver_fixup.patch @@ -0,0 +1,122 @@ +Cherry-picked from a14ff91254f40cf36e0fee199e26fb11260fab49. + +move _WIN32_WINNT defintions before first #include + +_WIN32_WINNT and WIN32_LEAN_AND_MEAN need to be defined +before the windows.h is included for the first time. +Avoid the confusion of indirect #include by defining +before any. + +diff --git a/event_iocp.c b/event_iocp.c +index 6b2a2e15..4955e426 100644 +--- a/event_iocp.c ++++ b/event_iocp.c +@@ -23,12 +23,14 @@ + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +-#include "evconfig-private.h" + + #ifndef _WIN32_WINNT + /* Minimum required for InitializeCriticalSectionAndSpinCount */ + #define _WIN32_WINNT 0x0403 + #endif ++ ++#include "evconfig-private.h" ++ + #include + #include + #include +diff --git a/evthread_win32.c b/evthread_win32.c +index 2ec80560..8647f72b 100644 +--- a/evthread_win32.c ++++ b/evthread_win32.c +@@ -23,18 +23,21 @@ + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +-#include "event2/event-config.h" +-#include "evconfig-private.h" + + #ifdef _WIN32 + #ifndef _WIN32_WINNT + /* Minimum required for InitializeCriticalSectionAndSpinCount */ + #define _WIN32_WINNT 0x0403 + #endif +-#include + #define WIN32_LEAN_AND_MEAN ++#endif ++ ++#include "event2/event-config.h" ++#include "evconfig-private.h" ++ ++#ifdef _WIN32 ++#include + #include +-#undef WIN32_LEAN_AND_MEAN + #include + #endif + +diff --git a/evutil.c b/evutil.c +index 9817f086..8537ffe8 100644 +--- a/evutil.c ++++ b/evutil.c +@@ -24,6 +24,14 @@ + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + ++#ifdef _WIN32 ++#ifndef _WIN32_WINNT ++/* For structs needed by GetAdaptersAddresses */ ++#define _WIN32_WINNT 0x0501 ++#endif ++#define WIN32_LEAN_AND_MEAN ++#endif ++ + #include "event2/event-config.h" + #include "evconfig-private.h" + +@@ -31,15 +39,10 @@ + #include + #include + #include +-#define WIN32_LEAN_AND_MEAN + #include +-#undef WIN32_LEAN_AND_MEAN + #include + #include + #include +-#undef _WIN32_WINNT +-/* For structs needed by GetAdaptersAddresses */ +-#define _WIN32_WINNT 0x0501 + #include + #include + #endif +diff --git a/listener.c b/listener.c +index f5c00c9c..d1080e76 100644 +--- a/listener.c ++++ b/listener.c +@@ -24,16 +24,19 @@ + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + ++#ifdef _WIN32 ++#ifndef _WIN32_WINNT ++/* Minimum required for InitializeCriticalSectionAndSpinCount */ ++#define _WIN32_WINNT 0x0403 ++#endif ++#endif ++ + #include "event2/event-config.h" + #include "evconfig-private.h" + + #include + + #ifdef _WIN32 +-#ifndef _WIN32_WINNT +-/* Minimum required for InitializeCriticalSectionAndSpinCount */ +-#define _WIN32_WINNT 0x0403 +-#endif + #include + #include + #include diff --git a/depends/patches/native_capnp/fix_openbsd_build.patch b/depends/patches/native_capnp/fix_openbsd_build.patch new file mode 100644 index 000000000000..eb143c61e4dc --- /dev/null +++ b/depends/patches/native_capnp/fix_openbsd_build.patch @@ -0,0 +1,71 @@ +From 0cd1792332dce6a3afae6e2bc2939da69fea65fa Mon Sep 17 00:00:00 2001 +From: Sebastian Falbesoner +Date: Sat, 31 May 2025 00:49:44 +0200 +Subject: [PATCH 1/2] In cidr.c++, include on all non-Windows + systems + +The motivation for this commit is to fix the build for OpenBSD, +but it may also solves the same potential problem for other systems +without causing any harm. + +Suggested already twice, see +https://github.com/capnproto/capnproto/pull/1846#discussion_r1399499535 +https://github.com/capnproto/capnproto/pull/1907#discussion_r1452602424 +--- + c++/src/kj/cidr.c++ | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/c++/src/kj/cidr.c++ b/c++/src/kj/cidr.c++ +index 6a1fa32e..9432b8f4 100644 +--- a/c++/src/kj/cidr.c++ ++++ b/c++/src/kj/cidr.c++ +@@ -39,9 +39,6 @@ + #else + #include + #include +-#endif +- +-#if __FreeBSD__ + #include + #endif + +-- +2.49.0 + + +From 2e76d17db3fc484061487c0779b16495939d30c3 Mon Sep 17 00:00:00 2001 +From: Sebastian Falbesoner +Date: Sat, 31 May 2025 01:06:42 +0200 +Subject: [PATCH 2/2] Don't set KJ_USE_KQUEUE on OpenBSD + +OpenBSD doesn't support user event filters yet, hence +the build fails as it misses the symbol EVFILT_USER in +the kqueue implementation in async-unix.c++. Fix that +by not setting KJ_USE_KQUEUE on OpenBSD, so the poll()- +based implementation is used instead. + +Suggested in +https://github.com/capnproto/capnproto/pull/1907/commits/829d3f03735f8f6762a50fc346db56bf02140f02#r1452600300 +--- + c++/src/kj/async-unix.h | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/c++/src/kj/async-unix.h b/c++/src/kj/async-unix.h +index 665305ea..e66ad8e4 100644 +--- a/c++/src/kj/async-unix.h ++++ b/c++/src/kj/async-unix.h +@@ -37,8 +37,9 @@ KJ_BEGIN_HEADER + #if __linux__ + // Default to epoll on Linux. + #define KJ_USE_EPOLL 1 +-#elif __APPLE__ || __FreeBSD__ || __OpenBSD__ || __NetBSD__ || __DragonFly__ +-// MacOS and BSDs prefer kqueue() for event notification. ++#elif __APPLE__ || __FreeBSD__ || __NetBSD__ || __DragonFly__ ++// MacOS and most BSDs prefer kqueue() for event notification. ++// (Note that OpenBSD's kqueue(2) doesn't support user event filters yet) + #define KJ_USE_KQUEUE 1 + #endif + #endif +-- +2.49.0 + diff --git a/depends/patches/qt/CVE-2025-30348-qtbase-5.15.patch b/depends/patches/qt/CVE-2025-30348-qtbase-5.15.patch new file mode 100644 index 000000000000..b13574f3ba27 --- /dev/null +++ b/depends/patches/qt/CVE-2025-30348-qtbase-5.15.patch @@ -0,0 +1,156 @@ +From 16918c1df3e709df2a97281e3825d94c84edb668 Mon Sep 17 00:00:00 2001 +From: Christian Ehrlicher +Date: Tue, 06 Aug 2024 22:39:44 +0200 +Subject: [PATCH] XML/QDom: speedup encodeText() + +The code copied the whole string, then replaced parts inline, at +the cost of relocating everything beyond, at each replacement. +Instead, copy character by character (in chunks where possible) +and append replacements as we skip what they replace. + +Manual conflict resolution for 6.5: +- This is a manual cherry-pick. The original change was only + picked to 6.8, but the quadratic behavior is present in Qt 5, too. +- Changed Task-number to Fixes: because this is the real fix; + the QString change, 315210de916d060c044c01e53ff249d676122b1b, + was unrelated to the original QTBUG-127549. + +Manual conflcit resolution for 5.15: +- Kept/re-added QTextCodec::canEncode() check +- Ported from Qt 6 to 5, to wit: + - qsizetype -> int + - QStringView::first/sliced(n) -> left/mid(n) + (these functions are clearly called in-range, so the widened + contract of the Qt 5 functions doesn't matter) +- Ported from C++17- and C++14-isms to C++11: + - replaced polymorphic lambda with a normal one (this requires + rewriting the !canEncode() branch to use QByteArray/QLatin1String + instead of QString) +- As a drive-by, corrected the indentation of the case labels to + horizontally align existing code (and follow Qt style) + +Fixes: QTBUG-127549 +Change-Id: I368482859ed0c4127f1eec2919183711b5488ada +Reviewed-by: Edward Welbourne +(cherry picked from commit 2ce08e3671b8d18b0284447e5908ce15e6e8f80f) +Reviewed-by: Qt Cherry-pick Bot +(cherry picked from commit 225e235cf966a44af23dbe9aaaa2fd20ab6430ee) +Reviewed-by: Fabian Kosmale +(cherry picked from commit 905a5bd421efff6a1d90b6140500d134d32ca745) +--- + +diff --git a/qtbase/src/xml/dom/qdom.cpp b/qtbase/src/xml/dom/qdom.cpp +index 872221c..bf70477 100644 +--- a/qtbase/src/xml/dom/qdom.cpp ++++ b/qtbase/src/xml/dom/qdom.cpp +@@ -3676,59 +3676,67 @@ + const QTextCodec *const codec = s.codec(); + Q_ASSERT(codec); + #endif +- QString retval(str); +- int len = retval.length(); +- int i = 0; ++ QString retval; ++ int start = 0; ++ auto appendToOutput = [&](int cur, QLatin1String replacement) ++ { ++ if (start < cur) { ++ retval.reserve(str.size() + replacement.size()); ++ retval.append(QStringView(str).left(cur).mid(start)); ++ } ++ // Skip over str[cur], replaced by replacement ++ start = cur + 1; ++ retval.append(replacement); ++ }; + +- while (i < len) { +- const QChar ati(retval.at(i)); +- +- if (ati == QLatin1Char('<')) { +- retval.replace(i, 1, QLatin1String("<")); +- len += 3; +- i += 4; +- } else if (encodeQuotes && (ati == QLatin1Char('"'))) { +- retval.replace(i, 1, QLatin1String(""")); +- len += 5; +- i += 6; +- } else if (ati == QLatin1Char('&')) { +- retval.replace(i, 1, QLatin1String("&")); +- len += 4; +- i += 5; +- } else if (ati == QLatin1Char('>') && i >= 2 && retval[i - 1] == QLatin1Char(']') && retval[i - 2] == QLatin1Char(']')) { +- retval.replace(i, 1, QLatin1String(">")); +- len += 3; +- i += 4; +- } else if (performAVN && +- (ati == QChar(0xA) || +- ati == QChar(0xD) || +- ati == QChar(0x9))) { +- const QString replacement(QLatin1String("&#x") + QString::number(ati.unicode(), 16) + QLatin1Char(';')); +- retval.replace(i, 1, replacement); +- i += replacement.length(); +- len += replacement.length() - 1; +- } else if (encodeEOLs && ati == QChar(0xD)) { +- retval.replace(i, 1, QLatin1String(" ")); // Replace a single 0xD with a ref for 0xD +- len += 4; +- i += 5; +- } else { ++ const int len = str.size(); ++ for (int cur = 0; cur < len; ++cur) { ++ switch (const char16_t ati = str[cur].unicode()) { ++ case u'<': ++ appendToOutput(cur, QLatin1String("<")); ++ break; ++ case u'"': ++ if (encodeQuotes) ++ appendToOutput(cur, QLatin1String(""")); ++ break; ++ case u'&': ++ appendToOutput(cur, QLatin1String("&")); ++ break; ++ case u'>': ++ if (cur >= 2 && str[cur - 1] == u']' && str[cur - 2] == u']') ++ appendToOutput(cur, QLatin1String(">")); ++ break; ++ case u'\r': ++ if (performAVN || encodeEOLs) ++ appendToOutput(cur, QLatin1String(" ")); // \r == 0x0d ++ break; ++ case u'\n': ++ if (performAVN) ++ appendToOutput(cur, QLatin1String(" ")); // \n == 0x0a ++ break; ++ case u'\t': ++ if (performAVN) ++ appendToOutput(cur, QLatin1String(" ")); // \t == 0x09 ++ break; ++ default: + #if QT_CONFIG(textcodec) + if(codec->canEncode(ati)) +- ++i; ++ ; // continue + else + #endif + { + // We have to use a character reference to get it through. +- const ushort codepoint(ati.unicode()); +- const QString replacement(QLatin1String("&#x") + QString::number(codepoint, 16) + QLatin1Char(';')); +- retval.replace(i, 1, replacement); +- i += replacement.length(); +- len += replacement.length() - 1; ++ const QByteArray replacement = "&#x" + QByteArray::number(uint{ati}, 16) + ';'; ++ appendToOutput(cur, QLatin1String{replacement}); + } ++ break; + } + } +- +- return retval; ++ if (start > 0) { ++ retval.append(QStringView(str).left(len).mid(start)); ++ return retval; ++ } ++ return str; + } + + void QDomAttrPrivate::save(QTextStream& s, int, int) const diff --git a/depends/patches/qt/CVE-2025-4211-qtbase-5.15.patch b/depends/patches/qt/CVE-2025-4211-qtbase-5.15.patch new file mode 100644 index 000000000000..0682ed28b61c --- /dev/null +++ b/depends/patches/qt/CVE-2025-4211-qtbase-5.15.patch @@ -0,0 +1,61 @@ +From 3d20cd0105c2ae06605c5078e7675e200f1a001a Mon Sep 17 00:00:00 2001 +From: Mårten Nordheim +Date: Mon, 17 Mar 2025 14:22:11 +0100 +Subject: [PATCH] QFileSystemEngine/Win: Use GetTempPath2 when available + +Because the documentation for GetTempPath nows says apps should call +GetTempPath2.[0] + +Starting with Windows 11[1], and recently Windows 10[2], +GetTempPath2 was added. The difference being that elevated +processes are returned a different directory. Usually +'C:\Windows\SystemTemp'. + +Currently temporary files of an elevated process may be placed in a +world write-able location. GetTempPath2, by default, but can be +overridden, places it in a directory that's only accessible by SYSTEM +and administrators. + +[0] https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettemppathw#remarks +[1] https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettemppath2w +(Minimum supported client - Windows 11 Build 22000) +[2] https://blogs.windows.com/windows-insider/2025/03/13/releasing-windows-10-build-19045-5674-to-the-release-preview-channel/ +(This update enables system processes to store temporary files ...) + +[ChangeLog][QtCore][Important Behavior Changes] On +Windows, generating temporary directories for processes with elevated +privileges may now return a different path with a stricter +set of permissions. Please consult Microsoft's documentation from when +they made the same change for the .NET framework: +https://support.microsoft.com/en-us/topic/gettemppath-changes-in-windows-february-cumulative-update-preview-4cc631fb-9d97-4118-ab6d-f643cd0a7259 + +Change-Id: I5caf11151fb2f711bbc5599231f140598b3c9d03 +Reviewed-by: Marc Mutz +(cherry picked from commit 69633bcb58e681bac5bff3744e5a2352788dc36c) +Reviewed-by: Qt Cherry-pick Bot +(cherry picked from commit 6a684a53b371ec483b27bf243af24819be63f85f) +(cherry picked from commit bbeccc0c22e520f46f0b33e281fa5ac85ac9c727) +(cherry picked from commit 59d7eb9bbb4f13cccbd9323fd995a8c108b56e60) +--- + +diff --git a/qtbase/src/corelib/io/qfilesystemengine_win.cpp b/qtbase/src/corelib/io/qfilesystemengine_win.cpp +index 75c661f..37a400f 100644 +--- a/qtbase/src/corelib/io/qfilesystemengine_win.cpp ++++ b/qtbase/src/corelib/io/qfilesystemengine_win.cpp +@@ -1390,7 +1390,15 @@ + QString ret; + #ifndef Q_OS_WINRT + wchar_t tempPath[MAX_PATH]; +- const DWORD len = GetTempPath(MAX_PATH, tempPath); ++ using GetTempPathPrototype = DWORD (WINAPI *)(DWORD, LPWSTR); ++ // We try to resolve GetTempPath2 and use that, otherwise fall back to GetTempPath: ++ static GetTempPathPrototype getTempPathW = []() { ++ const HMODULE kernel32 = GetModuleHandleW(L"kernel32.dll"); ++ if (auto *func = QFunctionPointer(GetProcAddress(kernel32, "GetTempPath2W"))) ++ return GetTempPathPrototype(func); ++ return GetTempPath; ++ }(); ++ const DWORD len = getTempPathW(MAX_PATH, tempPath); + if (len) { // GetTempPath() can return short names, expand. + wchar_t longTempPath[MAX_PATH]; + const DWORD longLen = GetLongPathName(tempPath, longTempPath, MAX_PATH); diff --git a/depends/patches/qt/CVE-2025-5455-qtbase-5.15.patch b/depends/patches/qt/CVE-2025-5455-qtbase-5.15.patch new file mode 100644 index 000000000000..352be5e20266 --- /dev/null +++ b/depends/patches/qt/CVE-2025-5455-qtbase-5.15.patch @@ -0,0 +1,20 @@ +diff --git a/qtbase/src/corelib/io/qdataurl.cpp b/qtbase/src/corelib/io/qdataurl.cpp +index f14d399301f..83e59e3ac00 100644 +--- a/qtbase/src/corelib/io/qdataurl.cpp ++++ b/qtbase/src/corelib/io/qdataurl.cpp +@@ -76,10 +76,11 @@ Q_CORE_EXPORT bool qDecodeDataUrl(const QUrl &uri, QString &mimeType, QByteArray + } + + if (data.toLower().startsWith("charset")) { +- int i = 7; // strlen("charset") +- while (data.at(i) == ' ') +- ++i; +- if (data.at(i) == '=') ++ int prefixSize = 7; // strlen("charset") ++ QLatin1String copy(data.constData() + prefixSize, data.size() - prefixSize); ++ while (copy.startsWith(QLatin1String(" "))) ++ copy = copy.mid(1); ++ if (copy.startsWith(QLatin1String("="))) + data.prepend("text/plain;"); + } + diff --git a/depends/patches/qt/clang_18_libpng.patch b/depends/patches/qt/clang_18_libpng.patch deleted file mode 100644 index e807905b321a..000000000000 --- a/depends/patches/qt/clang_18_libpng.patch +++ /dev/null @@ -1,40 +0,0 @@ -fix Qt macOS build with Clang 18 - - See: - https://github.com/pnggroup/libpng/commit/893b8113f04d408cc6177c6de19c9889a48faa24. - - In a similar manner as zlib (madler/zlib#895), - libpng contains a header configuration that's no longer valid and - hasn't been exercised for the macOS target. - - - The target OS conditional macros are misused. Specifically - `TARGET_OS_MAC` covers all Apple targets, including iOS, and it - should not be checked with `#if defined` as they would always be - defined (to either 1 or 0) on Apple platforms. - - `#include ` no longer works for the macOS target and results - in a compilation failure. macOS ships all required functions in - `math.h`, and clients should use `math.h` instead. - ---- a/qtbase/src/3rdparty/libpng/pngpriv.h -+++ b/qtbase/src/3rdparty/libpng/pngpriv.h -@@ -514,18 +514,8 @@ - */ - # include - --# if (defined(__MWERKS__) && defined(macintosh)) || defined(applec) || \ -- defined(THINK_C) || defined(__SC__) || defined(TARGET_OS_MAC) -- /* We need to check that hasn't already been included earlier -- * as it seems it doesn't agree with , yet we should really use -- * if possible. -- */ --# if !defined(__MATH_H__) && !defined(__MATH_H) && !defined(__cmath__) --# include --# endif --# else --# include --# endif -+# include -+ - # if defined(_AMIGA) && defined(__SASC) && defined(_M68881) - /* Amiga SAS/C: We must include builtin FPU functions when compiling using - * MATH=68881 diff --git a/depends/patches/qt/fix-macos-linker.patch b/depends/patches/qt/fix-macos-linker.patch deleted file mode 100644 index e43968565655..000000000000 --- a/depends/patches/qt/fix-macos-linker.patch +++ /dev/null @@ -1,55 +0,0 @@ -qmake: Don't error out if QMAKE_DEFAULT_LIBDIRS is empty on macOS - -The new linker in Xcode 15 doesn't provide any default linker or -framework paths when requested via -v, but still seems to use the -default paths documented in the ld man page. - -We trust that linker will do the right thing, even if we don't -know of its default linker paths. - -We also need to opt out of the default fallback logic to -set the libdirs to /lib and /usr/lib. - -This may result in UnixMakefileGenerator::findLibraries finding -different libraries than expected, if additional paths are -passed with -L, which will then take precedence for qmake, -even if the linker itself will use the library from the -SDK's default paths. This should hopefully not be an issue -in practice, as we don't turn -lFoo into absolute paths in -qmake, so the only risk is that we're picking up the wrong -prl files and adding additional dependencies that the lib -in the SDK doesn't have. - -Upstream commits: - - Qt 5.15.16: Not yet publicly available. - - Qt dev: cdf64b0e47115cc473e1afd1472b4b09e130b2a5 - -For other Qt branches see -https://codereview.qt-project.org/q/I2347b26e2df0828471373b0e15b8c9089274c65d - ---- old/qtbase/mkspecs/features/toolchain.prf -+++ new/qtbase/mkspecs/features/toolchain.prf -@@ -288,9 +288,12 @@ isEmpty($${target_prefix}.INCDIRS) { - } - } - } -- isEmpty(QMAKE_DEFAULT_LIBDIRS)|isEmpty(QMAKE_DEFAULT_INCDIRS): \ -+ isEmpty(QMAKE_DEFAULT_INCDIRS): \ - !integrity: \ -- error("failed to parse default search paths from compiler output") -+ error("failed to parse default include paths from compiler output") -+ isEmpty(QMAKE_DEFAULT_LIBDIRS): \ -+ !integrity:!darwin: \ -+ error("failed to parse default library paths from compiler output") - QMAKE_DEFAULT_LIBDIRS = $$unique(QMAKE_DEFAULT_LIBDIRS) - } else: ghs { - cmd = $$QMAKE_CXX $$QMAKE_CXXFLAGS -$${LITERAL_HASH} -o /tmp/fake_output /tmp/fake_input.cpp -@@ -412,7 +415,7 @@ isEmpty($${target_prefix}.INCDIRS) { - QMAKE_DEFAULT_INCDIRS = $$split(INCLUDE, $$QMAKE_DIRLIST_SEP) - } - -- unix:if(!cross_compile|host_build) { -+ unix:!darwin:if(!cross_compile|host_build) { - isEmpty(QMAKE_DEFAULT_INCDIRS): QMAKE_DEFAULT_INCDIRS = /usr/include /usr/local/include - isEmpty(QMAKE_DEFAULT_LIBDIRS): QMAKE_DEFAULT_LIBDIRS = /lib /usr/lib - } diff --git a/depends/patches/qt/memory_resource.patch b/depends/patches/qt/memory_resource.patch index 312f0669f631..14e25121c00a 100644 --- a/depends/patches/qt/memory_resource.patch +++ b/depends/patches/qt/memory_resource.patch @@ -14,36 +14,3 @@ and https://bugreports.qt.io/browse/QTBUG-114316 # include # include #else - ---- a/qtbase/src/corelib/global/qcompilerdetection.h -+++ b/qtbase/src/corelib/global/qcompilerdetection.h -@@ -1055,16 +1055,22 @@ - # endif // !_HAS_CONSTEXPR - # endif // !__GLIBCXX__ && !_LIBCPP_VERSION - # endif // Q_OS_QNX --# if (defined(Q_CC_CLANG) || defined(Q_CC_INTEL)) && defined(Q_OS_MAC) && defined(__GNUC_LIBSTD__) \ -- && ((__GNUC_LIBSTD__-0) * 100 + __GNUC_LIBSTD_MINOR__-0 <= 402) -+# if (defined(Q_CC_CLANG) || defined(Q_CC_INTEL)) && defined(Q_OS_MAC) -+# if defined(__GNUC_LIBSTD__) && ((__GNUC_LIBSTD__-0) * 100 + __GNUC_LIBSTD_MINOR__-0 <= 402) - // Apple has not updated libstdc++ since 2007, which means it does not have - // or std::move. Let's disable these features --# undef Q_COMPILER_INITIALIZER_LISTS --# undef Q_COMPILER_RVALUE_REFS --# undef Q_COMPILER_REF_QUALIFIERS -+# undef Q_COMPILER_INITIALIZER_LISTS -+# undef Q_COMPILER_RVALUE_REFS -+# undef Q_COMPILER_REF_QUALIFIERS - // Also disable , since it's clearly not there --# undef Q_COMPILER_ATOMICS --# endif -+# undef Q_COMPILER_ATOMICS -+# endif -+# if defined(__cpp_lib_memory_resource) \ -+ && ((defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED < 140000) \ -+ || (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED < 170000)) -+# undef __cpp_lib_memory_resource // Only supported on macOS 14 and iOS 17 -+# endif -+# endif // (defined(Q_CC_CLANG) || defined(Q_CC_INTEL)) && defined(Q_OS_MAC) - # if defined(Q_CC_CLANG) && defined(Q_CC_INTEL) && Q_CC_INTEL >= 1500 - // ICC 15.x and 16.0 have their own implementation of std::atomic, which is activated when in Clang mode - // (probably because libc++'s on OS X failed to compile), but they're missing some diff --git a/depends/patches/qt/zlib-timebits64.patch b/depends/patches/qt/zlib-timebits64.patch deleted file mode 100644 index 139c1dfa77f3..000000000000 --- a/depends/patches/qt/zlib-timebits64.patch +++ /dev/null @@ -1,31 +0,0 @@ -From a566e156b3fa07b566ddbf6801b517a9dba04fa3 Mon Sep 17 00:00:00 2001 -From: Mark Adler -Date: Sat, 29 Jul 2023 22:13:09 -0700 -Subject: [PATCH] Avoid compiler complaints if _TIME_BITS defined when building - zlib. - -zlib does not use time_t, so _TIME_BITS is irrelevant. However it -may be defined anyway as part of a sledgehammer indiscriminately -applied to all builds. - -From https://github.com/madler/zlib/commit/a566e156b3fa07b566ddbf6801b517a9dba04fa3.patch ---- - qtbase/src/3rdparty/zlib/src/gzguts.h | 5 ++--- - 1 file changed, 2 insertions(+), 3 deletions(-) - -diff --git a/qtbase/src/3rdparty/zlib/src/gzguts.h b/qtbase/src/3rdparty/zlib/src/gzguts.h -index e23f831f5..f9375047e 100644 ---- a/qtbase/src/3rdparty/zlib/src/gzguts.h -+++ b/qtbase/src/3rdparty/zlib/src/gzguts.h -@@ -26,9 +26,8 @@ - # ifndef _LARGEFILE_SOURCE - # define _LARGEFILE_SOURCE 1 - # endif --# ifdef _FILE_OFFSET_BITS --# undef _FILE_OFFSET_BITS --# endif -+# undef _FILE_OFFSET_BITS -+# undef _TIME_BITS - #endif - - #ifdef HAVE_HIDDEN diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in index 8d54cb41ef7e..611e4941a07e 100644 --- a/doc/Doxyfile.in +++ b/doc/Doxyfile.in @@ -2093,7 +2093,7 @@ INCLUDE_FILE_PATTERNS = # recursively expanded use the := operator instead of the = operator. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -PREDEFINED = HAVE_BOOST_PROCESS +PREDEFINED = ENABLE_EXTERNAL_SIGNER # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this # tag can be used to specify a list of macro names that should be expanded. The diff --git a/doc/README.md b/doc/README.md index 89bf34b7df65..384ba6442f66 100644 --- a/doc/README.md +++ b/doc/README.md @@ -58,6 +58,7 @@ The Dash Core repo's [root README](/README.md) contains relevant information on - [BIPS](bips.md) - [Dnsseed Policy](dnsseed-policy.md) - [Benchmarking](benchmarking.md) +- [Internal Design Docs](design/) ### Resources * See the [Dash Developer Documentation](https://dashcore.readme.io/) @@ -68,7 +69,6 @@ The Dash Core repo's [root README](/README.md) contains relevant information on ### Miscellaneous - [Assets Attribution](assets-attribution.md) -- [Assumeutxo design](assumeutxo.md) - [dash.conf Configuration File](dash-conf.md) - [CJDNS Support](cjdns.md) - [Files](files.md) diff --git a/doc/bips.md b/doc/bips.md index fdd9afe17e77..b2db8e8637fb 100644 --- a/doc/bips.md +++ b/doc/bips.md @@ -29,6 +29,7 @@ Versions and PRs are relevant to Bitcoin's core if not mentioned other. and it is disabled by default at build time since **v0.19.0** ([PR #15584](https://github.com/bitcoin/bitcoin/pull/15584)). It has been removed as of **v0.20.0** ([PR 17165](https://github.com/bitcoin/bitcoin/pull/17165)). * [`BIP 84`](https://github.com/bitcoin/bips/blob/master/bip-0084.mediawiki): The experimental descriptor wallets introduced in **v0.21.0** by default use the Hierarchical Deterministic Wallet derivation proposed by BIP 84. ([PR #16528](https://github.com/bitcoin/bitcoin/pull/16528)) +* [`BIP 86`](https://github.com/bitcoin/bips/blob/master/bip-0086.mediawiki): Descriptor wallets by default use the Hierarchical Deterministic Wallet derivation proposed by BIP 86 since **v23.0** ([PR #22364](https://github.com/bitcoin/bitcoin/pull/22364)). * [`BIP 90`](https://github.com/bitcoin/bips/blob/master/bip-0090.mediawiki): Trigger mechanism for activation of BIPs 34, 65, and 66 has been simplified to block height checks since **v0.14.0** ([PR #8391](https://github.com/bitcoin/bitcoin/pull/8391)). * [`BIP 111`](https://github.com/bitcoin/bips/blob/master/bip-0111.mediawiki): `NODE_BLOOM` service bit added, and enforced for all peer versions as of **v0.13.0** ([PR #6579](https://github.com/bitcoin/bitcoin/pull/6579) and [PR #6641](https://github.com/bitcoin/bitcoin/pull/6641)). * [`BIP 112`](https://github.com/bitcoin/bips/blob/master/bip-0112.mediawiki): The CHECKSEQUENCEVERIFY opcode has been implemented since **v0.12.1** ([PR #7524](https://github.com/bitcoin/bitcoin/pull/7524)), and has been *buried* since **v0.19.0** ([PR #16060](https://github.com/bitcoin/bitcoin/pull/16060)). diff --git a/doc/build-freebsd.md b/doc/build-freebsd.md index 06c1dd4387a0..d33629b551c8 100644 --- a/doc/build-freebsd.md +++ b/doc/build-freebsd.md @@ -10,7 +10,7 @@ This guide describes how to build dashd, command-line utilities, and GUI on Free 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 autoconf automake boost-libs git gmake libevent libtool pkgconf libbacktrace ``` @@ -41,13 +41,30 @@ pkg install sqlite3 ``` ###### Legacy Wallet Support -`db5` is only required to support legacy wallets. -Skip if you don't intend to use legacy wallets. +BerkeleyDB is only required if legacy wallet support is required. + +It is required to use Berkeley DB 4.8. You **cannot** use the BerkeleyDB library +from ports. However, you can build DB 4.8 yourself [using depends](/depends). -```bash -pkg install db5 ``` ---- +gmake -C depends NO_BOOST=1 NO_LIBEVENT=1 NO_QT=1 NO_SQLITE=1 NO_NATPMP=1 NO_UPNP=1 NO_ZMQ=1 NO_USDT=1 +``` + +When the build is complete, the Berkeley DB installation location will be displayed: + +``` +to: /path/to/dash/depends/x86_64-unknown-freebsd[release-number] +``` + +Finally, set `BDB_PREFIX` to this path according to your shell: + +``` +csh: setenv BDB_PREFIX [path displayed above] +``` + +``` +sh/bash: export BDB_PREFIX=[path displayed above] +``` #### GUI Dependencies ###### Qt5 @@ -96,12 +113,12 @@ This explicitly enables the GUI and disables legacy wallet support, assuming `sq ##### Descriptor & Legacy Wallet. No GUI: This enables support for both wallet types and disables the GUI, assuming -`sqlite3` and `db5` are both installed. +`sqlite3` and `db4` are both installed. ```bash ./autogen.sh -./configure --with-gui=no --with-incompatible-bdb \ - BDB_LIBS="-ldb_cxx-5" \ - BDB_CFLAGS="-I/usr/local/include/db5" \ +./configure --with-gui=no \ + BDB_LIBS="-L${BDB_PREFIX}/lib -ldb_cxx-4.8" \ + BDB_CFLAGS="-I${BDB_PREFIX}/include" \ MAKE=gmake ``` diff --git a/doc/build-netbsd.md b/doc/build-netbsd.md index cd02fc693234..86f72e1096e4 100644 --- a/doc/build-netbsd.md +++ b/doc/build-netbsd.md @@ -1,95 +1,118 @@ -NetBSD Build Guide -====================== -**Updated for NetBSD [8.0](https://www.netbsd.org/releases/formal-8/NetBSD-8.0.html)** +# NetBSD Build Guide -This guide describes how to build dashd and command-line utilities on NetBSD. +Updated for NetBSD [9.2](https://netbsd.org/releases/formal-9/NetBSD-9.2.html). -This guide does not contain instructions for building the GUI. +This guide describes how to build dashd, command-line utilities, and GUI on NetBSD. -**This guide has not been tested for building Dash Core and is expected to fail due to missing `bls_dash` and `backtrace`. Please report your results; contributions welcome.** +**This guide has not been tested for building Dash Core and may fail. Please report your results; contributions welcome.** -Preparation -------------- +## Preparation -You will need the following modules, which can be installed via pkgsrc or pkgin: +### 1. Install Required Dependencies + +Install the required dependencies the usual way you [install software on NetBSD](https://www.netbsd.org/docs/guide/en/chap-boot.html#chap-boot-pkgsrc). +The example commands below use `pkgin`. + +```bash +pkgin install autoconf automake libtool pkg-config git gmake boost libevent gmp ``` -autoconf -automake -boost -git -gmake -gmp -libevent -libtool -pkg-config -python37 -git clone https://github.com/dashpay/dash.git +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. + +For example, grab `gcc9`: +``` +pkgin install gcc9 +``` + +Then, when configuring, pass the following: +```bash +./configure + ... + CC="/usr/pkg/gcc9/bin/gcc" \ + CXX="/usr/pkg/gcc9/bin/g++" \ + ... ``` See [dependencies.md](dependencies.md) for a complete overview. -### Building Dash Core +### 2. Clone Dash Core Repo -**Important**: Use `gmake` (the non-GNU `make` will exit with an error). +Clone the Dash Core repository to a directory. All build scripts and commands will run from this directory. -#### With descriptor wallet: +```bash +git clone https://github.com/dashpay/dash.git +``` + +### 3. Install Optional Dependencies + +#### Wallet Dependencies + +It is not necessary to build wallet functionality to run dashd or the GUI. + +###### Descriptor Wallet Support + +`sqlite3` is required to enable support for [descriptor wallets](https://github.com/dashpay/dash/blob/master/doc/descriptors.md). -The descriptor wallet uses `sqlite3`. You can install it using: ```bash pkgin install sqlite3 ``` +###### Legacy Wallet Support + +`db4` is required to enable support for legacy wallets. + ```bash -./autogen.sh -./configure --with-gui=no --without-bdb \ - CPPFLAGS="-I/usr/pkg/include" \ - LDFLAGS="-L/usr/pkg/lib" \ - BOOST_CPPFLAGS="-I/usr/pkg/include" \ - MAKE=gmake +pkgin install db4 ``` -#### With legacy wallet: - -BerkeleyDB is use for legacy wallet functionality. +#### GUI Dependencies -It is recommended to use Berkeley DB 4.8. You cannot use the BerkeleyDB library -from ports. -You can use [the installation script included in contrib/](/contrib/install_db4.sh) like so: +Dash Core includes a GUI built with the cross-platform Qt Framework. To compile the GUI, we need to install `qt5`. ```bash -./contrib/install_db4.sh `pwd` +pkgin install qt5 ``` -from the root of the repository. Then set `BDB_PREFIX` for the next section: +The GUI can encode addresses in a QR Code. To build in QR support for the GUI, install `qrencode`. ```bash -export BDB_PREFIX="$PWD/db4" +pkgin install qrencode ``` +#### 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: + ```bash -./autogen.sh -./configure --with-gui=no CPPFLAGS="-I/usr/pkg/include" \ - LDFLAGS="-L/usr/pkg/lib" \ - BOOST_CPPFLAGS="-I/usr/pkg/include" \ - BDB_LIBS="-L${BDB_PREFIX}/lib -ldb_cxx-4.8" \ - BDB_CFLAGS="-I${BDB_PREFIX}/include" \ - MAKE=gmake +pkgin install python37 ``` -#### Without wallet: +### Building Dash Core + +**Note**: Use `gmake` (the non-GNU `make` will exit with an error). + + +### 1. Configuration + +There are many ways to configure Dash Core. Here is an example that +explicitly disables the wallet and GUI: + ```bash ./autogen.sh -./configure --with-gui=no --disable-wallet \ +./configure --without-wallet --with-gui=no \ CPPFLAGS="-I/usr/pkg/include" \ - LDFLAGS="-L/usr/pkg/lib" \ - BOOST_CPPFLAGS="-I/usr/pkg/include" \ MAKE=gmake ``` +For a full list of configuration options, see the output of `./configure --help` + +### 2. Compile + Build and run the tests: + ```bash gmake # use "-j N" here for N parallel jobs -gmake check +gmake check # Run tests if Python 3 is available ``` diff --git a/doc/build-openbsd.md b/doc/build-openbsd.md index afcc43355dd5..8b0ee196eb46 100644 --- a/doc/build-openbsd.md +++ b/doc/build-openbsd.md @@ -1,113 +1,130 @@ -OpenBSD build guide -====================== -**Updated for OpenBSD [7.4](https://www.openbsd.org/74.html)** +# OpenBSD Build Guide -This guide describes how to build dashd, dash-qt, and command-line utilities on OpenBSD. +**Updated for OpenBSD [7.3](https://www.openbsd.org/73.html)** -Preparation -------------- +This guide describes how to build dashd, command-line utilities, and GUI on OpenBSD. -Run the following as root to install the base dependencies for building: +## Preparation + +### 1. Install Required Dependencies +Run the following as root to install the base dependencies for building. ```bash -pkg_add git gmake libevent libtool -pkg_add qt5 # (optional for enabling the GUI) -pkg_add autoconf # (select highest version, e.g. 2.69) -pkg_add automake # (select highest version, e.g. 1.15) -pkg_add python # (select highest version, e.g. 3.9) -pkg_add gmp -pkg_add bash -pkg_add boost +pkg_add bash git gmake gmp libevent libtool boost +# Select the newest version of the following packages: +pkg_add autoconf automake python git clone https://github.com/dashpay/dash.git ``` See [dependencies.md](dependencies.md) for a complete overview. -**Important**: From OpenBSD 6.2 onwards a C++11-supporting clang compiler is -part of the base image, and while building it is necessary to make sure that -this compiler is used and not ancient g++ 4.2.1. This is done by appending -`CC=cc CXX=c++` to configuration commands. Mixing different compilers within -the same executable will result in errors. +### 2. Clone Dash Core Repo +Clone the Dash Core repository to a directory. All build scripts and commands will run from this directory. +``` bash +git clone https://github.com/dashpay/dash.git +``` + +### 3. Install Optional Dependencies + +#### Wallet Dependencies -### Building BerkeleyDB +It is not necessary to build wallet functionality to run either `dashd` or `dash-qt`. + +###### Descriptor Wallet Support + +`sqlite3` is required to support [descriptor wallets](descriptors.md). + +``` bash +pkg_add sqlite3 +``` -BerkeleyDB is only necessary for the wallet functionality. To skip this, pass -`--disable-wallet` to `./configure` and skip to the next section. +###### Legacy Wallet Support +BerkeleyDB is only required to support legacy wallets. It is recommended to use Berkeley DB 4.8. You cannot use the BerkeleyDB library -from ports, for the same reason as boost above (g++/libstd++ incompatibility). -If you have to build it yourself, you can use [the installation script included -in contrib/](/contrib/install_db4.sh) like so: +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 +... +to: /path/to/dash/depends/x86_64-unknown-openbsd +``` + +Then set `BDB_PREFIX`: ```bash -./contrib/install_db4.sh `pwd` CC=cc CXX=c++ +export BDB_PREFIX="/path/to/dash/depends/x86_64-unknown-openbsd" ``` -from the root of the repository. Then set `BDB_PREFIX` for the next section: +#### GUI Dependencies +###### Qt5 + +Dash Core includes a GUI built with the cross-platform Qt Framework. To compile the GUI, Qt 5 is required. ```bash -export BDB_PREFIX="$PWD/db4" +pkg_add qt5 ``` -### Building Dash Core +## Building Dash Core **Important**: Use `gmake` (the non-GNU `make` will exit with an error). Preparation: ```bash -export AUTOCONF_VERSION=2.69 # replace this with the autoconf version that you installed -export AUTOMAKE_VERSION=1.15 # replace this with the automake version that you installed + +# Adapt the following for the version you installed (major.minor only): +export AUTOCONF_VERSION=2.71 +export AUTOMAKE_VERSION=1.16 + ./autogen.sh ``` -Make sure `BDB_PREFIX` is set to the appropriate path from the above steps. -To configure with wallet: -```bash -./configure --with-gui=no CC=cc CXX=c++ \ - BDB_LIBS="-L${BDB_PREFIX}/lib -ldb_cxx-4.8" \ - BDB_CFLAGS="-I${BDB_PREFIX}/include" \ - MAKE=gmake -``` +### 1. Configuration + +There are many ways to configure Dash 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. -To configure without wallet: ```bash -./configure --disable-wallet --with-gui=no CC=cc CXX=c++ MAKE=gmake +./configure MAKE=gmake ``` -To configure with GUI: +##### Descriptor & Legacy Wallet. No GUI: +This enables support for both wallet types and disables the GUI: + ```bash -./configure --with-gui=yes CC=cc CXX=c++ \ +./configure --with-gui=no \ BDB_LIBS="-L${BDB_PREFIX}/lib -ldb_cxx-4.8" \ BDB_CFLAGS="-I${BDB_PREFIX}/include" \ MAKE=gmake ``` -Build and run the tests: +### 2. Compile +**Important**: Use `gmake` (the non-GNU `make` will exit with an error). + ```bash -gmake # use "-j N" here for N parallel jobs -gmake check +gmake # use "-j N" for N parallel jobs +gmake check # Run tests if Python 3 is available ``` -Resource limits -------------------- +## Resource limits If the build runs into out-of-memory errors, the instructions in this section might help. The standard ulimit restrictions in OpenBSD are very strict: - - data(kbytes) 1572864 +```bash +data(kbytes) 1572864 +``` This, unfortunately, in some cases not enough to compile some `.cpp` files in the project, (see issue [#6658](https://github.com/bitcoin/bitcoin/issues/6658)). If your user is in the `staff` group the limit can be raised with: - - ulimit -d 3000000 - +```bash +ulimit -d 3000000 +``` The change will only affect the current shell and processes spawned by it. To make the change system-wide, change `datasize-cur` and `datasize-max` in `/etc/login.conf`, and reboot. - diff --git a/doc/build-osx.md b/doc/build-osx.md index 3a9d7f0e92be..e6e9384356c3 100644 --- a/doc/build-osx.md +++ b/doc/build-osx.md @@ -79,29 +79,21 @@ git clone https://github.com/dashpay/dash.git #### Wallet Dependencies It is not necessary to build wallet functionality to run `dashd` or `dash-qt`. -To enable legacy wallets, you must install `berkeley-db@4`. -To enable [descriptor wallets](https://github.com/dashpay/dash/blob/master/doc/descriptors.md), `sqlite` is required. -Skip `berkeley-db@4` if you intend to *exclusively* use descriptor wallets. -###### Legacy Wallet Support +###### Descriptor Wallet Support -`berkeley-db@4` is required to enable support for legacy wallets. -Skip if you don't intend to use legacy wallets. +`sqlite` is required to support for descriptor wallets. -``` bash -brew install berkeley-db@4 -``` +macOS ships with a useable `sqlite` package, meaning you don't need to +install anything. -###### Descriptor Wallet Support - -Note: Apple has included a useable `sqlite` package since macOS 10.14. -You may not need to install this package. +###### Legacy Wallet Support -`sqlite` is required to enable support for descriptor wallets. -Skip if you don't intend to use descriptor wallets. +`berkeley-db@4` is only required to support for legacy wallets. +Skip if you don't intend to use legacy wallets. ``` bash -brew install sqlite +brew install berkeley-db@4 ``` --- @@ -117,14 +109,6 @@ Skip if you don't intend to use the GUI. brew install qt@5 ``` -Ensure that the `qt@5` package is installed, not the `qt` package. -If 'qt' is installed, the build process will fail. -if installed, remove the `qt` package with the following command: - -``` bash -brew uninstall qt -``` - Note: Building with Qt binaries downloaded from the Qt website is not officially supported. See the notes in [#7714](https://github.com/dashpay/dash/issues/7714). @@ -211,17 +195,6 @@ Additionally, this explicitly disables the GUI. ./autogen.sh ./configure --with-gui=no ``` - -###### Berkeley DB - -It is recommended to use Berkeley DB 4.8. If you have to build it yourself, -you can use [the installation script included in contrib/](contrib/install_db4.sh) -like so: - -```shell -./contrib/install_db4.sh . -``` - ##### Wallet (only SQlite) and GUI Support: This explicitly enables the GUI and disables legacy wallet support. diff --git a/doc/build-unix.md b/doc/build-unix.md index 946b4fd0eebd..20e845a115e0 100644 --- a/doc/build-unix.md +++ b/doc/build-unix.md @@ -58,9 +58,12 @@ sudo apt-get install build-essential libtool autotools-dev automake pkg-config b Now, you can either build from self-compiled [depends](/depends/README.md) or install the required dependencies: ```sh -sudo apt-get install libevent-dev libboost-dev +sudo apt-get install libbacktrace-dev libevent-dev libboost-dev ``` +Note: libbacktrace-dev is available in Debian 13 (Trixie) and Ubuntu 25.04+. +For older releases, use the /depends/README.md which includes all required libraries. + SQLite is required for the descriptor wallet: ```sh @@ -142,6 +145,8 @@ Now, you can either build from self-compiled [depends](/depends/README.md) or in sudo dnf install libevent-devel boost-devel ``` +Note: Fedora repositories do not include libbacktrace. To build Dash Core without stack trace support, configure with `--disable-stacktraces`. + SQLite is required for the descriptor wallet: ```sh @@ -236,17 +241,21 @@ Berkeley DB ----------- The legacy wallet uses Berkeley DB. To ensure backwards compatibility it is -recommended to use Berkeley DB 4.8. If you have to build it yourself, you can -use [the installation script included in contrib/](/contrib/install_db4.sh) -like so: - -```sh -./contrib/install_db4.sh `pwd` +recommended to use Berkeley DB 4.8. If you have to build it yourself, and don't +want to use any other libraries built in depends, you can do: +```bash +make -C depends NO_BOOST=1 NO_LIBEVENT=1 NO_QT=1 NO_SQLITE=1 NO_NATPMP=1 NO_UPNP=1 NO_ZMQ=1 NO_USDT=1 +... +to: /path/to/dash/depends/x86_64-pc-linux-gnu ``` +and configure using the following: +```bash +export BDB_PREFIX="/path/to/dash/depends/x86_64-pc-linux-gnu" -from the root of the repository. - -Otherwise, you can build Dash Core from self-compiled [depends](/depends/README.md). +./configure \ + BDB_LIBS="-L${BDB_PREFIX}/lib -ldb_cxx-4.8" \ + BDB_CFLAGS="-I${BDB_PREFIX}/include" +``` **Note**: You only need Berkeley DB if the legacy wallet is enabled (see [*Disable-wallet mode*](#disable-wallet-mode)). @@ -272,20 +281,16 @@ A list of additional configure flags can be displayed with: Setup and Build Example: Arch Linux ----------------------------------- -This example lists the steps necessary to setup and build a command line only, non-wallet distribution of the latest changes on Arch Linux: +This example lists the steps necessary to setup and build a command line only distribution of the latest changes on Arch Linux: ```sh -pacman -S git base-devel boost libevent python +pacman --sync --needed autoconf automake boost gcc git libbacktrace libevent libtool make pkgconf python sqlite git clone https://github.com/dashpay/dash.git cd dash/ ./autogen.sh -./configure --disable-wallet --without-gui --without-miniupnpc +./configure make check +./src/dashd ``` -Note: -Enabling wallet support requires either compiling against a Berkeley DB newer than 4.8 (package `db`) using `--with-incompatible-bdb`, -or building and depending on a local version of Berkeley DB 4.8. The readily available Arch Linux packages are currently built using -`--with-incompatible-bdb` according to the [PKGBUILD](https://github.com/archlinux/svntogit-community/blob/packages/bitcoin/trunk/PKGBUILD). -As mentioned above, when maintaining portability of the wallet between the standard Dash Core distributions and independently built -node software is desired, Berkeley DB 4.8 must be used. +If you intend to work with legacy Berkeley DB wallets, see [Berkeley DB](#berkeley-db) section. diff --git a/doc/build-windows.md b/doc/build-windows.md index 3670b59cf71f..873d8d67af62 100644 --- a/doc/build-windows.md +++ b/doc/build-windows.md @@ -27,31 +27,8 @@ 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-get install build-essential libtool autotools-dev automake pkg-config bsdmainutils curl git bison - -A host toolchain (`build-essential`) is necessary because some dependency -packages need to build host utilities that are used in the build process. - -See [dependencies.md](dependencies.md) for a complete overview. - -## Building for 64-bit Windows - -The first step is to install the mingw-w64 cross-compilation tool chain: - - on modern systems (Ubuntu 21.04 Hirsute Hippo or newer, Debian 11 Bullseye or newer): - -```sh -sudo apt install g++-mingw-w64-x86-64-posix -``` - - - on older systems: - -```sh -sudo apt install g++-mingw-w64-x86-64 -``` - -Once the toolchain is installed the build steps are common: +See [README.md](../depends/README.md) in the depends directory for which +dependencies to install and [dependencies.md](dependencies.md) for a complete overview. Note that for WSL the Dash Core source path MUST be somewhere in the default mount file system, for example /usr/src/dash, AND not under /mnt/d/. If this is not the case the dependency autoconf scripts will fail. diff --git a/doc/cjdns.md b/doc/cjdns.md index df2228194ae9..5d44871fafac 100644 --- a/doc/cjdns.md +++ b/doc/cjdns.md @@ -10,7 +10,8 @@ CJDNS is like a distributed, shared VPN with multiple entry points where every participant can reach any other participant. All participants use addresses from the `fc00::/8` network (reserved IPv6 range). Installation and configuration is done outside of Dash Core, similarly to a VPN (either in the host/OS or on -the network router). +the network router). See https://github.com/cjdelisle/cjdns#readme and +https://github.com/hyperboria/docs#hyperboriadocs for more information. Compared to IPv4/IPv6, CJDNS provides end-to-end encryption and protects nodes from traffic analysis and filtering. @@ -23,17 +24,37 @@ somewhat centralized. I2P connections have a source address and I2P is slow. CJDNS is fast but does not hide the sender and the recipient from intermediate routers. -## Installing CJDNS and connecting to the network +## Installing CJDNS and finding a peer to connect to the network To install and set up CJDNS, follow the instructions at -https://github.com/cjdelisle/cjdns#cjdns. +https://github.com/cjdelisle/cjdns#how-to-install-cjdns. -Don't skip steps +You need to initiate an outbound connection to a peer on the CJDNS network +before it will work with your Dash Core node. This is described in steps ["2. Find a friend"](https://github.com/cjdelisle/cjdns#2-find-a-friend) and ["3. Connect your node to your friend's -node"](https://github.com/cjdelisle/cjdns#3-connect-your-node-to-your-friends-node). -You need to be connected to the CJDNS network before it will work with your -Dash Core node. +node"](https://github.com/cjdelisle/cjdns#3-connect-your-node-to-your-friends-node) +in the CJDNS documentation. + +One quick way to accomplish these two steps is to query for available public +peers on [Hyperboria](https://github.com/hyperboria) by running the following: + +``` +git clone https://github.com/hyperboria/peers hyperboria-peers +cd hyperboria-peers +./testAvailable.py +``` + +For each peer, the `./testAvailable.py` script prints the filename of the peer's +credentials followed by the ping result. + +Choose one or several peers, copy their credentials from their respective files, +paste them into the relevant IPv4 or IPv6 "connectTo" JSON object in the +`cjdroute.conf` file you created in step ["1. Generate a new configuration +file"](https://github.com/cjdelisle/cjdns#1-generate-a-new-configuration-file), +and save the file. + +## Launching CJDNS Typically, CJDNS might be launched from its directory with `sudo ./cjdroute < cjdroute.conf` and it sheds permissions after setting up the diff --git a/doc/dash-conf.md b/doc/dash-conf.md index 13fa0ab70889..3d1c9580948d 100644 --- a/doc/dash-conf.md +++ b/doc/dash-conf.md @@ -63,4 +63,12 @@ Windows | `%APPDATA%\DashCore\` | `C:\Users\username\AppData\Roaming\DashCore\da Linux | `$HOME/.dashcore/` | `/home/username/.dashcore/dash.conf` macOS | `$HOME/Library/Application Support/DashCore/` | `/Users/username/Library/Application Support/DashCore/dash.conf` -You can find an example dash.conf file in [share/examples/dash.conf](../share/examples/dash.conf). +An example configuration file can be generated by [contrib/devtools/gen-dash-conf.sh](../contrib/devtools/gen-dash-conf.sh). +Run this script after compiling to generate an up-to-date configuration file. +The output is placed under `contrib/debian/examples/dash.conf`. +To use the generated configuration file, copy the example file into your data directory and edit it there, like so: + +``` +# example copy command for linux user +cp contrib/debian/examples/dash.conf ~/.dashcore +``` diff --git a/doc/dependencies.md b/doc/dependencies.md index cef8516ac5ab..2a2b7ec28370 100644 --- a/doc/dependencies.md +++ b/doc/dependencies.md @@ -4,13 +4,13 @@ These are the dependencies used by Dash Core. You can find installation instructions in the `build-*.md` file for your platform. "Runtime" and "Version Used" are both in reference to the release binaries. -| Compiler | Minimum required | +| 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) | [16.0](https://github.com/bitcoin/bitcoin/pull/30263) | | [GCC](https://gcc.gnu.org) | [11.1](https://github.com/bitcoin/bitcoin/pull/29091) | -| [Python](https://www.python.org) (scripts, tests) | [3.9](https://github.com/bitcoin/bitcoin/pull/28211) | +| [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 @@ -33,13 +33,13 @@ 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.3](https://github.com/bitcoin/bitcoin/pull/24668) | [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.18](https://github.com/dashpay/dash/pull/6949) | [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 [07004b9...](https://github.com/miniupnp/libnatpmp/tree/07004b97cf691774efebe70404cf22201e4d330d) | | No | -| [MiniUPnPc](../depends/packages/miniupnpc.mk) | [link](https://miniupnp.tuxfamily.org/) | [2.2.2](https://github.com/bitcoin/bitcoin/pull/20421) | 1.9 | No | +| [MiniUPnPc](../depends/packages/miniupnpc.mk) | [link](https://miniupnp.tuxfamily.org/) | [2.2.2](https://github.com/bitcoin/bitcoin/pull/20421) | 2.1 | No | ### Notifications | Dependency | Releases | Version used | Minimum required | Runtime | diff --git a/doc/assumeutxo.md b/doc/design/assumeutxo.md similarity index 100% rename from doc/assumeutxo.md rename to doc/design/assumeutxo.md diff --git a/doc/design/libraries.md b/doc/design/libraries.md new file mode 100644 index 000000000000..548e8c861847 --- /dev/null +++ b/doc/design/libraries.md @@ -0,0 +1,106 @@ +# Libraries + +| Name | Description | +|--------------------------|-------------| +| *libbitcoin_cli* | RPC client functionality used by *dash-cli* executable | +| *libbitcoin_common* | Home for common functionality shared by different executables and libraries. Similar to *libbitcoin_util*, but higher-level (see [Dependencies](#dependencies)). | +| *libdash_consensus* | Stable, backwards-compatible consensus functionality used by *libbitcoin_node* and *libbitcoin_wallet* and also exposed as a [shared library](../shared-libraries.md). | +| *libbitcoinconsensus* | Shared library build of static *libdash_consensus* library | +| *libbitcoin_kernel* | Consensus engine and support library used for validation by *libbitcoin_node* and also exposed as a [shared library](../shared-libraries.md). | +| *libbitcoinqt* | GUI functionality used by *dash-qt* and *dash-gui* executables | +| *libbitcoin_ipc* | IPC functionality used by *dash-node*, *dash-wallet*, *dash-gui* executables to communicate when [`--enable-multiprocess`](multiprocess.md) is used. | +| *libbitcoin_node* | P2P and RPC server functionality used by *dashd* and *dash-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 *dashd* and *dash-wallet* executables. | +| *libbitcoin_wallet_tool* | Lower-level wallet functionality used by *dash-wallet* executable. | +| *libbitcoin_zmq* | [ZeroMQ](../zmq.md) functionality used by *dashd* and *dash-qt* executables. | + +Note: libbitcoin_kernel is a subject to be backported & dashified. + +## Conventions + +- 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. Exceptions are *libdash_consensus* and *libdash_kernel* which have external interfaces documented at [../shared-libraries.md](../shared-libraries.md). + +- 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: + + - *libbitcoin_node* code lives in `src/node/` in the `node::` namespace + - *libbitcoin_wallet* code lives in `src/wallet/` in the `wallet::` namespace + - *libbitcoin_ipc* code lives in `src/ipc/` in the `ipc::` namespace + - *libbitcoin_util* code lives in `src/util/` in the `util::` namespace + - *libdash_consensus* code lives in `src/consensus/` in the `Consensus::` namespace + +## Dependencies + +- Libraries should minimize what other libraries they depend on, and only reference symbols following the arrows shown in the dependency graph below: + +
+ +```mermaid + +%%{ init : { "flowchart" : { "curve" : "linear" }}}%% + +graph TD; + +dash-cli[dash-cli]-->libbitcoin_cli; + +dashd[dashd]-->libbitcoin_node; +dashd[dashd]-->libbitcoin_wallet; + +dash-qt[dash-qt]-->libbitcoin_node; +dash-qt[dash-qt]-->libbitcoinqt; +dash-qt[dash-qt]-->libbitcoin_wallet; + +dash-wallet[dash-wallet]-->libbitcoin_wallet; +dash-wallet[dash-wallet]-->libbitcoin_wallet_tool; + +libbitcoin_cli-->libbitcoin_common; +libbitcoin_cli-->libbitcoin_util; + +libbitcoin_common-->libbitcoin_util; +libbitcoin_common-->libdash_consensus; + +libbitcoin_kernel-->libdash_consensus; +libbitcoin_kernel-->libbitcoin_util; + +libbitcoin_node-->libbitcoin_common; +libbitcoin_node-->libdash_consensus; +libbitcoin_node-->libbitcoin_kernel; +libbitcoin_node-->libbitcoin_util; + +libbitcoinqt-->libbitcoin_common; +libbitcoinqt-->libbitcoin_util; + +libbitcoin_wallet-->libbitcoin_common; +libbitcoin_wallet-->libbitcoin_util; + +libbitcoin_wallet_tool-->libbitcoin_util; +libbitcoin_wallet_tool-->libbitcoin_wallet; + +classDef bold stroke-width:2px, font-weight:bold, font-size: smaller; +class dash-qt,dashd,dash-cli,dash-wallet bold +``` +
+ +**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. + +
+ +- The graph shows what _linker symbols_ (functions and variables) from each library other libraries can call and reference directly, but it is not a call graph. For example, there is no arrow connecting *libbitcoin_wallet* and *libbitcoin_node* libraries, because these libraries are intended to be modular and not depend on each other's internal implementation details. But wallet code still is still able to call node code indirectly through the `interfaces::Chain` abstract class in [`interfaces/chain.h`](../../src/interfaces/chain.h) and node code calls wallet code through the `interfaces::ChainClient` and `interfaces::Chain::Notifications` abstract classes in the same file. In general, defining abstract classes in [`src/interfaces/`](../../src/interfaces/) can be a convenient way of avoiding unwanted direct dependencies or circular dependencies between libraries. + +- *libdash_consensus* 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_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 *libdash_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_kernel* should only depend on *libbitcoin_util* and *libdash_consensus*. + +- 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 *libdash_consensus*, *libbitcoin_common*, 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) diff --git a/doc/multiprocess.md b/doc/design/multiprocess.md similarity index 82% rename from doc/multiprocess.md rename to doc/design/multiprocess.md index 3463130110dd..6e305c0f9b24 100644 --- a/doc/multiprocess.md +++ b/doc/design/multiprocess.md @@ -19,7 +19,7 @@ The `-debug=ipc` command line option can be used to see requests and responses b ## Installation -The multiprocess feature requires [Cap'n Proto](https://capnproto.org/) and [libmultiprocess](https://github.com/chaincodelabs/libmultiprocess) as dependencies. A simple way to get starting using it without installing these dependencies manually is to use the [depends system](../depends) with the `MULTIPROCESS=1` [dependency option](../depends#dependency-options) passed to make: +The multiprocess feature requires [Cap'n Proto](https://capnproto.org/) and [libmultiprocess](https://github.com/bitcoin-core/libmultiprocess) as dependencies. A simple way to get starting using it without installing these dependencies manually is to use the [depends system](../depends) with the `MULTIPROCESS=1` [dependency option](../depends#dependency-options) passed to make: ``` cd @@ -32,7 +32,7 @@ DASHD=dash-node 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). -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#installation) 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/bitcoin-core/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/bitcoin-core/libmultiprocess#installation) 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. ## IPC implementation details @@ -48,7 +48,7 @@ interface method invokes the implementation directly. When code is running in different processes, calling an interface method invokes a proxy interface implementation that communicates with a remote process and invokes the real implementation in the remote process. The -[libmultiprocess](https://github.com/chaincodelabs/libmultiprocess) code +[libmultiprocess](https://github.com/bitcoin-core/libmultiprocess) code generation tool internally generates proxy client classes and proxy server classes for this purpose that are thin wrappers around Cap'n Proto [client](https://capnproto.org/cxxrpc.html#clients) and @@ -67,6 +67,6 @@ a corresponding thread in the invoked process responsible for executing all method calls from the source thread, without blocking I/O or holding up another call, and using the same thread local variables, locks, and callbacks between calls. The forwarding, tracking, and threading is implemented inside the -[libmultiprocess](https://github.com/chaincodelabs/libmultiprocess) library +[libmultiprocess](https://github.com/bitcoin-core/libmultiprocess) library which has the design goal of making calls between processes look like calls in the same process to the extent possible. diff --git a/doc/developer-notes.md b/doc/developer-notes.md index 67f377b200e1..3fe03af70e2f 100644 --- a/doc/developer-notes.md +++ b/doc/developer-notes.md @@ -612,10 +612,10 @@ Threads : Started from `main()` in `bitcoind.cpp`. Responsible for starting up and shutting down the application. -- [ThreadImport (`d-loadblk`)](https://doxygen.bitcoincore.org/init_8cpp.html#ae9e290a0e829ec0198518de2eda579d1) +- [ThreadImport (`d-loadblk`)](https://doxygen.bitcoincore.org/namespacenode.html#ab4305679079866f0f420f7dbf278381d) : Loads blocks from `blk*.dat` files or `-loadblock=` on startup. -- [ThreadScriptCheck (`d-scriptch.x`)](https://doxygen.bitcoincore.org/validation_8cpp.html#a925a33e7952a157922b0bbb8dab29a20) +- [CCheckQueue::Loop (`d-scriptch.x`)](https://doxygen.bitcoincore.org/class_c_check_queue.html#a6e7fa51d3a25e7cb65446d4b50e6a987) : Parallel script validation threads for transactions in blocks. - [ThreadHTTP (`d-http`)](https://doxygen.bitcoincore.org/httpserver_8cpp.html#abb9f6ea8819672bd9a62d3695070709c) @@ -631,7 +631,7 @@ Threads : Does asynchronous background tasks like dumping wallet contents, dumping addrman and running asynchronous validationinterface callbacks. -- [TorControlThread (`d-torcontrol`)](https://doxygen.bitcoincore.org/torcontrol_8cpp.html#a4faed3692d57a0d7bdbecf3b37f72de0) +- [TorControlThread (`d-torcontrol`)](https://doxygen.bitcoincore.org/torcontrol_8cpp.html#a52a3efff23634500bb42c6474f306091) : Libevent thread for tor connections. - Net threads: @@ -643,7 +643,7 @@ Threads - [ThreadDNSAddressSeed (`d-dnsseed`)](https://doxygen.bitcoincore.org/class_c_connman.html#aa7c6970ed98a4a7bafbc071d24897d13) : Loads addresses of peers from the DNS. - - [ThreadMapPort (`d-upnp`)](https://doxygen.bitcoincore.org/net_8cpp.html#a63f82a71c4169290c2db1651a9bbe249) + - ThreadMapPort (`d-mapport`) : Universal plug-and-play startup/shutdown. - [ThreadSocketHandler (`d-net`)](https://doxygen.bitcoincore.org/class_c_connman.html#a765597cbfe99c083d8fa3d61bb464e34) @@ -655,6 +655,9 @@ Threads - [ThreadOpenConnections (`d-opencon`)](https://doxygen.bitcoincore.org/class_c_connman.html#a55e9feafc3bab78e5c9d408c207faa45) : Initiates new connections to peers. + - [ThreadI2PAcceptIncoming (`d-i2paccept`)](https://doxygen.bitcoincore.org/class_c_connman.html#a57787b4f9ac847d24065fbb0dd6e70f8) + : Listens for and accepts incoming I2P connections through the I2P SAM proxy. + - ThreadOpenMasternodeConnections (`d-mncon`) : Opens network connections to masternodes. @@ -863,12 +866,12 @@ Strings and formatting buffer overflows, and surprises with `\0` characters. Also, some C string manipulations tend to act differently depending on platform, or even the user locale. -- Use `ParseInt32`, `ParseInt64`, `ParseUInt32`, `ParseUInt64`, `ParseDouble` from `utilstrencodings.h` for number parsing. +- Use `ToIntegral` from [`strencodings.h`](/src/util/strencodings.h) for number parsing. In legacy code you might also find `ParseInt*` family of functions, `ParseDouble` or `LocaleIndependentAtoi`. - *Rationale*: These functions do overflow checking and avoid pesky locale issues. - Avoid using locale dependent functions if possible. You can use the provided - [`lint-locale-dependence.sh`](/test/lint/lint-locale-dependence.sh) + [`lint-locale-dependence.py`](/test/lint/lint-locale-dependence.py) to check for accidental use of locale dependent functions. - *Rationale*: Unnecessary locale dependence can cause bugs that are very tricky to isolate and fix. @@ -947,10 +950,20 @@ Threads and synchronization - Prefer `Mutex` type to `RecursiveMutex` one. - Consistently use [Clang Thread Safety Analysis](https://clang.llvm.org/docs/ThreadSafetyAnalysis.html) annotations to - get compile-time warnings about potential race conditions in code. Combine annotations in function declarations with - run-time asserts in function definitions (`AssertLockNotHeld()` can be omitted if `LOCK()` is - called unconditionally after it because `LOCK()` does the same check as - `AssertLockNotHeld()` internally, for non-recursive mutexes): + get compile-time warnings about potential race conditions or deadlocks in code. + + - In functions that are declared separately from where they are defined, the + thread safety annotations should be added exclusively to the function + declaration. Annotations on the definition could lead to false positives + (lack of compile failure) at call sites between the two. + + - Prefer locks that are in a class rather than global, and that are + internal to a class (private or protected) rather than public. + + - Combine annotations in function declarations with run-time asserts in + function definitions (`AssertLockNotHeld()` can be omitted if `LOCK()` is + called unconditionally after it because `LOCK()` does the same check as + `AssertLockNotHeld()` internally, for non-recursive mutexes): ```C++ // txmempool.h @@ -975,21 +988,37 @@ void CTxMemPool::UpdateTransactionsFromBlock(...) ```C++ // validation.h -class ChainstateManager +class CChainState { +protected: + ... + Mutex m_chainstate_mutex; + ... public: ... - bool ProcessNewBlock(...) LOCKS_EXCLUDED(::cs_main); + bool ActivateBestChain( + BlockValidationState& state, + std::shared_ptr pblock = nullptr) + EXCLUSIVE_LOCKS_REQUIRED(!m_chainstate_mutex) + LOCKS_EXCLUDED(::cs_main); + ... + bool PreciousBlock(BlockValidationState& state, CBlockIndex* pindex) + EXCLUSIVE_LOCKS_REQUIRED(!m_chainstate_mutex) + LOCKS_EXCLUDED(::cs_main); ... } // validation.cpp -bool ChainstateManager::ProcessNewBlock(...) +bool CChainState::PreciousBlock(BlockValidationState& state, CBlockIndex* pindex) { + AssertLockNotHeld(m_chainstate_mutex); AssertLockNotHeld(::cs_main); - ... - LOCK(::cs_main); - ... + { + LOCK(cs_main); + ... + } + + return ActivateBestChain(state, std::shared_ptr()); } ``` diff --git a/doc/evodb-verify-repair.md b/doc/evodb-verify-repair.md new file mode 100644 index 000000000000..5ebb0edf63ec --- /dev/null +++ b/doc/evodb-verify-repair.md @@ -0,0 +1,160 @@ +# EvoDb Verify and Repair RPC Commands + +### `evodb verify` + +Verifies the integrity of evodb diff records between snapshots stored every 576 blocks. + +**Syntax:** +``` +evodb verify [startBlock] [stopBlock] +``` + +**Parameters:** +- `startBlock` (optional): Starting block height. Defaults to DIP0003 activation height. +- `stopBlock` (optional): Ending block height. Defaults to current chain tip. + +**Returns:** +```json +{ + "startHeight": n, // Actual starting height (may be clamped to DIP0003) + "stopHeight": n, // Ending block height + "diffsRecalculated": 0, // Always 0 for verify mode + "snapshotsVerified": n, // Number of snapshot pairs that passed verification + "verificationErrors": [ // Array of errors (empty if verification passed) + "error message", + ... + ] +} +``` + +**Description:** + +This is a **read-only** operation that checks whether applying the stored diffs between consecutive snapshots produces the expected results. It does not modify the database. + +The command processes snapshot pairs (snapshots are stored every 576 blocks) and applies all diffs between them, verifying that the result matches the target snapshot. If all verification passes, `verificationErrors` will be empty. + +**Use cases:** +- Diagnose suspected evodb corruption +- Verify database integrity after hardware issues +- Confirm successful repair operations + +**Example:** +```bash +# Verify entire chain +dash-cli evodb verify + +# Verify specific range +dash-cli evodb verify 1000 10000 +``` + +--- + +### `evodb repair` + +Repairs corrupted evodb diff records by recalculating them from blockchain data. + +**Syntax:** +``` +evodb repair [startBlock] [stopBlock] +``` + +**Parameters:** +- `startBlock` (optional): Starting block height. Defaults to DIP0003 activation height. +- `stopBlock` (optional): Ending block height. Defaults to current chain tip. + +**Returns:** +```json +{ + "startHeight": n, // Actual starting height (may be clamped to DIP0003) + "stopHeight": n, // Ending block height + "diffsRecalculated": n, // Number of diffs successfully recalculated + "snapshotsVerified": n, // Number of snapshot pairs that passed verification + "verificationErrors": [ // Errors during verification phase + "error message", + ... + ], + "repairErrors": [ // Critical errors during repair phase + "error message", // Non-empty means full reindex required + ... + ] +} +``` + +**Description:** + +This command first runs verification on all snapshot pairs in the specified range. For any pairs that fail verification, it recalculates the diffs from actual blockchain data and writes the corrected diffs to the database. + +The repair process: +1. **Verification phase**: Checks all snapshot pairs for corruption +2. **Repair phase**: For failed pairs, recalculates diffs from blockchain blocks +3. **Database update**: Writes repaired diffs in efficient 16MB batches +4. **Cache clearing**: Clears both diff and list caches to prevent serving stale data + +**Important notes:** +- Requires all blockchain data to be available (blocks must not be pruned in the repair range) +- If repair encounters critical errors (block read failures, missing snapshots), a full reindex is required +- Critical errors are prefixed with "CRITICAL:" in error messages +- Successfully repaired diffs are verified before being committed to the database + +**Use cases:** +- Repair corrupted evodb after unclean shutdown +- Fix database inconsistencies after hardware failures +- Recover from disk corruption without full reindex (when possible) + +**Example:** +```bash +# Repair entire chain +dash-cli evodb repair + +# Repair specific range +dash-cli evodb repair 1000 10000 +``` + +--- + +## When to Use These Commands + +### Use `evodb verify` when: +- You suspect evodb corruption but want to diagnose before taking action +- Verifying integrity after hardware issues or crashes +- Confirming successful repairs + +### Use `evodb repair` when: +- `evodb verify` reports verification errors +- You experience masternode list inconsistencies +- After unclean shutdown or disk errors +- As an alternative to full reindex when snapshots are intact + +### Full reindex required when: +- Repair reports errors prefixed with "CRITICAL:" +- Snapshots are missing or corrupted (cannot be repaired by this tool) +- Block data is unavailable (pruned nodes in repair range) + +--- + +## Technical Details + +### Verification Process +- Processes snapshot pairs sequentially (snapshots stored every 576 blocks) +- Applies all stored diffs between snapshots +- Verifies result matches target snapshot using `CDeterministicMNList::IsEqual` +- Reports all errors without stopping early + +### Repair Process +- Reads actual blockchain blocks from disk +- Processes special transactions to rebuild masternode lists +- Uses dummy coins view (avoids UTXO lookups for historical blocks) +- Calculates correct diffs and verifies before committing +- Fails fast on critical errors (missing blocks, missing snapshots) + +### Performance Considerations +- Repair is I/O intensive (reads blockchain blocks, writes database) +- Progress logged every 100 snapshot pairs +- Database writes batched in 16MB chunks for efficiency +- Caches cleared after repair to ensure consistency + +### Implementation Notes +- Both commands require `::cs_main` lock +- Special handling for initial DIP0003 snapshot (may not exist in older databases) +- Only diffs can be repaired; missing snapshots require full reindex +- Repair verification must pass before diffs are committed to database diff --git a/doc/external-signer.md b/doc/external-signer.md new file mode 100644 index 000000000000..fc69fb4391b2 --- /dev/null +++ b/doc/external-signer.md @@ -0,0 +1,171 @@ +# Support for signing transactions outside of Dash Core + +Dash Core can be launched with `-signer=` where `` is an external tool which can sign transactions and perform other functions. For example, it can be used to communicate with a hardware wallet. + +## Example usage + +The following example is based on the [HWI](https://github.com/dashpay/HWI) tool. Version 2.0 or newer is required. Although this tool is hosted under the Dash Core GitHub organization and maintained by Dash Core developers, it should be used with caution. It is considered experimental and has far less review than Dash Core itself. Be particularly careful when running tools such as these on a computer with private keys on it. + +When using a hardware wallet, consult the manufacturer website for (alternative) software they recommend. As long as their software conforms to the standard below, it should be able to work with Dash Core. + +Start Dash Core: + +```sh +$ dashd -signer=../HWI/hwi.py +``` + +### Device setup + +Follow the hardware manufacturers instructions for the initial device setup, as well as their instructions for creating a backup. Alternatively, for some devices, you can use the `setup`, `restore` and `backup` commands provided by [HWI](https://github.com/dashpay/HWI). + +### Create wallet and import keys + +Get a list of signing devices / services: + +``` +$ dash-cli enumeratesigners +{ + "signers": [ + { + "fingerprint": "c8df832a" + } +] +``` + +The master key fingerprint is used to identify a device. + +Create a wallet, this automatically imports the public keys: + +```sh +$ dash-cli createwallet "hww" true true "" true true true +``` + +### Verify an address + +Display an address on the device: + +```sh +$ dash-cli -rpcwallet= getnewaddress +$ dash-cli -rpcwallet= walletdisplayaddress
+``` + +Replace `
` with the result of `getnewaddress`. + +### Spending + +Under the hood this uses a [Partially Signed Blockchain Transaction](psbt.md). + +```sh +$ dash-cli -rpcwallet= sendtoaddress
+``` + +This prompts your hardware wallet to sign, and fail if it's not connected. If successful +it automatically broadcasts the transaction. + +```sh +{"complete": true, "txid": } +``` + +## Signer API + +In order to be compatible with Dash Core any signer command should conform to the specification below. This specification is subject to change. Ideally a BIP should propose a standard so that other wallets can also make use of it. + +Prerequisite knowledge: +* [Output Descriptors](descriptors.md) +* Partially Signed Blockchain Transaction ([PSBT](psbt.md)) + +### `enumerate` (required) + +Usage: +``` +$ enumerate +[ + { + "fingerprint": "00000000" + } +] +``` + +The command MUST return an (empty) array with at least a `fingerprint` field. + +A future extension could add an optional return field with device capabilities. Perhaps a descriptor with wildcards. For example: `["pkh("44'/0'/$'/{0,1}/*"), sh(wpkh("49'/0'/$'/{0,1}/*")), wpkh("84'/0'/$'/{0,1}/*")]`. This would indicate the device supports legacy, wrapped SegWit and native SegWit. In addition it restricts the derivation paths that can used for those, to maintain compatibility with other wallet software. It also indicates the device, or the driver, doesn't support multisig. + +A future extension could add an optional return field `reachable`, in case `` knows a signer exists but can't currently reach it. + +### `signtransaction` (required) + +Usage: +``` +$ --fingerprint= (--testnet) signtransaction +base64_encode_signed_psbt +``` + +The command returns a psbt with any signatures. + +The `psbt` SHOULD include bip32 derivations. The command SHOULD fail if none of the bip32 derivations match a key owned by the device. + +The command SHOULD fail if the user cancels. + +The command MAY complain if `--testnet` is set, but any of the BIP32 derivation paths contain a coin type other than `1h` (and vice versa). + +### `getdescriptors` (optional) + +Usage: + +``` +$ --fingerprint= (--testnet) getdescriptors + +``` + +Returns descriptors supported by the device. Example: + +``` +$ --fingerprint=00000000 --testnet getdescriptors +{ + "receive": [ + "pkh([00000000/44h/0h/0h]xpub6C.../0/*)#fn95jwmg", + "sh(wpkh([00000000/49h/0h/0h]xpub6B..../0/*))#j4r9hntt", + "wpkh([00000000/84h/0h/0h]xpub6C.../0/*)#qw72dxa9" + ], + "internal": [ + "pkh([00000000/44h/0h/0h]xpub6C.../1/*)#c8q40mts", + "sh(wpkh([00000000/49h/0h/0h]xpub6B..../1/*))#85dn0v75", + "wpkh([00000000/84h/0h/0h]xpub6C..../1/*)#36mtsnda" + ] +} +``` + +### `displayaddress` (optional) + +Usage: +``` + --fingerprint= (--testnet) displayaddress --desc descriptor +``` + +Example, display the first native SegWit receive address on Testnet: + +``` + --fingerprint=00000000 --testnet displayaddress --desc "wpkh([00000000/84h/1h/0h]tpubDDUZ..../0/0)" +``` + +The command MUST be able to figure out the address type from the descriptor. + +If contains a master key fingerprint, the command MUST fail if it does not match the fingerprint known by the device. + +If contains an xpub, the command MUST fail if it does not match the xpub known by the device. + +The command MAY complain if `--testnet` is set, but the BIP32 coin type is not `1h` (and vice versa). + +## How Dash Core uses the Signer API + +The `enumeratesigners` RPC simply calls ` enumerate`. + +The `createwallet` RPC calls: + +* ` --fingerprint=00000000 getdescriptors 0` + +It then imports descriptors for all support address types, in a BIP44/49/84 compatible manner. + +The `walletdisplayaddress` RPC reuses some code from `getaddressinfo` on the provided address and obtains the inferred descriptor. It then calls ` --fingerprint=00000000 displayaddress --desc=`. + +`sendtoaddress` and `sendmany` check `inputs->bip32_derivs` to see if any inputs have the same `master_fingerprint` as the signer. If so, it calls ` --fingerprint=00000000 signtransaction `. It waits for the device to return a (partially) signed psbt, tries to finalize it and broadcasts the transaction. diff --git a/doc/man/dash-cli.1 b/doc/man/dash-cli.1 index 07c8198332fd..d74ed986f458 100644 --- a/doc/man/dash-cli.1 +++ b/doc/man/dash-cli.1 @@ -1,7 +1,7 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3. -.TH DASH-CLI "1" "February 2025" "dash-cli v22.1.0" "User Commands" +.TH DASH-CLI "1" "October 2025" "dash-cli v23.0.0" "User Commands" .SH NAME -dash-cli \- manual page for dash-cli v22.1.0 +dash-cli \- manual page for dash-cli v23.0.0 .SH SYNOPSIS .B dash-cli [\fI\,options\/\fR] \fI\, \/\fR[\fI\,params\/\fR] \fI\,Send command to Dash Core\/\fR @@ -15,7 +15,7 @@ dash-cli \- manual page for dash-cli v22.1.0 .B dash-cli [\fI\,options\/\fR] \fI\,help Get help for a command\/\fR .SH DESCRIPTION -Dash Core RPC client version v22.1.0 +Dash Core RPC client version v23.0.0 .SH OPTIONS .HP \-? @@ -45,8 +45,8 @@ Specify data directory .HP \fB\-generate\fR .IP -Generate blocks immediately, equivalent to RPC getnewaddress followed by -RPC generatetoaddress. Optional positional integer arguments are +Generate blocks, equivalent to RPC getnewaddress followed by RPC +generatetoaddress. Optional positional integer arguments are number of blocks to generate (default: 1) and maximum iterations to try (default: 1000000), equivalent to RPC generatetoaddress nblocks and maxtries arguments. Example: dash\-cli \fB\-generate\fR 4 @@ -55,8 +55,8 @@ nblocks and maxtries arguments. Example: dash\-cli \fB\-generate\fR 4 \fB\-getinfo\fR .IP Get general information from the remote server. Note that unlike -server\-side RPC calls, the results of \fB\-getinfo\fR is the result of -multiple non\-atomic requests. Some entries in the result may +server\-side RPC calls, the output of \fB\-getinfo\fR 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) .HP @@ -162,4 +162,4 @@ The source code is available from . This is experimental software. Distributed under the MIT software license, see the accompanying file COPYING -or \ No newline at end of file +or diff --git a/doc/man/dash-qt.1 b/doc/man/dash-qt.1 index 0734575bcc41..653b59a47b4a 100644 --- a/doc/man/dash-qt.1 +++ b/doc/man/dash-qt.1 @@ -1,12 +1,14 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3. -.TH DASH-QT "1" "February 2025" "dash-qt v22.1.0" "User Commands" +.TH DASH-QT "1" "October 2025" "dash-qt v23.0.0" "User Commands" .SH NAME -dash-qt \- manual page for dash-qt v22.1.0 +dash-qt \- manual page for dash-qt v23.0.0 .SH SYNOPSIS .B dash-qt -[\fI\,command-line options\/\fR] +[\fI\,command-line options\/\fR] [\fI\,URI\/\fR] .SH DESCRIPTION -Dash Core version v22.1.0 +Dash Core version v23.0.0 +.PP +Optional URI is a Dash address in BIP21 URI format. .SH OPTIONS .HP \-? @@ -23,15 +25,16 @@ message) 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: -000000000000001cf26547602d982dcaa909231bbcd1e70c0eb3c65de25473ba, +0000000000000009ba1e8f47851d036bb618a4f6565eb3c32d1f647d450ff195, testnet: -000000eef20eb0062abd4e799967e98bdebb165dd1c567ab4118c1c86c6e948f) +00000107d42829a38e31c1a38c660d621e1ca376a880df1520e85e38af175d3a) .HP \fB\-blockfilterindex=\fR .IP Maintain an index of compact filters by block (default: 0, values: basic). If is not supplied or if = 1, indexes for -all known types are enabled. +all known types are enabled. Automatically enabled for +masternodes with value 'basic'. .HP \fB\-blocknotify=\fR .IP @@ -122,7 +125,12 @@ Do not keep transactions in the mempool longer than hours (default: .HP \fB\-par=\fR .IP -Set the number of script verification threads (\fB\-16\fR to 15, 0 = auto, <0 = +Set the number of script verification threads (\fB\-24\fR to 15, 0 = auto, <0 = +leave that many cores free, default: 0) +.HP +\fB\-parbls=\fR +.IP +Set the number of BLS verification threads (\fB\-24\fR to 33, 0 = auto, <0 = leave that many cores free, default: 0) .HP \fB\-persistmempool\fR @@ -229,7 +237,7 @@ Allow DNS lookups for \fB\-addnode\fR, \fB\-seednode\fR and \fB\-connect\fR (def \fB\-dnsseed\fR .IP Query for peer addresses via DNS lookup, if low on addresses (default: 1 -unless \fB\-connect\fR used) +unless \fB\-connect\fR used or \fB\-maxconnections\fR=\fI\,0\/\fR) .HP \fB\-externalip=\fR .IP @@ -257,7 +265,8 @@ none) .HP \fB\-listen\fR .IP -Accept connections from outside (default: 1 if no \fB\-proxy\fR or \fB\-connect\fR) +Accept connections from outside (default: 1 if no \fB\-proxy\fR, \fB\-connect\fR or +\fB\-maxconnections\fR=\fI\,0\/\fR) .HP \fB\-listenonion\fR .IP @@ -302,10 +311,11 @@ Use NAT\-PMP to map the listening port (default: 0) Enable all P2P network activity (default: 1). Can be changed by the setnetworkactive RPC command .HP -\fB\-onion=\fR +\fB\-onion=\fR .IP Use separate SOCKS5 proxy to reach peers via Tor onion services, set -\fB\-noonion\fR to disable (default: \fB\-proxy\fR) +\fB\-noonion\fR to disable (default: \fB\-proxy\fR). May be a local file path +prefixed with 'unix:'. .HP \fB\-onlynet=\fR .IP @@ -316,7 +326,8 @@ allow multiple networks. .HP \fB\-peerblockfilters\fR .IP -Serve compact block filters to peers per BIP 157 (default: 0) +Serve compact block filters to peers per BIP 157 (default: 0, +automatically enabled for masternodes) .HP \fB\-peerbloomfilters\fR .IP @@ -329,20 +340,17 @@ Specify a p2p connection timeout delay in seconds. After connecting to a peer, wait this amount of time before considering disconnection based on inactivity (minimum: 1, default: 60) .HP -\fB\-permitbaremultisig\fR -.IP -Relay non\-P2SH multisig (default: 1) -.HP \fB\-port=\fR .IP Listen for connections on . Nodes not using the default ports (default: 9999, testnet: 19999, regtest: 19899) are unlikely to get incoming connections. Not relevant for I2P (see doc/i2p.md). .HP -\fB\-proxy=\fR +\fB\-proxy=\fR .IP Connect through SOCKS5 proxy, set \fB\-noproxy\fR to disable (default: -disabled) +disabled). May be a local file path prefixed with 'unix:' if the +proxy supports it. .HP \fB\-proxyrandomize\fR .IP @@ -378,8 +386,7 @@ Tor control port password (default: empty) .HP \fB\-upnp\fR .IP -Use UPnP to map the listening port (default: 1 when listening and no -\fB\-proxy\fR) +Use UPnP to map the listening port (default: 0) .HP \fB\-v2transport\fR .IP @@ -484,10 +491,6 @@ Specify statsd host (default: ) Specify the number of seconds between periodic measurements (default: 60) .HP -\fB\-statsport=\fR -.IP -Specify statsd port (default: 8125) -.HP \fB\-statsprefix=\fR .IP Specify an optional string prepended to every stats key (default: ) @@ -509,6 +512,12 @@ limitation and possibly a larger\-than\-necessary number of inputs being used. Always enabled for wallets with "avoid_reuse" enabled, otherwise default: 0. .HP +\fB\-consolidatefeerate=\fR +.IP +The maximum feerate (in DASH/kvB) at which transaction building may use +more inputs than strictly necessary so that the wallet's UTXO +pool can be reduced (default: 0.00001). +.HP \fB\-createwalletbackups=\fR .IP Number of automatic wallet backups (default: 10) @@ -1014,6 +1023,10 @@ Maximum size of data in data carrier transactions we relay and mine Fees (in DASH/kB) smaller than this are considered zero fee for relaying, mining and transaction creation (default: 0.00001) .HP +\fB\-permitbaremultisig\fR +.IP +Relay non\-P2SH multisig (default: 1) +.HP \fB\-whitelistforcerelay\fR .IP Add 'forcerelay' permission to whitelisted inbound peers with default @@ -1045,10 +1058,11 @@ Accept public REST requests (default: 0) .HP \fB\-rpcallowip=\fR .IP -Allow JSON\-RPC connections from specified source. Valid for are a -single IP (e.g. 1.2.3.4), a network/netmask (e.g. -1.2.3.4/255.255.255.0) or a network/CIDR (e.g. 1.2.3.4/24). This -option can be specified multiple times +Allow JSON\-RPC connections from specified source. Valid values for +are a single IP (e.g. 1.2.3.4), a network/netmask (e.g. +1.2.3.4/255.255.255.0), a network/CIDR (e.g. 1.2.3.4/24), all +ipv4 (0.0.0.0/0), or all ipv6 (::/0). This option can be +specified multiple times .HP \fB\-rpcauth=\fR .IP @@ -1174,4 +1188,4 @@ The source code is available from . This is experimental software. Distributed under the MIT software license, see the accompanying file COPYING -or \ No newline at end of file +or diff --git a/doc/man/dash-tx.1 b/doc/man/dash-tx.1 index 03bc412fe9fc..48c8c6622977 100644 --- a/doc/man/dash-tx.1 +++ b/doc/man/dash-tx.1 @@ -1,7 +1,7 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3. -.TH DASH-TX "1" "February 2025" "dash-tx v22.1.0" "User Commands" +.TH DASH-TX "1" "October 2025" "dash-tx v23.0.0" "User Commands" .SH NAME -dash-tx \- manual page for dash-tx v22.1.0 +dash-tx \- manual page for dash-tx v23.0.0 .SH SYNOPSIS .B dash-tx [\fI\,options\/\fR] \fI\, \/\fR[\fI\,commands\/\fR] \fI\,Update hex-encoded dash transaction\/\fR @@ -9,7 +9,7 @@ dash-tx \- manual page for dash-tx v22.1.0 .B dash-tx [\fI\,options\/\fR] \fI\,-create \/\fR[\fI\,commands\/\fR] \fI\,Create hex-encoded dash transaction\/\fR .SH DESCRIPTION -Dash Core dash\-tx utility version v22.1.0 +Dash Core dash\-tx utility version v23.0.0 .SH OPTIONS .HP \-? @@ -119,4 +119,4 @@ The source code is available from . This is experimental software. Distributed under the MIT software license, see the accompanying file COPYING -or \ No newline at end of file +or diff --git a/doc/man/dash-wallet.1 b/doc/man/dash-wallet.1 index 1c3b7032c974..8f6403314a0f 100644 --- a/doc/man/dash-wallet.1 +++ b/doc/man/dash-wallet.1 @@ -1,9 +1,9 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3. -.TH DASH-WALLET "1" "February 2025" "dash-wallet v22.1.0" "User Commands" +.TH DASH-WALLET "1" "October 2025" "dash-wallet v23.0.0" "User Commands" .SH NAME -dash-wallet \- manual page for dash-wallet v22.1.0 +dash-wallet \- manual page for dash-wallet v23.0.0 .SH DESCRIPTION -Dash Core dash\-wallet version v22.1.0 +Dash Core dash\-wallet version v23.0.0 .PP dash\-wallet is an offline tool for creating and interacting with Dash Core wallet files. By default dash\-wallet will act on wallets in the default mainnet wallet directory in the datadir. @@ -109,4 +109,4 @@ The source code is available from . This is experimental software. Distributed under the MIT software license, see the accompanying file COPYING -or \ No newline at end of file +or diff --git a/doc/man/dashd.1 b/doc/man/dashd.1 index 997a2eda72bd..437f7b0c0017 100644 --- a/doc/man/dashd.1 +++ b/doc/man/dashd.1 @@ -1,22 +1,12 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3. -.TH DASHD "1" "February 2025" "dashd v22.1.0" "User Commands" +.TH DASHD "1" "October 2025" "dashd v23.0.0" "User Commands" .SH NAME -dashd \- manual page for dashd v22.1.0 +dashd \- manual page for dashd v23.0.0 .SH SYNOPSIS .B dashd [\fI\,options\/\fR] \fI\,Start Dash Core\/\fR .SH DESCRIPTION -Dash Core version v22.1.0 -Copyright \(co 2014\-2025 The Dash Core developers -Copyright \(co 2009\-2025 The Bitcoin Core developers -.PP -Please contribute if you find Dash Core useful. Visit for -further information about the software. -The source code is available from . -.PP -This is experimental software. -Distributed under the MIT software license, see the accompanying file COPYING -or +Dash Core version v23.0.0 .SH OPTIONS .HP \-? @@ -33,15 +23,16 @@ message) 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: -000000000000001cf26547602d982dcaa909231bbcd1e70c0eb3c65de25473ba, +0000000000000009ba1e8f47851d036bb618a4f6565eb3c32d1f647d450ff195, testnet: -000000eef20eb0062abd4e799967e98bdebb165dd1c567ab4118c1c86c6e948f) +00000107d42829a38e31c1a38c660d621e1ca376a880df1520e85e38af175d3a) .HP \fB\-blockfilterindex=\fR .IP Maintain an index of compact filters by block (default: 0, values: basic). If is not supplied or if = 1, indexes for -all known types are enabled. +all known types are enabled. Automatically enabled for +masternodes with value 'basic'. .HP \fB\-blocknotify=\fR .IP @@ -132,7 +123,12 @@ Do not keep transactions in the mempool longer than hours (default: .HP \fB\-par=\fR .IP -Set the number of script verification threads (\fB\-16\fR to 15, 0 = auto, <0 = +Set the number of script verification threads (\fB\-24\fR to 15, 0 = auto, <0 = +leave that many cores free, default: 0) +.HP +\fB\-parbls=\fR +.IP +Set the number of BLS verification threads (\fB\-24\fR to 33, 0 = auto, <0 = leave that many cores free, default: 0) .HP \fB\-persistmempool\fR @@ -239,7 +235,7 @@ Allow DNS lookups for \fB\-addnode\fR, \fB\-seednode\fR and \fB\-connect\fR (def \fB\-dnsseed\fR .IP Query for peer addresses via DNS lookup, if low on addresses (default: 1 -unless \fB\-connect\fR used) +unless \fB\-connect\fR used or \fB\-maxconnections\fR=\fI\,0\/\fR) .HP \fB\-externalip=\fR .IP @@ -267,7 +263,8 @@ none) .HP \fB\-listen\fR .IP -Accept connections from outside (default: 1 if no \fB\-proxy\fR or \fB\-connect\fR) +Accept connections from outside (default: 1 if no \fB\-proxy\fR, \fB\-connect\fR or +\fB\-maxconnections\fR=\fI\,0\/\fR) .HP \fB\-listenonion\fR .IP @@ -312,10 +309,11 @@ Use NAT\-PMP to map the listening port (default: 0) Enable all P2P network activity (default: 1). Can be changed by the setnetworkactive RPC command .HP -\fB\-onion=\fR +\fB\-onion=\fR .IP Use separate SOCKS5 proxy to reach peers via Tor onion services, set -\fB\-noonion\fR to disable (default: \fB\-proxy\fR) +\fB\-noonion\fR to disable (default: \fB\-proxy\fR). May be a local file path +prefixed with 'unix:'. .HP \fB\-onlynet=\fR .IP @@ -326,7 +324,8 @@ allow multiple networks. .HP \fB\-peerblockfilters\fR .IP -Serve compact block filters to peers per BIP 157 (default: 0) +Serve compact block filters to peers per BIP 157 (default: 0, +automatically enabled for masternodes) .HP \fB\-peerbloomfilters\fR .IP @@ -339,20 +338,17 @@ Specify a p2p connection timeout delay in seconds. After connecting to a peer, wait this amount of time before considering disconnection based on inactivity (minimum: 1, default: 60) .HP -\fB\-permitbaremultisig\fR -.IP -Relay non\-P2SH multisig (default: 1) -.HP \fB\-port=\fR .IP Listen for connections on . Nodes not using the default ports (default: 9999, testnet: 19999, regtest: 19899) are unlikely to get incoming connections. Not relevant for I2P (see doc/i2p.md). .HP -\fB\-proxy=\fR +\fB\-proxy=\fR .IP Connect through SOCKS5 proxy, set \fB\-noproxy\fR to disable (default: -disabled) +disabled). May be a local file path prefixed with 'unix:' if the +proxy supports it. .HP \fB\-proxyrandomize\fR .IP @@ -388,8 +384,7 @@ Tor control port password (default: empty) .HP \fB\-upnp\fR .IP -Use UPnP to map the listening port (default: 1 when listening and no -\fB\-proxy\fR) +Use UPnP to map the listening port (default: 0) .HP \fB\-v2transport\fR .IP @@ -494,10 +489,6 @@ Specify statsd host (default: ) Specify the number of seconds between periodic measurements (default: 60) .HP -\fB\-statsport=\fR -.IP -Specify statsd port (default: 8125) -.HP \fB\-statsprefix=\fR .IP Specify an optional string prepended to every stats key (default: ) @@ -519,6 +510,12 @@ limitation and possibly a larger\-than\-necessary number of inputs being used. Always enabled for wallets with "avoid_reuse" enabled, otherwise default: 0. .HP +\fB\-consolidatefeerate=\fR +.IP +The maximum feerate (in DASH/kvB) at which transaction building may use +more inputs than strictly necessary so that the wallet's UTXO +pool can be reduced (default: 0.00001). +.HP \fB\-createwalletbackups=\fR .IP Number of automatic wallet backups (default: 10) @@ -1024,6 +1021,10 @@ Maximum size of data in data carrier transactions we relay and mine Fees (in DASH/kB) smaller than this are considered zero fee for relaying, mining and transaction creation (default: 0.00001) .HP +\fB\-permitbaremultisig\fR +.IP +Relay non\-P2SH multisig (default: 1) +.HP \fB\-whitelistforcerelay\fR .IP Add 'forcerelay' permission to whitelisted inbound peers with default @@ -1055,10 +1056,11 @@ Accept public REST requests (default: 0) .HP \fB\-rpcallowip=\fR .IP -Allow JSON\-RPC connections from specified source. Valid for are a -single IP (e.g. 1.2.3.4), a network/netmask (e.g. -1.2.3.4/255.255.255.0) or a network/CIDR (e.g. 1.2.3.4/24). This -option can be specified multiple times +Allow JSON\-RPC connections from specified source. Valid values for +are a single IP (e.g. 1.2.3.4), a network/netmask (e.g. +1.2.3.4/255.255.255.0), a network/CIDR (e.g. 1.2.3.4/24), all +ipv4 (0.0.0.0/0), or all ipv6 (::/0). This option can be +specified multiple times .HP \fB\-rpcauth=\fR .IP @@ -1135,4 +1137,4 @@ The source code is available from . This is experimental software. Distributed under the MIT software license, see the accompanying file COPYING -or \ No newline at end of file +or diff --git a/doc/policy/packages.md b/doc/policy/packages.md index 1e2ddbd82f96..aa720050588c 100644 --- a/doc/policy/packages.md +++ b/doc/policy/packages.md @@ -60,3 +60,40 @@ test accepts): - *Rationale*: We want to prevent potential censorship vectors. We should not reject entire packages because we already have one of the transactions. Also, if an attacker first broadcasts a competing package, the honest package should still be considered for acceptance. + +### Package Fees and Feerate + +*Package Feerate* is the total modified fees (base fees + any fee delta from +`prioritisetransaction`) divided by the total size of all transactions in the package. +If any transactions in the package are already in the mempool, they are not submitted again +("deduplicated") and are thus excluded from this calculation. + +To meet the two feerate requirements of a mempool, i.e., the pre-configured minimum relay feerate +(`minRelayTxFee`) and the dynamic mempool minimum feerate, the total package feerate is used instead +of the individual feerate. The individual transactions are allowed to be below the feerate +requirements if the package meets the feerate requirements. For example, the parent(s) in the +package can pay no fees but be paid for by the child. + +*Rationale*: This can be thought of as "CPFP within a package," solving the issue of a parent not +meeting minimum fees on its own. This would allow contracting applications to adjust their fees at +broadcast time instead of overshooting or risking becoming stuck or pinned. + +*Rationale*: It would be incorrect to use the fees of transactions that are already in the mempool, as +we do not want a transaction's fees to be double-counted. + +Implementation Note: Transactions within a package are always validated individually first, and +package validation is used for the transactions that failed. Since package feerate is only +calculated using transactions that are not in the mempool, this implementation detail affects the +outcome of package validation. + +*Rationale*: We must not allow a low-feerate child to prevent its parent from being accepted; fees +of children should not negatively impact their parents, since they are not necessary for the parents +to be mined. More generally, if transaction B is not needed in order for transaction A to be mined, +B's fees cannot harm A. In a child-with-parents package, simply validating parents individually +first is sufficient to ensure this. + +*Rationale*: As a principle, we want to avoid accidentally restricting policy in order to be +backward-compatible for users and applications that rely on p2p transaction relay. Concretely, +package validation should not prevent the acceptance of a transaction that would otherwise be +policy-valid on its own. By always accepting a transaction that passes individual validation before +trying package validation, we prevent any unintentional restriction of policy. diff --git a/doc/release-notes-6666.md b/doc/release-notes-6666.md index 2043e461c923..e9c3a61f5d38 100644 --- a/doc/release-notes-6666.md +++ b/doc/release-notes-6666.md @@ -3,7 +3,7 @@ Notable Changes * Dash Core has added support for the ability to register multiple addr:port pairs to a masternode and for specifying distinct addresses for platform P2P and platform HTTPS endpoints. The consensus and format changes needed to enable - this capability is referred to as "extended addresses" and is enabled by the deployment of the v23 fork, affecting + this capability is referred to as "extended addresses" and is enabled by the deployment of the v24 fork, affecting new masternode registrations and service updates to basic BLS masternodes. * Operators must upgrade from legacy BLS scheme to basic BLS scheme before utilizing extended address capabilities diff --git a/doc/release-notes-6729.md b/doc/release-notes-6729.md index da7a26fa50ad..15f7bccbcea2 100644 --- a/doc/release-notes-6729.md +++ b/doc/release-notes-6729.md @@ -1,7 +1,7 @@ Notable Changes --------------- -* Dash Core will no longer permit the registration of new legacy scheme masternodes after the deployment of the v23 +* Dash Core will no longer permit the registration of new legacy scheme masternodes after the deployment of the v24 fork. Existing basic scheme masternodes will also be prohibited from downgrading to the legacy scheme after the deployment is active. diff --git a/doc/release-notes-6835.md b/doc/release-notes-6835.md new file mode 100644 index 000000000000..294485a7570a --- /dev/null +++ b/doc/release-notes-6835.md @@ -0,0 +1,21 @@ +Mobile CoinJoin Compatibility +------------ + +- Fixed an issue where CoinJoin funds mixed in Dash Android wallet were + invisible when importing the mnemonic into Dash Core. Descriptor Wallets now + include an additional default descriptor for mobile CoinJoin funds, ensuring + seamless wallet migration and complete fund visibility across different + Dash wallet implementations. + +- This is a breaking change that increases the default number of descriptors + from 2 to 3 on mainnet (internal, external, mobile CoinJoin) for newly created + descriptor wallets only - existing wallets are unaffected. + + +Updated RPCs +------------ + +- The `listdescriptors` RPC now includes an optional coinjoin field to identify + CoinJoin descriptors. + +(#6835) diff --git a/doc/release-notes-6837.md b/doc/release-notes-6837.md new file mode 100644 index 000000000000..757baeeb86d0 --- /dev/null +++ b/doc/release-notes-6837.md @@ -0,0 +1,17 @@ +Statistics +---------- + +- IPv6 hosts are now supported by the StatsD client. + +- `-statshost` now accepts URLs to allow specifying the protocol, host and port in one argument. + +- Specifying invalid values will no longer result in silent disablement of the StatsD client and will now cause errors + at startup. + +### Deprecations + +- `-statsport` has been deprecated and ports are now specified using the new URL syntax supported by `-statshost`. + `-statsport` will be removed in a future release. + + - If both `-statsport` and `-statshost` with a URL specifying a port is supplied, the `-statsport` value will be + ignored. diff --git a/doc/release-notes-6870.md b/doc/release-notes-6870.md new file mode 100644 index 000000000000..dd2eede82adc --- /dev/null +++ b/doc/release-notes-6870.md @@ -0,0 +1,9 @@ +Wallet +------ + +- CoinJoin denomination creation now respects the wallet's "avoid_reuse" + setting. When the wallet has `avoid_reuse` enabled, change is sent to a + fresh change address to avoid address/public key reuse. Otherwise, change + goes back to the source address (legacy behavior). (#6870) + + diff --git a/doc/release-notes-6877.md b/doc/release-notes-6877.md new file mode 100644 index 000000000000..8e2a997cdbe2 --- /dev/null +++ b/doc/release-notes-6877.md @@ -0,0 +1,4 @@ +P2P and Network Changes +----------------------- + +`MIN_PEER_PROTO_VERSION` has been bumped to `70221` diff --git a/doc/release-notes-6901.md b/doc/release-notes-6901.md new file mode 100644 index 000000000000..6efdf775b694 --- /dev/null +++ b/doc/release-notes-6901.md @@ -0,0 +1,8 @@ +Notable changes +=============== + +New settings +------------ + +- The `shutdownnotify` option is used to specify a command to execute synchronously +before Dash Core has begun its shutdown sequence. diff --git a/doc/release-notes-6946.md b/doc/release-notes-6946.md new file mode 100644 index 000000000000..f522978dba54 --- /dev/null +++ b/doc/release-notes-6946.md @@ -0,0 +1,6 @@ +GUI changes +-------- + +- A mnemonic verification dialog is now shown after creating a new HD wallet, requiring users to verify they have written down their recovery phrase (#6946). +- A new menu item "Show Recovery Phrase…" has been added to the Settings menu to view the recovery phrase for existing HD wallets (#6946). + diff --git a/doc/release-notes-6969.md b/doc/release-notes-6969.md new file mode 100644 index 000000000000..ee3a494cd4fb --- /dev/null +++ b/doc/release-notes-6969.md @@ -0,0 +1,6 @@ +RPC changes +----------- + +- Two new hidden RPC commands have been added for diagnosing and repairing corrupted evodb diff records: + - `evodb verify` - Verifies the integrity of evodb diff records between snapshots (read-only operation). Returns verification errors if any corruption is detected. + - `evodb repair` - Repairs corrupted evodb diff records by recalculating them from blockchain data. Automatically verifies repairs before committing to database. Reports critical errors that require full reindex. diff --git a/doc/release-notes-empty-template.md b/doc/release-notes-empty-template.md new file mode 100644 index 000000000000..9a2d1a30c38b --- /dev/null +++ b/doc/release-notes-empty-template.md @@ -0,0 +1,100 @@ +*The release notes draft is a temporary file that can be added to by anyone. See +[/doc/developer-notes.md#release-notes](/doc/developer-notes.md#release-notes) +for the process.* + +# Dash Core version *version* +=============================== + +This is a new minor version release, bringing various bugfixes and performance improvements. +This release is **optional** for all nodes, although recommended. + +Please report bugs using the issue tracker at GitHub: + + + + +# Upgrading and downgrading + +## 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/Dash-Qt` (on Mac) or +`dashd`/`dash-qt` (on Linux). + +## Downgrade warning + +### Downgrade to a version < *version* + +Downgrading to a version older than *version* may not be supported, and will +likely require a reindex. + +# Release Notes + +Notable changes +=============== + +P2P and network changes +----------------------- + +Updated RPCs +------------ + + +Changes to wallet related RPCs can be found in the Wallet section below. + +New RPCs +-------- + +Build System +------------ + +Updated settings +---------------- + + +Changes to GUI or wallet related settings can be found in the GUI or Wallet section below. + +New settings +------------ + +Tools and Utilities +------------------- + +Wallet +------ + +GUI changes +----------- + +Low-level changes +================= + +RPC +--- + +Tests +----- + +See detailed [set of changes][set-of-changes]. + +# Credits + +Thanks to everyone who directly contributed to this release: + +- +- +- + +As well as everyone that submitted issues, reviewed pull requests and helped +debug the release candidates. + +# Older releases + +These releases are considered obsolete. Old release notes can be found here: + +- +- +- + +[set-of-changes]: https://github.com/dashpay/dash/compare/*version*...dashpay:*version* diff --git a/doc/release-notes/release-notes-24408.md b/doc/release-notes/release-notes-24408.md new file mode 100644 index 000000000000..1072ec786a53 --- /dev/null +++ b/doc/release-notes/release-notes-24408.md @@ -0,0 +1,5 @@ +New RPCs +-------- + +- A new `gettxspendingprevout` RPC has been added, which scans the mempool to find + transactions spending any of the given outpoints. (#24408) \ No newline at end of file diff --git a/doc/release-process.md b/doc/release-process.md index aca1c12e52da..a86ae7684e07 100644 --- a/doc/release-process.md +++ b/doc/release-process.md @@ -1,15 +1,17 @@ Release Process ==================== -* [ ] Update translations, see [translation_process.md](https://github.com/dashpay/dash/blob/master/doc/translation_process.md#synchronising-translations). -* [ ] Update manpages (after rebuilding the binaries), see [gen-manpages.py](https://github.com/bitcoin/bitcoin/blob/master/contrib/devtools/README.md#gen-manpagespy). +* [ ] Update translations, see [translation_process.md](https://github.com/dashpay/dash/blob/develop/doc/translation_process.md#synchronising-translations). +* [ ] Update manpages (after rebuilding the binaries), see [gen-manpages.py](https://github.com/dashpay/dash/blob/develop/contrib/devtools/README.md#gen-manpagespy). +* [ ] Update dash.conf and commit, see [gen-dash-conf.sh](https://github.com/dashpay/dash/blob/develop/contrib/devtools/README.md#gen-dash-confsh). Before every minor and major release: * [ ] Review ["Needs backport" labels](https://github.com/dashpay/dash/labels?q=backport). * [ ] Update DIPs with any changes introduced by this release (see [this pull request](https://github.com/dashpay/dips/pull/142) for an example) * [ ] Update version in `configure.ac` (don't forget to set `CLIENT_VERSION_IS_RELEASE` to `true`) -* [ ] Write release notes (see below) +* [ ] Write release notes (see below). To clear the release notes: `cp doc/release-notes-empty-template.md doc/release-notes.md` +* [ ] Update flatpak [metainfo file](contrib/flatpak/org.dash.dash-core.metainfo.xml) with latest release tag and estimated release date * [ ] Update `src/chainparams.cpp` `nMinimumChainWork` with information from the `getblockchaininfo` rpc. * [ ] Update `src/chainparams.cpp` `defaultAssumeValid` with information from the `getblockhash` rpc. - The selected value must not be orphaned so it may be useful to set the value two blocks back from the tip. @@ -83,7 +85,7 @@ against other `guix-attest` signatures. git -C ./guix.sigs pull ``` -### Create the macOS SDK tarball: (first time, or when SDK version changes) +### Create the macOS SDK tarball (first time, or when SDK version changes) _Note: this step can be skipped if [our CI](https://github.com/dashpay/dash/blob/master/ci/test/00_setup_env.sh#L64) still uses bitcoin's SDK package (see SDK_URL)_ @@ -91,7 +93,7 @@ Create the macOS SDK tarball, see the [macOS build instructions](build-osx.md#deterministic-macos-app-notes) for details. -### Build and attest to build outputs: +### Build and attest to build outputs Follow the relevant Guix README.md sections: - [Building](/contrib/guix/README.md#building) @@ -99,16 +101,12 @@ Follow the relevant Guix README.md sections: _Note: we ship releases for only some supported HOSTs so consider providing limited `HOSTS` variable or run `./contrib/containers/guix/scripts/guix-start` instead of `./contrib/guix/guix-build` when building binaries for quicker builds that exclude the supported but not shipped HOSTs_ -### Verify other builders' signatures to your own. (Optional) +### Verify other builders' signatures to your own (optional) -Add other builders keys to your gpg keyring, and/or refresh keys: See `../dash/contrib/builder-keys/README.md`. - -Follow the relevant Guix README.md sections: +- [Add other builders keys to your gpg keyring, and/or refresh keys](/contrib/builder-keys/README.md) - [Verifying build output attestations](/contrib/guix/README.md#verifying-build-output-attestations) -### Next steps: - -Commit your signature to `guix.sigs`: +### Commit your non codesigned signature to guix.sigs ```sh pushd guix.sigs @@ -118,24 +116,22 @@ git push # Assuming you can push to the guix.sigs tree popd ``` -Codesigner only: Create Windows/macOS detached signatures: -- Only one person handles codesigning. Everyone else should skip to the next step. -- Only once the Windows/macOS builds each have 3 matching signatures may they be signed with their respective release keys. +## Codesigning -Codesigner only: Sign the macOS binary: +### macOS codesigner only: Create detached macOS signatures (assuming [signapple](https://github.com/achow101/signapple/) is installed and up to date with master branch) * Transfer `dashcore-osx-unsigned.tar.gz` to macOS for signing * Extract and sign: ```sh tar xf dashcore-osx-unsigned.tar.gz - ./detached-sig-create.sh -s "Key ID" -o runtime + ./detached-sig-create.sh /path/to/codesign.p12 -o runtime ``` * Enter the keychain password and authorize the signature -* Move `signature-osx.tar.gz` back to the guix-build host +* `signature-osx.tar.gz` will be created -Codesigner only: Sign the windows binaries: +### Windows codesigner only: Create detached Windows signatures * Extract and sign: @@ -147,13 +143,14 @@ Codesigner only: Sign the windows binaries: * Enter the passphrase for the key when prompted * `signature-win.tar.gz` will be created -Code-signer only: It is advised to test that the code signature attaches properly prior to tagging by performing the `guix-codesign` step. -However if this is done, once the release has been tagged in the bitcoin-detached-sigs repo, the `guix-codesign` step must be performed again in order for the guix attestation to be valid when compared against the attestations of non-codesigner builds. +### Windows and macOS codesigners only: test code signatures +It is advised to test that the code signature attaches properly prior to tagging by performing the `guix-codesign` step. +However if this is done, once the release has been tagged in the dash-detached-sigs repo, the `guix-codesign` step must be performed again in order for the guix attestation to be valid when compared against the attestations of non-codesigner builds. -Codesigner only: Commit the detached codesign payloads: +### Windows and macOS codesigners only: Commit the detached codesign payloads ```sh -pushd ~/dashcore-detached-sigs +pushd ~/dash-detached-sigs # checkout the appropriate branch for this release series git checkout "v${VERSION}" rm -rf * @@ -165,15 +162,20 @@ git push popd ``` -Non-codesigners: wait for Windows/macOS detached signatures: +### Non-codesigners: wait for Windows and macOS detached signatures -- Once the Windows/macOS builds each have 3 matching signatures, they will be signed with their respective release keys. +- Once the Windows and macOS builds each have 3 matching signatures, they will be signed with their respective release keys. - Detached signatures will then be committed to the [dash-detached-sigs](https://github.com/dashpay/dash-detached-sigs) repository, which can be combined with the unsigned apps to create signed binaries. -Create (and optionally verify) the codesigned outputs: -- [Codesigning](/contrib/guix/README.md#codesigning) +### Create the codesigned build outputs +- [Codesigning build outputs](/contrib/guix/README.md#codesigning-build-outputs) + +### Verify other builders' signatures to your own (optional) + +- [Add other builders keys to your gpg keyring, and/or refresh keys](/contrib/builder-keys/README.md) +- [Verifying build output attestations](/contrib/guix/README.md#verifying-build-output-attestations) -Commit your signature for the signed macOS/Windows binaries: +### Commit your codesigned signature to guix.sigs (for the signed macOS/Windows binaries) ```sh pushd ./guix.sigs @@ -183,7 +185,7 @@ git push # Assuming you can push to the guix.sigs tree popd ``` -### After 3 or more people have guix-built and their results match: +## After 3 or more people have guix-built and their results match * [ ] Combine the `all.SHA256SUMS.asc` file from all signers into `SHA256SUMS.asc`: ```sh diff --git a/doc/translation_process.md b/doc/translation_process.md index 529dada5fe32..894bf6c2c61f 100644 --- a/doc/translation_process.md +++ b/doc/translation_process.md @@ -45,23 +45,7 @@ Visit the [Transifex Signup](https://app.transifex.com/signup/) page to create a You can find the Dash translation project at . ### Installing the Transifex client command-line tool -The client is used to fetch updated translations. If you are having problems, or need more details, see . - -**For Linux and Mac** - -`pip install transifex-client` - -Setup your Transifex client config as follows. Please *ignore the token field*. - -```ini -nano ~/.transifexrc - -[https://www.transifex.com] -hostname = https://www.transifex.com -password = PASSWORD -token = -username = USERNAME -``` +The client is used to fetch updated translations. Please check installation instructions and any other details at . **For Windows** diff --git a/share/setup.nsi.in b/share/setup.nsi.in index 79097c8744af..ad6791c7868a 100644 --- a/share/setup.nsi.in +++ b/share/setup.nsi.in @@ -75,13 +75,15 @@ Section -Main SEC0000 File @abs_top_builddir@/release/@BITCOIN_GUI_NAME@@EXEEXT@ File /oname=COPYING.txt @abs_top_srcdir@/COPYING File /oname=readme.txt @abs_top_srcdir@/doc/README_windows.txt + File @abs_top_srcdir@/contrib/debian/examples/dash.conf + SetOutPath $INSTDIR\share\rpcauth + File @abs_top_srcdir@/share/rpcauth/*.* SetOutPath $INSTDIR\daemon File @abs_top_builddir@/release/@BITCOIN_DAEMON_NAME@@EXEEXT@ File @abs_top_builddir@/release/@BITCOIN_CLI_NAME@@EXEEXT@ File @abs_top_builddir@/release/@BITCOIN_TX_NAME@@EXEEXT@ File @abs_top_builddir@/release/@BITCOIN_WALLET_TOOL_NAME@@EXEEXT@ - SetOutPath $INSTDIR\doc - File /r /x Makefile* @abs_top_srcdir@/doc\*.* + File @abs_top_builddir@/release/@BITCOIN_TEST_NAME@@EXEEXT@ SetOutPath $INSTDIR WriteRegStr HKCU "${REGKEY}\Components" Main 1 SectionEnd @@ -128,8 +130,9 @@ Section /o -un.Main UNSEC0000 Delete /REBOOTOK $INSTDIR\@BITCOIN_GUI_NAME@@EXEEXT@ Delete /REBOOTOK $INSTDIR\COPYING.txt Delete /REBOOTOK $INSTDIR\readme.txt + Delete /REBOOTOK $INSTDIR\dash.conf + RMDir /r /REBOOTOK $INSTDIR\share RMDir /r /REBOOTOK $INSTDIR\daemon - RMDir /r /REBOOTOK $INSTDIR\doc DeleteRegValue HKCU "${REGKEY}\Components" Main SectionEnd diff --git a/src/.clang-tidy b/src/.clang-tidy index 3d8b242963ff..76978140ecd7 100644 --- a/src/.clang-tidy +++ b/src/.clang-tidy @@ -1,14 +1,28 @@ Checks: ' -*, bugprone-argument-comment, +bugprone-use-after-move, +misc-unused-using-decls, +modernize-use-default-member-init, modernize-use-nullptr, +performance-for-range-copy, +performance-move-const-arg, +performance-unnecessary-copy-initialization, readability-const-return-type, readability-redundant-declaration, readability-redundant-string-init, ' WarningsAsErrors: ' bugprone-argument-comment, +bugprone-use-after-move, +misc-unused-using-decls, +modernize-use-default-member-init, modernize-use-nullptr, +performance-move-const-arg, +performance-unnecessary-copy-initialization, readability-redundant-declaration, readability-redundant-string-init, ' +CheckOptions: + - key: performance-move-const-arg.CheckTriviallyCopyableMove + value: false diff --git a/src/Makefile.am b/src/Makefile.am index d6386416c7ef..f76c844973a4 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -9,9 +9,9 @@ print-%: FORCE DIST_SUBDIRS = secp256k1 -AM_LDFLAGS = $(LIBTOOL_LDFLAGS) $(HARDENED_LDFLAGS) $(GPROF_LDFLAGS) $(SANITIZER_LDFLAGS) $(CORE_LDFLAGS) -AM_CFLAGS = $(DEBUG_CFLAGS) -AM_CXXFLAGS = $(DEBUG_CXXFLAGS) $(HARDENED_CXXFLAGS) $(WARN_CXXFLAGS) $(NOWARN_CXXFLAGS) $(ERROR_CXXFLAGS) $(GPROF_CXXFLAGS) $(SANITIZER_CXXFLAGS) $(CORE_CXXFLAGS) +AM_LDFLAGS = $(LIBTOOL_LDFLAGS) $(HARDENED_LDFLAGS) $(GPROF_LDFLAGS) $(SANITIZER_LDFLAGS) $(CORE_LDFLAGS) $(BACKTRACE_LDFLAGS) +AM_CFLAGS = $(DEBUG_CFLAGS) $(BACKTRACE_FLAGS) +AM_CXXFLAGS = $(DEBUG_CXXFLAGS) $(HARDENED_CXXFLAGS) $(WARN_CXXFLAGS) $(NOWARN_CXXFLAGS) $(ERROR_CXXFLAGS) $(GPROF_CXXFLAGS) $(SANITIZER_CXXFLAGS) $(CORE_CXXFLAGS) $(BACKTRACE_FLAGS) AM_OBJCXXFLAGS = $(AM_CXXFLAGS) AM_CPPFLAGS = $(DEBUG_CPPFLAGS) $(HARDENED_CPPFLAGS) $(CORE_CPPFLAGS) AM_LIBTOOLFLAGS = --preserve-dup-deps @@ -36,16 +36,10 @@ if TARGET_WINDOWS LDFLAGS_WRAP_EXCEPTIONS += -Wl,-wrap,_assert -Wl,-wrap,_wassert else LDFLAGS_WRAP_EXCEPTIONS += -Wl,-wrap,__assert_fail -endif -endif -endif - -if TARGET_WINDOWS -BACKTRACE_LIB = -ldbghelp -lbacktrace -else -BACKTRACE_LIB = -lbacktrace -endif -endif #ENABLE_STACKTRACES +endif # TARGET_WINDOWS +endif # CRASH_HOOKS_WRAPPED_CXX_ABI +endif # ENABLE_CRASH_HOOKS +endif # ENABLE_STACKTRACES BITCOIN_INCLUDES=-I$(builddir) -I$(srcdir)/$(MINISKETCH_INCLUDE_DIR_INT) -I$(srcdir)/secp256k1/include -I$(srcdir)/$(UNIVALUE_INCLUDE_DIR_INT) $(LEVELDB_CPPFLAGS) BITCOIN_INCLUDES+=-isystem$(srcdir)/dashbls/include -isystem$(srcdir)/dashbls/depends/relic/include -isystem$(srcdir)/dashbls/depends/minialloc/include @@ -179,12 +173,13 @@ BITCOIN_CORE_H = \ coinjoin/coinjoin.h \ coinjoin/client.h \ coinjoin/common.h \ - coinjoin/context.h \ coinjoin/options.h \ coinjoin/server.h \ coinjoin/util.h \ + coinjoin/walletman.h \ coins.h \ common/bloom.h \ + common/run_command.h \ compat/assumptions.h \ compat/byteswap.h \ compat/compat.h \ @@ -221,12 +216,14 @@ BITCOIN_CORE_H = \ evo/specialtx_filter.h \ evo/specialtxman.h \ evo/types.h \ + external_signer.h \ dsnotificationinterface.h \ - governance/governance.h \ governance/classes.h \ governance/common.h \ + governance/governance.h \ governance/exceptions.h \ governance/object.h \ + governance/signing.h \ governance/validators.h \ governance/vote.h \ governance/votedb.h \ @@ -257,7 +254,9 @@ BITCOIN_CORE_H = \ instantsend/db.h \ instantsend/instantsend.h \ instantsend/lock.h \ + instantsend/net_instantsend.h \ instantsend/signing.h \ + kernel/coinstats.h \ key.h \ key_io.h \ limitedmap.h \ @@ -291,6 +290,7 @@ BITCOIN_CORE_H = \ memusage.h \ merkleblock.h \ messagesigner.h \ + msg_result.h \ net.h \ net_permissions.h \ net_processing.h \ @@ -304,7 +304,6 @@ BITCOIN_CORE_H = \ node/caches.h \ node/chainstate.h \ node/coin.h \ - node/coinstats.h \ node/connection_types.h \ node/context.h \ node/eviction.h \ @@ -345,6 +344,7 @@ BITCOIN_CORE_H = \ scheduler.h \ script/descriptor.h \ script/keyorigin.h \ + script/miniscript.h \ script/sigcache.h \ script/sign.h \ script/signingprovider.h \ @@ -405,6 +405,7 @@ BITCOIN_CORE_H = \ util/sock.h \ util/string.h \ util/spanparsing.h \ + util/subprocess.hpp \ util/syserror.h \ util/system.h \ util/time.h \ @@ -432,6 +433,7 @@ BITCOIN_CORE_H = \ wallet/crypter.h \ wallet/db.h \ wallet/dump.h \ + wallet/external_signer_scriptpubkeyman.h \ wallet/fees.h \ wallet/hdchain.h \ wallet/ismine.h \ @@ -484,8 +486,8 @@ libbitcoin_node_a_SOURCES = \ chainlock/clsig.cpp \ chainlock/signing.cpp \ coinjoin/coinjoin.cpp \ - coinjoin/context.cpp \ coinjoin/server.cpp \ + coinjoin/walletman.cpp \ consensus/tx_verify.cpp \ dbwrapper.cpp \ deploymentstatus.cpp \ @@ -510,6 +512,7 @@ libbitcoin_node_a_SOURCES = \ governance/exceptions.cpp \ governance/governance.cpp \ governance/object.cpp \ + governance/signing.cpp \ governance/validators.cpp \ governance/vote.cpp \ governance/votedb.cpp \ @@ -525,7 +528,9 @@ libbitcoin_node_a_SOURCES = \ instantsend/db.cpp \ instantsend/instantsend.cpp \ instantsend/lock.cpp \ + instantsend/net_instantsend.cpp \ instantsend/signing.cpp \ + kernel/coinstats.cpp \ llmq/blockprocessor.cpp \ llmq/commitment.cpp \ llmq/context.cpp \ @@ -557,7 +562,6 @@ libbitcoin_node_a_SOURCES = \ node/caches.cpp \ node/chainstate.cpp \ node/coin.cpp \ - node/coinstats.cpp \ node/connection_types.cpp \ node/context.cpp \ node/eviction.cpp \ @@ -643,6 +647,7 @@ libbitcoin_wallet_a_SOURCES = \ wallet/crypter.cpp \ wallet/db.cpp \ wallet/dump.cpp \ + wallet/external_signer_scriptpubkeyman.cpp \ wallet/fees.cpp \ wallet/hdchain.cpp \ wallet/interfaces.cpp \ @@ -888,7 +893,7 @@ libbitcoin_consensus_a_SOURCES = \ version.h # common: shared between dashd, and dash-qt and non-server tools -libbitcoin_common_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) +libbitcoin_common_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BOOST_CPPFLAGS) libbitcoin_common_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_common_a_SOURCES = \ base58.cpp \ @@ -896,16 +901,19 @@ libbitcoin_common_a_SOURCES = \ chainparams.cpp \ coins.cpp \ common/bloom.cpp \ + common/run_command.cpp \ compressor.cpp \ core_read.cpp \ core_write.cpp \ deploymentinfo.cpp \ evo/core_write.cpp \ evo/netinfo.cpp \ + external_signer.cpp \ governance/common.cpp \ init/common.cpp \ key.cpp \ key_io.cpp \ + llmq/core_write.cpp \ merkleblock.cpp \ net_types.cpp \ netaddress.cpp \ @@ -918,10 +926,12 @@ libbitcoin_common_a_SOURCES = \ psbt.cpp \ rpc/evo_util.cpp \ rpc/rawtransaction_util.cpp \ + rpc/external_signer.cpp \ rpc/util.cpp \ saltedhasher.cpp \ scheduler.cpp \ script/descriptor.cpp \ + script/miniscript.cpp \ script/sign.cpp \ script/signingprovider.cpp \ script/standard.cpp \ @@ -1022,7 +1032,7 @@ bitcoin_bin_ldadd = \ $(LIBMEMENV) \ $(LIBSECP256K1) -bitcoin_bin_ldadd += $(BACKTRACE_LIB) $(BDB_LIBS) $(MINIUPNPC_LIBS) $(NATPMP_LIBS) $(SQLITE_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(ZMQ_LIBS) $(GMP_LIBS) +bitcoin_bin_ldadd += $(BACKTRACE_LIBS) $(BDB_LIBS) $(MINIUPNPC_LIBS) $(NATPMP_LIBS) $(SQLITE_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(ZMQ_LIBS) $(GMP_LIBS) dashd_SOURCES = $(bitcoin_daemon_sources) init/bitcoind.cpp dashd_CPPFLAGS = $(bitcoin_bin_cppflags) @@ -1051,7 +1061,7 @@ dash_cli_LDADD = \ $(LIBUNIVALUE) \ $(LIBBITCOIN_UTIL) \ $(LIBBITCOIN_CRYPTO) -dash_cli_LDADD += $(BACKTRACE_LIB) $(EVENT_LIBS) $(GMP_LIBS) +dash_cli_LDADD += $(BACKTRACE_LIBS) $(EVENT_LIBS) $(GMP_LIBS) # # dash-tx binary # @@ -1073,7 +1083,7 @@ dash_tx_LDADD = \ $(LIBDASHBLS) \ $(LIBSECP256K1) -dash_tx_LDADD += $(BACKTRACE_LIB) $(GMP_LIBS) +dash_tx_LDADD += $(BACKTRACE_LIBS) $(GMP_LIBS) # # dash-wallet binary # @@ -1081,7 +1091,21 @@ dash_wallet_SOURCES = bitcoin-wallet.cpp dash_wallet_CPPFLAGS = $(bitcoin_bin_cppflags) dash_wallet_CXXFLAGS = $(bitcoin_bin_cxxflags) dash_wallet_LDFLAGS = $(bitcoin_bin_ldflags) -dash_wallet_LDADD = $(LIBBITCOIN_WALLET_TOOL) $(bitcoin_bin_ldadd) +dash_wallet_LDADD = \ + $(LIBBITCOIN_WALLET_TOOL) \ + $(LIBBITCOIN_WALLET) \ + $(LIBBITCOIN_COMMON) \ + $(LIBBITCOIN_UTIL) \ + $(LIBUNIVALUE) \ + $(LIBBITCOIN_CONSENSUS) \ + $(LIBBITCOIN_CRYPTO) \ + $(LIBDASHBLS) \ + $(LIBSECP256K1) \ + $(BACKTRACE_LIBS) \ + $(BOOST_LIBS) \ + $(BDB_LIBS) \ + $(SQLITE_LIBS) \ + $(GMP_LIBS) if TARGET_WINDOWS dash_wallet_SOURCES += dash-wallet-res.rc @@ -1156,7 +1180,7 @@ clean-local: -rm -rf *.dSYM test/*.dSYM bench/*.dSYM qt/*.dSYM qt/test/*.dSYM .rc.o: - @test -f $(WINDRES) || (echo "windres $(WINDRES) not found, but is required to compile windows resource files"; exit 1) + @command -v $(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 $@ diff --git a/src/Makefile.bench.include b/src/Makefile.bench.include index dc17fc2bfb68..be7bfe2d2dcc 100644 --- a/src/Makefile.bench.include +++ b/src/Makefile.bench.include @@ -23,6 +23,7 @@ bench_bench_dash_SOURCES = \ bench/block_assemble.cpp \ bench/bls.cpp \ bench/bls_dkg.cpp \ + bench/bls_pubkey_agg.cpp \ bench/ccoins_caching.cpp \ bench/chacha20.cpp \ bench/checkblock.cpp \ @@ -80,7 +81,7 @@ bench_bench_dash_LDADD = \ $(MINIUPNPC_LIBS) \ $(NATPMP_LIBS) \ $(GMP_LIBS) \ - $(BACKTRACE_LIB) + $(BACKTRACE_LIBS) if ENABLE_ZMQ bench_bench_dash_LDADD += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS) diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index f50ac4602bfb..488cbb21ff78 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -27,6 +27,7 @@ QT_FORMS_UI = \ qt/forms/intro.ui \ qt/forms/modaloverlay.ui \ qt/forms/masternodelist.ui \ + qt/forms/mnemonicverificationdialog.ui \ qt/forms/qrdialog.ui \ qt/forms/openuridialog.ui \ qt/forms/optionsdialog.ui \ @@ -66,6 +67,7 @@ QT_MOC_CPP = \ qt/moc_macnotificationhandler.cpp \ qt/moc_modaloverlay.cpp \ qt/moc_masternodelist.cpp \ + qt/moc_mnemonicverificationdialog.cpp \ qt/moc_notificator.cpp \ qt/moc_openuridialog.cpp \ qt/moc_optionsdialog.cpp \ @@ -144,6 +146,7 @@ BITCOIN_QT_H = \ qt/macos_appnap.h \ qt/modaloverlay.h \ qt/masternodelist.h \ + qt/mnemonicverificationdialog.h \ qt/networkstyle.h \ qt/notificator.h \ qt/openuridialog.h \ @@ -257,6 +260,7 @@ BITCOIN_QT_WALLET_CPP = \ qt/governancelist.cpp \ qt/proposalwizard.cpp \ qt/masternodelist.cpp \ + qt/mnemonicverificationdialog.cpp \ qt/openuridialog.cpp \ qt/overviewpage.cpp \ qt/paymentserver.cpp \ @@ -413,7 +417,7 @@ if ENABLE_ZMQ bitcoin_qt_ldadd += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS) endif bitcoin_qt_ldadd += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CONSENSUS) $(LIBBITCOIN_CRYPTO) $(LIBDASHBLS) $(LIBUNIVALUE) $(LIBLEVELDB) $(LIBMEMENV) \ - $(BACKTRACE_LIB) $(QT_LIBS) $(QT_DBUS_LIBS) $(QR_LIBS) $(BDB_LIBS) $(MINIUPNPC_LIBS) $(NATPMP_LIBS) $(SQLITE_LIBS) $(LIBSECP256K1) \ + $(BACKTRACE_LIBS) $(QT_LIBS) $(QT_DBUS_LIBS) $(QR_LIBS) $(BDB_LIBS) $(MINIUPNPC_LIBS) $(NATPMP_LIBS) $(SQLITE_LIBS) $(LIBSECP256K1) \ $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(GMP_LIBS) bitcoin_qt_ldflags = $(LDFLAGS_WRAP_EXCEPTIONS) $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) $(PTHREAD_FLAGS) bitcoin_qt_libtoolflags = $(AM_LIBTOOLFLAGS) --tag CXX diff --git a/src/Makefile.qttest.include b/src/Makefile.qttest.include index 56e9225cb9da..83cdbefc1424 100644 --- a/src/Makefile.qttest.include +++ b/src/Makefile.qttest.include @@ -59,7 +59,7 @@ if ENABLE_ZMQ qt_test_test_dash_qt_LDADD += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS) endif qt_test_test_dash_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CONSENSUS) $(LIBBITCOIN_CRYPTO) $(LIBDASHBLS) $(LIBUNIVALUE) $(LIBLEVELDB) \ - $(LIBMEMENV) $(BACKTRACE_LIB) $(QT_LIBS) $(QT_DBUS_LIBS) $(QT_TEST_LIBS) \ + $(LIBMEMENV) $(BACKTRACE_LIBS) $(QT_LIBS) $(QT_DBUS_LIBS) $(QT_TEST_LIBS) \ $(QR_LIBS) $(BDB_LIBS) $(MINIUPNPC_LIBS) $(NATPMP_LIBS) $(SQLITE_LIBS) $(LIBSECP256K1) \ $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(GMP_LIBS) qt_test_test_dash_qt_LDFLAGS = $(LDFLAGS_WRAP_EXCEPTIONS) $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) $(PTHREAD_FLAGS) diff --git a/src/Makefile.test.include b/src/Makefile.test.include index b05116eaee52..a6cc2ce79318 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -43,10 +43,10 @@ FUZZ_SUITE_LD_COMMON = \ $(LIBTEST_FUZZ) \ $(LIBTEST_UTIL) \ $(LIBBITCOIN_NODE) \ + $(LIBBITCOIN_WALLET) \ $(LIBBITCOIN_COMMON) \ $(LIBBITCOIN_UTIL) \ $(LIBBITCOIN_CONSENSUS) \ - $(LIBBITCOIN_WALLET) \ $(LIBBITCOIN_CRYPTO) \ $(LIBBITCOIN_CLI) \ $(LIBDASHBLS) \ @@ -60,7 +60,7 @@ FUZZ_SUITE_LD_COMMON = \ $(EVENT_LIBS) \ $(EVENT_PTHREADS_LIBS) \ $(GMP_LIBS) \ - $(BACKTRACE_LIB) + $(BACKTRACE_LIBS) if USE_UPNP FUZZ_SUITE_LD_COMMON += $(MINIUPNPC_LIBS) @@ -145,6 +145,7 @@ BITCOIN_TESTS =\ test/mempool_tests.cpp \ test/merkle_tests.cpp \ test/merkleblock_tests.cpp \ + test/miniscript_tests.cpp \ test/minisketch_tests.cpp \ test/miner_tests.cpp \ test/multisig_tests.cpp \ @@ -221,7 +222,6 @@ BITCOIN_TESTS += \ wallet/test/scriptpubkeyman_tests.cpp FUZZ_SUITE_LD_COMMON +=\ - $(LIBBITCOIN_WALLET) \ $(SQLITE_LIBS) \ $(BDB_LIBS) @@ -255,7 +255,7 @@ test_test_dash_LDADD += $(LIBBITCOIN_WALLET) test_test_dash_CPPFLAGS += $(BDB_CPPFLAGS) endif test_test_dash_LDADD += $(LIBBITCOIN_NODE) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CONSENSUS) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) \ - $(LIBDASHBLS) $(LIBLEVELDB) $(LIBMEMENV) $(BACKTRACE_LIB) $(LIBSECP256K1) $(EVENT_LIBS) $(EVENT_PTHREADS_LIBS) $(MINISKETCH_LIBS) + $(LIBDASHBLS) $(LIBLEVELDB) $(LIBMEMENV) $(BACKTRACE_LIBS) $(LIBSECP256K1) $(EVENT_LIBS) $(EVENT_PTHREADS_LIBS) $(MINISKETCH_LIBS) test_test_dash_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) test_test_dash_LDADD += $(BDB_LIBS) $(MINIUPNPC_LIBS) $(SQLITE_LIBS) $(NATPMP_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(GMP_LIBS) @@ -320,6 +320,7 @@ test_fuzz_fuzz_SOURCES = \ test/fuzz/locale.cpp \ test/fuzz/merkleblock.cpp \ test/fuzz/message.cpp \ + test/fuzz/miniscript.cpp \ test/fuzz/minisketch.cpp \ test/fuzz/muhash.cpp \ test/fuzz/multiplication_overflow.cpp \ diff --git a/src/base58.h b/src/base58.h index 9ba5af73e059..d2a8d5e3bc47 100644 --- a/src/base58.h +++ b/src/base58.h @@ -14,7 +14,6 @@ #ifndef BITCOIN_BASE58_H #define BITCOIN_BASE58_H -#include #include #include diff --git a/src/bench/bench_bitcoin.cpp b/src/bench/bench_bitcoin.cpp index c5fe3fbdfddb..4db5412e16d6 100644 --- a/src/bench/bench_bitcoin.cpp +++ b/src/bench/bench_bitcoin.cpp @@ -4,6 +4,7 @@ #include +#include #include #include #include @@ -64,6 +65,8 @@ int main(int argc, char** argv) SetupBenchArgs(argsman); SapphireAutoDetect(); SHA256AutoDetect(); + BLSInit(); + bls::bls_legacy_scheme.store(false); std::string error; if (!argsman.ParseParameters(argc, argv, error)) { tfm::format(std::cerr, "Error parsing command line arguments: %s\n", error); diff --git a/src/bench/bls.cpp b/src/bench/bls.cpp index 9199f1f33360..e6206d241d9f 100644 --- a/src/bench/bls.cpp +++ b/src/bench/bls.cpp @@ -255,7 +255,7 @@ static void BLS_Verify_Batched(benchmark::Bench& bench) std::vector sigs; std::vector msgHashes; std::vector invalid; - BuildTestVectors(bench.output() ? 1000 : 1, 10, pubKeys, secKeys, sigs, msgHashes, invalid); + BuildTestVectors(bench.output() ? 1000 : 1, bench.output() ? 10 : 1, pubKeys, secKeys, sigs, msgHashes, invalid); // Benchmark. size_t i = 0; @@ -311,7 +311,7 @@ static void BLS_Verify_BatchedParallel(benchmark::Bench& bench) std::vector sigs; std::vector msgHashes; std::vector invalid; - BuildTestVectors(bench.output() ? 1000 : 1, 10, pubKeys, secKeys, sigs, msgHashes, invalid); + BuildTestVectors(bench.output() ? 1000 : 1, bench.output() ? 10 : 1, pubKeys, secKeys, sigs, msgHashes, invalid); std::list>> futures; diff --git a/src/bench/bls_pubkey_agg.cpp b/src/bench/bls_pubkey_agg.cpp new file mode 100644 index 000000000000..ab732e93806a --- /dev/null +++ b/src/bench/bls_pubkey_agg.cpp @@ -0,0 +1,99 @@ +// Copyright (c) 2025 The Dash Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include +#include +#include + +// Benchmark for the OLD approach: iterative aggregation +// This mimics the code before commit d87ea73533e6477441ad995347ea5b4fddf64f9b +static void BLS_PubKeyAggregate_Iterative(size_t count, benchmark::Bench& bench) +{ + // Generate test public keys + std::vector pubKeys; + pubKeys.reserve(count); + + for (size_t i = 0; i < count; i++) { + CBLSSecretKey secKey; + secKey.MakeNewKey(); + pubKeys.push_back(secKey.GetPublicKey()); + } + + // Benchmark: OLD approach - iterative aggregation + bench.minEpochIterations(100).run([&] { + CBLSPublicKey aggPubKey; + + for (const auto& pubKey : pubKeys) { + if (!aggPubKey.IsValid()) { + aggPubKey = pubKey; + } else { + aggPubKey.AggregateInsecure(pubKey); + } + } + + // Ensure the result is used to prevent optimization + assert(aggPubKey.IsValid()); + }); +} + +// Benchmark for the NEW approach: batch aggregation +// This mimics the code after commit d87ea73533e6477441ad995347ea5b4fddf64f9b +static void BLS_PubKeyAggregate_Batch(size_t count, benchmark::Bench& bench) +{ + // Generate test public keys + std::vector pubKeys; + pubKeys.reserve(count); + + for (size_t i = 0; i < count; i++) { + CBLSSecretKey secKey; + secKey.MakeNewKey(); + pubKeys.push_back(secKey.GetPublicKey()); + } + + // Benchmark: NEW approach - batch aggregation + bench.minEpochIterations(100).run([&] { + CBLSPublicKey aggPubKey = CBLSPublicKey::AggregateInsecure(pubKeys); + // Ensure the result is used to prevent optimization + assert(aggPubKey.IsValid()); + }); +} + +// Benchmarks for different sizes + +// Small aggregation (5 keys) - typical for small quorum subsets +static void BLS_PubKeyAggregate_Iterative_5(benchmark::Bench& bench) { BLS_PubKeyAggregate_Iterative(5, bench); } + +static void BLS_PubKeyAggregate_Batch_5(benchmark::Bench& bench) { BLS_PubKeyAggregate_Batch(5, bench); } + +// Medium aggregation (25 keys) - typical for medium quorum subsets +static void BLS_PubKeyAggregate_Iterative_25(benchmark::Bench& bench) { BLS_PubKeyAggregate_Iterative(25, bench); } + +static void BLS_PubKeyAggregate_Batch_25(benchmark::Bench& bench) { BLS_PubKeyAggregate_Batch(25, bench); } + +// Large aggregation (50 keys) - typical for larger quorums +static void BLS_PubKeyAggregate_Iterative_50(benchmark::Bench& bench) { BLS_PubKeyAggregate_Iterative(50, bench); } + +static void BLS_PubKeyAggregate_Batch_50(benchmark::Bench& bench) { BLS_PubKeyAggregate_Batch(50, bench); } + +// Very large aggregation (100 keys) - stress test +static void BLS_PubKeyAggregate_Iterative_100(benchmark::Bench& bench) { BLS_PubKeyAggregate_Iterative(100, bench); } + +static void BLS_PubKeyAggregate_Batch_100(benchmark::Bench& bench) { BLS_PubKeyAggregate_Batch(100, bench); } + +// Extra large aggregation (200 keys) - extreme case +static void BLS_PubKeyAggregate_Iterative_200(benchmark::Bench& bench) { BLS_PubKeyAggregate_Iterative(200, bench); } + +static void BLS_PubKeyAggregate_Batch_200(benchmark::Bench& bench) { BLS_PubKeyAggregate_Batch(200, bench); } + +// Register all benchmarks +BENCHMARK(BLS_PubKeyAggregate_Iterative_5) +BENCHMARK(BLS_PubKeyAggregate_Batch_5) +BENCHMARK(BLS_PubKeyAggregate_Iterative_25) +BENCHMARK(BLS_PubKeyAggregate_Batch_25) +BENCHMARK(BLS_PubKeyAggregate_Iterative_50) +BENCHMARK(BLS_PubKeyAggregate_Batch_50) +BENCHMARK(BLS_PubKeyAggregate_Iterative_100) +BENCHMARK(BLS_PubKeyAggregate_Batch_100) +BENCHMARK(BLS_PubKeyAggregate_Iterative_200) +BENCHMARK(BLS_PubKeyAggregate_Batch_200) diff --git a/src/bench/checkblock.cpp b/src/bench/checkblock.cpp index b4ff0ee3373f..b5e866d3a1b7 100644 --- a/src/bench/checkblock.cpp +++ b/src/bench/checkblock.cpp @@ -9,8 +9,11 @@ #include #include #include +#include #include +#include + // 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. @@ -38,8 +41,8 @@ static void DeserializeAndCheckBlockTest(benchmark::Bench& bench) ArgsManager bench_args; const auto chainParams = CreateChainParams(bench_args, CBaseChainParams::MAIN); // CheckBlock calls g_stats_client internally, we aren't using a testing setup - // so we need to do this manually. - ::g_stats_client = InitStatsClient(bench_args); + // so we need to do this manually. We can use the stub interface for this. + ::g_stats_client = std::make_unique(); bench.unit("block").run([&] { CBlock block; // Note that CBlock caches its checked state, so we need to recreate it here diff --git a/src/bench/checkqueue.cpp b/src/bench/checkqueue.cpp index 85b3ce61bcc7..d861faac243f 100644 --- a/src/bench/checkqueue.cpp +++ b/src/bench/checkqueue.cpp @@ -29,8 +29,7 @@ static void CCheckQueueSpeedPrevectorJob(benchmark::Bench& bench) struct PrevectorJob { prevector p; - PrevectorJob(){ - } + PrevectorJob() = default; explicit PrevectorJob(FastRandomContext& insecure_rand){ p.resize(insecure_rand.randrange(PREVECTOR_SIZE*2)); } diff --git a/src/bench/load_external.cpp b/src/bench/load_external.cpp index 68d7895f49b4..2d691484a3bd 100644 --- a/src/bench/load_external.cpp +++ b/src/bench/load_external.cpp @@ -28,7 +28,7 @@ static void LoadExternalBlockFile(benchmark::Bench& bench) // block data) as a stream object. const fs::path blkfile{testing_setup.get()->m_path_root / "blk.dat"}; CDataStream ss(SER_DISK, 0); - auto params{Params()}; + const auto& params{Params()}; ss << params.MessageStart(); ss << static_cast(benchmark::data::block813851.size()); // We can't use the streaming serialization (ss << benchmark::data::block813851) diff --git a/src/bench/prevector.cpp b/src/bench/prevector.cpp index 3b2682001fd8..8de8e05c067f 100644 --- a/src/bench/prevector.cpp +++ b/src/bench/prevector.cpp @@ -11,8 +11,8 @@ #include struct nontrivial_t { - int x; - nontrivial_t() :x(-1) {} + int x{-1}; + nontrivial_t() = default; SERIALIZE_METHODS(nontrivial_t, obj) { READWRITE(obj.x); } }; typedef prevector<28, unsigned char> prevec; @@ -112,6 +112,7 @@ static void PrevectorFillVectorDirect(benchmark::Bench& bench) { bench.run([&] { std::vector> vec; + vec.reserve(260); for (size_t i = 0; i < 260; ++i) { vec.emplace_back(); } @@ -124,6 +125,7 @@ static void PrevectorFillVectorIndirect(benchmark::Bench& bench) { bench.run([&] { std::vector> vec; + vec.reserve(260); for (size_t i = 0; i < 260; ++i) { // force allocation vec.emplace_back(29, T{}); diff --git a/src/bench/wallet_loading.cpp b/src/bench/wallet_loading.cpp index b01732b615a1..1a2bd7eceb32 100644 --- a/src/bench/wallet_loading.cpp +++ b/src/bench/wallet_loading.cpp @@ -19,14 +19,12 @@ using wallet::CWallet; using wallet::DatabaseFormat; using wallet::DatabaseOptions; -using wallet::ISMINE_SPENDABLE; -using wallet::MakeWalletDatabase; using wallet::TxStateInactive; using wallet::WALLET_FLAG_DESCRIPTORS; using wallet::WalletContext; using wallet::WalletDatabase; -static const std::shared_ptr BenchLoadWallet(std::unique_ptr database, WalletContext& context, DatabaseOptions& options) +static std::shared_ptr BenchLoadWallet(std::unique_ptr database, WalletContext& context, DatabaseOptions& options) { bilingual_str error; std::vector warnings; diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp index 29f262e0c25b..2f3b807131e9 100644 --- a/src/bitcoin-cli.cpp +++ b/src/bitcoin-cli.cpp @@ -199,10 +199,10 @@ static int AppInitRPC(int argc, char* argv[]) /** Reply structure for request_done to fill in */ struct HTTPReply { - HTTPReply(): status(0), error(-1) {} + HTTPReply() = default; - int status; - int error; + int status{0}; + int error{-1}; std::string body; }; @@ -263,7 +263,7 @@ static void http_error_cb(enum evhttp_request_error err, void *ctx) class BaseRequestHandler { public: - virtual ~BaseRequestHandler() {} + virtual ~BaseRequestHandler() = default; virtual UniValue PrepareRequest(const std::string& method, const std::vector& args) = 0; virtual UniValue ProcessReply(const UniValue &batch_in) = 0; }; @@ -948,7 +948,7 @@ static void GetWalletBalances(UniValue& result) UniValue balances(UniValue::VOBJ); for (const UniValue& wallet : wallets.getValues()) { - const std::string wallet_name = wallet.get_str(); + const std::string& wallet_name = wallet.get_str(); const UniValue getbalances = ConnectAndCallRPC(&rh, "getbalances", /* args=*/{}, wallet_name); const UniValue& balance = getbalances.find_value("result")["mine"]["trusted"]; balances.pushKV(wallet_name, balance); diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp index b97ec594abeb..9951ca31a50f 100644 --- a/src/bitcoin-tx.cpp +++ b/src/bitcoin-tx.cpp @@ -279,7 +279,7 @@ static void MutateTxAddOutAddr(CMutableTransaction& tx, const std::string& strIn CAmount value = ExtractAndValidateValue(vStrInputParts[0]); // extract and validate ADDRESS - std::string strAddr = vStrInputParts[1]; + const std::string& strAddr = vStrInputParts[1]; CTxDestination destination = DecodeDestination(strAddr); if (!IsValidDestination(destination)) { throw std::runtime_error("invalid TX output address"); @@ -311,7 +311,7 @@ static void MutateTxAddOutPubKey(CMutableTransaction& tx, const std::string& str // Extract and validate FLAGS bool bScriptHash = false; if (vStrInputParts.size() == 3) { - std::string flags = vStrInputParts[2]; + const std::string& flags = vStrInputParts[2]; bScriptHash = (flags.find('S') != std::string::npos); } @@ -363,7 +363,7 @@ static void MutateTxAddOutMultiSig(CMutableTransaction& tx, const std::string& s // Extract FLAGS bool bScriptHash = false; if (vStrInputParts.size() == numkeys + 4) { - std::string flags = vStrInputParts.back(); + const std::string& flags = vStrInputParts.back(); bScriptHash = (flags.find('S') != std::string::npos); } else if (vStrInputParts.size() > numkeys + 4) { @@ -428,13 +428,13 @@ static void MutateTxAddOutScript(CMutableTransaction& tx, const std::string& str CAmount value = ExtractAndValidateValue(vStrInputParts[0]); // extract and validate script - std::string strScript = vStrInputParts[1]; + const std::string& strScript = vStrInputParts[1]; CScript scriptPubKey = ParseScript(strScript); // Extract FLAGS bool bScriptHash = false; if (vStrInputParts.size() == 3) { - std::string flags = vStrInputParts.back(); + const std::string& flags = vStrInputParts.back(); bScriptHash = (flags.find('S') != std::string::npos); } @@ -555,7 +555,7 @@ static void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr) UniValue prevtxsObj = registers["prevtxs"]; { for (unsigned int previdx = 0; previdx < prevtxsObj.size(); previdx++) { - UniValue prevOut = prevtxsObj[previdx]; + const UniValue& prevOut = prevtxsObj[previdx]; if (!prevOut.isObject()) throw std::runtime_error("expected prevtxs internal object"); @@ -627,7 +627,7 @@ static void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr) SignatureData sigdata = DataFromTransaction(mergedTx, i, coin.out); // Only sign SIGHASH_SINGLE if there's a corresponding output: if (!fHashSingle || (i < mergedTx.vout.size())) - ProduceSignature(keystore, MutableTransactionSignatureCreator(&mergedTx, i, amount, nHashType), prevPubKey, sigdata); + ProduceSignature(keystore, MutableTransactionSignatureCreator(mergedTx, i, amount, nHashType), prevPubKey, sigdata); UpdateInput(txin, sigdata); } diff --git a/src/blockfilter.cpp b/src/blockfilter.cpp index f4638dabcc0d..364ed1c7ec72 100644 --- a/src/blockfilter.cpp +++ b/src/blockfilter.cpp @@ -170,7 +170,7 @@ const std::set& AllBlockFilterTypes() static std::once_flag flag; std::call_once(flag, []() { - for (auto entry : g_filter_types) { + for (const auto& entry : g_filter_types) { types.insert(entry.first); } }); diff --git a/src/bls/bls_batchverifier.h b/src/bls/bls_batchverifier.h index 282c2f869f61..e22bbf8d8240 100644 --- a/src/bls/bls_batchverifier.h +++ b/src/bls/bls_batchverifier.h @@ -82,27 +82,27 @@ class CBLSBatchVerifier } // revert to per-source verification - for (const auto& p : messagesBySource) { + for (const auto& [from, message_map] : messagesBySource) { bool batchValid = false; // no need to verify it again if there was just one source if (messagesBySource.size() != 1) { byMessageHash.clear(); - for (auto it = p.second.begin(); it != p.second.end(); ++it) { + for (auto it = message_map.begin(); it != message_map.end(); ++it) { byMessageHash[(*it)->second.msgHash].emplace_back(*it); } batchValid = VerifyBatch(byMessageHash); } if (!batchValid) { - badSources.emplace(p.first); + badSources.emplace(from); if (perMessageFallback) { // revert to per-message verification - if (p.second.size() == 1) { + if (message_map.size() == 1) { // no need to re-verify a single message - badMessages.emplace(p.second[0]->second.msgId); + badMessages.emplace(message_map[0]->second.msgId); } else { - for (const auto& msgIt : p.second) { + for (const auto& msgIt : message_map) { if (badMessages.count(msgIt->first)) { // same message might be invalid from different source, so no need to re-verify it continue; @@ -134,39 +134,33 @@ class CBLSBatchVerifier bool VerifyBatchInsecure(const std::map>& byMessageHash) { - CBLSSignature aggSig; + std::vector sigsToAggregate; std::vector msgHashes; std::vector pubKeys; std::set dups; msgHashes.reserve(messages.size()); pubKeys.reserve(messages.size()); + sigsToAggregate.reserve(messages.size()); - for (const auto& p : byMessageHash) { - const auto& msgHash = p.first; + std::vector pubKeysToAggregate; + for (const auto& [msgHash, vec_message_it] : byMessageHash) { + pubKeysToAggregate.clear(); + pubKeysToAggregate.reserve(vec_message_it.size()); - CBLSPublicKey aggPubKey; - - for (const auto& msgIt : p.second) { + for (const auto& msgIt : vec_message_it) { const auto& msg = msgIt->second; if (!dups.emplace(msg.msgId).second) { continue; } - if (!aggSig.IsValid()) { - aggSig = msg.sig; - } else { - aggSig.AggregateInsecure(msg.sig); - } - - if (!aggPubKey.IsValid()) { - aggPubKey = msg.pubKey; - } else { - aggPubKey.AggregateInsecure(msg.pubKey); - } + sigsToAggregate.push_back(msg.sig); + pubKeysToAggregate.push_back(msg.pubKey); } + CBLSPublicKey aggPubKey = CBLSPublicKey::AggregateInsecure(pubKeysToAggregate); + if (!aggPubKey.IsValid()) { // only duplicates for this msgHash continue; @@ -180,6 +174,7 @@ class CBLSBatchVerifier return true; } + CBLSSignature aggSig = CBLSSignature::AggregateInsecure(sigsToAggregate); return aggSig.VerifyInsecureAggregated(pubKeys, msgHashes); } @@ -199,13 +194,14 @@ class CBLSBatchVerifier bool VerifyBatchSecureStep(std::map>& byMessageHash) { - CBLSSignature aggSig; + std::vector sigsToAggregate; std::vector msgHashes; std::vector pubKeys; std::set dups; msgHashes.reserve(messages.size()); pubKeys.reserve(messages.size()); + sigsToAggregate.reserve(messages.size()); for (auto it = byMessageHash.begin(); it != byMessageHash.end(); ) { const auto& msgHash = it->first; @@ -215,12 +211,7 @@ class CBLSBatchVerifier if (dups.emplace(msg.msgId).second) { msgHashes.emplace_back(msgHash); pubKeys.emplace_back(msg.pubKey); - - if (!aggSig.IsValid()) { - aggSig = msg.sig; - } else { - aggSig.AggregateInsecure(msg.sig); - } + sigsToAggregate.push_back(msg.sig); } messageIts.pop_back(); @@ -233,6 +224,7 @@ class CBLSBatchVerifier assert(!msgHashes.empty()); + CBLSSignature aggSig = CBLSSignature::AggregateInsecure(sigsToAggregate); return aggSig.VerifyInsecureAggregated(pubKeys, msgHashes); } }; diff --git a/src/bls/bls_worker.cpp b/src/bls/bls_worker.cpp index 8041d14fc511..44f15e46c22b 100644 --- a/src/bls/bls_worker.cpp +++ b/src/bls/bls_worker.cpp @@ -15,7 +15,7 @@ template bool VerifyVectorHelper(Span vec) { std::set set; - for (auto item : vec) { + for (const auto& item : vec) { if (!item.IsValid()) return false; // check duplicates @@ -59,7 +59,7 @@ CBLSWorker::~CBLSWorker() void CBLSWorker::Start() { int workerCount = std::thread::hardware_concurrency() / 2; - workerCount = std::max(std::min(1, workerCount), 4); + workerCount = std::clamp(workerCount, 1, 4); workerPool.resize(workerCount); RenameThreadPool(workerPool, "bls-work"); } diff --git a/src/bls/bls_worker.h b/src/bls/bls_worker.h index ba93d571fa47..9fbf812aaa88 100644 --- a/src/bls/bls_worker.h +++ b/src/bls/bls_worker.h @@ -49,6 +49,8 @@ class CBLSWorker std::vector sigVerifyQueue; public: + CBLSWorker(const CBLSWorker&) = delete; + CBLSWorker& operator=(CBLSWorker const&) = delete; CBLSWorker(); ~CBLSWorker(); diff --git a/src/chain.h b/src/chain.h index 2fdac98e85c0..47d1e3096774 100644 --- a/src/chain.h +++ b/src/chain.h @@ -121,7 +121,7 @@ enum BlockStatus : uint32_t { * If set, this indicates that the block index entry is assumed-valid. * Certain diagnostics will be skipped in e.g. CheckBlockIndex(). * It almost certainly means that the block's full validation is pending - * on a background chainstate. See `doc/assumeutxo.md`. + * on a background chainstate. See `doc/design/assumeutxo.md`. */ BLOCK_ASSUMED_VALID = 256, }; diff --git a/src/chainlock/chainlock.cpp b/src/chainlock/chainlock.cpp index d87dcb52ba1b..8ea6e20c3912 100644 --- a/src/chainlock/chainlock.cpp +++ b/src/chainlock/chainlock.cpp @@ -32,7 +32,6 @@ using node::GetTransaction; namespace llmq { namespace { -static constexpr auto CLEANUP_INTERVAL{30s}; static constexpr auto CLEANUP_SEEN_TIMEOUT{24h}; //! How long to wait for islocks until we consider a block with non-islocked TXs to be safe to sign static constexpr auto WAIT_FOR_ISLOCK_TIMEOUT{10min}; @@ -43,8 +42,8 @@ bool AreChainLocksEnabled(const CSporkManager& sporkman) return sporkman.IsSporkActive(SPORK_19_CHAINLOCKS_ENABLED); } -CChainLocksHandler::CChainLocksHandler(CChainState& chainstate, CQuorumManager& _qman, CSigningManager& _sigman, - CSporkManager& sporkman, CTxMemPool& _mempool, const CMasternodeSync& mn_sync) : +CChainLocksHandler::CChainLocksHandler(CChainState& chainstate, CQuorumManager& _qman, CSporkManager& sporkman, + CTxMemPool& _mempool, const CMasternodeSync& mn_sync) : m_chainstate{chainstate}, qman{_qman}, spork_manager{sporkman}, @@ -135,7 +134,7 @@ MessageProcessingResult CChainLocksHandler::ProcessNewChainLock(const NodeId fro } if (!bestChainLock.IsNull() && clsig.getHeight() <= bestChainLock.getHeight()) { - // no need to process/relay older CLSIGs + // no need to process older/same CLSIGs return {}; } } @@ -154,6 +153,11 @@ MessageProcessingResult CChainLocksHandler::ProcessNewChainLock(const NodeId fro { LOCK(cs); + // newer chainlock could be processed via another thread while we were not holding the lock, re-verify + if (!bestChainLock.IsNull() && clsig.getHeight() <= bestChainLock.getHeight()) { + // no need to process older/same CLSIGs + return {}; + } bestChainLockHash = hash; bestChainLock = clsig; @@ -433,14 +437,14 @@ bool CChainLocksHandler::HasConflictingChainLock(int nHeight, const uint256& blo void CChainLocksHandler::Cleanup() { + constexpr auto CLEANUP_INTERVAL{30s}; if (!m_mn_sync.IsBlockchainSynced()) { return; } - if (GetTime() - lastCleanupTime.load() < CLEANUP_INTERVAL) { + if (!cleanupThrottler.TryCleanup(CLEANUP_INTERVAL)) { return; } - lastCleanupTime = GetTime(); { LOCK(cs); diff --git a/src/chainlock/chainlock.h b/src/chainlock/chainlock.h index a9f375223636..14c9aa9a3f55 100644 --- a/src/chainlock/chainlock.h +++ b/src/chainlock/chainlock.h @@ -12,13 +12,18 @@ #include #include #include +#include #include #include #include +#include +#include #include +#include +#include #include class CBlock; @@ -63,11 +68,14 @@ class CChainLocksHandler final : public chainlock::ChainLockSignerParent std::map seenChainLocks GUARDED_BY(cs); - std::atomic lastCleanupTime{0s}; + CleanupThrottler cleanupThrottler; public: - explicit CChainLocksHandler(CChainState& chainstate, CQuorumManager& _qman, CSigningManager& _sigman, - CSporkManager& sporkman, CTxMemPool& _mempool, const CMasternodeSync& mn_sync); + CChainLocksHandler() = delete; + CChainLocksHandler(const CChainLocksHandler&) = delete; + CChainLocksHandler& operator=(const CChainLocksHandler&) = delete; + explicit CChainLocksHandler(CChainState& chainstate, CQuorumManager& _qman, CSporkManager& sporkman, + CTxMemPool& _mempool, const CMasternodeSync& mn_sync); ~CChainLocksHandler(); void ConnectSigner(gsl::not_null signer) diff --git a/src/chainlock/signing.cpp b/src/chainlock/signing.cpp index 3524fd204466..9b574d5cc6ee 100644 --- a/src/chainlock/signing.cpp +++ b/src/chainlock/signing.cpp @@ -9,6 +9,7 @@ #include #include +#include #include #include @@ -140,7 +141,7 @@ void ChainLockSigner::TrySignChainTip(const llmq::CInstantSendManager& isman) lastSignedMsgHash = msgHash; } - m_sigman.AsyncSignIfMember(Params().GetConsensus().llmqTypeChainLocks, m_shareman, requestId, msgHash); + m_shareman.AsyncSignIfMember(Params().GetConsensus().llmqTypeChainLocks, m_sigman, requestId, msgHash); } void ChainLockSigner::EraseFromBlockHashTxidMap(const uint256& hash) diff --git a/src/chainlock/signing.h b/src/chainlock/signing.h index ac9ee1fbada1..357b3295f757 100644 --- a/src/chainlock/signing.h +++ b/src/chainlock/signing.h @@ -63,6 +63,9 @@ class ChainLockSigner final : public llmq::CRecoveredSigsListener uint256 lastSignedMsgHash GUARDED_BY(cs_signer); public: + ChainLockSigner() = delete; + ChainLockSigner(const ChainLockSigner&) = delete; + ChainLockSigner& operator=(const ChainLockSigner&) = delete; explicit ChainLockSigner(CChainState& chainstate, ChainLockSignerParent& clhandler, llmq::CSigningManager& sigman, llmq::CSigSharesManager& shareman, CSporkManager& sporkman, const CMasternodeSync& mn_sync); ~ChainLockSigner(); diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 31d47f4d4d12..be5b6110fa2f 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -209,20 +209,20 @@ class CMainParams : public CChainParams { consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT; consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].min_activation_height = 0; // No activation delay - consensus.vDeployments[Consensus::DEPLOYMENT_V23].bit = 12; - consensus.vDeployments[Consensus::DEPLOYMENT_V23].nStartTime = Consensus::BIP9Deployment::NEVER_ACTIVE; // TODO - consensus.vDeployments[Consensus::DEPLOYMENT_V23].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT; // TODO - consensus.vDeployments[Consensus::DEPLOYMENT_V23].nWindowSize = 4032; - consensus.vDeployments[Consensus::DEPLOYMENT_V23].nThresholdStart = 3226; // 80% of 4032 - consensus.vDeployments[Consensus::DEPLOYMENT_V23].nThresholdMin = 2420; // 60% of 4032 - consensus.vDeployments[Consensus::DEPLOYMENT_V23].nFalloffCoeff = 5; // this corresponds to 10 periods - consensus.vDeployments[Consensus::DEPLOYMENT_V23].useEHF = true; + consensus.vDeployments[Consensus::DEPLOYMENT_V24].bit = 12; + consensus.vDeployments[Consensus::DEPLOYMENT_V24].nStartTime = Consensus::BIP9Deployment::NEVER_ACTIVE; // TODO + consensus.vDeployments[Consensus::DEPLOYMENT_V24].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT; // TODO + consensus.vDeployments[Consensus::DEPLOYMENT_V24].nWindowSize = 4032; + consensus.vDeployments[Consensus::DEPLOYMENT_V24].nThresholdStart = 3226; // 80% of 4032 + consensus.vDeployments[Consensus::DEPLOYMENT_V24].nThresholdMin = 2420; // 60% of 4032 + consensus.vDeployments[Consensus::DEPLOYMENT_V24].nFalloffCoeff = 5; // this corresponds to 10 periods + consensus.vDeployments[Consensus::DEPLOYMENT_V24].useEHF = true; // The best chain should have at least this much work. - consensus.nMinimumChainWork = uint256S("0x00000000000000000000000000000000000000000000aa587876325b0a1080c8"); // 2301632 + consensus.nMinimumChainWork = uint256S("0x00000000000000000000000000000000000000000000ae8d578b28f390b9c630"); // 2361500 // By default assume that the signatures in ancestors of this block are valid. - consensus.defaultAssumeValid = uint256S("0x000000000000000630fdfb37764bc6df460d301effa5e0fd4e8ef9ba821f36da"); // 2301632 + consensus.defaultAssumeValid = uint256S("0x0000000000000009ba1e8f47851d036bb618a4f6565eb3c32d1f647d450ff195"); // 2361500 /** * The message start string is designed to be unlikely to occur in normal data. @@ -237,7 +237,7 @@ class CMainParams : public CChainParams { nDefaultPlatformP2PPort = 26656; nDefaultPlatformHTTPPort = 443; nPruneAfterHeight = 100000; - m_assumed_blockchain_size = 50; + m_assumed_blockchain_size = 54; m_assumed_chain_state_size = 1; genesis = CreateGenesisBlock(1390095618, 28917698, 0x1e0ffff0, 1, 50 * COIN); @@ -333,6 +333,7 @@ class CMainParams : public CChainParams { {2109672, uint256S("0x000000000000001889bd33ef019065e250d32bd46911f4003d3fdd8128b5358d")}, {2175051, uint256S("0x000000000000001cf26547602d982dcaa909231bbcd1e70c0eb3c65de25473ba")}, {2216986, uint256S("0x0000000000000010b1135dc743f27f6fc8a138c6420a9d963fc676f96c2048f4")}, + {2361500, uint256S("0x0000000000000009ba1e8f47851d036bb618a4f6565eb3c32d1f647d450ff195")}, } }; @@ -340,12 +341,12 @@ class CMainParams : public CChainParams { // TODO to be specified in a future patch. }; - // getchaintxstats 17280 000000000000001cf26547602d982dcaa909231bbcd1e70c0eb3c65de25473ba + // getchaintxstats 17280 0000000000000009ba1e8f47851d036bb618a4f6565eb3c32d1f647d450ff195 chainTxData = ChainTxData{ - 1732068694, // * UNIX timestamp of last known number of transactions (Block 1969000) - 55191134, // * total number of transactions between genesis and that timestamp + 1761459807, // * UNIX timestamp of last known number of transactions (Block 2361500) + 60108260, // * total number of transactions between genesis and that timestamp // (the tx=... number in the ChainStateFlushed debug.log lines) - 0.1528060985790164, // * estimated number of transactions per second after that timestamp + 0.2794041165322403, // * estimated number of transactions per second after that timestamp }; } }; @@ -407,20 +408,20 @@ class CTestNetParams : public CChainParams { consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT; consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].min_activation_height = 0; // No activation delay - consensus.vDeployments[Consensus::DEPLOYMENT_V23].bit = 12; - consensus.vDeployments[Consensus::DEPLOYMENT_V23].nStartTime = Consensus::BIP9Deployment::NEVER_ACTIVE; // TODO - consensus.vDeployments[Consensus::DEPLOYMENT_V23].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT; - consensus.vDeployments[Consensus::DEPLOYMENT_V23].nWindowSize = 100; - consensus.vDeployments[Consensus::DEPLOYMENT_V23].nThresholdStart = 80; // 80% of 100 - consensus.vDeployments[Consensus::DEPLOYMENT_V23].nThresholdMin = 60; // 60% of 100 - consensus.vDeployments[Consensus::DEPLOYMENT_V23].nFalloffCoeff = 5; // this corresponds to 10 periods - consensus.vDeployments[Consensus::DEPLOYMENT_V23].useEHF = true; + consensus.vDeployments[Consensus::DEPLOYMENT_V24].bit = 12; + consensus.vDeployments[Consensus::DEPLOYMENT_V24].nStartTime = Consensus::BIP9Deployment::NEVER_ACTIVE; // TODO + consensus.vDeployments[Consensus::DEPLOYMENT_V24].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT; + consensus.vDeployments[Consensus::DEPLOYMENT_V24].nWindowSize = 100; + consensus.vDeployments[Consensus::DEPLOYMENT_V24].nThresholdStart = 80; // 80% of 100 + consensus.vDeployments[Consensus::DEPLOYMENT_V24].nThresholdMin = 60; // 60% of 100 + consensus.vDeployments[Consensus::DEPLOYMENT_V24].nFalloffCoeff = 5; // this corresponds to 10 periods + consensus.vDeployments[Consensus::DEPLOYMENT_V24].useEHF = true; // The best chain should have at least this much work. - consensus.nMinimumChainWork = uint256S("0x00000000000000000000000000000000000000000000000003472e1b8bd6a3b7"); // 1254997 + consensus.nMinimumChainWork = uint256S("0x000000000000000000000000000000000000000000000000036073cd80626b9c"); // 1295700 // By default assume that the signatures in ancestors of this block are valid. - consensus.defaultAssumeValid = uint256S("0x000001d20827f1394354452ba2e836de387e4fbf2d1d35b3281adbb14adf89a1"); // 1254997 + consensus.defaultAssumeValid = uint256S("0x00000107d42829a38e31c1a38c660d621e1ca376a880df1520e85e38af175d3a"); // 1295700 pchMessageStart[0] = 0xce; pchMessageStart[1] = 0xe2; @@ -430,7 +431,7 @@ class CTestNetParams : public CChainParams { nDefaultPlatformP2PPort = 22000; nDefaultPlatformHTTPPort = 22001; nPruneAfterHeight = 1000; - m_assumed_blockchain_size = 5; + m_assumed_blockchain_size = 10; m_assumed_chain_state_size = 1; genesis = CreateGenesisBlock(1390666206UL, 3861367235UL, 0x1e0ffff0, 1, 50 * COIN); @@ -507,6 +508,7 @@ class CTestNetParams : public CChainParams { {1069875, uint256S("0x00000034bfeb926662ba547c0b8dd4ba8cbb6e0c581f4e7d1bddce8f9ca3a608")}, {1143608, uint256S("0x000000eef20eb0062abd4e799967e98bdebb165dd1c567ab4118c1c86c6e948f")}, {1189000, uint256S("0x000001690314036dfbbecbdf382b230ead8e9c584241290a51f9f05a87a9cf7e")}, + {1295700, uint256S("0x00000107d42829a38e31c1a38c660d621e1ca376a880df1520e85e38af175d3a")}, } }; @@ -514,12 +516,12 @@ class CTestNetParams : public CChainParams { // TODO to be specified in a future patch. }; - // getchaintxstats 17280 000000eef20eb0062abd4e799967e98bdebb165dd1c567ab4118c1c86c6e948f + // getchaintxstats 17280 00000107d42829a38e31c1a38c660d621e1ca376a880df1520e85e38af175d3a chainTxData = ChainTxData{ - 1732068833, // * UNIX timestamp of last known number of transactions (Block 905100) - 6701197, // * total number of transactions between genesis and that timestamp + 1753531407, // * UNIX timestamp of last known number of transactions (Block 1295700) + 7089137, // * total number of transactions between genesis and that timestamp // (the tx=... number in the ChainStateFlushed debug.log lines) - 0.01528131540752872, // * estimated number of transactions per second after that timestamp + 0.01231252383519851, // * estimated number of transactions per second after that timestamp }; } }; @@ -580,14 +582,14 @@ class CDevNetParams : public CChainParams { consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT; consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].min_activation_height = 0; // No activation delay - consensus.vDeployments[Consensus::DEPLOYMENT_V23].bit = 12; - consensus.vDeployments[Consensus::DEPLOYMENT_V23].nStartTime = 1751328000; // July 1, 2025 - consensus.vDeployments[Consensus::DEPLOYMENT_V23].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT; - consensus.vDeployments[Consensus::DEPLOYMENT_V23].nWindowSize = 120; - consensus.vDeployments[Consensus::DEPLOYMENT_V23].nThresholdStart = 96; // 80% of 120 - consensus.vDeployments[Consensus::DEPLOYMENT_V23].nThresholdMin = 72; // 60% of 120 - consensus.vDeployments[Consensus::DEPLOYMENT_V23].nFalloffCoeff = 5; // this corresponds to 10 periods - consensus.vDeployments[Consensus::DEPLOYMENT_V23].useEHF = true; + consensus.vDeployments[Consensus::DEPLOYMENT_V24].bit = 12; + consensus.vDeployments[Consensus::DEPLOYMENT_V24].nStartTime = 1751328000; // July 1, 2025 + consensus.vDeployments[Consensus::DEPLOYMENT_V24].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT; + consensus.vDeployments[Consensus::DEPLOYMENT_V24].nWindowSize = 120; + consensus.vDeployments[Consensus::DEPLOYMENT_V24].nThresholdStart = 96; // 80% of 120 + consensus.vDeployments[Consensus::DEPLOYMENT_V24].nThresholdMin = 72; // 60% of 120 + consensus.vDeployments[Consensus::DEPLOYMENT_V24].nFalloffCoeff = 5; // this corresponds to 10 periods + consensus.vDeployments[Consensus::DEPLOYMENT_V24].useEHF = true; // The best chain should have at least this much work. consensus.nMinimumChainWork = uint256S("0x000000000000000000000000000000000000000000000000000000000000000"); @@ -817,14 +819,14 @@ class CRegTestParams : public CChainParams { consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT; consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].min_activation_height = 0; // No activation delay - consensus.vDeployments[Consensus::DEPLOYMENT_V23].bit = 12; - consensus.vDeployments[Consensus::DEPLOYMENT_V23].nStartTime = 0; - consensus.vDeployments[Consensus::DEPLOYMENT_V23].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT; - consensus.vDeployments[Consensus::DEPLOYMENT_V23].nWindowSize = 250; - consensus.vDeployments[Consensus::DEPLOYMENT_V23].nThresholdStart = 250 / 5 * 4; // 80% of window size - consensus.vDeployments[Consensus::DEPLOYMENT_V23].nThresholdMin = 250 / 5 * 3; // 60% of window size - consensus.vDeployments[Consensus::DEPLOYMENT_V23].nFalloffCoeff = 5; // this corresponds to 10 periods - consensus.vDeployments[Consensus::DEPLOYMENT_V23].useEHF = true; + consensus.vDeployments[Consensus::DEPLOYMENT_V24].bit = 12; + consensus.vDeployments[Consensus::DEPLOYMENT_V24].nStartTime = 0; + consensus.vDeployments[Consensus::DEPLOYMENT_V24].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT; + consensus.vDeployments[Consensus::DEPLOYMENT_V24].nWindowSize = 250; + consensus.vDeployments[Consensus::DEPLOYMENT_V24].nThresholdStart = 250 / 5 * 4; // 80% of window size + consensus.vDeployments[Consensus::DEPLOYMENT_V24].nThresholdMin = 250 / 5 * 3; // 60% of window size + consensus.vDeployments[Consensus::DEPLOYMENT_V24].nFalloffCoeff = 5; // this corresponds to 10 periods + consensus.vDeployments[Consensus::DEPLOYMENT_V24].useEHF = true; // The best chain should have at least this much work. consensus.nMinimumChainWork = uint256S("0x00"); diff --git a/src/chainparamsseeds.h b/src/chainparamsseeds.h index 734090de975f..831904836c4d 100644 --- a/src/chainparamsseeds.h +++ b/src/chainparamsseeds.h @@ -7,47 +7,30 @@ * Each line contains a BIP155 serialized (networkID, addr, port) tuple. */ static const uint8_t chainparams_seed_main[] = { - 0x04,0x20,0xbb,0x03,0x67,0x8e,0x51,0x93,0x74,0x61,0x81,0x95,0x71,0x49,0x2c,0x63,0xb9,0x89,0xa0,0x29,0x5a,0x4e,0x74,0x62,0x7d,0x75,0x37,0xfc,0x31,0xcb,0x68,0xc5,0x9c,0xe6,0x27,0x0f, 0x04,0x20,0xba,0x5b,0xab,0x3a,0x87,0x7c,0x74,0x98,0xc2,0x70,0x06,0xd1,0x35,0x08,0x49,0xb9,0x6b,0x17,0xd5,0x26,0x21,0xcc,0xa8,0xc1,0x73,0x31,0x9a,0x44,0x76,0xcb,0xd7,0x77,0x27,0x0f, - 0x04,0x20,0xb6,0x4b,0xea,0x7c,0xa4,0x80,0x3d,0xd5,0x60,0x7d,0x73,0xb1,0x8a,0xdb,0x71,0xbb,0xb3,0x48,0xb2,0x99,0x36,0x63,0xc8,0xee,0x11,0x41,0x9a,0x4d,0xdd,0x69,0xec,0xc1,0x27,0x0f, 0x04,0x20,0xb4,0xc3,0x8d,0x95,0x48,0x1f,0x09,0x00,0x29,0xa5,0xab,0x00,0xa3,0x7a,0xae,0x2d,0x5e,0x30,0x72,0x8a,0x3d,0x08,0x2f,0xab,0xba,0x6b,0xbf,0xe6,0xfa,0x59,0xb8,0xaa,0x27,0x0f, 0x04,0x20,0xa1,0x76,0xe9,0xd6,0x29,0x6a,0x7e,0x68,0xd9,0x9f,0x92,0xad,0x25,0x97,0xcb,0x9a,0x02,0xed,0x70,0xea,0x72,0xe3,0x6a,0x62,0xf8,0xbf,0xf1,0x95,0x81,0x76,0x6d,0x1f,0x27,0x0f, 0x04,0x20,0x9d,0x32,0x9c,0x4d,0x1e,0x35,0x2d,0xbd,0x49,0x82,0xb9,0xa5,0x66,0x4f,0x45,0x52,0x56,0xac,0x5d,0xb3,0xe7,0xe3,0x39,0x3e,0xac,0x81,0x22,0x10,0x2f,0x23,0x26,0x0d,0x27,0x0f, 0x04,0x20,0x93,0x69,0xab,0x82,0x0b,0xd8,0xa2,0x7d,0x07,0x93,0xf1,0xb5,0x6b,0x91,0x86,0x8b,0xf2,0xc0,0x5c,0xb7,0x58,0x39,0x3a,0x03,0xdb,0x0b,0x5f,0xa7,0x9c,0xf7,0xb4,0x7c,0x27,0x0f, - 0x04,0x20,0x8d,0x97,0xce,0x7e,0x2e,0xba,0xd6,0xa5,0xb2,0x0a,0x60,0x5f,0xd0,0x43,0x41,0xba,0x79,0x5b,0x65,0xcc,0xbf,0x88,0xb5,0xb8,0x6e,0x35,0x05,0xda,0x90,0xcd,0x8c,0x7d,0x27,0x0f, - 0x04,0x20,0x82,0x84,0x39,0xe7,0xc4,0x4a,0x30,0x23,0x13,0xc8,0xd9,0xbd,0x4c,0x17,0xcc,0xe2,0x2a,0x1c,0x7e,0x7f,0xfc,0xb1,0x3f,0xe0,0x99,0x5d,0xac,0x79,0xb0,0x32,0x56,0xff,0x27,0x0f, - 0x04,0x20,0x80,0x60,0x0d,0xfd,0x9f,0xa2,0x10,0x4f,0x6f,0xfa,0xdb,0x28,0x7c,0x99,0x7c,0x95,0xa0,0x9a,0xcb,0xce,0x18,0xf2,0x79,0xe6,0xdd,0x51,0x37,0xa9,0xf3,0xe0,0x67,0x97,0x27,0x0f, - 0x04,0x20,0x80,0x1c,0x2c,0x6a,0x00,0x54,0xc0,0x54,0x53,0x38,0x1e,0xd1,0xc0,0x3f,0x14,0x55,0x63,0xa3,0xc7,0xc5,0xb2,0x49,0x3f,0x6b,0xa2,0x85,0x83,0x68,0x77,0x11,0xe4,0x20,0x27,0x0f, - 0x04,0x20,0x78,0x80,0x18,0x86,0xe3,0x5d,0xcd,0x80,0xa3,0x18,0x55,0x10,0x21,0x01,0x32,0x2e,0x41,0x96,0x20,0xd5,0x17,0xc4,0x46,0x40,0x39,0x7c,0x2d,0xd1,0xd3,0x5f,0x44,0x00,0x27,0x0f, 0x04,0x20,0x7e,0x87,0xe8,0x9b,0xd5,0x3f,0x4b,0xb6,0x26,0x21,0xff,0x57,0xa7,0xbe,0xf3,0x08,0x5e,0x90,0x97,0x9d,0xac,0xc9,0x87,0xec,0x5c,0xa6,0xdb,0x72,0xb9,0xb6,0x79,0x32,0x27,0x0f, 0x04,0x20,0x62,0x7b,0x98,0x6d,0xc4,0x70,0xd7,0x69,0x11,0x6a,0xe8,0x5b,0x7e,0xac,0xe8,0xa1,0xed,0x4a,0x67,0xd7,0x33,0x10,0x9b,0xf1,0x41,0x6b,0xda,0x70,0x31,0x45,0xec,0xfe,0x27,0x0f, 0x04,0x20,0x5c,0x0d,0xe6,0x94,0x24,0x57,0x78,0x50,0xc8,0xc3,0xc0,0xa1,0xe8,0x91,0x3f,0x20,0xe0,0x23,0x71,0xf2,0xf3,0x20,0xca,0xca,0x11,0xf7,0x3a,0x82,0x08,0x33,0xf8,0xb3,0x27,0x0f, 0x04,0x20,0x57,0x83,0x98,0x4d,0x47,0x9e,0x71,0x94,0x12,0x67,0x43,0x76,0xa5,0x62,0x5b,0xe6,0xa2,0xbc,0x89,0x90,0x54,0x65,0xd4,0x04,0x12,0x3c,0x04,0xb1,0x53,0x5b,0x21,0xe9,0x27,0x0f, 0x04,0x20,0x57,0x4c,0x36,0x9a,0xa0,0x62,0xed,0x86,0x58,0xfa,0x03,0x7d,0x05,0x83,0x2f,0x35,0x56,0x75,0x46,0x8a,0x04,0x9d,0xe6,0xd7,0xbe,0x1e,0xfa,0xf2,0x36,0x6f,0x29,0xd0,0x27,0x0f, - 0x04,0x20,0x57,0x77,0xa2,0xc2,0xa6,0xcc,0x1d,0x34,0xf8,0x8f,0x2d,0xb7,0x12,0x8b,0x7f,0xf9,0x17,0x14,0xee,0x63,0xe7,0xf3,0x30,0x0f,0x53,0x53,0x7d,0x5b,0x36,0xde,0x69,0xee,0x27,0x0f, 0x04,0x20,0x4c,0x25,0x24,0xe1,0xb5,0x5c,0x2c,0x54,0x3a,0x23,0x6d,0x2f,0xaa,0xc2,0x7e,0x32,0xdb,0x1d,0x97,0x0f,0xc3,0xcb,0x60,0x4a,0x28,0xc8,0x5f,0x63,0x85,0x3a,0x5d,0x67,0x27,0x0f, 0x04,0x20,0x4a,0x52,0x7b,0x62,0x4a,0xe4,0xf6,0x8f,0xb6,0x29,0xc5,0xf1,0x12,0xf3,0x09,0x4c,0x18,0xe5,0x93,0x83,0x73,0xac,0x60,0x7d,0xad,0x56,0x12,0x83,0xec,0xec,0x47,0xe1,0x27,0x0f, 0x04,0x20,0x46,0x3d,0x6c,0x95,0xfe,0xe9,0x7a,0xf2,0x10,0xf0,0xa4,0x04,0x78,0x3c,0x91,0xbf,0x63,0xc8,0x4b,0x01,0x2b,0x2b,0x51,0xa4,0xe4,0xd0,0x15,0xb4,0x1b,0xcf,0x9e,0xc1,0x27,0x0f, 0x04,0x20,0x44,0xd4,0x09,0x8b,0x46,0x79,0x55,0x4a,0x85,0x89,0x2a,0xee,0x68,0x81,0xaa,0x9a,0x63,0x27,0x28,0x5f,0xb0,0xa8,0xda,0x6b,0xac,0x87,0xdf,0x38,0x32,0x5f,0x2d,0x89,0x27,0x0f, - 0x04,0x20,0x40,0xc6,0x11,0x07,0xd7,0xcc,0x43,0x14,0xbf,0x36,0x0b,0xb2,0x72,0x6d,0xf9,0x99,0xa2,0x75,0x59,0x2e,0xff,0x9d,0xcb,0x2a,0x2f,0x47,0x36,0xfe,0xa7,0x00,0xf2,0x6b,0x27,0x0f, 0x04,0x20,0x47,0xfb,0x8b,0x87,0x27,0xca,0x95,0xe8,0x77,0xae,0x41,0xbd,0x72,0x20,0x62,0x25,0xe5,0x67,0x98,0x41,0x85,0x0e,0x9a,0x5d,0x4a,0xb1,0x0f,0x8f,0x46,0xa9,0x87,0xa4,0x27,0x0f, 0x04,0x20,0x3d,0x39,0xb9,0x4c,0x25,0x2e,0x5e,0x62,0xa2,0xec,0xc9,0xaf,0xc0,0x13,0x52,0x7f,0xba,0xd8,0xa6,0x88,0xf2,0x80,0x6c,0xc4,0xea,0x7c,0x0e,0xc3,0x49,0x5a,0x50,0x5a,0x27,0x0f, - 0x04,0x20,0x3c,0xa1,0xc1,0xa9,0xec,0x30,0xb7,0x82,0x22,0x2f,0x45,0x0a,0xe7,0xa9,0xcd,0x00,0x6f,0x0f,0x69,0x4b,0xe6,0xea,0xac,0xc7,0x1e,0xed,0x4e,0xff,0x8a,0x6b,0xc2,0xf6,0x27,0x0f, 0x04,0x20,0x3f,0x23,0x81,0x37,0x6b,0x32,0xe6,0x03,0xde,0xa5,0xbc,0xc9,0xe8,0xe6,0x98,0xa6,0xdc,0xe0,0x6c,0xbb,0x07,0x5e,0x23,0x64,0xea,0xa9,0xfa,0x10,0x40,0x88,0xfc,0xb7,0x27,0x0f, 0x04,0x20,0x3e,0x84,0xf8,0x31,0x23,0xdc,0x60,0x43,0xc5,0xdd,0xd4,0xa6,0x43,0xa3,0x95,0x6e,0x1c,0x5b,0xe1,0x85,0x80,0xe4,0x4b,0x88,0xe7,0x2f,0xc6,0xf0,0x85,0x4e,0x82,0x98,0x27,0x0f, - 0x04,0x20,0x31,0xb1,0x83,0x9b,0x98,0x8e,0x85,0x5e,0x08,0x29,0x20,0xc5,0x2e,0x6c,0x06,0xdd,0x4f,0xb8,0x57,0x0d,0x03,0xe6,0xc5,0x9b,0xd8,0xcb,0x9a,0xee,0x9c,0xe6,0x4c,0x10,0x27,0x0f, 0x04,0x20,0x30,0x4d,0xab,0x0f,0x94,0xb0,0xba,0xaf,0xdb,0xa9,0xdd,0xb9,0xec,0xc4,0x9e,0x8f,0x50,0xe2,0x66,0x8b,0x32,0x62,0x85,0x12,0x77,0xaf,0x20,0x45,0x60,0x39,0x36,0xb3,0x27,0x0f, - 0x04,0x20,0x37,0xb4,0xb1,0x9f,0xad,0x20,0xe8,0xa2,0xab,0xa7,0xab,0x94,0xdf,0x66,0x61,0x3b,0x20,0xbf,0x43,0xf0,0x21,0xa3,0x0f,0x0c,0x39,0xc5,0x72,0x88,0xff,0x57,0x24,0x60,0x27,0x0f, 0x04,0x20,0x2e,0x5d,0xec,0xf0,0x62,0x4c,0xca,0x6e,0x90,0xdf,0x00,0x65,0x1c,0xca,0x4a,0xcb,0x66,0xee,0xa2,0xa6,0x94,0x27,0x8d,0x6c,0xec,0x15,0x4b,0xe0,0xa4,0x86,0xe3,0x21,0x27,0x0f, - 0x04,0x20,0x24,0xd1,0x42,0xa9,0x1d,0x14,0x82,0xe1,0x88,0xf8,0xc3,0xa1,0x5e,0x06,0xbc,0x83,0x35,0x7c,0x81,0x69,0x40,0xdb,0x29,0xf1,0x47,0x5f,0xb7,0xab,0xa8,0x71,0x92,0x10,0x27,0x0f, 0x04,0x20,0x21,0x09,0xf1,0x0f,0x0d,0x0a,0x69,0xf7,0x82,0xfc,0xe5,0x59,0xb0,0xbb,0xe0,0x06,0x51,0xfd,0x40,0x30,0x35,0x95,0x37,0xd5,0x5b,0xf9,0xdd,0x73,0x7d,0x2a,0x81,0x33,0x27,0x0f, 0x04,0x20,0x1d,0xb9,0x4f,0x00,0xd6,0xf1,0x95,0x3c,0xff,0x0a,0x61,0xae,0xdf,0xb3,0x65,0x61,0x9a,0xdc,0x04,0xe7,0x5b,0x51,0x23,0xed,0x75,0x6d,0x30,0xb1,0x07,0xb6,0x15,0xb3,0x27,0x0f, - 0x04,0x20,0x13,0x0f,0x1e,0xc7,0x6b,0x81,0xf1,0xf4,0x0b,0x44,0x09,0x10,0xbf,0x78,0xb3,0x16,0x7b,0x4f,0x6b,0x30,0xec,0x0e,0x12,0x8f,0x3d,0xda,0xfd,0x28,0x5d,0x69,0x3f,0xf3,0x27,0x0f, - 0x04,0x20,0x17,0x60,0x73,0xf6,0xf1,0xb3,0x5c,0xd6,0x4d,0xa8,0x01,0xbb,0x1f,0x84,0xb3,0x2d,0x88,0xd4,0x5a,0x7a,0x2f,0x8a,0x34,0x5e,0x1b,0xf8,0xbe,0x66,0xd1,0xa1,0x4e,0x4d,0x27,0x0f, - 0x04,0x20,0x0d,0x1d,0xb2,0x4f,0x77,0xae,0x46,0x98,0x29,0xf7,0xf2,0x24,0x24,0xe7,0x8e,0x25,0xf1,0x48,0x9d,0xe1,0x7a,0xf6,0x89,0x73,0xc3,0xf7,0x76,0xa2,0xa2,0x6b,0xd1,0x87,0x27,0x0f, 0x04,0x20,0x06,0x0f,0x6b,0x3d,0x30,0xe4,0x4d,0xb0,0xc9,0x61,0x9c,0xff,0x82,0x26,0x18,0x3d,0x05,0x80,0x42,0x41,0x0f,0xe6,0xde,0x74,0x2b,0x3f,0x23,0xfb,0xa7,0xda,0xb1,0x5c,0x27,0x0f, 0x04,0x20,0xed,0x7a,0xb3,0x0c,0x6e,0x58,0x90,0x39,0xcf,0x50,0x61,0xd9,0x5c,0x28,0x1a,0x25,0x8f,0x3e,0x31,0x4c,0x62,0x7f,0xb9,0x96,0xd4,0x43,0x16,0x25,0x19,0x90,0x0f,0x57,0x27,0x0f, - 0x04,0x20,0xe9,0x9b,0x8c,0x52,0xef,0x55,0xa5,0x0a,0xfa,0x4c,0xd1,0x09,0xa5,0x7a,0x80,0x45,0x21,0xd0,0x60,0x08,0x7a,0x59,0xbd,0xb7,0xaf,0xb1,0x35,0xaa,0x22,0x7b,0xfe,0x1d,0x27,0x0f, 0x04,0x20,0xef,0x34,0x68,0xe6,0xb3,0xc6,0xc4,0xd0,0xcf,0x22,0xdc,0x92,0x09,0xd0,0x2a,0x63,0x4f,0x6d,0x6a,0xfd,0x31,0x6a,0xd4,0xe9,0x71,0x73,0x06,0xf0,0x46,0xcb,0x17,0x13,0x27,0x0f, 0x04,0x20,0xe0,0xc1,0xc9,0x78,0xb5,0xce,0xad,0x3f,0x7f,0x4a,0xbd,0xe0,0x68,0x83,0x88,0xa4,0x5d,0x39,0x71,0x2d,0xce,0x58,0x47,0xac,0x23,0x9f,0xc0,0x14,0x5f,0xdd,0xe9,0x52,0x27,0x0f, 0x04,0x20,0xdd,0x2a,0x24,0xe1,0x88,0x45,0xd1,0xe6,0xf9,0x9a,0x7f,0x8b,0x23,0x61,0x37,0x55,0xf4,0x22,0x00,0x92,0x1f,0xc8,0xe7,0xa3,0x6f,0xfa,0x5b,0xbf,0x71,0x1d,0xcf,0xb9,0x27,0x0f, @@ -56,210 +39,203 @@ static const uint8_t chainparams_seed_main[] = { 0x01,0x04,0xd8,0xfa,0x61,0x34,0x27,0x0f, 0x01,0x04,0xd8,0xee,0x4b,0x2e,0x27,0x0f, 0x01,0x04,0xd8,0xe6,0xe8,0x7d,0x27,0x0f, + 0x01,0x04,0xd5,0xda,0xd1,0xb9,0x27,0x0f, 0x01,0x04,0xd5,0xda,0xd1,0x22,0x27,0x0f, - 0x01,0x04,0xd5,0xc7,0x22,0xfa,0x27,0x0f, + 0x01,0x04,0xd5,0xda,0xd1,0x08,0x27,0x0f, 0x01,0x04,0xd5,0xab,0x0f,0x7d,0x27,0x0f, 0x01,0x04,0xd5,0x9f,0x4d,0xdd,0x27,0x0f, 0x01,0x04,0xd4,0x34,0x00,0xd2,0x27,0x0f, - 0x01,0x04,0xd4,0x18,0x6e,0x80,0x27,0x0f, + 0x01,0x04,0xd4,0x26,0x59,0x6a,0x27,0x0f, + 0x01,0x04,0xd4,0x18,0x68,0xe1,0x27,0x0f, 0x01,0x04,0xd1,0x91,0x30,0x9a,0x27,0x0f, 0x01,0x04,0xd1,0x8d,0x24,0xce,0x27,0x0f, 0x01,0x04,0xd1,0x3a,0xa4,0x2a,0x27,0x0f, 0x01,0x04,0xd0,0x57,0x66,0x5b,0x27,0x0f, 0x01,0x04,0xcf,0xf4,0xf7,0x28,0x27,0x0f, + 0x01,0x04,0xca,0x47,0x0e,0x4f,0x27,0x0f, 0x01,0x04,0xca,0x05,0x10,0x21,0x27,0x0f, + 0x01,0x04,0xc6,0xd3,0x7f,0xcb,0x27,0x0f, 0x01,0x04,0xc6,0x07,0x73,0x30,0x27,0x0f, - 0x01,0x04,0xc3,0xb5,0xd3,0x40,0x27,0x0f, 0x01,0x04,0xc3,0x62,0x5f,0xd2,0x27,0x0f, - 0x01,0x04,0xc2,0x87,0x51,0xd6,0x27,0x0f, + 0x01,0x04,0xc2,0xee,0x19,0xc7,0x27,0x0f, + 0x01,0x04,0xc2,0xb6,0x54,0x98,0x27,0x0f, + 0x01,0x04,0xc2,0x87,0x54,0x64,0x27,0x0f, 0x01,0x04,0xc2,0x05,0x9d,0xd6,0x27,0x0f, + 0x01,0x04,0xc0,0xaf,0x7f,0xc6,0x27,0x0f, 0x01,0x04,0xc0,0xa9,0x06,0x57,0x27,0x0f, - 0x01,0x04,0xbc,0x7f,0xed,0xf3,0x27,0x0f, - 0x01,0x04,0xbc,0x7f,0xe6,0x28,0x27,0x0f, 0x01,0x04,0xbc,0x28,0xb2,0x43,0x27,0x0f, 0x01,0x04,0xb9,0xf3,0x73,0xdb,0x27,0x0f, 0x01,0x04,0xb9,0xe4,0x53,0x9c,0x27,0x0f, - 0x01,0x04,0xb9,0xd9,0x7f,0x8b,0x27,0x0f, - 0x01,0x04,0xb9,0xd5,0x18,0x22,0x27,0x0f, - 0x01,0x04,0xb9,0xc6,0xea,0x36,0x27,0x0f, + 0x01,0x04,0xb9,0xe4,0x53,0x84,0x27,0x0f, 0x01,0x04,0xb9,0xc6,0xea,0x21,0x27,0x0f, - 0x01,0x04,0xb9,0xc6,0xea,0x19,0x27,0x0f, - 0x01,0x04,0xb9,0xc6,0xea,0x11,0x27,0x0f, - 0x01,0x04,0xb9,0xb9,0x28,0xab,0x27,0x0f, + 0x01,0x04,0xb9,0xc6,0xea,0x0c,0x27,0x0f, + 0x01,0x04,0xb9,0xc1,0x13,0xd6,0x27,0x0f, 0x01,0x04,0xb9,0xb9,0x28,0x68,0x27,0x0f, + 0x01,0x04,0xb9,0xaf,0x38,0xd4,0x27,0x0f, 0x01,0x04,0xb9,0xa6,0xd9,0x9a,0x27,0x0f, 0x01,0x04,0xb9,0xa5,0xab,0x75,0x27,0x0f, 0x01,0x04,0xb9,0xa4,0xa3,0xda,0x27,0x0f, 0x01,0x04,0xb9,0xa4,0xa3,0x55,0x27,0x0f, - 0x01,0x04,0xb9,0x9e,0x6b,0x7c,0x27,0x0f, - 0x01,0x04,0xb9,0x9b,0x63,0x22,0x27,0x0f, 0x01,0x04,0xb9,0x8e,0xd4,0x90,0x27,0x0f, + 0x01,0x04,0xb9,0x8d,0xd8,0x04,0x27,0x0f, + 0x01,0x04,0xb9,0x70,0xf9,0x35,0x27,0x0f, 0x01,0x04,0xb9,0x70,0xf9,0x31,0x27,0x0f, - 0x01,0x04,0xb9,0x57,0x95,0x3d,0x27,0x0f, + 0x01,0x04,0xb8,0x6b,0xb6,0x41,0x27,0x0f, + 0x01,0x04,0xb2,0xd7,0xed,0x87,0x27,0x0f, + 0x01,0x04,0xb2,0xd7,0xed,0x86,0x27,0x0f, 0x01,0x04,0xb2,0xd0,0x57,0xe2,0x27,0x0f, 0x01,0x04,0xb2,0xd0,0x57,0xd5,0x27,0x0f, 0x01,0x04,0xb2,0x9f,0x02,0x0c,0x27,0x0f, - 0x01,0x04,0xb2,0x9d,0x5b,0xb8,0x27,0x0f, - 0x01,0x04,0xb2,0x9d,0x5b,0xb2,0x27,0x0f, 0x01,0x04,0xb2,0x9d,0x5b,0xb1,0x27,0x0f, 0x01,0x04,0xb2,0x3f,0x79,0x81,0x27,0x0f, + 0x01,0x04,0xb1,0x5d,0x8d,0x56,0x27,0x0f, + 0x01,0x04,0xb1,0x5d,0x8d,0x3c,0x27,0x0f, 0x01,0x04,0xb0,0x66,0x41,0x91,0x27,0x0f, - 0x01,0x04,0xae,0x22,0xe9,0xd4,0x27,0x0f, - 0x01,0x04,0xae,0x22,0xe9,0xd3,0x27,0x0f, - 0x01,0x04,0xae,0x22,0xe9,0xd1,0x27,0x0f, - 0x01,0x04,0xae,0x22,0xe9,0xcc,0x27,0x0f, + 0x01,0x04,0xad,0xd4,0xf5,0x76,0x27,0x0f, + 0x01,0x04,0xac,0xec,0xf4,0x51,0x27,0x0f, + 0x01,0x04,0xac,0xe9,0x42,0x46,0x27,0x0f, 0x01,0x04,0xac,0x68,0x91,0xa6,0x27,0x0f, - 0x01,0x04,0xac,0x68,0x5a,0xf9,0x27,0x0f, - 0x01,0x04,0xaa,0x4b,0xa7,0xf4,0x27,0x0f, - 0x01,0x04,0xaa,0x4b,0xa2,0xd4,0x27,0x0f, 0x01,0x04,0xa8,0x77,0x50,0x04,0x27,0x0f, 0x01,0x04,0xa7,0x58,0xa9,0x10,0x27,0x0f, 0x01,0x04,0xa7,0x58,0xa5,0xaf,0x27,0x0f, + 0x01,0x04,0xa7,0x58,0x2e,0xaa,0x27,0x0f, 0x01,0x04,0xa5,0x16,0xea,0x87,0x27,0x0f, 0x01,0x04,0xa3,0xac,0x42,0x29,0x27,0x0f, - 0x01,0x04,0xa3,0xac,0x14,0xd2,0x27,0x0f, - 0x01,0x04,0xa3,0xac,0x14,0xd1,0x27,0x0f, - 0x01,0x04,0xa3,0xac,0x14,0xcd,0x27,0x0f, 0x01,0x04,0xa2,0xfa,0xbf,0x1f,0x27,0x0f, + 0x01,0x04,0xa2,0xfa,0xbc,0xcf,0x27,0x0f, 0x01,0x04,0xa2,0xf6,0x11,0xf8,0x27,0x0f, + 0x01,0x04,0xa2,0xd4,0x23,0x68,0x27,0x0f, + 0x01,0x04,0xa2,0xd4,0x23,0x64,0x27,0x0f, + 0x01,0x04,0x9f,0xcb,0x2c,0xd8,0x27,0x0f, 0x01,0x04,0x9f,0x4b,0x79,0xa3,0x27,0x0f, 0x01,0x04,0x9d,0xad,0xca,0x0e,0x27,0x0f, - 0x01,0x04,0x9d,0x42,0x51,0xa2,0x27,0x0f, - 0x01,0x04,0x9d,0x0a,0xc7,0x52,0x27,0x0f, - 0x01,0x04,0x9d,0x0a,0xc7,0x4f,0x27,0x0f, - 0x01,0x04,0x9d,0x0a,0xc7,0x4d,0x27,0x0f, - 0x01,0x04,0x9a,0x7f,0x39,0x3f,0x27,0x0f, + 0x01,0x04,0x98,0x35,0x90,0x35,0x27,0x0f, 0x01,0x04,0x96,0x9e,0x30,0x06,0x27,0x0f, 0x01,0x04,0x93,0x2d,0xb7,0x80,0x27,0x0f, 0x01,0x04,0x93,0x2d,0x67,0x63,0x27,0x0f, - 0x01,0x04,0x92,0xbe,0xe6,0x68,0x27,0x0f, - 0x01,0x04,0x92,0x67,0x30,0xd1,0x27,0x0f, 0x01,0x04,0x92,0x67,0x30,0xcb,0x27,0x0f, - 0x01,0x04,0x92,0x3b,0x2d,0xeb,0x27,0x0f, - 0x01,0x04,0x8b,0xa2,0x83,0xc5,0x27,0x0f, - 0x01,0x04,0x87,0xb5,0x35,0x82,0x27,0x0f, + 0x01,0x04,0x8b,0x1c,0x61,0x02,0x27,0x0f, 0x01,0x04,0x86,0xff,0xb6,0xba,0x27,0x0f, - 0x01,0x04,0x85,0x12,0xe4,0x54,0x27,0x0f, + 0x01,0x04,0x85,0x12,0x61,0xe2,0x27,0x0f, 0x01,0x04,0x82,0xa2,0xe9,0xba,0x27,0x0f, 0x01,0x04,0x82,0x3d,0x78,0xfc,0x27,0x0f, 0x01,0x04,0x7b,0xc1,0x40,0xa6,0x27,0x0f, - 0x01,0x04,0x6d,0xeb,0x45,0x52,0x27,0x0f, + 0x01,0x04,0x73,0x78,0xee,0xf0,0x27,0x0f, + 0x01,0x04,0x6d,0xeb,0x43,0xf6,0x27,0x0f, 0x01,0x04,0x6d,0xad,0xf0,0xe9,0x27,0x0f, 0x01,0x04,0x6b,0xbd,0x03,0x4a,0x27,0x0f, - 0x01,0x04,0x6b,0xaa,0xfe,0xa0,0x27,0x0f, + 0x01,0x04,0x6b,0xb3,0xca,0x4a,0x27,0x0f, + 0x01,0x04,0x6b,0xae,0xcc,0xa6,0x27,0x0f, 0x01,0x04,0x6a,0x37,0x09,0x16,0x27,0x0f, - 0x01,0x04,0x68,0xe1,0x9f,0xe8,0x27,0x0f, - 0x01,0x04,0x68,0xc8,0x18,0xc4,0x27,0x0f, 0x01,0x04,0x5f,0xd3,0xc4,0x2e,0x27,0x0f, 0x01,0x04,0x5f,0xd3,0xc4,0x22,0x27,0x0f, 0x01,0x04,0x5f,0xd3,0xc4,0x20,0x27,0x0f, - 0x01,0x04,0x5f,0xd3,0xc4,0x08,0x27,0x0f, 0x01,0x04,0x5f,0xb7,0x33,0x8d,0x27,0x0f, 0x01,0x04,0x5f,0xab,0x15,0x83,0x27,0x0f, - 0x01,0x04,0x5f,0xa9,0xb5,0x47,0x27,0x0f, 0x01,0x04,0x5e,0xac,0x6d,0xa1,0x27,0x0f, - 0x01,0x04,0x5d,0x15,0x4c,0xb9,0x27,0x0f, - 0x01,0x04,0x5c,0x3f,0xb0,0xca,0x27,0x0f, - 0x01,0x04,0x5b,0xea,0x23,0x84,0x27,0x0f, - 0x01,0x04,0x5b,0xde,0xed,0x62,0x27,0x0f, + 0x01,0x04,0x5d,0x73,0xac,0x27,0x27,0x0f, + 0x01,0x04,0x5d,0x73,0xac,0x25,0x27,0x0f, 0x01,0x04,0x5b,0xc7,0x95,0xb1,0x27,0x0f, 0x01,0x04,0x59,0xb3,0x49,0x60,0x27,0x0f, - 0x01,0x04,0x59,0x75,0x13,0x0a,0x27,0x0f, - 0x01,0x04,0x59,0x28,0x0d,0x50,0x27,0x0f, - 0x01,0x04,0x59,0x28,0x0a,0x2d,0x27,0x0f, - 0x01,0x04,0x59,0x28,0x08,0xa0,0x27,0x0f, - 0x01,0x04,0x59,0x28,0x00,0x6d,0x27,0x0f, - 0x01,0x04,0x59,0x23,0x83,0x3d,0x27,0x0f, + 0x01,0x04,0x59,0x23,0x83,0x95,0x27,0x0f, + 0x01,0x04,0x57,0xe5,0x16,0xfa,0x27,0x0f, 0x01,0x04,0x57,0xe4,0x18,0x40,0x27,0x0f, - 0x01,0x04,0x57,0xd1,0xf5,0xe3,0x27,0x0f, - 0x01,0x04,0x56,0x6b,0xa8,0x2f,0x27,0x0f, - 0x01,0x04,0x56,0x6b,0xa8,0x2e,0x27,0x0f, - 0x01,0x04,0x56,0x6b,0xa8,0x2b,0x27,0x0f, - 0x01,0x04,0x56,0x6b,0xa8,0x1d,0x27,0x0f, - 0x01,0x04,0x55,0xd7,0x6b,0xca,0x27,0x0f, - 0x01,0x04,0x55,0xd1,0xf1,0xb9,0x27,0x0f, + 0x01,0x04,0x56,0x6b,0x65,0x80,0x27,0x0f, + 0x01,0x04,0x55,0xd1,0xf1,0xf5,0x27,0x0f, + 0x01,0x04,0x55,0xd1,0xf1,0x5d,0x27,0x0f, + 0x01,0x04,0x55,0xd1,0xf1,0x57,0x27,0x0f, 0x01,0x04,0x55,0xd1,0xf1,0x56,0x27,0x0f, - 0x01,0x04,0x55,0xd1,0xf1,0x47,0x27,0x0f, - 0x01,0x04,0x55,0xd1,0xf1,0x23,0x27,0x0f, + 0x01,0x04,0x54,0xf7,0x9b,0x0b,0x27,0x0f, 0x01,0x04,0x54,0xf2,0xb3,0xcc,0x27,0x0f, + 0x01,0x04,0x54,0x62,0x0c,0xc4,0x27,0x0f, 0x01,0x04,0x54,0x09,0x32,0x11,0x27,0x0f, - 0x01,0x04,0x53,0xef,0x63,0x28,0x27,0x0f, - 0x01,0x04,0x52,0xd3,0x19,0xc1,0x27,0x0f, + 0x01,0x04,0x53,0xde,0x09,0xfd,0x27,0x0f, 0x01,0x04,0x52,0xd3,0x19,0x69,0x27,0x0f, + 0x01,0x04,0x52,0xd3,0x15,0xf0,0x27,0x0f, 0x01,0x04,0x52,0xd3,0x15,0xb3,0x27,0x0f, 0x01,0x04,0x52,0xd3,0x15,0x17,0x27,0x0f, 0x01,0x04,0x52,0xca,0xe6,0x53,0x27,0x0f, + 0x01,0x04,0x52,0xb4,0x92,0xc0,0x27,0x0f, 0x01,0x04,0x51,0xe3,0xfa,0x33,0x27,0x0f, + 0x01,0x04,0x51,0x0e,0xe4,0x57,0x27,0x0f, 0x01,0x04,0x50,0xf9,0x93,0x08,0x27,0x0f, 0x01,0x04,0x50,0xf0,0x84,0xe7,0x27,0x0f, - 0x01,0x04,0x50,0xd1,0xea,0xaa,0x27,0x0f, + 0x01,0x04,0x50,0xd0,0xe6,0x90,0x27,0x0f, 0x01,0x04,0x4e,0x53,0x13,0x00,0x27,0x0f, 0x01,0x04,0x4d,0xdf,0x63,0x04,0x27,0x0f, 0x01,0x04,0x4d,0xdd,0x94,0xcc,0x27,0x0f, 0x01,0x04,0x4a,0x32,0x5a,0x71,0x27,0x0f, + 0x01,0x04,0x48,0x3c,0x26,0xa0,0x27,0x0f, 0x01,0x04,0x45,0x3d,0x6b,0xd7,0x27,0x0f, 0x01,0x04,0x42,0xf5,0xc4,0x34,0x27,0x0f, 0x01,0x04,0x42,0xf4,0xf3,0x46,0x27,0x0f, 0x01,0x04,0x42,0xf4,0xf3,0x45,0x27,0x0f, + 0x01,0x04,0x3e,0x3c,0xf4,0xae,0x27,0x0f, 0x01,0x04,0x34,0x24,0x66,0x5b,0x27,0x0f, 0x01,0x04,0x34,0x21,0x09,0xac,0x27,0x0f, - 0x01,0x04,0x33,0x26,0x8e,0x42,0x27,0x0f, - 0x01,0x04,0x33,0x26,0x8e,0x3e,0x27,0x0f, + 0x01,0x04,0x33,0x9e,0xa9,0xed,0x27,0x0f, + 0x01,0x04,0x33,0x4d,0xe6,0xd2,0x27,0x0f, 0x01,0x04,0x33,0x26,0x8e,0x3d,0x27,0x0f, - 0x01,0x04,0x2f,0x6e,0xb8,0xaa,0x27,0x0f, 0x01,0x04,0x2e,0xfe,0xf1,0x09,0x27,0x0f, - 0x01,0x04,0x2e,0xfe,0xf1,0x08,0x27,0x0f, 0x01,0x04,0x2e,0xfe,0xf1,0x07,0x27,0x0f, + 0x01,0x04,0x2e,0xfe,0xf1,0x06,0x27,0x0f, 0x01,0x04,0x2e,0xfe,0xf1,0x04,0x27,0x0f, + 0x01,0x04,0x2e,0xfa,0xfe,0x0a,0x27,0x0f, 0x01,0x04,0x2e,0x24,0x28,0xf2,0x27,0x0f, - 0x01,0x04,0x2e,0x1e,0xbd,0xfb,0x27,0x0f, - 0x01,0x04,0x2e,0x1e,0xbd,0xd6,0x27,0x0f, - 0x01,0x04,0x2e,0x1e,0xbd,0xd5,0x27,0x0f, - 0x01,0x04,0x2e,0x1e,0xbd,0x74,0x27,0x0f, - 0x01,0x04,0x2d,0x99,0xba,0x64,0x27,0x0f, + 0x01,0x04,0x2e,0x04,0xa2,0x7f,0x27,0x0f, 0x01,0x04,0x2d,0x8c,0x13,0xc9,0x27,0x0f, - 0x01,0x04,0x2d,0x87,0xb4,0x4f,0x27,0x0f, - 0x01,0x04,0x2d,0x5b,0x5e,0xd9,0x27,0x0f, + 0x01,0x04,0x2d,0x84,0x4a,0x59,0x27,0x0f, + 0x01,0x04,0x2d,0x80,0x9c,0x1e,0x27,0x0f, 0x01,0x04,0x2d,0x53,0x7a,0x7a,0x27,0x0f, - 0x01,0x04,0x2d,0x4c,0x53,0x5b,0x27,0x0f, - 0x01,0x04,0x2d,0x47,0x9f,0x68,0x27,0x0f, - 0x01,0x04,0x2d,0x47,0x9e,0x6c,0x27,0x0f, - 0x01,0x04,0x2d,0x47,0x9e,0x3a,0x27,0x0f, + 0x01,0x04,0x2d,0x4f,0x12,0x6a,0x27,0x0f, + 0x01,0x04,0x2d,0x4d,0xa9,0xcf,0x27,0x0f, 0x01,0x04,0x2d,0x3d,0xba,0x79,0x27,0x0f, 0x01,0x04,0x2d,0x3a,0x38,0x4f,0x27,0x0f, - 0x01,0x04,0x2d,0x20,0x9f,0x30,0x27,0x0f, - 0x01,0x04,0x2d,0x0b,0xb6,0x40,0x27,0x0f, + 0x01,0x04,0x2d,0x20,0xe4,0xa6,0x27,0x0f, 0x01,0x04,0x2c,0xf0,0x63,0xd6,0x27,0x0f, 0x01,0x04,0x2b,0xe5,0x4d,0x2e,0x27,0x0f, 0x01,0x04,0x2b,0xa7,0xf4,0x6d,0x27,0x0f, 0x01,0x04,0x2b,0xa7,0xf0,0x5a,0x27,0x0f, + 0x01,0x04,0x2b,0xa7,0xef,0x91,0x27,0x0f, 0x01,0x04,0x2b,0xa3,0xfb,0x33,0x27,0x0f, - 0x01,0x04,0x2b,0x80,0x48,0x72,0x27,0x0f, - 0x01,0x04,0x26,0x63,0x52,0xe6,0x27,0x0f, + 0x01,0x04,0x26,0x66,0x7d,0x6c,0x27,0x0f, + 0x01,0x04,0x26,0x63,0x52,0x3c,0x27,0x0f, 0x01,0x04,0x26,0x63,0x52,0x15,0x27,0x0f, 0x01,0x04,0x26,0x5b,0x65,0x5c,0x27,0x0f, 0x01,0x04,0x26,0x5b,0x64,0xca,0x27,0x0f, - 0x01,0x04,0x26,0x58,0x7d,0x33,0x27,0x0f, - 0x01,0x04,0x26,0x58,0x7d,0x32,0x27,0x0f, + 0x01,0x04,0x25,0xfc,0x11,0xd6,0x27,0x0f, 0x01,0x04,0x25,0x61,0xe3,0x15,0x27,0x0f, - 0x01,0x04,0x23,0xae,0xd9,0x62,0x27,0x0f, 0x01,0x04,0x22,0xf6,0xb0,0x19,0x27,0x0f, - 0x01,0x04,0x1f,0x94,0x63,0x68,0x27,0x0f, + 0x01,0x04,0x1f,0x94,0x63,0x94,0x27,0x0f, 0x01,0x04,0x1f,0x39,0xbe,0xbc,0x27,0x0f, 0x01,0x04,0x1f,0x39,0xbe,0x1f,0x27,0x0f, 0x01,0x04,0x1f,0x0a,0x61,0x24,0x27,0x0f, 0x01,0x04,0x05,0xff,0x6a,0xc0,0x27,0x0f, + 0x01,0x04,0x05,0xe6,0x77,0xce,0x27,0x0f, + 0x01,0x04,0x05,0xe6,0x77,0xb8,0x27,0x0f, + 0x01,0x04,0x05,0xe6,0x77,0xb7,0x27,0x0f, + 0x01,0x04,0x05,0xbd,0xa4,0xfd,0x27,0x0f, 0x01,0x04,0x05,0xa1,0x6e,0x4f,0x27,0x0f, - 0x01,0x04,0x05,0x23,0x67,0x1a,0x27,0x0f, + 0x01,0x04,0x05,0x4f,0x6d,0xf3,0x27,0x0f, 0x01,0x04,0x05,0x23,0x67,0x19,0x27,0x0f, 0x01,0x04,0x05,0x23,0x67,0x13,0x27,0x0f, 0x01,0x04,0x05,0x02,0x49,0x3a,0x27,0x0f, + 0x01,0x04,0x05,0x02,0x43,0xbe,0x27,0x0f, 0x01,0x04,0x02,0xe9,0x78,0x23,0x27,0x0f, + 0x01,0x04,0x02,0x38,0xd5,0xda,0x27,0x0f, }; static const uint8_t chainparams_seed_test[] = { - 0x01,0x04,0x2b,0xe5,0x4d,0x2e,0x4e,0x1f, - 0x01,0x04,0x2d,0x4d,0xa7,0xf7,0x4e,0x1f, - 0x01,0x04,0xb2,0x3e,0xcb,0xf9,0x4e,0x1f, + 0x01,0x04,0x3e,0x3c,0xf4,0xae,0x4e,0x1f, + 0x01,0x04,0x36,0xd5,0x5e,0xd8,0x4e,0x1f, + 0x01,0x04,0x36,0xbf,0x92,0x89,0x4e,0x1f, + 0x01,0x04,0x36,0xbc,0x45,0x59,0x4e,0x1f, + 0x01,0x04,0x34,0x59,0x9a,0x30,0x4e,0x1f, + 0x01,0x04,0x23,0xa2,0x12,0x74,0x4e,0x1f, + 0x01,0x04,0x23,0x5c,0x8f,0x07,0x4e,0x1f, + 0x01,0x04,0x23,0x5b,0xc5,0xda,0x4e,0x1f, + 0x01,0x04,0x23,0x5b,0x86,0x59,0x4e,0x1f, + 0x01,0x04,0x22,0xdc,0x86,0x1e,0x4e,0x1f, + 0x01,0x04,0x22,0xd2,0x1a,0xc3,0x4e,0x1f, }; #endif // BITCOIN_CHAINPARAMSSEEDS_H diff --git a/src/coinjoin/client.cpp b/src/coinjoin/client.cpp index c08a647cac7e..79651d64e428 100644 --- a/src/coinjoin/client.cpp +++ b/src/coinjoin/client.cpp @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -39,14 +38,23 @@ using wallet::CoinType; using wallet::CWallet; using wallet::ReserveDestination; -MessageProcessingResult CCoinJoinClientQueueManager::ProcessMessage(NodeId from, CConnman& connman, PeerManager& peerman, +CCoinJoinClientQueueManager::CCoinJoinClientQueueManager(CoinJoinWalletManager& walletman, CDeterministicMNManager& dmnman, + CMasternodeMetaMan& mn_metaman, const CMasternodeSync& mn_sync) : + m_walletman{walletman}, + m_dmnman{dmnman}, + m_mn_metaman{mn_metaman}, + m_mn_sync{mn_sync} +{ +} + +CCoinJoinClientQueueManager::~CCoinJoinClientQueueManager() = default; + +MessageProcessingResult CCoinJoinClientQueueManager::ProcessMessage(NodeId from, CConnman& connman, std::string_view msg_type, CDataStream& vRecv) { if (msg_type != NetMsgType::DSQUEUE) { return {}; } - - if (m_is_masternode) return {}; if (!m_mn_sync.IsBlockchainSynced()) return {}; assert(m_mn_metaman.IsValid()); @@ -116,17 +124,11 @@ MessageProcessingResult CCoinJoinClientQueueManager::ProcessMessage(NodeId from, LogPrint(BCLog::COINJOIN, "DSQUEUE -- CoinJoin queue is ready, masternode=%s, queue=%s\n", dmn->proTxHash.ToString(), dsq.ToString()); return ret; } else { - int64_t nLastDsq = m_mn_metaman.GetMetaInfo(dmn->proTxHash)->GetLastDsq(); - int64_t nDsqThreshold = m_mn_metaman.GetDsqThreshold(dmn->proTxHash, tip_mn_list.GetValidMNsCount()); - LogPrint(BCLog::COINJOIN, "DSQUEUE -- nLastDsq: %d nDsqThreshold: %d nDsqCount: %d\n", nLastDsq, - nDsqThreshold, m_mn_metaman.GetDsqCount()); - // don't allow a few nodes to dominate the queuing process - if (nLastDsq != 0 && nDsqThreshold > m_mn_metaman.GetDsqCount()) { + if (m_mn_metaman.IsMixingThresholdExceeded(dmn->proTxHash, tip_mn_list.GetValidMNsCount())) { LogPrint(BCLog::COINJOIN, "DSQUEUE -- Masternode %s is sending too many dsq messages\n", dmn->proTxHash.ToString()); return ret; } - m_mn_metaman.AllowMixing(dmn->proTxHash); LogPrint(BCLog::COINJOIN, "DSQUEUE -- new CoinJoin queue, masternode=%s, queue=%s\n", dmn->proTxHash.ToString(), dsq.ToString()); @@ -138,13 +140,34 @@ MessageProcessingResult CCoinJoinClientQueueManager::ProcessMessage(NodeId from, WITH_LOCK(cs_vecqueue, vecCoinJoinQueue.push_back(dsq)); } } // cs_ProcessDSQueue - peerman.RelayDSQ(dsq); + ret.m_dsq.push_back(dsq); return ret; } +void CCoinJoinClientQueueManager::DoMaintenance() +{ + if (!m_mn_sync.IsBlockchainSynced() || ShutdownRequested()) return; + + CheckQueue(); +} + +CCoinJoinClientManager::CCoinJoinClientManager(const std::shared_ptr& wallet, + CDeterministicMNManager& dmnman, CMasternodeMetaMan& mn_metaman, + const CMasternodeSync& mn_sync, const llmq::CInstantSendManager& isman, + const std::unique_ptr& queueman) : + m_wallet{wallet}, + m_dmnman{dmnman}, + m_mn_metaman{mn_metaman}, + m_mn_sync{mn_sync}, + m_isman{isman}, + m_queueman{queueman} +{ +} + +CCoinJoinClientManager::~CCoinJoinClientManager() = default; + void CCoinJoinClientManager::ProcessMessage(CNode& peer, CChainState& active_chainstate, CConnman& connman, const CTxMemPool& mempool, std::string_view msg_type, CDataStream& vRecv) { - if (m_is_masternode) return; if (!CCoinJoinClientOptions::IsEnabled()) return; if (!m_mn_sync.IsBlockchainSynced()) return; @@ -169,21 +192,18 @@ void CCoinJoinClientManager::ProcessMessage(CNode& peer, CChainState& active_cha CCoinJoinClientSession::CCoinJoinClientSession(const std::shared_ptr& wallet, CCoinJoinClientManager& clientman, CDeterministicMNManager& dmnman, CMasternodeMetaMan& mn_metaman, const CMasternodeSync& mn_sync, const llmq::CInstantSendManager& isman, - const std::unique_ptr& queueman, - bool is_masternode) : + const std::unique_ptr& queueman) : m_wallet(wallet), m_clientman(clientman), m_dmnman(dmnman), m_mn_metaman(mn_metaman), m_mn_sync(mn_sync), m_isman{isman}, - m_queueman(queueman), - m_is_masternode{is_masternode} + m_queueman(queueman) {} void CCoinJoinClientSession::ProcessMessage(CNode& peer, CChainState& active_chainstate, CConnman& connman, const CTxMemPool& mempool, std::string_view msg_type, CDataStream& vRecv) { - if (m_is_masternode) return; if (!CCoinJoinClientOptions::IsEnabled()) return; if (!m_mn_sync.IsBlockchainSynced()) return; @@ -255,7 +275,6 @@ void CCoinJoinClientSession::ResetPool() void CCoinJoinClientManager::ResetPool() { nCachedLastSuccessBlock = 0; - vecMasternodesUsed.clear(); AssertLockNotHeld(cs_deqsessions); LOCK(cs_deqsessions); for (auto& session : deqSessions) { @@ -386,8 +405,6 @@ bool CCoinJoinClientManager::GetMixingMasternodesInfo(std::vector >& vecPSInOutPairsIn, CConnman& connman) { - if (m_is_masternode) { - WalletCJLogPrint(m_wallet, "CCoinJoinClientSession::SendDenominate -- CoinJoin from a Masternode is not supported currently.\n"); - return false; - } - if (CTransaction(txMyCollateral).IsNull()) { WalletCJLogPrint(m_wallet, "CCoinJoinClient:SendDenominate -- CoinJoin collateral not set\n"); return false; @@ -498,8 +509,6 @@ bool CCoinJoinClientSession::SendDenominate(const std::vectorcs_wallet); @@ -682,8 +690,6 @@ bool CCoinJoinClientSession::SignFinalTransaction(CNode& peer, CChainState& acti // mixing transaction was completed (failed or successful) void CCoinJoinClientSession::CompletedTransaction(PoolMessage nMessageID) { - if (m_is_masternode) return; - if (nMessageID == MSG_SUCCESS) { m_clientman.UpdatedSuccessBlock(); keyHolderStorage.KeepAll(); @@ -699,7 +705,6 @@ void CCoinJoinClientSession::CompletedTransaction(PoolMessage nMessageID) void CCoinJoinClientManager::UpdatedSuccessBlock() { - if (m_is_masternode) return; nCachedLastSuccessBlock = nCachedBlockHeight; } @@ -791,7 +796,6 @@ bool CCoinJoinClientManager::CheckAutomaticBackup() bool CCoinJoinClientSession::DoAutomaticDenominating(ChainstateManager& chainman, CConnman& connman, const CTxMemPool& mempool, bool fDryRun) { - if (m_is_masternode) return false; // no client-side mixing on masternodes if (nState != POOL_STATE_IDLE) return false; if (!m_mn_sync.IsBlockchainSynced()) { @@ -972,7 +976,6 @@ bool CCoinJoinClientSession::DoAutomaticDenominating(ChainstateManager& chainman bool CCoinJoinClientManager::DoAutomaticDenominating(ChainstateManager& chainman, CConnman& connman, const CTxMemPool& mempool, bool fDryRun) { - if (m_is_masternode) return false; // no client-side mixing on masternodes if (!CCoinJoinClientOptions::IsEnabled() || !IsMixing()) return false; if (!m_mn_sync.IsBlockchainSynced()) { @@ -990,18 +993,21 @@ bool CCoinJoinClientManager::DoAutomaticDenominating(ChainstateManager& chainman // If we've used 90% of the Masternode list then drop the oldest first ~30% int nThreshold_high = nMnCountEnabled * 0.9; int nThreshold_low = nThreshold_high * 0.7; - WalletCJLogPrint(m_wallet, "Checking vecMasternodesUsed: size: %d, threshold: %d\n", (int)vecMasternodesUsed.size(), nThreshold_high); + size_t used_count{m_mn_metaman.GetUsedMasternodesCount()}; + + WalletCJLogPrint(m_wallet, "Checking threshold - used: %d, threshold: %d\n", (int)used_count, nThreshold_high); - if ((int)vecMasternodesUsed.size() > nThreshold_high) { - vecMasternodesUsed.erase(vecMasternodesUsed.begin(), vecMasternodesUsed.begin() + vecMasternodesUsed.size() - nThreshold_low); - WalletCJLogPrint(m_wallet, " vecMasternodesUsed: new size: %d, threshold: %d\n", (int)vecMasternodesUsed.size(), nThreshold_high); + if ((int)used_count > nThreshold_high) { + m_mn_metaman.RemoveUsedMasternodes(used_count - nThreshold_low); + WalletCJLogPrint(m_wallet, " new used: %d, threshold: %d\n", (int)m_mn_metaman.GetUsedMasternodesCount(), + nThreshold_high); } bool fResult = true; AssertLockNotHeld(cs_deqsessions); LOCK(cs_deqsessions); if (int(deqSessions.size()) < CCoinJoinClientOptions::GetSessions()) { - deqSessions.emplace_back(m_wallet, *this, m_dmnman, m_mn_metaman, m_mn_sync, m_isman, m_queueman, m_is_masternode); + deqSessions.emplace_back(m_wallet, *this, m_dmnman, m_mn_metaman, m_mn_sync, m_isman, m_queueman); } for (auto& session : deqSessions) { if (!CheckAutomaticBackup()) return false; @@ -1018,9 +1024,9 @@ bool CCoinJoinClientManager::DoAutomaticDenominating(ChainstateManager& chainman return fResult; } -void CCoinJoinClientManager::AddUsedMasternode(const COutPoint& outpointMn) +void CCoinJoinClientManager::AddUsedMasternode(const uint256& proTxHash) { - vecMasternodesUsed.push_back(outpointMn); + m_mn_metaman.AddUsedMasternode(proTxHash); } CDeterministicMNCPtr CCoinJoinClientManager::GetRandomNotUsedMasternode() @@ -1028,7 +1034,7 @@ CDeterministicMNCPtr CCoinJoinClientManager::GetRandomNotUsedMasternode() auto mnList = m_dmnman.GetListAtChainTip(); size_t nCountEnabled = mnList.GetValidMNsCount(); - size_t nCountNotExcluded = nCountEnabled - vecMasternodesUsed.size(); + size_t nCountNotExcluded{nCountEnabled - m_mn_metaman.GetUsedMasternodesCount()}; WalletCJLogPrint(m_wallet, "CCoinJoinClientManager::%s -- %d enabled masternodes, %d masternodes to choose from\n", __func__, nCountEnabled, nCountNotExcluded); if (nCountNotExcluded < 1) { @@ -1045,15 +1051,14 @@ CDeterministicMNCPtr CCoinJoinClientManager::GetRandomNotUsedMasternode() // shuffle pointers Shuffle(vpMasternodesShuffled.begin(), vpMasternodesShuffled.end(), FastRandomContext()); - std::set excludeSet(vecMasternodesUsed.begin(), vecMasternodesUsed.end()); - - // loop through + // loop through - using direct O(1) lookup instead of creating a set copy for (const auto& dmn : vpMasternodesShuffled) { - if (excludeSet.count(dmn->collateralOutpoint)) { + if (m_mn_metaman.IsUsedMasternode(dmn->proTxHash)) { continue; } - WalletCJLogPrint(m_wallet, "CCoinJoinClientManager::%s -- found, masternode=%s\n", __func__, dmn->collateralOutpoint.ToStringShort()); + WalletCJLogPrint(m_wallet, "CCoinJoinClientManager::%s -- found, masternode=%s\n", __func__, + dmn->proTxHash.ToString()); return dmn; } @@ -1106,7 +1111,7 @@ bool CCoinJoinClientSession::JoinExistingQueue(CAmount nBalanceNeedsAnonymized, continue; } - m_clientman.AddUsedMasternode(dsq.masternodeOutpoint); + m_clientman.AddUsedMasternode(dmn->proTxHash); if (connman.IsMasternodeOrDisconnectRequested(dmn->pdmnState->netInfo->GetPrimary())) { WalletCJLogPrint(m_wallet, /* Continued */ @@ -1160,7 +1165,7 @@ bool CCoinJoinClientSession::StartNewQueue(CAmount nBalanceNeedsAnonymized, CCon return false; } - m_clientman.AddUsedMasternode(dmn->collateralOutpoint); + m_clientman.AddUsedMasternode(dmn->proTxHash); // skip next mn payments winners if (dmn->pdmnState->nLastPaidHeight + nWeightedMnCount < mnList.GetHeight() + WinnersToSkip()) { @@ -1169,13 +1174,10 @@ bool CCoinJoinClientSession::StartNewQueue(CAmount nBalanceNeedsAnonymized, CCon continue; } - int64_t nLastDsq = m_mn_metaman.GetMetaInfo(dmn->proTxHash)->GetLastDsq(); - int64_t nDsqThreshold = m_mn_metaman.GetDsqThreshold(dmn->proTxHash, nMnCount); - if (nLastDsq != 0 && nDsqThreshold > m_mn_metaman.GetDsqCount()) { + if (m_mn_metaman.IsMixingThresholdExceeded(dmn->proTxHash, nMnCount)) { WalletCJLogPrint(m_wallet, /* Continued */ - "CCoinJoinClientSession::StartNewQueue -- too early to mix with node," /* Continued */ - " masternode=%s, nLastDsq=%d, nDsqThreshold=%d, nDsqCount=%d\n", - dmn->proTxHash.ToString(), nLastDsq, nDsqThreshold, m_mn_metaman.GetDsqCount()); + "CCoinJoinClientSession::StartNewQueue -- too early to mix with node masternode=%s\n", + dmn->proTxHash.ToString()); nTries++; continue; } @@ -1838,19 +1840,9 @@ void CCoinJoinClientManager::UpdatedBlockTip(const CBlockIndex* pindex) WalletCJLogPrint(m_wallet, "CCoinJoinClientManager::UpdatedBlockTip -- nCachedBlockHeight: %d\n", nCachedBlockHeight); } -void CCoinJoinClientQueueManager::DoMaintenance() -{ - if (m_is_masternode) return; // no client-side mixing on masternodes - - if (!m_mn_sync.IsBlockchainSynced() || ShutdownRequested()) return; - - CheckQueue(); -} - void CCoinJoinClientManager::DoMaintenance(ChainstateManager& chainman, CConnman& connman, const CTxMemPool& mempool) { if (!CCoinJoinClientOptions::IsEnabled()) return; - if (m_is_masternode) return; // no client-side mixing on masternodes if (!m_mn_sync.IsBlockchainSynced() || ShutdownRequested()) return; @@ -1899,12 +1891,34 @@ void CCoinJoinClientManager::GetJsonInfo(UniValue& obj) const obj.pushKV("sessions", arrSessions); } +CoinJoinWalletManager::CoinJoinWalletManager(ChainstateManager& chainman, CDeterministicMNManager& dmnman, + CMasternodeMetaMan& mn_metaman, const CTxMemPool& mempool, + const CMasternodeSync& mn_sync, const llmq::CInstantSendManager& isman, + const std::unique_ptr& queueman) : + m_chainman{chainman}, + m_dmnman{dmnman}, + m_mn_metaman{mn_metaman}, + m_mempool{mempool}, + m_mn_sync{mn_sync}, + m_isman{isman}, + m_queueman{queueman} +{ +} + +CoinJoinWalletManager::~CoinJoinWalletManager() +{ + LOCK(cs_wallet_manager_map); + for (auto& [wallet_name, cj_man] : m_wallet_manager_map) { + cj_man.reset(); + } +} + void CoinJoinWalletManager::Add(const std::shared_ptr& wallet) { LOCK(cs_wallet_manager_map); m_wallet_manager_map.try_emplace(wallet->GetName(), std::make_unique(wallet, m_dmnman, m_mn_metaman, m_mn_sync, - m_isman, m_queueman, m_is_masternode)); + m_isman, m_queueman)); } void CoinJoinWalletManager::DoMaintenance(CConnman& connman) diff --git a/src/coinjoin/client.h b/src/coinjoin/client.h index 79dccfc938dd..2b1933841c71 100644 --- a/src/coinjoin/client.h +++ b/src/coinjoin/client.h @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -29,7 +30,6 @@ class CMasternodeSync; class CNode; class CoinJoinWalletManager; class CTxMemPool; -class PeerManager; class UniValue; @@ -75,36 +75,25 @@ class CoinJoinWalletManager { using wallet_name_cjman_map = std::map>; public: - CoinJoinWalletManager(ChainstateManager& chainman, CDeterministicMNManager& dmnman, CMasternodeMetaMan& mn_metaman, - const CTxMemPool& mempool, const CMasternodeSync& mn_sync, const llmq::CInstantSendManager& isman, - const std::unique_ptr& queueman, bool is_masternode) : - m_chainman(chainman), - m_dmnman(dmnman), - m_mn_metaman(mn_metaman), - m_mempool(mempool), - m_mn_sync(mn_sync), - m_isman{isman}, - m_queueman(queueman), - m_is_masternode{is_masternode} - {} - - ~CoinJoinWalletManager() { - LOCK(cs_wallet_manager_map); - for (auto& [wallet_name, cj_man] : m_wallet_manager_map) { - cj_man.reset(); - } - } + CoinJoinWalletManager() = delete; + CoinJoinWalletManager(const CoinJoinWalletManager&) = delete; + CoinJoinWalletManager& operator=(const CoinJoinWalletManager&) = delete; + explicit CoinJoinWalletManager(ChainstateManager& chainman, CDeterministicMNManager& dmnman, + CMasternodeMetaMan& mn_metaman, const CTxMemPool& mempool, + const CMasternodeSync& mn_sync, const llmq::CInstantSendManager& isman, + const std::unique_ptr& queueman); + ~CoinJoinWalletManager(); - void Add(const std::shared_ptr& wallet); - void DoMaintenance(CConnman& connman); + void Add(const std::shared_ptr& wallet) EXCLUSIVE_LOCKS_REQUIRED(!cs_wallet_manager_map); + void DoMaintenance(CConnman& connman) EXCLUSIVE_LOCKS_REQUIRED(!cs_wallet_manager_map); - void Remove(const std::string& name); - void Flush(const std::string& name); + void Remove(const std::string& name) EXCLUSIVE_LOCKS_REQUIRED(!cs_wallet_manager_map); + void Flush(const std::string& name) EXCLUSIVE_LOCKS_REQUIRED(!cs_wallet_manager_map); - CCoinJoinClientManager* Get(const std::string& name) const; + CCoinJoinClientManager* Get(const std::string& name) const EXCLUSIVE_LOCKS_REQUIRED(!cs_wallet_manager_map); template - void ForEachCJClientMan(Callable&& func) + void ForEachCJClientMan(Callable&& func) EXCLUSIVE_LOCKS_REQUIRED(!cs_wallet_manager_map) { LOCK(cs_wallet_manager_map); for (auto&& [_, clientman] : m_wallet_manager_map) { @@ -113,7 +102,7 @@ class CoinJoinWalletManager { }; template - bool ForAnyCJClientMan(Callable&& func) + bool ForAnyCJClientMan(Callable&& func) EXCLUSIVE_LOCKS_REQUIRED(!cs_wallet_manager_map) { LOCK(cs_wallet_manager_map); return ranges::any_of(m_wallet_manager_map, [&](auto& pair) { return func(pair.second); }); @@ -128,8 +117,6 @@ class CoinJoinWalletManager { const llmq::CInstantSendManager& m_isman; const std::unique_ptr& m_queueman; - const bool m_is_masternode; - mutable Mutex cs_wallet_manager_map; wallet_name_cjman_map m_wallet_manager_map GUARDED_BY(cs_wallet_manager_map); }; @@ -145,9 +132,6 @@ class CCoinJoinClientSession : public CCoinJoinBaseSession const llmq::CInstantSendManager& m_isman; const std::unique_ptr& m_queueman; - // Track node type - const bool m_is_masternode; - std::vector vecOutPointLocked; bilingual_str strLastMessage; @@ -202,7 +186,7 @@ class CCoinJoinClientSession : public CCoinJoinBaseSession explicit CCoinJoinClientSession(const std::shared_ptr& wallet, CCoinJoinClientManager& clientman, CDeterministicMNManager& dmnman, CMasternodeMetaMan& mn_metaman, const CMasternodeSync& mn_sync, const llmq::CInstantSendManager& isman, - const std::unique_ptr& queueman, bool is_masternode); + const std::unique_ptr& queueman); void ProcessMessage(CNode& peer, CChainState& active_chainstate, CConnman& connman, const CTxMemPool& mempool, std::string_view msg_type, CDataStream& vRecv); @@ -239,21 +223,18 @@ class CCoinJoinClientQueueManager : public CCoinJoinBaseManager const CMasternodeSync& m_mn_sync; mutable Mutex cs_ProcessDSQueue; - const bool m_is_masternode; public: + CCoinJoinClientQueueManager() = delete; + CCoinJoinClientQueueManager(const CCoinJoinClientQueueManager&) = delete; + CCoinJoinClientQueueManager& operator=(const CCoinJoinClientQueueManager&) = delete; explicit CCoinJoinClientQueueManager(CoinJoinWalletManager& walletman, CDeterministicMNManager& dmnman, - CMasternodeMetaMan& mn_metaman, const CMasternodeSync& mn_sync, - bool is_masternode) : - m_walletman(walletman), - m_dmnman(dmnman), - m_mn_metaman(mn_metaman), - m_mn_sync(mn_sync), - m_is_masternode{is_masternode} {}; - - [[nodiscard]] MessageProcessingResult ProcessMessage(NodeId from, CConnman& connman, PeerManager& peerman, std::string_view msg_type, + CMasternodeMetaMan& mn_metaman, const CMasternodeSync& mn_sync); + ~CCoinJoinClientQueueManager(); + + [[nodiscard]] MessageProcessingResult ProcessMessage(NodeId from, CConnman& connman, std::string_view msg_type, CDataStream& vRecv) - EXCLUSIVE_LOCKS_REQUIRED(!cs_vecqueue); + EXCLUSIVE_LOCKS_REQUIRED(!cs_vecqueue, !cs_ProcessDSQueue); void DoMaintenance(); }; @@ -269,12 +250,6 @@ class CCoinJoinClientManager const llmq::CInstantSendManager& m_isman; const std::unique_ptr& m_queueman; - // Track node type - const bool m_is_masternode; - - // Keep track of the used Masternodes - std::vector vecMasternodesUsed; - mutable Mutex cs_deqsessions; // TODO: or map ?? std::deque deqSessions GUARDED_BY(cs_deqsessions); @@ -298,22 +273,13 @@ class CCoinJoinClientManager bool fCreateAutoBackups{true}; // builtin support for automatic backups CCoinJoinClientManager() = delete; - CCoinJoinClientManager(CCoinJoinClientManager const&) = delete; - CCoinJoinClientManager& operator=(CCoinJoinClientManager const&) = delete; - + CCoinJoinClientManager(const CCoinJoinClientManager&) = delete; + CCoinJoinClientManager& operator=(const CCoinJoinClientManager&) = delete; explicit CCoinJoinClientManager(const std::shared_ptr& wallet, CDeterministicMNManager& dmnman, CMasternodeMetaMan& mn_metaman, const CMasternodeSync& mn_sync, const llmq::CInstantSendManager& isman, - const std::unique_ptr& queueman, bool is_masternode) : - m_wallet(wallet), - m_dmnman(dmnman), - m_mn_metaman(mn_metaman), - m_mn_sync(mn_sync), - m_isman{isman}, - m_queueman(queueman), - m_is_masternode{is_masternode} - { - } + const std::unique_ptr& queueman); + ~CCoinJoinClientManager(); void ProcessMessage(CNode& peer, CChainState& active_chainstate, CConnman& connman, const CTxMemPool& mempool, std::string_view msg_type, CDataStream& vRecv) EXCLUSIVE_LOCKS_REQUIRED(!cs_deqsessions); @@ -338,7 +304,7 @@ class CCoinJoinClientManager void ProcessPendingDsaRequest(CConnman& connman) EXCLUSIVE_LOCKS_REQUIRED(!cs_deqsessions); - void AddUsedMasternode(const COutPoint& outpointMn); + void AddUsedMasternode(const uint256& proTxHash); CDeterministicMNCPtr GetRandomNotUsedMasternode(); void UpdatedSuccessBlock(); diff --git a/src/coinjoin/coinjoin.cpp b/src/coinjoin/coinjoin.cpp index 07ddb2018090..1d129d8521e6 100644 --- a/src/coinjoin/coinjoin.cpp +++ b/src/coinjoin/coinjoin.cpp @@ -16,7 +16,6 @@ #include #include #include -#include #include #include @@ -45,18 +44,6 @@ uint256 CCoinJoinQueue::GetSignatureHash() const } uint256 CCoinJoinQueue::GetHash() const { return SerializeHash(*this, SER_NETWORK, PROTOCOL_VERSION); } -bool CCoinJoinQueue::Sign(const CActiveMasternodeManager& mn_activeman) -{ - uint256 hash = GetSignatureHash(); - CBLSSignature sig = mn_activeman.Sign(hash, /*is_legacy=*/ false); - if (!sig.IsValid()) { - return false; - } - vchSig = sig.ToByteVector(false); - - return true; -} - bool CCoinJoinQueue::CheckSignature(const CBLSPublicKey& blsPubKey) const { if (!CBLSSignature(Span{vchSig}, false).VerifyInsecure(blsPubKey, GetSignatureHash(), false)) { @@ -84,18 +71,6 @@ uint256 CCoinJoinBroadcastTx::GetSignatureHash() const return SerializeHash(*this, SER_GETHASH, PROTOCOL_VERSION); } -bool CCoinJoinBroadcastTx::Sign(const CActiveMasternodeManager& mn_activeman) -{ - uint256 hash = GetSignatureHash(); - CBLSSignature sig = mn_activeman.Sign(hash, /*is_legacy=*/ false); - if (!sig.IsValid()) { - return false; - } - vchSig = sig.ToByteVector(false); - - return true; -} - bool CCoinJoinBroadcastTx::CheckSignature(const CBLSPublicKey& blsPubKey) const { if (!CBLSSignature(Span{vchSig}, false).VerifyInsecure(blsPubKey, GetSignatureHash(), false)) { @@ -147,6 +122,10 @@ void CCoinJoinBaseSession::SetNull() nTimeLastSuccessfulStep = GetTime(); } +CCoinJoinBaseManager::CCoinJoinBaseManager() = default; + +CCoinJoinBaseManager::~CCoinJoinBaseManager() = default; + void CCoinJoinBaseManager::SetNull() { LOCK(cs_vecqueue); @@ -419,6 +398,10 @@ bilingual_str CoinJoin::GetMessageByID(PoolMessage nMessageID) } } +CDSTXManager::CDSTXManager() = default; + +CDSTXManager::~CDSTXManager() = default; + void CDSTXManager::AddDSTX(const CCoinJoinBroadcastTx& dstx) { AssertLockNotHeld(cs_mapdstx); diff --git a/src/coinjoin/coinjoin.h b/src/coinjoin/coinjoin.h index d69d6c12d051..9a15be8b6c03 100644 --- a/src/coinjoin/coinjoin.h +++ b/src/coinjoin/coinjoin.h @@ -22,14 +22,12 @@ #include #include -class CActiveMasternodeManager; class CChainState; class CBLSPublicKey; class CBlockIndex; class ChainstateManager; class CMasternodeSync; class CTxMemPool; -class TxValidationState; namespace llmq { class CChainLocksHandler; @@ -209,14 +207,7 @@ class CCoinJoinQueue [[nodiscard]] uint256 GetHash() const; [[nodiscard]] uint256 GetSignatureHash() const; - /** Sign this mixing transaction - * return true if all conditions are met: - * 1) we have an active Masternode, - * 2) we have a valid Masternode private key, - * 3) we signed the message successfully, and - * 4) we verified the message successfully - */ - bool Sign(const CActiveMasternodeManager& mn_activeman); + /// Check if we have a valid Masternode address [[nodiscard]] bool CheckSignature(const CBLSPublicKey& blsPubKey) const; @@ -284,7 +275,6 @@ class CCoinJoinBroadcastTx [[nodiscard]] uint256 GetSignatureHash() const; - bool Sign(const CActiveMasternodeManager& mn_activeman); [[nodiscard]] bool CheckSignature(const CBLSPublicKey& blsPubKey) const; // Used only for unit tests @@ -341,7 +331,8 @@ class CCoinJoinBaseManager void CheckQueue() EXCLUSIVE_LOCKS_REQUIRED(!cs_vecqueue); public: - CCoinJoinBaseManager() = default; + CCoinJoinBaseManager(); + virtual ~CCoinJoinBaseManager(); int GetQueueSize() const EXCLUSIVE_LOCKS_REQUIRED(!cs_vecqueue) { LOCK(cs_vecqueue); return vecCoinJoinQueue.size(); } bool GetQueueItemAndTry(CCoinJoinQueue& dsqRet) EXCLUSIVE_LOCKS_REQUIRED(!cs_vecqueue); @@ -381,7 +372,11 @@ class CDSTXManager std::map mapDSTX GUARDED_BY(cs_mapdstx); public: - CDSTXManager() = default; + CDSTXManager(const CDSTXManager&) = delete; + CDSTXManager& operator=(const CDSTXManager&) = delete; + CDSTXManager(); + ~CDSTXManager(); + void AddDSTX(const CCoinJoinBroadcastTx& dstx) EXCLUSIVE_LOCKS_REQUIRED(!cs_mapdstx); CCoinJoinBroadcastTx GetDSTX(const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(!cs_mapdstx); diff --git a/src/coinjoin/context.cpp b/src/coinjoin/context.cpp deleted file mode 100644 index 52884e802b0e..000000000000 --- a/src/coinjoin/context.cpp +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) 2023-2025 The Dash Core developers -// Distributed under the MIT/X11 software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include - -#ifdef ENABLE_WALLET -#include -#endif // ENABLE_WALLET -#include - -CJContext::CJContext(ChainstateManager& chainman, CDeterministicMNManager& dmnman, CMasternodeMetaMan& mn_metaman, - CTxMemPool& mempool, const CActiveMasternodeManager* const mn_activeman, - const CMasternodeSync& mn_sync, const llmq::CInstantSendManager& isman, bool relay_txes) : -#ifdef ENABLE_WALLET - walletman{std::make_unique(chainman, dmnman, mn_metaman, mempool, mn_sync, isman, queueman, - /*is_masternode=*/mn_activeman != nullptr)}, - queueman{relay_txes ? std::make_unique(*walletman, dmnman, mn_metaman, mn_sync, - /*is_masternode=*/mn_activeman != nullptr) - : nullptr}, -#endif // ENABLE_WALLET - dstxman{std::make_unique()} -{} - -CJContext::~CJContext() {} diff --git a/src/coinjoin/context.h b/src/coinjoin/context.h deleted file mode 100644 index eb924f345772..000000000000 --- a/src/coinjoin/context.h +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) 2023-2025 The Dash Core developers -// Distributed under the MIT/X11 software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef BITCOIN_COINJOIN_CONTEXT_H -#define BITCOIN_COINJOIN_CONTEXT_H - -#if defined(HAVE_CONFIG_H) -#include -#endif - -#include - -class CActiveMasternodeManager; -class CDeterministicMNManager; -class CDSTXManager; -class ChainstateManager; -class CMasternodeMetaMan; -class CMasternodeSync; -class CTxMemPool; -namespace llmq { -class CInstantSendManager; -}; - -#ifdef ENABLE_WALLET -class CCoinJoinClientQueueManager; -class CoinJoinWalletManager; -#endif // ENABLE_WALLET - -struct CJContext { - CJContext() = delete; - CJContext(const CJContext&) = delete; - CJContext(ChainstateManager& chainman, CDeterministicMNManager& dmnman, CMasternodeMetaMan& mn_metaman, - CTxMemPool& mempool, const CActiveMasternodeManager* const mn_activeman, const CMasternodeSync& mn_sync, - const llmq::CInstantSendManager& isman, bool relay_txes); - ~CJContext(); - -#ifdef ENABLE_WALLET - // The main object for accessing mixing - const std::unique_ptr walletman; - const std::unique_ptr queueman; -#endif // ENABLE_WALLET - const std::unique_ptr dstxman; -}; - -#endif // BITCOIN_COINJOIN_CONTEXT_H diff --git a/src/coinjoin/interfaces.cpp b/src/coinjoin/interfaces.cpp index 98091b694c12..07f7d889701d 100644 --- a/src/coinjoin/interfaces.cpp +++ b/src/coinjoin/interfaces.cpp @@ -5,8 +5,8 @@ #include #include -#include #include +#include #include #include #include @@ -77,9 +77,9 @@ class CoinJoinClientImpl : public interfaces::CoinJoin::Client class CoinJoinLoaderImpl : public interfaces::CoinJoin::Loader { private: - CoinJoinWalletManager& walletman() + CJWalletManager& manager() { - return *Assert(Assert(m_node.cj_ctx)->walletman); + return *Assert(m_node.cj_walletman); } interfaces::WalletLoader& wallet_loader() @@ -97,21 +97,21 @@ class CoinJoinLoaderImpl : public interfaces::CoinJoin::Loader void AddWallet(const std::shared_ptr& wallet) override { - walletman().Add(wallet); + manager().addWallet(wallet); g_wallet_init_interface.InitCoinJoinSettings(*this, wallet_loader()); } void RemoveWallet(const std::string& name) override { - walletman().Remove(name); + manager().removeWallet(name); g_wallet_init_interface.InitCoinJoinSettings(*this, wallet_loader()); } void FlushWallet(const std::string& name) override { - walletman().Flush(name); + manager().flushWallet(name); } std::unique_ptr GetClient(const std::string& name) override { - auto clientman = walletman().Get(name); + auto clientman = manager().getClient(name); return clientman ? std::make_unique(*clientman) : nullptr; } diff --git a/src/coinjoin/server.cpp b/src/coinjoin/server.cpp index 23c8f5e09a86..98069a79cf11 100644 --- a/src/coinjoin/server.cpp +++ b/src/coinjoin/server.cpp @@ -23,6 +23,27 @@ #include +CCoinJoinServer::CCoinJoinServer(ChainstateManager& chainman, CConnman& _connman, CDeterministicMNManager& dmnman, + CDSTXManager& dstxman, CMasternodeMetaMan& mn_metaman, CTxMemPool& mempool, + PeerManager& peerman, const CActiveMasternodeManager& mn_activeman, + const CMasternodeSync& mn_sync, const llmq::CInstantSendManager& isman) : + m_chainman{chainman}, + connman{_connman}, + m_dmnman{dmnman}, + m_dstxman{dstxman}, + m_mn_metaman{mn_metaman}, + mempool{mempool}, + m_peerman{peerman}, + m_mn_activeman{mn_activeman}, + m_mn_sync{mn_sync}, + m_isman{isman}, + vecSessionCollaterals{}, + fUnitTest{false} +{ +} + +CCoinJoinServer::~CCoinJoinServer() = default; + MessageProcessingResult CCoinJoinServer::ProcessMessage(CNode& peer, std::string_view msg_type, CDataStream& vRecv) { if (!m_mn_sync.IsBlockchainSynced()) return {}; @@ -78,9 +99,7 @@ void CCoinJoinServer::ProcessDSACCEPT(CNode& peer, CDataStream& vRecv) } } - int64_t nLastDsq = m_mn_metaman.GetMetaInfo(dmn->proTxHash)->GetLastDsq(); - int64_t nDsqThreshold = m_mn_metaman.GetDsqThreshold(dmn->proTxHash, mnList.GetValidMNsCount()); - if (nLastDsq != 0 && nDsqThreshold > m_mn_metaman.GetDsqCount()) { + if (m_mn_metaman.IsMixingThresholdExceeded(dmn->proTxHash, mnList.GetValidMNsCount())) { if (fLogIPs) { LogPrint(BCLog::COINJOIN, "DSACCEPT -- last dsq too recent, must wait: peer=%d, addr=%s\n", peer.GetId(), peer.addr.ToStringAddrPort()); @@ -117,6 +136,13 @@ MessageProcessingResult CCoinJoinServer::ProcessDSQUEUE(NodeId from, CDataStream MessageProcessingResult ret{}; ret.m_to_erase = CInv{MSG_DSQ, dsq.GetHash()}; + // Validate denomination first + if (!CoinJoin::IsValidDenomination(dsq.nDenom)) { + LogPrint(BCLog::COINJOIN, "DSQUEUE -- invalid denomination %d from peer %d\n", dsq.nDenom, from); + ret.m_error = MisbehavingError{10}; + return ret; + } + if (dsq.masternodeOutpoint.IsNull() && dsq.m_protxHash.IsNull()) { ret.m_error = MisbehavingError{100}; return ret; @@ -166,11 +192,8 @@ MessageProcessingResult CCoinJoinServer::ProcessDSQUEUE(NodeId from, CDataStream } if (!dsq.fReady) { - int64_t nLastDsq = m_mn_metaman.GetMetaInfo(dmn->proTxHash)->GetLastDsq(); - int64_t nDsqThreshold = m_mn_metaman.GetDsqThreshold(dmn->proTxHash, tip_mn_list.GetValidMNsCount()); - LogPrint(BCLog::COINJOIN, "DSQUEUE -- nLastDsq: %d nDsqThreshold: %d nDsqCount: %d\n", nLastDsq, nDsqThreshold, m_mn_metaman.GetDsqCount()); //don't allow a few nodes to dominate the queuing process - if (nLastDsq != 0 && nDsqThreshold > m_mn_metaman.GetDsqCount()) { + if (m_mn_metaman.IsMixingThresholdExceeded(dmn->proTxHash, tip_mn_list.GetValidMNsCount())) { LogPrint(BCLog::COINJOIN, "DSQUEUE -- node sending too many dsq messages, masternode=%s\n", dmn->proTxHash.ToString()); return ret; } @@ -181,7 +204,7 @@ MessageProcessingResult CCoinJoinServer::ProcessDSQUEUE(NodeId from, CDataStream TRY_LOCK(cs_vecqueue, lockRecv); if (!lockRecv) return ret; vecCoinJoinQueue.push_back(dsq); - m_peerman.RelayDSQ(dsq); + ret.m_dsq.push_back(dsq); } return ret; } @@ -338,7 +361,7 @@ void CCoinJoinServer::CommitFinalTransaction() if (!m_dstxman.GetDSTX(hashTx)) { CCoinJoinBroadcastTx dstxNew(finalTransaction, m_mn_activeman.GetOutPoint(), m_mn_activeman.GetProTxHash(), GetAdjustedTime()); - dstxNew.Sign(m_mn_activeman); + dstxNew.vchSig = m_mn_activeman.SignBasic(dstxNew.GetSignatureHash()); m_dstxman.AddDSTX(dstxNew); } @@ -497,7 +520,7 @@ void CCoinJoinServer::CheckForCompleteQueue() GetAdjustedTime(), true); LogPrint(BCLog::COINJOIN, "CCoinJoinServer::CheckForCompleteQueue -- queue is ready, signing and relaying (%s) " /* Continued */ "with %d participants\n", dsq.ToString(), vecSessionCollaterals.size()); - dsq.Sign(m_mn_activeman); + dsq.vchSig = m_mn_activeman.SignBasic(dsq.GetSignatureHash()); m_peerman.RelayDSQ(dsq); WITH_LOCK(cs_vecqueue, vecCoinJoinQueue.push_back(dsq)); } @@ -707,7 +730,7 @@ bool CCoinJoinServer::CreateNewSession(const CCoinJoinAccept& dsa, PoolMessage& CCoinJoinQueue dsq(nSessionDenom, m_mn_activeman.GetOutPoint(), m_mn_activeman.GetProTxHash(), GetAdjustedTime(), false); LogPrint(BCLog::COINJOIN, "CCoinJoinServer::CreateNewSession -- signing and relaying new queue: %s\n", dsq.ToString()); - dsq.Sign(m_mn_activeman); + dsq.vchSig = m_mn_activeman.SignBasic(dsq.GetSignatureHash()); m_peerman.RelayDSQ(dsq); LOCK(cs_vecqueue); vecCoinJoinQueue.push_back(dsq); diff --git a/src/coinjoin/server.h b/src/coinjoin/server.h index 31099a6ac384..cae4b8f8dddb 100644 --- a/src/coinjoin/server.h +++ b/src/coinjoin/server.h @@ -6,6 +6,7 @@ #define BITCOIN_COINJOIN_SERVER_H #include +#include #include #include @@ -93,23 +94,14 @@ class CCoinJoinServer : public CCoinJoinBaseSession, public CCoinJoinBaseManager void SetNull() override EXCLUSIVE_LOCKS_REQUIRED(cs_coinjoin); public: + CCoinJoinServer() = delete; + CCoinJoinServer(const CCoinJoinServer&) = delete; + CCoinJoinServer& operator=(const CCoinJoinServer&) = delete; explicit CCoinJoinServer(ChainstateManager& chainman, CConnman& _connman, CDeterministicMNManager& dmnman, CDSTXManager& dstxman, CMasternodeMetaMan& mn_metaman, CTxMemPool& mempool, PeerManager& peerman, const CActiveMasternodeManager& mn_activeman, - const CMasternodeSync& mn_sync, const llmq::CInstantSendManager& isman) : - m_chainman(chainman), - connman(_connman), - m_dmnman(dmnman), - m_dstxman(dstxman), - m_mn_metaman(mn_metaman), - mempool(mempool), - m_peerman(peerman), - m_mn_activeman(mn_activeman), - m_mn_sync(mn_sync), - m_isman{isman}, - vecSessionCollaterals(), - fUnitTest(false) - {} + const CMasternodeSync& mn_sync, const llmq::CInstantSendManager& isman); + ~CCoinJoinServer(); [[nodiscard]] MessageProcessingResult ProcessMessage(CNode& pfrom, std::string_view msg_type, CDataStream& vRecv); diff --git a/src/coinjoin/util.cpp b/src/coinjoin/util.cpp index dd4c27281217..a494b8755d0d 100644 --- a/src/coinjoin/util.cpp +++ b/src/coinjoin/util.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include @@ -125,8 +126,13 @@ CTransactionBuilder::CTransactionBuilder(CWallet& wallet, const CompactTallyItem coinControl.m_discard_feerate = ::GetDiscardRate(m_wallet); // Generate a feerate which will be used by calculations of this class and also by CWallet::CreateTransaction coinControl.m_feerate = std::max(GetRequiredFeeRate(m_wallet), m_wallet.m_pay_tx_fee); - // Change always goes back to origin - coinControl.destChange = tallyItemIn.txdest; + // If wallet does not have the avoid-reuse feature enabled, keep legacy + // behavior: force change to go back to the origin address. When + // WALLET_FLAG_AVOID_REUSE is enabled, let the wallet select a fresh + // change destination to avoid address reuse. + if (!m_wallet.IsWalletFlagSet(wallet::WALLET_FLAG_AVOID_REUSE)) { + coinControl.destChange = tallyItemIn.txdest; + } // Only allow tallyItems inputs for tx creation coinControl.m_allow_other_inputs = false; // Create dummy tx to calculate the exact required fees upfront for accurate amount and fee calculations diff --git a/src/coinjoin/util.h b/src/coinjoin/util.h index ab0122d1bb64..8f1a26b4fc7e 100644 --- a/src/coinjoin/util.h +++ b/src/coinjoin/util.h @@ -117,7 +117,11 @@ class CTransactionBuilder /// Check if an amounts should be considered as dust bool IsDust(CAmount nAmount) const; /// Get the total number of added outputs - int CountOutputs() const { LOCK(cs_outputs); return vecOutputs.size(); } + int CountOutputs() const EXCLUSIVE_LOCKS_REQUIRED(!cs_outputs) + { + LOCK(cs_outputs); + return vecOutputs.size(); + } /// Create and Commit the transaction to the wallet bool Commit(bilingual_str& strResult) EXCLUSIVE_LOCKS_REQUIRED(!cs_outputs); /// Convert to a string diff --git a/src/coinjoin/walletman.cpp b/src/coinjoin/walletman.cpp new file mode 100644 index 000000000000..50b552d766fb --- /dev/null +++ b/src/coinjoin/walletman.cpp @@ -0,0 +1,163 @@ +// Copyright (c) 2023-2025 The Dash Core developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#if defined(HAVE_CONFIG_H) +#include +#endif + +#include + +#include +#include +#include + +#include + +#ifdef ENABLE_WALLET +#include +#endif // ENABLE_WALLET + +#include + +#ifdef ENABLE_WALLET +class CJWalletManagerImpl final : public CJWalletManager +{ +public: + CJWalletManagerImpl(ChainstateManager& chainman, CDeterministicMNManager& dmnman, CMasternodeMetaMan& mn_metaman, + CTxMemPool& mempool, const CMasternodeSync& mn_sync, const llmq::CInstantSendManager& isman, + bool relay_txes); + virtual ~CJWalletManagerImpl() = default; + +public: + void Schedule(CConnman& connman, CScheduler& scheduler) override; + +public: + bool hasQueue(const uint256& hash) const override; + CCoinJoinClientManager* getClient(const std::string& name) override; + MessageProcessingResult processMessage(CNode& peer, CChainState& chainstate, CConnman& connman, CTxMemPool& mempool, + std::string_view msg_type, CDataStream& vRecv) override; + std::optional getQueueFromHash(const uint256& hash) const override; + std::optional getQueueSize() const override; + std::vector getMixingMasternodes() override; + void addWallet(const std::shared_ptr& wallet) override; + void removeWallet(const std::string& name) override; + void flushWallet(const std::string& name) override; + +protected: + // CValidationInterface + void UpdatedBlockTip(const CBlockIndex* pindexNew, const CBlockIndex* pindexFork, bool fInitialDownload) override; + +private: + const bool m_relay_txes; + + CoinJoinWalletManager walletman; + const std::unique_ptr queueman; +}; + +CJWalletManagerImpl::CJWalletManagerImpl(ChainstateManager& chainman, CDeterministicMNManager& dmnman, + CMasternodeMetaMan& mn_metaman, CTxMemPool& mempool, + const CMasternodeSync& mn_sync, const llmq::CInstantSendManager& isman, + bool relay_txes) : + m_relay_txes{relay_txes}, + walletman{chainman, dmnman, mn_metaman, mempool, mn_sync, isman, queueman}, + queueman{m_relay_txes ? std::make_unique(walletman, dmnman, mn_metaman, mn_sync) : nullptr} +{ +} + +void CJWalletManagerImpl::Schedule(CConnman& connman, CScheduler& scheduler) +{ + if (!m_relay_txes) return; + scheduler.scheduleEvery(std::bind(&CCoinJoinClientQueueManager::DoMaintenance, std::ref(*queueman)), + std::chrono::seconds{1}); + scheduler.scheduleEvery(std::bind(&CoinJoinWalletManager::DoMaintenance, std::ref(walletman), std::ref(connman)), + std::chrono::seconds{1}); +} + +void CJWalletManagerImpl::UpdatedBlockTip(const CBlockIndex* pindexNew, const CBlockIndex* pindexFork, bool fInitialDownload) +{ + if (fInitialDownload || pindexNew == pindexFork) // In IBD or blocks were disconnected without any new ones + return; + + walletman.ForEachCJClientMan( + [&pindexNew](std::unique_ptr& clientman) { clientman->UpdatedBlockTip(pindexNew); }); +} + +bool CJWalletManagerImpl::hasQueue(const uint256& hash) const +{ + if (queueman) { + return queueman->HasQueue(hash); + } + return false; +} + +CCoinJoinClientManager* CJWalletManagerImpl::getClient(const std::string& name) +{ + return walletman.Get(name); +} + +MessageProcessingResult CJWalletManagerImpl::processMessage(CNode& pfrom, CChainState& chainstate, CConnman& connman, + CTxMemPool& mempool, std::string_view msg_type, + CDataStream& vRecv) +{ + walletman.ForEachCJClientMan([&](std::unique_ptr& clientman) { + clientman->ProcessMessage(pfrom, chainstate, connman, mempool, msg_type, vRecv); + }); + if (queueman) { + return queueman->ProcessMessage(pfrom.GetId(), connman, msg_type, vRecv); + } + return {}; +} + +std::optional CJWalletManagerImpl::getQueueFromHash(const uint256& hash) const +{ + if (queueman) { + return queueman->GetQueueFromHash(hash); + } + return std::nullopt; +} + +std::optional CJWalletManagerImpl::getQueueSize() const +{ + if (queueman) { + return queueman->GetQueueSize(); + } + return std::nullopt; +} + +std::vector CJWalletManagerImpl::getMixingMasternodes() +{ + std::vector ret{}; + walletman.ForEachCJClientMan( + [&](const std::unique_ptr& clientman) { clientman->GetMixingMasternodesInfo(ret); }); + return ret; +} + +void CJWalletManagerImpl::addWallet(const std::shared_ptr& wallet) +{ + walletman.Add(wallet); +} + +void CJWalletManagerImpl::flushWallet(const std::string& name) +{ + walletman.Flush(name); +} + +void CJWalletManagerImpl::removeWallet(const std::string& name) +{ + walletman.Remove(name); +} +#endif // ENABLE_WALLET + +std::unique_ptr CJWalletManager::make(ChainstateManager& chainman, CDeterministicMNManager& dmnman, + CMasternodeMetaMan& mn_metaman, CTxMemPool& mempool, + const CMasternodeSync& mn_sync, + const llmq::CInstantSendManager& isman, bool relay_txes) +{ +#ifdef ENABLE_WALLET + return std::make_unique(chainman, dmnman, mn_metaman, mempool, mn_sync, isman, relay_txes); +#else + // Cannot be constructed if wallet support isn't built + return nullptr; +#endif // ENABLE_WALLET +} diff --git a/src/coinjoin/walletman.h b/src/coinjoin/walletman.h new file mode 100644 index 000000000000..720a4bdf2f81 --- /dev/null +++ b/src/coinjoin/walletman.h @@ -0,0 +1,66 @@ +// Copyright (c) 2023-2025 The Dash Core developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_COINJOIN_WALLETMAN_H +#define BITCOIN_COINJOIN_WALLETMAN_H + +#include +#include + +#include + +#include +#include + +class CBlockIndex; +class CChainState; +class CCoinJoinClientManager; +class CCoinJoinQueue; +class CConnman; +class CDataStream; +class CDeterministicMNManager; +class ChainstateManager; +class CMasternodeMetaMan; +class CMasternodeSync; +class CNode; +class CScheduler; +class CTxMemPool; +namespace llmq { +class CInstantSendManager; +} // namespace llmq +namespace wallet { +class CWallet; +} // namespace wallet + +class CJWalletManager : public CValidationInterface +{ +public: + static std::unique_ptr make(ChainstateManager& chainman, CDeterministicMNManager& dmnman, + CMasternodeMetaMan& mn_metaman, CTxMemPool& mempool, + const CMasternodeSync& mn_sync, const llmq::CInstantSendManager& isman, + bool relay_txes); + virtual ~CJWalletManager() = default; + +public: + virtual void Schedule(CConnman& connman, CScheduler& scheduler) = 0; + +public: + virtual bool hasQueue(const uint256& hash) const = 0; + virtual CCoinJoinClientManager* getClient(const std::string& name) = 0; + virtual MessageProcessingResult processMessage(CNode& peer, CChainState& chainstate, CConnman& connman, + CTxMemPool& mempool, std::string_view msg_type, CDataStream& vRecv) = 0; + virtual std::optional getQueueFromHash(const uint256& hash) const = 0; + virtual std::optional getQueueSize() const = 0; + virtual std::vector getMixingMasternodes() = 0; + virtual void addWallet(const std::shared_ptr& wallet) = 0; + virtual void removeWallet(const std::string& name) = 0; + virtual void flushWallet(const std::string& name) = 0; + +protected: + // CValidationInterface + virtual void UpdatedBlockTip(const CBlockIndex* pindexNew, const CBlockIndex* pindexFork, + bool fInitialDownload) override = 0; +}; + +#endif // BITCOIN_COINJOIN_WALLETMAN_H diff --git a/src/coins.cpp b/src/coins.cpp index 0aa3bf708484..d43e886b7603 100644 --- a/src/coins.cpp +++ b/src/coins.cpp @@ -356,7 +356,7 @@ bool CCoinsViewErrorCatcher::GetCoin(const COutPoint &outpoint, Coin &coin) cons try { return CCoinsViewBacked::GetCoin(outpoint, coin); } catch(const std::runtime_error& e) { - for (auto f : m_err_callbacks) { + for (const auto& f : m_err_callbacks) { f(); } LogPrintf("Error reading from database: %s\n", e.what()); diff --git a/src/common/run_command.cpp b/src/common/run_command.cpp new file mode 100644 index 000000000000..e5356490ef7f --- /dev/null +++ b/src/common/run_command.cpp @@ -0,0 +1,50 @@ +// Copyright (c) 2022 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#if defined(HAVE_CONFIG_H) +#include +#endif + +#include + +#include +#include + +#ifdef ENABLE_EXTERNAL_SIGNER +#include +#endif // ENABLE_EXTERNAL_SIGNER + +UniValue RunCommandParseJSON(const std::string& str_command, const std::string& str_std_in) +{ +#ifdef ENABLE_EXTERNAL_SIGNER + namespace sp = subprocess; + + UniValue result_json; + std::istringstream stdout_stream; + std::istringstream stderr_stream; + + if (str_command.empty()) return UniValue::VNULL; + + auto c = sp::Popen(str_command, sp::input{sp::PIPE}, sp::output{sp::PIPE}, sp::error{sp::PIPE}); + if (!str_std_in.empty()) { + c.send(str_std_in); + } + auto [out_res, err_res] = c.communicate(); + stdout_stream.str(std::string{out_res.buf.begin(), out_res.buf.end()}); + stderr_stream.str(std::string{err_res.buf.begin(), err_res.buf.end()}); + + std::string result; + std::string error; + std::getline(stdout_stream, result); + std::getline(stderr_stream, error); + + const int n_error = c.retcode(); + if (n_error) throw std::runtime_error(strprintf("RunCommandParseJSON error: process(%s) returned %d: %s\n", str_command, n_error, error)); + if (!result_json.read(result)) throw std::runtime_error("Unable to parse JSON: " + result); + + return result_json; +#else + throw std::runtime_error("Compiled without external signing support (required for external signing)."); +#endif // ENABLE_EXTERNAL_SIGNER +} diff --git a/src/common/run_command.h b/src/common/run_command.h new file mode 100644 index 000000000000..2fbdc071eeca --- /dev/null +++ b/src/common/run_command.h @@ -0,0 +1,21 @@ +// Copyright (c) 2022 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_COMMON_RUN_COMMAND_H +#define BITCOIN_COMMON_RUN_COMMAND_H + +#include + +class UniValue; + +/** + * Execute a command which returns JSON, and parse the result. + * + * @param str_command The command to execute, including any arguments + * @param str_std_in string to pass to stdin + * @return parsed JSON + */ +UniValue RunCommandParseJSON(const std::string& str_command, const std::string& str_std_in=""); + +#endif // BITCOIN_COMMON_RUN_COMMAND_H diff --git a/src/consensus/params.h b/src/consensus/params.h index c0457060f2aa..09cbd8c83fa5 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -40,7 +40,7 @@ constexpr bool ValidDeployment(BuriedDeployment dep) { return dep <= DEPLOYMENT_ enum DeploymentPos : uint16_t { DEPLOYMENT_TESTDUMMY, - DEPLOYMENT_V23, // Deployment of doubling withdrawal limit, extended addresses + DEPLOYMENT_V24, // Deployment of doubling withdrawal limit, extended addresses // NOTE: Also add new deployments to VersionBitsDeploymentInfo in deploymentinfo.cpp MAX_VERSION_BITS_DEPLOYMENTS }; diff --git a/src/core_io.h b/src/core_io.h index 00cec54e27e7..8dd365f95518 100644 --- a/src/core_io.h +++ b/src/core_io.h @@ -6,7 +6,6 @@ #define BITCOIN_CORE_IO_H #include -#include #include #include @@ -15,12 +14,13 @@ class CBlock; class CBlockHeader; class CScript; class CTransaction; -struct CMutableTransaction; -class uint256; -class UniValue; class CTxUndo; - +class uint256; +struct CMutableTransaction; struct CSpentIndexTxInfo; +struct RPCResult; + +class UniValue; /** * Verbose level for block's transaction @@ -57,4 +57,7 @@ std::string SighashToStr(unsigned char sighash_type); void ScriptToUniv(const CScript& script, UniValue& out, bool include_hex = true, bool include_address = false); void TxToUniv(const CTransaction& tx, const uint256& block_hash, UniValue& entry, bool include_hex = true, int serialize_flags = 0, const CTxUndo* txundo = nullptr, TxVerbosity verbosity = TxVerbosity::SHOW_DETAILS, const CSpentIndexTxInfo* ptxSpentInfo = nullptr); +// evo/core_write.cpp +RPCResult GetRpcResult(const std::string& key, bool optional = false); + #endif // BITCOIN_CORE_IO_H diff --git a/src/core_read.cpp b/src/core_read.cpp index 9f7c198d3f9e..b6753f9c1248 100644 --- a/src/core_read.cpp +++ b/src/core_read.cpp @@ -39,7 +39,7 @@ class OpCodeParser } mapOpNames[strName] = static_cast(op); // Convenience: OP_ADD and just ADD are both recognized: - if (strName.compare(0, 3, "OP_") == 0) { // strName starts with "OP_" + if (strName.starts_with("OP_")) { mapOpNames[strName.substr(3)] = static_cast(op); } } @@ -189,7 +189,7 @@ int ParseSighashString(const UniValue& sighash) {std::string("SINGLE"), int(SIGHASH_SINGLE)}, {std::string("SINGLE|ANYONECANPAY"), int(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY)}, }; - std::string strHashType = sighash.get_str(); + const std::string& strHashType = sighash.get_str(); const auto& it = map_sighash_values.find(strHashType); if (it != map_sighash_values.end()) { hash_type = it->second; diff --git a/src/crypto/muhash.cpp b/src/crypto/muhash.cpp index b79da158ba08..8c257c9ee705 100644 --- a/src/crypto/muhash.cpp +++ b/src/crypto/muhash.cpp @@ -298,7 +298,7 @@ void Num3072::ToBytes(unsigned char (&out)[BYTE_SIZE]) { Num3072 MuHash3072::ToNum3072(Span in) { unsigned char tmp[Num3072::BYTE_SIZE]; - uint256 hashed_in = (CHashWriter(SER_DISK, 0) << in).GetSHA256(); + uint256 hashed_in{(HashWriter{} << in).GetSHA256()}; static_assert(sizeof(tmp) % ChaCha20Aligned::BLOCKLEN == 0); ChaCha20Aligned{MakeByteSpan(hashed_in)}.Keystream(MakeWritableByteSpan(tmp)); Num3072 out{tmp}; @@ -319,7 +319,7 @@ void MuHash3072::Finalize(uint256& out) noexcept unsigned char data[Num3072::BYTE_SIZE]; m_numerator.ToBytes(data); - out = (CHashWriter(SER_DISK, 0) << data).GetSHA256(); + out = (HashWriter{} << data).GetSHA256(); } MuHash3072& MuHash3072::operator*=(const MuHash3072& mul) noexcept diff --git a/src/dashbls/.github/workflows/build-binds.yml b/src/dashbls/.github/workflows/build-binds.yml index 6fc729109d74..43dc8b212590 100644 --- a/src/dashbls/.github/workflows/build-binds.yml +++ b/src/dashbls/.github/workflows/build-binds.yml @@ -17,14 +17,15 @@ concurrency: jobs: build: - name: ${{ matrix.os }}, Python ${{ matrix.python }}, Go ${{ matrix.golang }} + name: ${{ matrix.os }}, Python ${{ matrix.python }}, Go ${{ matrix.golang }}, Rust ${{ matrix.rust }} runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: os: [macos-latest, ubuntu-latest] - golang: [ '1.22' ] - python: ['3.9', '3.10', '3.11', '3.12'] + golang: [ '1.24' ] + python: ['3.10', '3.11', '3.12', '3.13'] + rust: [ '1.91.0' ] steps: - name: Checkout code @@ -73,12 +74,23 @@ jobs: - name: Build library using CMake run: | mkdir -p build && cd build - cmake .. + cmake .. -DCMAKE_BUILD_TYPE=Debug cmake --build . -- -j 6 - name: Build Go bindings - # TODO: macos build is broken. Whoever needs this - please fix it and remove `if` below. - if: startsWith(matrix.os, 'ubuntu') run: | cd go-bindings + make config make + + - name: Install Rust + run: | + rustup toolchain install ${{ matrix.rust }} + rustup default ${{ matrix.rust }} + rustc --version + cargo --version + + - name: Build and test Rust bindings + run: | + cd rust-bindings/bls-dash-sys + cargo test diff --git a/src/dashbls/.github/workflows/build-test.yaml b/src/dashbls/.github/workflows/build-test.yaml index e023515ee2cb..90a550a5e4d2 100644 --- a/src/dashbls/.github/workflows/build-test.yaml +++ b/src/dashbls/.github/workflows/build-test.yaml @@ -22,7 +22,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ macos-latest, ubuntu-20.04 ] + os: [ macos-latest, ubuntu-latest ] builder: [ cmake, autotools ] compiler: - cc: gcc @@ -53,7 +53,7 @@ jobs: if: startsWith(matrix.builder, 'cmake') run: | mkdir -p build && cd build - CC=${{ matrix.compiler.cc }} CXX=${{ matrix.compiler.cxx }} cmake .. -DBUILD_BLS_PYTHON_BINDINGS=0 -DARITH=${{ matrix.backend }} + CC=${{ matrix.compiler.cc }} CXX=${{ matrix.compiler.cxx }} cmake .. -DARITH=${{ matrix.backend }} -DBUILD_BLS_PYTHON_BINDINGS=0 -DCMAKE_BUILD_TYPE=Debug cmake --build . -- -j 6 mv src/runtest .. diff --git a/src/dashbls/Makefile.mimalloc.include b/src/dashbls/Makefile.mimalloc.include index f062d90e83d2..fada5fe32819 100644 --- a/src/dashbls/Makefile.mimalloc.include +++ b/src/dashbls/Makefile.mimalloc.include @@ -1,10 +1,10 @@ -# Copyright (c) 2022 The Dash Core developers +# Copyright (c) 2022-2025 The Dash Core developers # Distributed under the MIT software license, see the accompanying # file COPYING.MIT or http://www.opensource.org/licenses/mit-license.php. LIBMIMALLOC = libmimalloc-secure.la -MIMALLOC_CFLAGS = \ +MIMALLOC_CPPFLAGS = \ -DMI_SECURE=4 \ -DNDEBUG @@ -13,32 +13,34 @@ MIMALLOC_INCLUDES = \ -I$(top_srcdir)/depends/mimalloc/src MIMALLOC_H = \ - depends/mimalloc/include/mimalloc.h \ - depends/mimalloc/include/mimalloc-atomic.h \ - depends/mimalloc/include/mimalloc-internal.h \ - depends/mimalloc/include/mimalloc-new-delete.h \ - depends/mimalloc/include/mimalloc-override.h \ - depends/mimalloc/include/mimalloc-track.h \ - depends/mimalloc/include/mimalloc-types.h \ + depends/mimalloc/include/mimalloc-new-delete.h \ + depends/mimalloc/include/mimalloc-override.h \ + depends/mimalloc/include/mimalloc-stats.h \ + depends/mimalloc/include/mimalloc.h \ depends/mimalloc/src/bitmap.h libmimalloc_secure_la_SOURCES = \ $(MIMALLOC_H) \ - depends/mimalloc/src/stats.c \ - depends/mimalloc/src/random.c \ - depends/mimalloc/src/os.c \ - depends/mimalloc/src/bitmap.c \ - depends/mimalloc/src/arena.c \ - depends/mimalloc/src/segment-cache.c \ - depends/mimalloc/src/segment.c \ - depends/mimalloc/src/page.c \ - depends/mimalloc/src/alloc.c \ depends/mimalloc/src/alloc-aligned.c \ depends/mimalloc/src/alloc-posix.c \ + depends/mimalloc/src/alloc.c \ + depends/mimalloc/src/arena-meta.c \ + depends/mimalloc/src/arena.c \ + depends/mimalloc/src/bitmap.c \ depends/mimalloc/src/heap.c \ + depends/mimalloc/src/init.c \ + depends/mimalloc/src/libc.c \ depends/mimalloc/src/options.c \ - depends/mimalloc/src/init.c + depends/mimalloc/src/os.c \ + depends/mimalloc/src/page-map.c \ + depends/mimalloc/src/page.c \ + depends/mimalloc/src/random.c \ + depends/mimalloc/src/stats.c \ + depends/mimalloc/src/prim/prim.c -libmimalloc_secure_la_CFLAGS = $(AM_CFLAGS) $(MIMALLOC_INCLUDES) $(MIMALLOC_CFLAGS) +libmimalloc_secure_la_CPPFLAGS = $(AM_CPPFLAGS) $(MIMALLOC_CPPFLAGS) $(MIMALLOC_INCLUDES) +libmimalloc_secure_la_CXXFLAGS = $(AM_CXXFLAGS) +libmimalloc_secure_la_CFLAGS = $(AM_CFLAGS) +libmimalloc_secure_la_LDFLAGS = $(AM_LDFLAGS) noinst_LTLIBRARIES += $(LIBMIMALLOC) diff --git a/src/dashbls/configure.ac b/src/dashbls/configure.ac index 815a015b03dc..56b8a78339e0 100644 --- a/src/dashbls/configure.ac +++ b/src/dashbls/configure.ac @@ -1,5 +1,5 @@ AC_PREREQ([2.60]) -AC_INIT([libdashbls],[1.3.5]) +AC_INIT([libdashbls],[2.0]) AC_CONFIG_AUX_DIR([build-aux]) AC_CONFIG_MACRO_DIR([build-aux/m4]) @@ -772,12 +772,6 @@ if test "$use_hardening" != "no"; then AX_CHECK_LINK_FLAG([-Wl,-z,now], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -Wl,-z,now"], [], []) AX_CHECK_LINK_FLAG([-Wl,-z,separate-code], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -Wl,-z,separate-code"], [], []) AX_CHECK_LINK_FLAG([-fPIE -pie], [HARDENED_FLAGS="$HARDENED_FLAGS -fPIE"; HARDENED_LDFLAGS="$HARDENED_LDFLAGS -pie"], [], []) - - case $host in - *mingw*) - AC_CHECK_LIB([ssp], [main], [], [AC_MSG_ERROR([libssp missing])]) - ;; - esac fi CORE_CPPFLAGS="$CORE_CPPFLAGS -DHAVE_BUILD_INFO" diff --git a/src/dashbls/depends/mimalloc/.gitignore b/src/dashbls/depends/mimalloc/.gitignore index f8b7f5eb8e99..bcedbc3f7d71 100644 --- a/src/dashbls/depends/mimalloc/.gitignore +++ b/src/dashbls/depends/mimalloc/.gitignore @@ -1,9 +1,13 @@ +build ide/vs20??/*.db ide/vs20??/*.opendb ide/vs20??/*.user -ide/vs20??/*.vcxproj.filters ide/vs20??/.vs ide/vs20??/VTune* out/ docs/ *.zip +*.tar +*.gz +.vscode +.DS_STore diff --git a/src/dashbls/depends/mimalloc/CMakeLists.txt b/src/dashbls/depends/mimalloc/CMakeLists.txt index 2550f0d51420..bb3682c48bb8 100644 --- a/src/dashbls/depends/mimalloc/CMakeLists.txt +++ b/src/dashbls/depends/mimalloc/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.0) +cmake_minimum_required(VERSION 3.18) project(libmimalloc C CXX) set(CMAKE_C_STANDARD 11) @@ -6,77 +6,179 @@ set(CMAKE_CXX_STANDARD 17) option(MI_SECURE "Use full security mitigations (like guard pages, allocation randomization, double-free mitigation, and free-list corruption detection)" OFF) option(MI_DEBUG_FULL "Use full internal heap invariant checking in DEBUG mode (expensive)" OFF) -option(MI_PADDING "Enable padding to detect heap block overflow (used only in DEBUG mode or with Valgrind)" ON) -option(MI_OVERRIDE "Override the standard malloc interface (e.g. define entry points for malloc() etc)" ON) +option(MI_PADDING "Enable padding to detect heap block overflow (always on in DEBUG or SECURE mode, or with Valgrind/ASAN)" OFF) +option(MI_OVERRIDE "Override the standard malloc interface (i.e. define entry points for 'malloc', 'free', etc)" ON) option(MI_XMALLOC "Enable abort() call on memory allocation failure by default" OFF) option(MI_SHOW_ERRORS "Show error and warning messages by default (only enabled by default in DEBUG mode)" OFF) -option(MI_VALGRIND "Compile with Valgrind support (adds a small overhead)" OFF) +option(MI_GUARDED "Build with guard pages behind certain object allocations (implies MI_NO_PADDING=ON)" OFF) option(MI_USE_CXX "Use the C++ compiler to compile the library (instead of the C compiler)" OFF) +option(MI_OPT_ARCH "Only for optimized builds: turn on architecture specific optimizations (for x64: '-march=haswell;-mavx2' (2013), for arm64: '-march=armv8.1-a' (2016))" OFF) +option(MI_OPT_SIMD "Use SIMD instructions (requires MI_OPT_ARCH to be enabled)" OFF) option(MI_SEE_ASM "Generate assembly files" OFF) option(MI_OSX_INTERPOSE "Use interpose to override standard malloc on macOS" ON) -option(MI_OSX_ZONE "Use malloc zone to override standard malloc on macOS" ON) +option(MI_OSX_ZONE "Use malloc zone to override standard malloc on macOS" ON) option(MI_WIN_REDIRECT "Use redirection module ('mimalloc-redirect') on Windows if compiling mimalloc as a DLL" ON) -option(MI_LOCAL_DYNAMIC_TLS "Use slightly slower, dlopen-compatible TLS mechanism (Unix)" OFF) +option(MI_WIN_USE_FIXED_TLS "Use a fixed TLS slot on Windows to avoid extra tests in the malloc fast path" OFF) +option(MI_LOCAL_DYNAMIC_TLS "Use local-dynamic-tls, a slightly slower but dlopen-compatible thread local storage mechanism (Unix)" OFF) +option(MI_LIBC_MUSL "Enable this when linking with musl libc" OFF) + +option(MI_DEBUG_TSAN "Build with thread sanitizer (needs clang)" OFF) +option(MI_DEBUG_UBSAN "Build with undefined-behavior sanitizer (needs clang++)" OFF) +option(MI_TRACK_VALGRIND "Compile with Valgrind support (adds a small overhead)" OFF) +option(MI_TRACK_ASAN "Compile with address sanitizer support (adds a small overhead)" OFF) +option(MI_TRACK_ETW "Compile with Windows event tracing (ETW) support (adds a small overhead)" OFF) + option(MI_BUILD_SHARED "Build shared library" ON) option(MI_BUILD_STATIC "Build static library" ON) option(MI_BUILD_OBJECT "Build object library" ON) option(MI_BUILD_TESTS "Build test executables" ON) -option(MI_DEBUG_TSAN "Build with thread sanitizer (needs clang)" OFF) -option(MI_DEBUG_UBSAN "Build with undefined-behavior sanitizer (needs clang++)" OFF) -option(MI_SKIP_COLLECT_ON_EXIT, "Skip collecting memory on program exit" OFF) + +option(MI_SKIP_COLLECT_ON_EXIT "Skip collecting memory on program exit" OFF) +option(MI_NO_PADDING "Force no use of padding even in DEBUG mode etc." OFF) +option(MI_INSTALL_TOPLEVEL "Install directly into $CMAKE_INSTALL_PREFIX instead of PREFIX/lib/mimalloc-version" OFF) +option(MI_NO_THP "Disable transparent huge pages support on Linux/Android for the mimalloc process only" OFF) +option(MI_EXTRA_CPPDEFS "Extra pre-processor definitions (use as `-DMI_EXTRA_CPPDEFS=\"opt1=val1;opt2=val2\"`)" "") + +# negated options for vcpkg features +option(MI_NO_USE_CXX "Use plain C compilation (has priority over MI_USE_CXX)" OFF) +option(MI_NO_OPT_ARCH "Do not use architecture specific optimizations (like '-march=armv8.1-a' for example) (has priority over MI_OPT_ARCH)" OFF) # deprecated options +option(MI_WIN_USE_FLS "Use Fiber local storage on Windows to detect thread termination (deprecated)" OFF) option(MI_CHECK_FULL "Use full internal invariant checking in DEBUG mode (deprecated, use MI_DEBUG_FULL instead)" OFF) -option(MI_INSTALL_TOPLEVEL "Install directly into $CMAKE_INSTALL_PREFIX instead of PREFIX/lib/mimalloc-version (deprecated)" OFF) option(MI_USE_LIBATOMIC "Explicitly link with -latomic (on older systems) (deprecated and detected automatically)" OFF) +include(CheckLinkerFlag) # requires cmake 3.18 include(CheckIncludeFiles) include(GNUInstallDirs) include("cmake/mimalloc-config-version.cmake") set(mi_sources - src/stats.c - src/random.c - src/os.c - src/bitmap.c - src/arena.c - src/segment-cache.c - src/segment.c - src/page.c src/alloc.c src/alloc-aligned.c src/alloc-posix.c + src/arena.c + src/arena-meta.c + src/bitmap.c src/heap.c + src/init.c + src/libc.c src/options.c - src/init.c) + src/os.c + src/page.c + src/page-map.c + src/random.c + src/stats.c + src/prim/prim.c) +set(mi_cflags "") +set(mi_cflags_static "") # extra flags for a static library build +set(mi_cflags_dynamic "") # extra flags for a shared-object library build +set(mi_libraries "") + +if(MI_EXTRA_CPPDEFS) + set(mi_defines ${MI_EXTRA_CPPDEFS}) +else() + set(mi_defines "") +endif() + +# pass git revision as a define +if(EXISTS "${CMAKE_SOURCE_DIR}/.git/index") + find_package(Git) + if(GIT_FOUND) + execute_process(COMMAND ${GIT_EXECUTABLE} "describe" OUTPUT_VARIABLE mi_git_describe RESULT_VARIABLE mi_git_res ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) + if(mi_git_res EQUAL "0") + list(APPEND mi_defines "MI_GIT_DESCRIBE=${mi_git_describe}") + # add to dependencies so we rebuild if the git head commit changes + set_property(GLOBAL APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${CMAKE_SOURCE_DIR}/.git/index") + endif() + endif() +endif() # ----------------------------------------------------------------------------- -# Convenience: set default build type depending on the build directory +# Convenience: set default build type and compiler depending on the build directory # ----------------------------------------------------------------------------- -message(STATUS "") +message(STATUS "") if (NOT CMAKE_BUILD_TYPE) - if ("${CMAKE_BINARY_DIR}" MATCHES ".*(D|d)ebug$" OR MI_DEBUG_FULL) - message(STATUS "No build type selected, default to: Debug") + if ("${CMAKE_BINARY_DIR}" MATCHES ".*((D|d)ebug|asan|tsan|ubsan|valgrind)$" OR MI_DEBUG_FULL) + message(STATUS "No build type selected, default to 'Debug'") set(CMAKE_BUILD_TYPE "Debug") else() - message(STATUS "No build type selected, default to: Release") + message(STATUS "No build type selected, default to 'Release'") set(CMAKE_BUILD_TYPE "Release") endif() endif() +if (CMAKE_GENERATOR MATCHES "^Visual Studio.*$") + message(STATUS "Note: when building with Visual Studio the build type is specified when building.") + message(STATUS "For example: 'cmake --build . --config=Release") +endif() + if("${CMAKE_BINARY_DIR}" MATCHES ".*(S|s)ecure$") message(STATUS "Default to secure build") set(MI_SECURE "ON") endif() +# Determine architecture +set(MI_OPT_ARCH_FLAGS "") +set(MI_ARCH "unknown") +if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(x86|i[3456]86)$" OR CMAKE_GENERATOR_PLATFORM MATCHES "^(x86|Win32)$") + set(MI_ARCH "x86") +elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(x86_64|x64|amd64|AMD64)$" OR CMAKE_GENERATOR_PLATFORM STREQUAL "x64" OR "x86_64" IN_LIST CMAKE_OSX_ARCHITECTURES) # must be before arm64 + set(MI_ARCH "x64") +elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch64|arm64|armv[89].?|ARM64)$" OR CMAKE_GENERATOR_PLATFORM STREQUAL "ARM64" OR "arm64" IN_LIST CMAKE_OSX_ARCHITECTURES) + set(MI_ARCH "arm64") +elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(arm|armv[34567].?|ARM)$") + set(MI_ARCH "arm32") +elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(riscv|riscv32|riscv64)$") + if(CMAKE_SIZEOF_VOID_P==4) + set(MI_ARCH "riscv32") + else() + set(MI_ARCH "riscv64") + endif() +else() + set(MI_ARCH ${CMAKE_SYSTEM_PROCESSOR}) +endif() +message(STATUS "Architecture: ${MI_ARCH}") # (${CMAKE_SYSTEM_PROCESSOR}, ${CMAKE_GENERATOR_PLATFORM}, ${CMAKE_GENERATOR})") + +# negative overrides (mainly to support vcpkg features) +if(MI_NO_USE_CXX) + set(MI_USE_CXX "OFF") +endif() +if(MI_NO_OPT_ARCH) + set(MI_OPT_ARCH "OFF") +elseif(MI_ARCH STREQUAL "arm64") + set(MI_OPT_ARCH "ON") # enable armv8.1-a by default on arm64 unless MI_NO_OPT_ARCH is set +endif() + + # ----------------------------------------------------------------------------- # Process options # ----------------------------------------------------------------------------- -if(CMAKE_C_COMPILER_ID MATCHES "MSVC|Intel") +if(CMAKE_C_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC") + set(MI_CLANG_CL "ON") +endif() + +# put -Wall early so other warnings can be disabled selectively +if(CMAKE_C_COMPILER_ID MATCHES "AppleClang|Clang") + if (MI_CLANG_CL) + list(APPEND mi_cflags -W) + else() + list(APPEND mi_cflags -Wall -Wextra -Wpedantic) + endif() +endif() +if(CMAKE_C_COMPILER_ID MATCHES "GNU") + list(APPEND mi_cflags -Wall -Wextra) +endif() +if(CMAKE_C_COMPILER_ID MATCHES "Intel") + list(APPEND mi_cflags -Wall) +endif() + +# force C++ compilation with msvc or clang-cl to use modern C++ atomics +if(CMAKE_C_COMPILER_ID MATCHES "MSVC|Intel" OR MI_CLANG_CL) set(MI_USE_CXX "ON") endif() @@ -86,8 +188,8 @@ if(MI_OVERRIDE) if(MI_OSX_ZONE) # use zone's on macOS message(STATUS " Use malloc zone to override malloc (MI_OSX_ZONE=ON)") - list(APPEND mi_sources src/alloc-override-osx.c) - list(APPEND mi_defines MI_OSX_ZONE=1) + list(APPEND mi_sources src/prim/osx/alloc-override-zone.c) + list(APPEND mi_defines MI_OSX_ZONE=1) if (NOT MI_OSX_INTERPOSE) message(STATUS " WARNING: zone overriding usually also needs interpose (use -DMI_OSX_INTERPOSE=ON)") endif() @@ -107,12 +209,6 @@ if(MI_OVERRIDE) endif() if(WIN32) - if (MI_WIN_REDIRECT) - if (MSVC_C_ARCHITECTURE_ID MATCHES "ARM") - message(STATUS "Cannot use redirection on Windows ARM (MI_WIN_REDIRECT=OFF)") - set(MI_WIN_REDIRECT OFF) - endif() - endif() if (NOT MI_WIN_REDIRECT) # use a negative define for backward compatibility list(APPEND mi_defines MI_WIN_NOREDIRECT=1) @@ -122,26 +218,75 @@ endif() if(MI_SECURE) message(STATUS "Set full secure build (MI_SECURE=ON)") list(APPEND mi_defines MI_SECURE=4) - #if (MI_VALGRIND) - # message(WARNING "Secure mode is a bit weakened when compiling with Valgrind support as buffer overflow detection is no longer byte-precise (if running without valgrind)") - #endif() endif() -if(MI_VALGRIND) +if(MI_TRACK_VALGRIND) CHECK_INCLUDE_FILES("valgrind/valgrind.h;valgrind/memcheck.h" MI_HAS_VALGRINDH) if (NOT MI_HAS_VALGRINDH) - set(MI_VALGRIND OFF) - message(WARNING "Cannot find the 'valgrind/valgrind.h' and 'valgrind/memcheck.h' -- install valgrind first") - message(STATUS "Compile **without** Valgrind support (MI_VALGRIND=OFF)") + set(MI_TRACK_VALGRIND OFF) + message(WARNING "Cannot find the 'valgrind/valgrind.h' and 'valgrind/memcheck.h' -- install valgrind first?") + message(STATUS "Disabling Valgrind support (MI_TRACK_VALGRIND=OFF)") else() - message(STATUS "Compile with Valgrind support (MI_VALGRIND=ON)") - list(APPEND mi_defines MI_VALGRIND=1) + message(STATUS "Compile with Valgrind support (MI_TRACK_VALGRIND=ON)") + list(APPEND mi_defines MI_TRACK_VALGRIND=1) + endif() +endif() + +if(MI_TRACK_ASAN) + if (APPLE AND MI_OVERRIDE) + set(MI_TRACK_ASAN OFF) + message(WARNING "Cannot enable address sanitizer support on macOS if MI_OVERRIDE is ON (MI_TRACK_ASAN=OFF)") + endif() + if (MI_TRACK_VALGRIND) + set(MI_TRACK_ASAN OFF) + message(WARNING "Cannot enable address sanitizer support with also Valgrind support enabled (MI_TRACK_ASAN=OFF)") + endif() + if(MI_TRACK_ASAN) + CHECK_INCLUDE_FILES("sanitizer/asan_interface.h" MI_HAS_ASANH) + if (NOT MI_HAS_ASANH) + set(MI_TRACK_ASAN OFF) + message(WARNING "Cannot find the 'sanitizer/asan_interface.h' -- install address sanitizer support first") + message(STATUS "Compile **without** address sanitizer support (MI_TRACK_ASAN=OFF)") + else() + message(STATUS "Compile with address sanitizer support (MI_TRACK_ASAN=ON)") + list(APPEND mi_defines MI_TRACK_ASAN=1) + list(APPEND mi_cflags -fsanitize=address) + list(APPEND mi_libraries -fsanitize=address) + endif() + endif() +endif() + +if(MI_TRACK_ETW) + if(NOT WIN32) + set(MI_TRACK_ETW OFF) + message(WARNING "Can only enable ETW support on Windows (MI_TRACK_ETW=OFF)") + endif() + if (MI_TRACK_VALGRIND OR MI_TRACK_ASAN) + set(MI_TRACK_ETW OFF) + message(WARNING "Cannot enable ETW support with also Valgrind or ASAN support enabled (MI_TRACK_ETW=OFF)") + endif() + if(MI_TRACK_ETW) + message(STATUS "Compile with Windows event tracing support (MI_TRACK_ETW=ON)") + list(APPEND mi_defines MI_TRACK_ETW=1) + endif() +endif() + +if(MI_GUARDED) + message(STATUS "Compile guard pages behind certain object allocations (MI_GUARDED=ON)") + list(APPEND mi_defines MI_GUARDED=1) + if(NOT MI_NO_PADDING) + message(STATUS " Disabling padding due to guard pages (MI_NO_PADDING=ON)") + set(MI_NO_PADDING ON) endif() endif() if(MI_SEE_ASM) message(STATUS "Generate assembly listings (MI_SEE_ASM=ON)") list(APPEND mi_cflags -save-temps) + if(CMAKE_C_COMPILER_ID MATCHES "AppleClang|Clang" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER 14) + message(STATUS "No GNU Line marker") + list(APPEND mi_cflags -Wno-gnu-line-marker) + endif() endif() if(MI_CHECK_FULL) @@ -159,9 +304,14 @@ if(MI_DEBUG_FULL) list(APPEND mi_defines MI_DEBUG=3) # full invariant checking endif() -if(NOT MI_PADDING) - message(STATUS "Disable padding of heap blocks in debug mode (MI_PADDING=OFF)") +if(MI_NO_PADDING) + message(STATUS "Suppress any padding of heap blocks (MI_NO_PADDING=ON)") list(APPEND mi_defines MI_PADDING=0) +else() + if(MI_PADDING) + message(STATUS "Enable explicit padding of heap blocks (MI_PADDING=ON)") + list(APPEND mi_defines MI_PADDING=1) + endif() endif() if(MI_XMALLOC) @@ -179,27 +329,28 @@ if(MI_DEBUG_TSAN) message(STATUS "Build with thread sanitizer (MI_DEBUG_TSAN=ON)") list(APPEND mi_defines MI_TSAN=1) list(APPEND mi_cflags -fsanitize=thread -g -O1) - list(APPEND CMAKE_EXE_LINKER_FLAGS -fsanitize=thread) + list(APPEND mi_libraries -fsanitize=thread) else() - message(WARNING "Can only use thread sanitizer with clang (MI_DEBUG_TSAN=ON but ignored)") - endif() + message(WARNING "Can only use thread sanitizer with clang (MI_DEBUG_TSAN=ON but ignored)") + endif() endif() if(MI_DEBUG_UBSAN) - if(CMAKE_BUILD_TYPE MATCHES "Debug") + if(CMAKE_BUILD_TYPE MATCHES "Debug") if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") message(STATUS "Build with undefined-behavior sanitizer (MI_DEBUG_UBSAN=ON)") + list(APPEND mi_defines MI_UBSAN=1) list(APPEND mi_cflags -fsanitize=undefined -g -fno-sanitize-recover=undefined) - list(APPEND CMAKE_EXE_LINKER_FLAGS -fsanitize=undefined) + list(APPEND mi_libraries -fsanitize=undefined) if (NOT MI_USE_CXX) message(STATUS "(switch to use C++ due to MI_DEBUG_UBSAN)") set(MI_USE_CXX "ON") endif() else() - message(WARNING "Can only use undefined-behavior sanitizer with clang++ (MI_DEBUG_UBSAN=ON but ignored)") - endif() + message(WARNING "Can only use undefined-behavior sanitizer with clang++ (MI_DEBUG_UBSAN=ON but ignored)") + endif() else() - message(WARNING "Can only use thread sanitizer with a debug build (CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE})") + message(WARNING "Can only use undefined-behavior sanitizer with a debug build (CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE})") endif() endif() @@ -215,74 +366,175 @@ if(MI_USE_CXX) endif() endif() +if(CMAKE_SYSTEM_NAME MATCHES "Linux|Android") + if(MI_NO_THP) + message(STATUS "Disable transparent huge pages support (MI_NO_THP=ON)") + list(APPEND mi_defines MI_NO_THP=1) + endif() +endif() + +if(MI_LIBC_MUSL) + message(STATUS "Assume using musl libc (MI_LIBC_MUSL=ON)") + list(APPEND mi_defines MI_LIBC_MUSL=1) +endif() + +if(MI_WIN_USE_FLS) + message(STATUS "Use the Fiber API to detect thread termination (deprecated) (MI_WIN_USE_FLS=ON)") + list(APPEND mi_defines MI_WIN_USE_FLS=1) +endif() + +if(MI_WIN_USE_FIXED_TLS) + message(STATUS "Use fixed TLS slot on Windows to avoid extra tests in the malloc fast path (MI_WIN_USE_FIXED_TLS=ON)") + list(APPEND mi_defines MI_WIN_USE_FIXED_TLS=1) +endif() + +# Check /proc/cpuinfo for an SV39 MMU and limit the virtual address bits. +# (this will skip the aligned hinting in that case. Issue #939, #949) +if (EXISTS /proc/cpuinfo) + file(STRINGS /proc/cpuinfo mi_sv39_mmu REGEX "^mmu[ \t]+:[ \t]+sv39$") + if (mi_sv39_mmu) + MESSAGE( STATUS "Set virtual address bits to 39 (SV39 MMU detected)" ) + list(APPEND mi_defines MI_DEFAULT_VIRTUAL_ADDRESS_BITS=39) + endif() +endif() + +# On Haiku use `-DCMAKE_INSTALL_PREFIX` instead, issue #788 +# if(CMAKE_SYSTEM_NAME MATCHES "Haiku") +# SET(CMAKE_INSTALL_LIBDIR ~/config/non-packaged/lib) +# SET(CMAKE_INSTALL_INCLUDEDIR ~/config/non-packaged/headers) +# endif() + # Compiler flags -if(CMAKE_C_COMPILER_ID MATCHES "AppleClang|Clang|GNU") - list(APPEND mi_cflags -Wall -Wextra -Wno-unknown-pragmas -fvisibility=hidden) +if(CMAKE_C_COMPILER_ID MATCHES "AppleClang|Clang|GNU" AND NOT MI_CLANG_CL) + list(APPEND mi_cflags -Wno-unknown-pragmas -fvisibility=hidden) if(NOT MI_USE_CXX) list(APPEND mi_cflags -Wstrict-prototypes) - endif() + endif() if(CMAKE_C_COMPILER_ID MATCHES "AppleClang|Clang") - list(APPEND mi_cflags -Wpedantic -Wno-static-in-inline) + list(APPEND mi_cflags -Wno-static-in-inline) endif() endif() if(CMAKE_C_COMPILER_ID MATCHES "Intel") - list(APPEND mi_cflags -Wall -fvisibility=hidden) + list(APPEND mi_cflags -fvisibility=hidden) endif() -if(CMAKE_C_COMPILER_ID MATCHES "AppleClang|Clang|GNU|Intel" AND NOT CMAKE_SYSTEM_NAME MATCHES "Haiku") +if(CMAKE_C_COMPILER_ID MATCHES "AppleClang|Clang|GNU|Intel" AND NOT CMAKE_SYSTEM_NAME MATCHES "Haiku" AND NOT MI_CLANG_CL) if(MI_LOCAL_DYNAMIC_TLS) list(APPEND mi_cflags -ftls-model=local-dynamic) else() - list(APPEND mi_cflags -ftls-model=initial-exec) + if(MI_LIBC_MUSL) + # with musl we use local-dynamic for the static build, see issue #644 + list(APPEND mi_cflags_static -ftls-model=local-dynamic) + list(APPEND mi_cflags_dynamic -ftls-model=initial-exec) + message(STATUS "Use local dynamic TLS for the static build (since MI_LIBC_MUSL=ON)") + else() + list(APPEND mi_cflags -ftls-model=initial-exec) + endif() endif() +endif() + +if(CMAKE_C_COMPILER_ID MATCHES "AppleClang|Clang|GNU|Intel") if(MI_OVERRIDE) list(APPEND mi_cflags -fno-builtin-malloc) endif() endif() -if (MSVC AND MSVC_VERSION GREATER_EQUAL 1914) +# Compiler and architecture specific flags +if(CMAKE_C_COMPILER_ID MATCHES "AppleClang|Clang|GNU|Intel" AND NOT CMAKE_SYSTEM_NAME MATCHES "Haiku") + if(MI_OPT_ARCH) + if(APPLE AND CMAKE_C_COMPILER_ID MATCHES "AppleClang|Clang" AND CMAKE_OSX_ARCHITECTURES) # to support multi-arch binaries (#999) + if("arm64" IN_LIST CMAKE_OSX_ARCHITECTURES) + list(APPEND MI_OPT_ARCH_FLAGS "-Xarch_arm64;-march=armv8.1-a") + endif() + if("x86_64" IN_LIST CMAKE_OSX_ARCHITECTURES) + list(APPEND MI_OPT_ARCH_FLAGS "-Xarch_x86_64;-march=haswell;-Xarch_x86_64;-mavx2") + endif() + elseif(MI_ARCH STREQUAL "x64") + set(MI_OPT_ARCH_FLAGS "-march=haswell;-mavx2") # fast bit scan (since 2013) + elseif(MI_ARCH STREQUAL "arm64") + set(MI_OPT_ARCH_FLAGS "-march=armv8.1-a") # fast atomics (since 2016) + endif() + endif() +endif() + +if (MSVC AND MSVC_VERSION GREATER_EQUAL 1914) # vs2017+ list(APPEND mi_cflags /Zc:__cplusplus) + if(MI_OPT_ARCH AND NOT MI_CLANG_CL) + if(MI_ARCH STREQUAL "x64") + set(MI_OPT_ARCH_FLAGS "/arch:AVX2") + elseif(MI_ARCH STREQUAL "arm64") + set(MI_OPT_ARCH_FLAGS "/arch:armv8.1") + endif() + endif() +endif() + +if(MINGW) + add_definitions(-D_WIN32_WINNT=0x600) # issue #976 +endif() + +if(MI_OPT_ARCH_FLAGS) + list(APPEND mi_cflags ${MI_OPT_ARCH_FLAGS}) + message(STATUS "Architecture specific optimization is enabled (with ${MI_OPT_ARCH_FLAGS}) (MI_OPT_ARCH=ON)") + if (MI_OPT_SIMD) + list(APPEND mi_defines "MI_OPT_SIMD=1") + message(STATUS "SIMD instructions are enabled (MI_OPT_SIMD=ON)") + endif() +elseif(MI_OPT_SIMD) + message(STATUS "SIMD instructions are not enabled (either MI_OPT_ARCH=OFF or this architecture has no SIMD support)") endif() # extra needed libraries + +# we prefer -l test over `find_library` as sometimes core libraries +# like `libatomic` are not on the system path (see issue #898) +function(find_link_library libname outlibname) + check_linker_flag(C "-l${libname}" mi_has_lib${libname}) + if (mi_has_lib${libname}) + message(VERBOSE "link library: -l${libname}") + set(${outlibname} ${libname} PARENT_SCOPE) + else() + find_library(MI_LIBPATH libname) + if (MI_LIBPATH) + message(VERBOSE "link library ${libname} at ${MI_LIBPATH}") + set(${outlibname} ${MI_LIBPATH} PARENT_SCOPE) + else() + message(VERBOSE "link library not found: ${libname}") + set(${outlibname} "" PARENT_SCOPE) + endif() + endif() +endfunction() + if(WIN32) list(APPEND mi_libraries psapi shell32 user32 advapi32 bcrypt) - set(pc_libraries "-lpsapi -lshell32 -luser32 -ladvapi32 -lbcrypt") else() - set(pc_libraries "") - find_library(MI_LIBPTHREAD pthread) - if (MI_LIBPTHREAD) - list(APPEND mi_libraries ${MI_LIBPTHREAD}) - set(pc_libraries "${pc_libraries} -pthread") + find_link_library("pthread" MI_LIB_PTHREAD) + if(MI_LIB_PTHREAD) + list(APPEND mi_libraries "${MI_LIB_PTHREAD}") endif() - find_library(MI_LIBRT rt) - if(MI_LIBRT) - list(APPEND mi_libraries ${MI_LIBRT}) - set(pc_libraries "${pc_libraries} -lrt") + find_link_library("rt" MI_LIB_RT) + if(MI_LIB_RT) + list(APPEND mi_libraries "${MI_LIB_RT}") endif() - find_library(MI_LIBATOMIC atomic) - if (NOT MI_LIBATOMIC AND MI_USE_LIBATOMIC) - set(MI_LIBATOMIC atomic) - endif() - if (MI_LIBATOMIC) - list(APPEND mi_libraries ${MI_LIBATOMIC}) - set(pc_libraries "${pc_libraries} -latomic") + find_link_library("atomic" MI_LIB_ATOMIC) + if(MI_LIB_ATOMIC) + list(APPEND mi_libraries "${MI_LIB_ATOMIC}") endif() endif() + # ----------------------------------------------------------------------------- # Install and output names # ----------------------------------------------------------------------------- # dynamic/shared library and symlinks always go to /usr/local/lib equivalent -set(mi_install_libdir "${CMAKE_INSTALL_LIBDIR}") +# we use ${CMAKE_INSTALL_BINDIR} and ${CMAKE_INSTALL_LIBDIR}. # static libraries and object files, includes, and cmake config files # are either installed at top level, or use versioned directories for side-by-side installation (default) if (MI_INSTALL_TOPLEVEL) set(mi_install_objdir "${CMAKE_INSTALL_LIBDIR}") - set(mi_install_incdir "${CMAKE_INSTALL_INCLUDEDIR}") + set(mi_install_incdir "${CMAKE_INSTALL_INCLUDEDIR}") set(mi_install_cmakedir "${CMAKE_INSTALL_LIBDIR}/cmake/mimalloc") else() set(mi_install_objdir "${CMAKE_INSTALL_LIBDIR}/mimalloc-${mi_version}") # for static library and object files @@ -290,16 +542,22 @@ else() set(mi_install_cmakedir "${CMAKE_INSTALL_LIBDIR}/cmake/mimalloc-${mi_version}") # for cmake package info endif() -set(mi_basename "mimalloc") +set(mi_libname "mimalloc") if(MI_SECURE) - set(mi_basename "${mi_basename}-secure") + set(mi_libname "${mi_libname}-secure") +endif() +if(MI_TRACK_VALGRIND) + set(mi_libname "${mi_libname}-valgrind") endif() -if(MI_VALGRIND) - set(mi_basename "${mi_basename}-valgrind") +if(MI_TRACK_ASAN) + set(mi_libname "${mi_libname}-asan") endif() string(TOLOWER "${CMAKE_BUILD_TYPE}" CMAKE_BUILD_TYPE_LC) -if(NOT(CMAKE_BUILD_TYPE_LC MATCHES "^(release|relwithdebinfo|minsizerel|none)$")) - set(mi_basename "${mi_basename}-${CMAKE_BUILD_TYPE_LC}") #append build type (e.g. -debug) if not a release version +list(APPEND mi_defines "MI_CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE_LC}") #todo: multi-config project needs $ ? +if(CMAKE_BUILD_TYPE_LC MATCHES "^(release|relwithdebinfo|minsizerel|none)$") + list(APPEND mi_defines MI_BUILD_RELEASE) +else() + set(mi_libname "${mi_libname}-${CMAKE_BUILD_TYPE_LC}") #append build type (e.g. -debug) if not a release version endif() if(MI_BUILD_SHARED) @@ -316,8 +574,8 @@ if(MI_BUILD_TESTS) endif() message(STATUS "") -message(STATUS "Library base name: ${mi_basename}") -message(STATUS "Version : ${mi_version}") +message(STATUS "Library name : ${mi_libname}") +message(STATUS "Version : ${mi_version}.${mi_version_patch}") message(STATUS "Build type : ${CMAKE_BUILD_TYPE_LC}") if(MI_USE_CXX) message(STATUS "C++ Compiler : ${CMAKE_CXX_COMPILER}") @@ -337,53 +595,66 @@ message(STATUS "") # shared library if(MI_BUILD_SHARED) add_library(mimalloc SHARED ${mi_sources}) - set_target_properties(mimalloc PROPERTIES VERSION ${mi_version} SOVERSION ${mi_version_major} OUTPUT_NAME ${mi_basename} ) + set_target_properties(mimalloc PROPERTIES VERSION ${mi_version} SOVERSION ${mi_version_major} OUTPUT_NAME ${mi_libname} ) target_compile_definitions(mimalloc PRIVATE ${mi_defines} MI_SHARED_LIB MI_SHARED_LIB_EXPORT) - target_compile_options(mimalloc PRIVATE ${mi_cflags}) - target_link_libraries(mimalloc PUBLIC ${mi_libraries}) + target_compile_options(mimalloc PRIVATE ${mi_cflags} ${mi_cflags_dynamic}) + target_link_libraries(mimalloc PRIVATE ${mi_libraries}) target_include_directories(mimalloc PUBLIC $ $ ) + install(TARGETS mimalloc EXPORT mimalloc ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) + install(EXPORT mimalloc DESTINATION ${mi_install_cmakedir}) + + if(WIN32 AND NOT MINGW) + # On windows, the import library name for the dll would clash with the static mimalloc.lib library + # so we postfix the dll import library with `.dll.lib` (and also the .pdb debug file) + set_property(TARGET mimalloc PROPERTY ARCHIVE_OUTPUT_NAME "${mi_libname}.dll" ) + install(FILES "$/${mi_libname}.dll.lib" DESTINATION ${CMAKE_INSTALL_LIBDIR}) + set_property(TARGET mimalloc PROPERTY PDB_NAME "${mi_libname}.dll") + # don't try to install the pdb since it may not be generated depending on the configuration + # install(FILES "$/${mi_libname}.dll.pdb" DESTINATION ${CMAKE_INSTALL_LIBDIR}) + endif() if(WIN32 AND MI_WIN_REDIRECT) + if(MINGW) + set_property(TARGET mimalloc PROPERTY PREFIX "") + endif() # On windows, link and copy the mimalloc redirection dll too. - if(CMAKE_SIZEOF_VOID_P EQUAL 4) + if(CMAKE_GENERATOR_PLATFORM STREQUAL "arm64ec") + set(MIMALLOC_REDIRECT_SUFFIX "-arm64ec") + elseif(MI_ARCH STREQUAL "x64") + set(MIMALLOC_REDIRECT_SUFFIX "") + if(CMAKE_SYSTEM_PROCESSOR STREQUAL "ARM64") + message(STATUS "Note: x64 code emulated on Windows for arm64 should use an arm64ec build of 'mimalloc.dll'") + message(STATUS " together with 'mimalloc-redirect-arm64ec.dll'. See the 'bin\\readme.md' for more information.") + endif() + elseif(MI_ARCH STREQUAL "x86") set(MIMALLOC_REDIRECT_SUFFIX "32") else() - set(MIMALLOC_REDIRECT_SUFFIX "") + set(MIMALLOC_REDIRECT_SUFFIX "-${MI_ARCH}") # -arm64 etc. endif() - target_link_libraries(mimalloc PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/bin/mimalloc-redirect${MIMALLOC_REDIRECT_SUFFIX}.lib) + target_link_libraries(mimalloc PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/bin/mimalloc-redirect${MIMALLOC_REDIRECT_SUFFIX}.lib) # the DLL import library add_custom_command(TARGET mimalloc POST_BUILD COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_CURRENT_SOURCE_DIR}/bin/mimalloc-redirect${MIMALLOC_REDIRECT_SUFFIX}.dll" $ COMMENT "Copy mimalloc-redirect${MIMALLOC_REDIRECT_SUFFIX}.dll to output directory") - install(FILES "$/mimalloc-redirect${MIMALLOC_REDIRECT_SUFFIX}.dll" DESTINATION ${mi_install_libdir}) + install(FILES "$/mimalloc-redirect${MIMALLOC_REDIRECT_SUFFIX}.dll" DESTINATION ${CMAKE_INSTALL_BINDIR}) endif() - - install(TARGETS mimalloc EXPORT mimalloc DESTINATION ${mi_install_libdir} LIBRARY) - install(EXPORT mimalloc DESTINATION ${mi_install_cmakedir}) endif() + # static library if (MI_BUILD_STATIC) add_library(mimalloc-static STATIC ${mi_sources}) + set_property(TARGET mimalloc-static PROPERTY OUTPUT_NAME ${mi_libname}) set_property(TARGET mimalloc-static PROPERTY POSITION_INDEPENDENT_CODE ON) target_compile_definitions(mimalloc-static PRIVATE ${mi_defines} MI_STATIC_LIB) - target_compile_options(mimalloc-static PRIVATE ${mi_cflags}) - target_link_libraries(mimalloc-static PUBLIC ${mi_libraries}) + target_compile_options(mimalloc-static PRIVATE ${mi_cflags} ${mi_cflags_static}) + target_link_libraries(mimalloc-static PRIVATE ${mi_libraries}) target_include_directories(mimalloc-static PUBLIC $ $ ) - if(WIN32) - # When building both static and shared libraries on Windows, a static library should use a - # different output name to avoid the conflict with the import library of a shared one. - string(REPLACE "mimalloc" "mimalloc-static" mi_output_name ${mi_basename}) - set_target_properties(mimalloc-static PROPERTIES OUTPUT_NAME ${mi_output_name}) - else() - set_target_properties(mimalloc-static PROPERTIES OUTPUT_NAME ${mi_basename}) - endif() - install(TARGETS mimalloc-static EXPORT mimalloc DESTINATION ${mi_install_objdir} LIBRARY) install(EXPORT mimalloc DESTINATION ${mi_install_cmakedir}) endif() @@ -392,6 +663,7 @@ endif() install(FILES include/mimalloc.h DESTINATION ${mi_install_incdir}) install(FILES include/mimalloc-override.h DESTINATION ${mi_install_incdir}) install(FILES include/mimalloc-new-delete.h DESTINATION ${mi_install_incdir}) +install(FILES include/mimalloc-stats.h DESTINATION ${mi_install_incdir}) install(FILES cmake/mimalloc-config.cmake DESTINATION ${mi_install_cmakedir}) install(FILES cmake/mimalloc-config-version.cmake DESTINATION ${mi_install_cmakedir}) @@ -401,31 +673,54 @@ if (MI_BUILD_OBJECT) add_library(mimalloc-obj OBJECT src/static.c) set_property(TARGET mimalloc-obj PROPERTY POSITION_INDEPENDENT_CODE ON) target_compile_definitions(mimalloc-obj PRIVATE ${mi_defines}) - target_compile_options(mimalloc-obj PRIVATE ${mi_cflags}) + target_compile_options(mimalloc-obj PRIVATE ${mi_cflags} ${mi_cflags_static}) target_include_directories(mimalloc-obj PUBLIC $ $ ) + # Copy the generated object file (`static.o`) to the output directory (as `mimalloc.o`) + if(CMAKE_GENERATOR MATCHES "^Visual Studio.*$") + set(mimalloc-obj-static "${CMAKE_CURRENT_BINARY_DIR}/mimalloc-obj.dir/$/static${CMAKE_C_OUTPUT_EXTENSION}") + else() + set(mimalloc-obj-static "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/mimalloc-obj.dir/src/static.c${CMAKE_C_OUTPUT_EXTENSION}") + endif() + set(mimalloc-obj-out "${CMAKE_CURRENT_BINARY_DIR}/${mi_libname}${CMAKE_C_OUTPUT_EXTENSION}") + add_custom_command(OUTPUT ${mimalloc-obj-out} DEPENDS mimalloc-obj COMMAND "${CMAKE_COMMAND}" -E copy "${mimalloc-obj-static}" "${mimalloc-obj-out}") + add_custom_target(mimalloc-obj-target ALL DEPENDS ${mimalloc-obj-out}) + + # the following seems to lead to cmake warnings/errors on some systems, disable for now :-( # install(TARGETS mimalloc-obj EXPORT mimalloc DESTINATION ${mi_install_objdir}) # the FILES expression can also be: $ # but that fails cmake versions less than 3.10 so we leave it as is for now - install(FILES ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/mimalloc-obj.dir/src/static.c${CMAKE_C_OUTPUT_EXTENSION} + install(FILES ${mimalloc-obj-static} DESTINATION ${mi_install_objdir} - RENAME ${mi_basename}${CMAKE_C_OUTPUT_EXTENSION} ) + RENAME ${mi_libname}${CMAKE_C_OUTPUT_EXTENSION} ) endif() + # pkg-config file support +set(mi_pc_libraries "") +foreach(item IN LISTS mi_libraries) + if(item MATCHES " *[-].*") + set(mi_pc_libraries "${mi_pc_libraries} ${item}") + else() + set(mi_pc_libraries "${mi_pc_libraries} -l${item}") + endif() +endforeach() + include("cmake/JoinPaths.cmake") -join_paths(includedir_for_pc_file "\${prefix}" "${CMAKE_INSTALL_INCLUDEDIR}") -join_paths(libdir_for_pc_file "\${prefix}" "${CMAKE_INSTALL_LIBDIR}") +join_paths(mi_pc_includedir "\${prefix}" "${CMAKE_INSTALL_INCLUDEDIR}") +join_paths(mi_pc_libdir "\${prefix}" "${CMAKE_INSTALL_LIBDIR}") configure_file(mimalloc.pc.in mimalloc.pc @ONLY) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/mimalloc.pc" DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig/") + + # ----------------------------------------------------------------------------- # API surface testing # ----------------------------------------------------------------------------- @@ -433,15 +728,41 @@ install(FILES "${CMAKE_CURRENT_BINARY_DIR}/mimalloc.pc" if (MI_BUILD_TESTS) enable_testing() + # static link tests foreach(TEST_NAME api api-fill stress) add_executable(mimalloc-test-${TEST_NAME} test/test-${TEST_NAME}.c) target_compile_definitions(mimalloc-test-${TEST_NAME} PRIVATE ${mi_defines}) target_compile_options(mimalloc-test-${TEST_NAME} PRIVATE ${mi_cflags}) target_include_directories(mimalloc-test-${TEST_NAME} PRIVATE include) - target_link_libraries(mimalloc-test-${TEST_NAME} PRIVATE mimalloc ${mi_libraries}) - + if(MI_BUILD_STATIC AND NOT MI_DEBUG_TSAN) + target_link_libraries(mimalloc-test-${TEST_NAME} PRIVATE mimalloc-static ${mi_libraries}) + elseif(MI_BUILD_SHARED) + target_link_libraries(mimalloc-test-${TEST_NAME} PRIVATE mimalloc ${mi_libraries}) + else() + message(STATUS "cannot build TSAN tests without MI_BUILD_SHARED being enabled") + endif() add_test(NAME test-${TEST_NAME} COMMAND mimalloc-test-${TEST_NAME}) endforeach() + + # dynamic override test + if(MI_BUILD_SHARED AND NOT (MI_TRACK_ASAN OR MI_DEBUG_TSAN OR MI_DEBUG_UBSAN)) + add_executable(mimalloc-test-stress-dynamic test/test-stress.c) + target_compile_definitions(mimalloc-test-stress-dynamic PRIVATE ${mi_defines} "USE_STD_MALLOC=1") + target_compile_options(mimalloc-test-stress-dynamic PRIVATE ${mi_cflags}) + target_include_directories(mimalloc-test-stress-dynamic PRIVATE include) + if(WIN32) + target_compile_definitions(mimalloc-test-stress-dynamic PRIVATE "MI_LINK_VERSION=1") # link mi_version + target_link_libraries(mimalloc-test-stress-dynamic PRIVATE mimalloc ${mi_libraries}) # link mi_version + add_test(NAME test-stress-dynamic COMMAND ${CMAKE_COMMAND} -E env MIMALLOC_VERBOSE=1 $) + else() + if(APPLE) + set(LD_PRELOAD "DYLD_INSERT_LIBRARIES") + else() + set(LD_PRELOAD "LD_PRELOAD") + endif() + add_test(NAME test-stress-dynamic COMMAND ${CMAKE_COMMAND} -E env MIMALLOC_VERBOSE=1 ${LD_PRELOAD}=$ $) + endif() + endif() endif() # ----------------------------------------------------------------------------- diff --git a/src/dashbls/depends/mimalloc/LICENSE b/src/dashbls/depends/mimalloc/LICENSE index 670b668a0c92..53315ebee557 100644 --- a/src/dashbls/depends/mimalloc/LICENSE +++ b/src/dashbls/depends/mimalloc/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2018-2021 Microsoft Corporation, Daan Leijen +Copyright (c) 2018-2025 Microsoft Corporation, Daan Leijen Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/dashbls/depends/mimalloc/SECURITY.md b/src/dashbls/depends/mimalloc/SECURITY.md new file mode 100644 index 000000000000..b3c89efc852e --- /dev/null +++ b/src/dashbls/depends/mimalloc/SECURITY.md @@ -0,0 +1,41 @@ + + +## Security + +Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet) and [Xamarin](https://github.com/xamarin). + +If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/security.md/definition), please report it to us as described below. + +## Reporting Security Issues + +**Please do not report security vulnerabilities through public GitHub issues.** + +Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/security.md/msrc/create-report). + +If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/security.md/msrc/pgp). + +You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc). + +Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: + + * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) + * Full paths of source file(s) related to the manifestation of the issue + * The location of the affected source code (tag/branch/commit or direct URL) + * Any special configuration required to reproduce the issue + * Step-by-step instructions to reproduce the issue + * Proof-of-concept or exploit code (if possible) + * Impact of the issue, including how an attacker might exploit the issue + +This information will help us triage your report more quickly. + +If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/security.md/msrc/bounty) page for more details about our active programs. + +## Preferred Languages + +We prefer all communications to be in English. + +## Policy + +Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/security.md/cvd). + + diff --git a/src/dashbls/depends/mimalloc/azure-pipelines.yml b/src/dashbls/depends/mimalloc/azure-pipelines.yml index eb2a3d4315b1..b71517ad5616 100644 --- a/src/dashbls/depends/mimalloc/azure-pipelines.yml +++ b/src/dashbls/depends/mimalloc/azure-pipelines.yml @@ -6,16 +6,15 @@ trigger: branches: include: - - master - - dev - - dev-slice + - main + - dev* tags: include: - v* -jobs: +jobs: - job: - displayName: Windows + displayName: Windows 2022 pool: vmImage: windows-2022 @@ -29,10 +28,30 @@ jobs: BuildType: release cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Release MSBuildConfiguration: Release + Release SIMD: + BuildType: release-simd + cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Release -DMI_OPT_ARCH=ON -DMI_OPT_SIMD=ON -DMI_WIN_USE_FIXED_TLS=ON + MSBuildConfiguration: Release Secure: BuildType: secure cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Release -DMI_SECURE=ON MSBuildConfiguration: Release + Debug x86: + BuildType: debug + cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Debug -DMI_DEBUG_FULL=ON -A Win32 + MSBuildConfiguration: Debug + Release x86: + BuildType: release + cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Release -A Win32 + MSBuildConfiguration: Release + Debug Fixed TLS: + BuildType: debug + cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Debug -DMI_DEBUG_FULL=ON -DMI_WIN_USE_FIXED_TLS=ON + MSBuildConfiguration: Debug + Release Fixed TLS: + BuildType: release + cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Release -DMI_WIN_USE_FIXED_TLS=ON + MSBuildConfiguration: Release steps: - task: CMake@1 inputs: @@ -43,7 +62,7 @@ jobs: solution: $(BuildType)/libmimalloc.sln configuration: '$(MSBuildConfiguration)' msbuildArguments: -m - - script: ctest --verbose --timeout 120 -C $(MSBuildConfiguration) + - script: ctest --verbose --timeout 240 -C $(MSBuildConfiguration) workingDirectory: $(BuildType) displayName: CTest #- script: $(BuildType)\$(BuildType)\mimalloc-test-stress @@ -52,10 +71,10 @@ jobs: # artifact: mimalloc-windows-$(BuildType) - job: - displayName: Linux + displayName: Ubuntu 22.04 pool: vmImage: - ubuntu-18.04 + ubuntu-22.04 strategy: matrix: Debug: @@ -88,6 +107,11 @@ jobs: CXX: clang++ BuildType: release-clang cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Release + Release SIMD Clang: + CC: clang + CXX: clang++ + BuildType: release-simd-clang + cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Release -DMI_OPT_ARCH=ON -DMI_OPT_SIMD=ON Secure Clang: CC: clang CXX: clang++ @@ -98,6 +122,27 @@ jobs: CXX: clang++ BuildType: debug-clang-cxx cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Debug -DMI_DEBUG_FULL=ON -DMI_USE_CXX=ON + Debug ASAN Clang: + CC: clang + CXX: clang++ + BuildType: debug-asan-clang + cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Debug -DMI_DEBUG_FULL=ON -DMI_TRACK_ASAN=ON + Debug UBSAN Clang: + CC: clang + CXX: clang++ + BuildType: debug-ubsan-clang + cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Debug -DMI_DEBUG_FULL=ON -DMI_DEBUG_UBSAN=ON + Debug TSAN Clang++: + CC: clang + CXX: clang++ + BuildType: debug-tsan-clang-cxx + cmakeExtraArgs: -DCMAKE_BUILD_TYPE=RelWithDebInfo -DMI_USE_CXX=ON -DMI_DEBUG_TSAN=ON + Debug Guarded Clang: + CC: clang + CXX: clang + BuildType: debug-guarded-clang + cmakeExtraArgs: -DCMAKE_BUILD_TYPE=RelWithDebInfo -DMI_DEBUG_FULL=ON -DMI_GUARDED=ON + steps: - task: CMake@1 inputs: @@ -105,17 +150,19 @@ jobs: cmakeArgs: .. $(cmakeExtraArgs) - script: make -j$(nproc) -C $(BuildType) displayName: Make - - script: ctest --verbose --timeout 120 + - script: ctest --verbose --timeout 240 workingDirectory: $(BuildType) displayName: CTest + env: + MIMALLOC_GUARDED_SAMPLE_RATE: 1000 # - upload: $(Build.SourcesDirectory)/$(BuildType) # artifact: mimalloc-ubuntu-$(BuildType) - job: - displayName: macOS + displayName: macOS 14 (Sonoma) pool: vmImage: - macOS-latest + macOS-14 strategy: matrix: Debug: @@ -124,6 +171,9 @@ jobs: Release: BuildType: release cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Release + Release SIMD: + BuildType: release-simd + cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Release -DMI_OPT_ARCH=ON -DMI_OPT_SIMD=ON Secure: BuildType: secure cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Release -DMI_SECURE=ON @@ -134,48 +184,104 @@ jobs: cmakeArgs: .. $(cmakeExtraArgs) - script: make -j$(sysctl -n hw.ncpu) -C $(BuildType) displayName: Make - # - script: MIMALLOC_VERBOSE=1 ./mimalloc-test-api - # workingDirectory: $(BuildType) - # displayName: TestAPI - # - script: MIMALLOC_VERBOSE=1 ./mimalloc-test-stress - # workingDirectory: $(BuildType) - # displayName: TestStress - - script: ctest --verbose --timeout 120 + - script: ctest --verbose --timeout 240 workingDirectory: $(BuildType) displayName: CTest - # - upload: $(Build.SourcesDirectory)/$(BuildType) # artifact: mimalloc-macos-$(BuildType) -# - job: -# displayName: Windows-2017 -# pool: -# vmImage: -# vs2017-win2016 -# strategy: -# matrix: -# Debug: -# BuildType: debug -# cmakeExtraArgs: -A x64 -DCMAKE_BUILD_TYPE=Debug -DMI_DEBUG_FULL=ON -# MSBuildConfiguration: Debug -# Release: -# BuildType: release -# cmakeExtraArgs: -A x64 -DCMAKE_BUILD_TYPE=Release -# MSBuildConfiguration: Release -# Secure: -# BuildType: secure -# cmakeExtraArgs: -A x64 -DCMAKE_BUILD_TYPE=Release -DMI_SECURE=ON -# MSBuildConfiguration: Release -# steps: -# - task: CMake@1 -# inputs: -# workingDirectory: $(BuildType) -# cmakeArgs: .. $(cmakeExtraArgs) -# - task: MSBuild@1 -# inputs: -# solution: $(BuildType)/libmimalloc.sln -# configuration: '$(MSBuildConfiguration)' -# - script: | -# cd $(BuildType) -# ctest --verbose --timeout 120 -# displayName: CTest +# ---------------------------------------------------------- +# Other OS versions (just debug mode) +# ---------------------------------------------------------- + +- job: + displayName: Ubuntu 24.04 + pool: + vmImage: + ubuntu-24.04 + strategy: + matrix: + Debug: + CC: gcc + CXX: g++ + BuildType: debug + cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Debug -DMI_DEBUG_FULL=ON + Debug++: + CC: gcc + CXX: g++ + BuildType: debug-cxx + cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Debug -DMI_DEBUG_FULL=ON -DMI_USE_CXX=ON + Debug Clang: + CC: clang + CXX: clang++ + BuildType: debug-clang + cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Debug -DMI_DEBUG_FULL=ON + Debug++ Clang: + CC: clang + CXX: clang++ + BuildType: debug-clang-cxx + cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Debug -DMI_DEBUG_FULL=ON -DMI_USE_CXX=ON + Release Clang: + CC: clang + CXX: clang++ + BuildType: release-clang + cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Release + steps: + - task: CMake@1 + inputs: + workingDirectory: $(BuildType) + cmakeArgs: .. $(cmakeExtraArgs) + - script: make -j$(nproc) -C $(BuildType) + displayName: Make + - script: ctest --verbose --timeout 240 + workingDirectory: $(BuildType) + displayName: CTest + +- job: + displayName: macOS 15 (Sequoia) + pool: + vmImage: + macOS-15 + strategy: + matrix: + Debug: + BuildType: debug + cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Debug -DMI_DEBUG_FULL=ON + Release: + BuildType: release + cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Release + steps: + - task: CMake@1 + inputs: + workingDirectory: $(BuildType) + cmakeArgs: .. $(cmakeExtraArgs) + - script: make -j$(sysctl -n hw.ncpu) -C $(BuildType) + displayName: Make + - script: ctest --verbose --timeout 240 + workingDirectory: $(BuildType) + displayName: CTest + +- job: + displayName: macOS 13 (Ventura) + pool: + vmImage: + macOS-13 + strategy: + matrix: + Debug: + BuildType: debug + cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Debug -DMI_DEBUG_FULL=ON + Release: + BuildType: release + cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Release + steps: + - task: CMake@1 + inputs: + workingDirectory: $(BuildType) + cmakeArgs: .. $(cmakeExtraArgs) + - script: make -j$(sysctl -n hw.ncpu) -C $(BuildType) + displayName: Make + - script: ctest --verbose --timeout 180 + workingDirectory: $(BuildType) + displayName: CTest + diff --git a/src/dashbls/depends/mimalloc/bin/mimalloc-redirect-arm64.dll b/src/dashbls/depends/mimalloc/bin/mimalloc-redirect-arm64.dll new file mode 100755 index 000000000000..27172d2c0d5f Binary files /dev/null and b/src/dashbls/depends/mimalloc/bin/mimalloc-redirect-arm64.dll differ diff --git a/src/dashbls/depends/mimalloc/bin/mimalloc-redirect-arm64.lib b/src/dashbls/depends/mimalloc/bin/mimalloc-redirect-arm64.lib new file mode 100755 index 000000000000..dca80b9b855c Binary files /dev/null and b/src/dashbls/depends/mimalloc/bin/mimalloc-redirect-arm64.lib differ diff --git a/src/dashbls/depends/mimalloc/bin/mimalloc-redirect-arm64ec.dll b/src/dashbls/depends/mimalloc/bin/mimalloc-redirect-arm64ec.dll new file mode 100755 index 000000000000..a228af39d5a0 Binary files /dev/null and b/src/dashbls/depends/mimalloc/bin/mimalloc-redirect-arm64ec.dll differ diff --git a/src/dashbls/depends/mimalloc/bin/mimalloc-redirect-arm64ec.lib b/src/dashbls/depends/mimalloc/bin/mimalloc-redirect-arm64ec.lib new file mode 100755 index 000000000000..0ce7743647b1 Binary files /dev/null and b/src/dashbls/depends/mimalloc/bin/mimalloc-redirect-arm64ec.lib differ diff --git a/src/dashbls/depends/mimalloc/bin/mimalloc-redirect.dll b/src/dashbls/depends/mimalloc/bin/mimalloc-redirect.dll old mode 100644 new mode 100755 index 83b6bd4f379b..ec035f1bd61e Binary files a/src/dashbls/depends/mimalloc/bin/mimalloc-redirect.dll and b/src/dashbls/depends/mimalloc/bin/mimalloc-redirect.dll differ diff --git a/src/dashbls/depends/mimalloc/bin/mimalloc-redirect.lib b/src/dashbls/depends/mimalloc/bin/mimalloc-redirect.lib old mode 100644 new mode 100755 index 059fb8702a71..785fa4751353 Binary files a/src/dashbls/depends/mimalloc/bin/mimalloc-redirect.lib and b/src/dashbls/depends/mimalloc/bin/mimalloc-redirect.lib differ diff --git a/src/dashbls/depends/mimalloc/bin/mimalloc-redirect32.dll b/src/dashbls/depends/mimalloc/bin/mimalloc-redirect32.dll old mode 100644 new mode 100755 index 2892d459fc53..92578f240e43 Binary files a/src/dashbls/depends/mimalloc/bin/mimalloc-redirect32.dll and b/src/dashbls/depends/mimalloc/bin/mimalloc-redirect32.dll differ diff --git a/src/dashbls/depends/mimalloc/bin/mimalloc-redirect32.lib b/src/dashbls/depends/mimalloc/bin/mimalloc-redirect32.lib old mode 100644 new mode 100755 index 7dadab3d657e..bf64978793de Binary files a/src/dashbls/depends/mimalloc/bin/mimalloc-redirect32.lib and b/src/dashbls/depends/mimalloc/bin/mimalloc-redirect32.lib differ diff --git a/src/dashbls/depends/mimalloc/bin/minject-arm64.exe b/src/dashbls/depends/mimalloc/bin/minject-arm64.exe new file mode 100644 index 000000000000..4293b0ff3ea8 Binary files /dev/null and b/src/dashbls/depends/mimalloc/bin/minject-arm64.exe differ diff --git a/src/dashbls/depends/mimalloc/bin/minject.exe b/src/dashbls/depends/mimalloc/bin/minject.exe index 625816f1f777..91c795129218 100644 Binary files a/src/dashbls/depends/mimalloc/bin/minject.exe and b/src/dashbls/depends/mimalloc/bin/minject.exe differ diff --git a/src/dashbls/depends/mimalloc/bin/minject32.exe b/src/dashbls/depends/mimalloc/bin/minject32.exe index 6857ad0ce1cc..077f235b587b 100644 Binary files a/src/dashbls/depends/mimalloc/bin/minject32.exe and b/src/dashbls/depends/mimalloc/bin/minject32.exe differ diff --git a/src/dashbls/depends/mimalloc/bin/readme.md b/src/dashbls/depends/mimalloc/bin/readme.md new file mode 100644 index 000000000000..69eed4115821 --- /dev/null +++ b/src/dashbls/depends/mimalloc/bin/readme.md @@ -0,0 +1,118 @@ +# Windows Override + +We use a separate redirection DLL to override mimalloc on Windows +such that we redirect all malloc/free calls that go through the (dynamic) C runtime allocator, +including those from other DLL's or libraries. As it intercepts all allocation calls on a low level, +it can be used on large programs that include other 3rd party components. +There are four requirements to make the overriding work well: + +1. Use the C-runtime library as a DLL (using the `/MD` or `/MDd` switch). + +2. Link your program explicitly with the `mimalloc.dll.lib` export library for + the `mimalloc.dll` -- which contains all mimalloc functionality. + To ensure the `mimalloc.dll` is actually loaded at run-time it is easiest + to insert some call to the mimalloc API in the `main` function, like `mi_version()` + (or use the `/include:mi_version` switch on the linker, or + similarly, `#pragma comment(linker, "/include:mi_version")` in some source file). + See the `mimalloc-test-override` project for an example on how to use this. + +3. The `mimalloc-redirect.dll` must be put in the same folder as the main + `mimalloc.dll` at runtime (as it is a dependency of that DLL). + The redirection DLL ensures that all calls to the C runtime malloc API get + redirected to mimalloc functions (which reside in `mimalloc.dll`). + +4. Ensure the `mimalloc.dll` comes as early as possible in the import + list of the final executable (so it can intercept all potential allocations). + You can use `minject -l ` to check this if needed. + +```csharp +┌──────────────┐ +│ Your Program │ +└────┬─────────┘ + │ + │ mi_version() ┌───────────────┐ ┌───────────────────────┐ + ├──────────────►│ mimalloc.dll ├────►│ mimalloc-redirect.dll │ + │ └──────┬────────┘ └───────────────────────┘ + │ ▼ + │ malloc() etc. ┌──────────────┐ + ├──────────────►│ ucrtbase.dll │ + │ └──────────────┘ + │ + │ + └──────────────► ... +``` + +For best performance on Windows with C++, it +is also recommended to also override the `new`/`delete` operations (by including +[`mimalloc-new-delete.h`](../include/mimalloc-new-delete.h) +a single(!) source file in your project). + +The environment variable `MIMALLOC_DISABLE_REDIRECT=1` can be used to disable dynamic +overriding at run-time. Use `MIMALLOC_VERBOSE=1` to check if mimalloc was successfully +redirected. + +### Other Platforms + +You always link with `mimalloc.dll` but for different platforms you may +need a specific redirection DLL: + +- __x64__: `mimalloc-redirect.dll`. +- __x86__: `mimalloc-redirect32.dll`. Use for older 32-bit Windows programs. +- __arm64__: `mimalloc-redirect-arm64.dll`. Use for native Windows arm64 programs. +- __arm64ec__: `mimalloc-redirect-arm64ec.dll`. The [arm64ec] ABI is "emulation compatible" + mode on Windows arm64. Unfortunately we cannot run x64 code emulated on Windows arm64 with + the x64 mimalloc override directly (since the C runtime always uses `arm64ec`). Instead: + 1. Build the program as normal for x64 and link as normal with the x64 + `mimalloc.dll.lib` export library. + 2. Now separately build `mimalloc.dll` in `arm64ec` mode and _overwrite_ your + previous (x64) `mimalloc.dll` -- the loader can handle the mix of arm64ec + and x64 code. Now use `mimalloc-redirect-arm64ec.dll` to match your new + arm64ec `mimalloc.dll`. The main program stays as is and can be fully x64 + or contain more arm64ec modules. At runtime, the arm64ec `mimalloc.dll` will + run with native arm64 instructions while the rest of the program runs emulated x64. + +[arm64ec]: https://learn.microsoft.com/en-us/windows/arm/arm64ec + + +### Minject + +We cannot always re-link an executable with `mimalloc.dll`, and similarly, we +cannot always ensure that the DLL comes first in the import table of the final executable. +In many cases though we can patch existing executables without any recompilation +if they are linked with the dynamic C runtime (`ucrtbase.dll`) -- just put the +`mimalloc.dll` into the import table (and put `mimalloc-redirect.dll` in the same +directory) Such patching can be done for example with [CFF Explorer](https://ntcore.com/?page_id=388). + +The `minject` program can also do this from the command line +Use `minject --help` for options: + +``` +> minject --help + +minject: + Injects the mimalloc dll into the import table of a 64-bit executable, + and/or ensures that it comes first in het import table. + +usage: + > minject [options] + +options: + -h --help show this help + -v --verbose be verbose + -l --list only list imported modules + -i --inplace update the exe in-place (make sure there is a backup!) + -f --force always overwrite without prompting + --postfix=

use

as a postfix to the mimalloc dll. + e.g. use --postfix=debug to link with mimalloc-debug.dll + +notes: + Without '--inplace' an injected is generated with the same name ending in '-mi'. + Ensure 'mimalloc-redirect.dll' is in the same folder as the mimalloc dll. + +examples: + > minject --list myprogram.exe + > minject --force --inplace myprogram.exe +``` + +For x86 32-bit binaries, use `minject32`, and for arm64 binaries use `minject-arm64`. + diff --git a/src/dashbls/depends/mimalloc/cmake/mimalloc-config-version.cmake b/src/dashbls/depends/mimalloc/cmake/mimalloc-config-version.cmake index f0669c84d166..97756d79a5f0 100644 --- a/src/dashbls/depends/mimalloc/cmake/mimalloc-config-version.cmake +++ b/src/dashbls/depends/mimalloc/cmake/mimalloc-config-version.cmake @@ -1,6 +1,6 @@ -set(mi_version_major 2) -set(mi_version_minor 0) -set(mi_version_patch 7) +set(mi_version_major 3) +set(mi_version_minor 1) +set(mi_version_patch 5) set(mi_version ${mi_version_major}.${mi_version_minor}) set(PACKAGE_VERSION ${mi_version}) diff --git a/src/dashbls/depends/mimalloc/cmake/mimalloc-config.cmake b/src/dashbls/depends/mimalloc/cmake/mimalloc-config.cmake index 8a28e37e7edd..a49b02a25a14 100644 --- a/src/dashbls/depends/mimalloc/cmake/mimalloc-config.cmake +++ b/src/dashbls/depends/mimalloc/cmake/mimalloc-config.cmake @@ -2,13 +2,13 @@ include(${CMAKE_CURRENT_LIST_DIR}/mimalloc.cmake) get_filename_component(MIMALLOC_CMAKE_DIR "${CMAKE_CURRENT_LIST_DIR}" PATH) # one up from the cmake dir, e.g. /usr/local/lib/cmake/mimalloc-2.0 get_filename_component(MIMALLOC_VERSION_DIR "${CMAKE_CURRENT_LIST_DIR}" NAME) string(REPLACE "/lib/cmake" "/lib" MIMALLOC_LIBRARY_DIR "${MIMALLOC_CMAKE_DIR}") -if("${MIMALLOC_VERSION_DIR}" EQUAL "mimalloc") +if("${MIMALLOC_VERSION_DIR}" EQUAL "mimalloc") # top level install string(REPLACE "/lib/cmake" "/include" MIMALLOC_INCLUDE_DIR "${MIMALLOC_CMAKE_DIR}") set(MIMALLOC_OBJECT_DIR "${MIMALLOC_LIBRARY_DIR}") -else() +else() # versioned string(REPLACE "/lib/cmake/" "/include/" MIMALLOC_INCLUDE_DIR "${CMAKE_CURRENT_LIST_DIR}") - string(REPLACE "/lib/cmake/" "/lib/" MIMALLOC_OBJECT_DIR "${CMAKE_CURRENT_LIST_DIR}") -endif() + string(REPLACE "/lib/cmake/" "/lib/" MIMALLOC_OBJECT_DIR "${CMAKE_CURRENT_LIST_DIR}") +endif() set(MIMALLOC_TARGET_DIR "${MIMALLOC_LIBRARY_DIR}") # legacy diff --git a/src/dashbls/depends/mimalloc/contrib/docker/alpine-arm32v7/Dockerfile b/src/dashbls/depends/mimalloc/contrib/docker/alpine-arm32v7/Dockerfile new file mode 100644 index 000000000000..daa60f50d55a --- /dev/null +++ b/src/dashbls/depends/mimalloc/contrib/docker/alpine-arm32v7/Dockerfile @@ -0,0 +1,28 @@ +# install from an image +# download first an appropriate tar.gz image into the current directory +# from +FROM scratch + +# Substitute the image name that was downloaded +ADD alpine-minirootfs-20240329-armv7.tar.gz / + +# Install tools +RUN apk add build-base make cmake +RUN apk add git +RUN apk add vim + +RUN mkdir -p /home/dev +WORKDIR /home/dev + +# Get mimalloc +RUN git clone https://github.com/microsoft/mimalloc -b dev2 +RUN mkdir -p mimalloc/out/release +RUN mkdir -p mimalloc/out/debug + +# Build mimalloc debug +WORKDIR /home/dev/mimalloc/out/debug +RUN cmake ../.. -DMI_DEBUG_FULL=ON +RUN make -j +RUN make test + +CMD ["/bin/sh"] diff --git a/src/dashbls/depends/mimalloc/contrib/docker/alpine-x86/Dockerfile b/src/dashbls/depends/mimalloc/contrib/docker/alpine-x86/Dockerfile new file mode 100644 index 000000000000..a0f76c17d768 --- /dev/null +++ b/src/dashbls/depends/mimalloc/contrib/docker/alpine-x86/Dockerfile @@ -0,0 +1,28 @@ +# install from an image +# download first an appropriate tar.gz image into the current directory +# from +FROM scratch + +# Substitute the image name that was downloaded +ADD alpine-minirootfs-20250108-x86.tar.gz / + +# Install tools +RUN apk add build-base make cmake +RUN apk add git +RUN apk add vim + +RUN mkdir -p /home/dev +WORKDIR /home/dev + +# Get mimalloc +RUN git clone https://github.com/microsoft/mimalloc -b dev2 +RUN mkdir -p mimalloc/out/release +RUN mkdir -p mimalloc/out/debug + +# Build mimalloc debug +WORKDIR /home/dev/mimalloc/out/debug +RUN cmake ../.. -DMI_DEBUG_FULL=ON +# RUN make -j +# RUN make test + +CMD ["/bin/sh"] diff --git a/src/dashbls/depends/mimalloc/contrib/docker/alpine/Dockerfile b/src/dashbls/depends/mimalloc/contrib/docker/alpine/Dockerfile new file mode 100644 index 000000000000..e1234a9b64b5 --- /dev/null +++ b/src/dashbls/depends/mimalloc/contrib/docker/alpine/Dockerfile @@ -0,0 +1,23 @@ +# alpine image +FROM alpine + +# Install tools +RUN apk add build-base make cmake +RUN apk add git +RUN apk add vim + +RUN mkdir -p /home/dev +WORKDIR /home/dev + +# Get mimalloc +RUN git clone https://github.com/microsoft/mimalloc -b dev2 +RUN mkdir -p mimalloc/out/release +RUN mkdir -p mimalloc/out/debug + +# Build mimalloc debug +WORKDIR /home/dev/mimalloc/out/debug +RUN cmake ../.. -DMI_DEBUG_FULL=ON +RUN make -j +RUN make test + +CMD ["/bin/sh"] \ No newline at end of file diff --git a/src/dashbls/depends/mimalloc/contrib/docker/manylinux-x64/Dockerfile b/src/dashbls/depends/mimalloc/contrib/docker/manylinux-x64/Dockerfile new file mode 100644 index 000000000000..ff54d674efc5 --- /dev/null +++ b/src/dashbls/depends/mimalloc/contrib/docker/manylinux-x64/Dockerfile @@ -0,0 +1,23 @@ +FROM quay.io/pypa/manylinux2014_x86_64 + +# Install tools +RUN yum install -y openssl-devel +RUN yum install -y gcc gcc-c++ kernel-devel make +RUN yum install -y git cmake +RUN yum install -y vim + +RUN mkdir -p /home/dev +WORKDIR /home/dev + +# Get mimalloc +RUN git clone https://github.com/microsoft/mimalloc -b dev2 +RUN mkdir -p mimalloc/out/release +RUN mkdir -p mimalloc/out/debug + +# Build mimalloc debug +WORKDIR /home/dev/mimalloc/out/debug +RUN cmake ../.. -DMI_DEBUG_FULL=ON +RUN make -j +RUN make test + +CMD ["/bin/sh"] \ No newline at end of file diff --git a/src/dashbls/depends/mimalloc/contrib/docker/readme.md b/src/dashbls/depends/mimalloc/contrib/docker/readme.md new file mode 100644 index 000000000000..b3d900940795 --- /dev/null +++ b/src/dashbls/depends/mimalloc/contrib/docker/readme.md @@ -0,0 +1,10 @@ +Various example docker files used for testing. + +Usage: + +``` +> cd +> docker build -t -mimalloc . +> docker run -it -mimalloc +>> make test +``` diff --git a/src/dashbls/depends/mimalloc/contrib/vcpkg/portfile.cmake b/src/dashbls/depends/mimalloc/contrib/vcpkg/portfile.cmake new file mode 100644 index 000000000000..a3be8101e607 --- /dev/null +++ b/src/dashbls/depends/mimalloc/contrib/vcpkg/portfile.cmake @@ -0,0 +1,64 @@ +vcpkg_from_github( + OUT_SOURCE_PATH SOURCE_PATH + REPO microsoft/mimalloc + HEAD_REF master + + # The "REF" can be a commit hash, branch name (dev2), or a version (v2.2.1). + REF "v${VERSION}" + # REF 6a89f8554eaab8d8d00e17b5b09f79e1d8dbf61b + + # The sha512 is the hash of the tar.gz bundle. + # (To get the sha512, run `vcpkg install "mimalloc[override]" --overlay-ports=./contrib/vcpkg` and copy the sha from the error message.) + SHA512 1e1268292283eb3c07a1f4de1bb919ebfeb18cbd4af0ca01d197d4dc46972ea127527e95e18f73381bda03593bcca5d3e4744c3ab49876c68567abebff030690 +) + +vcpkg_check_features(OUT_FEATURE_OPTIONS FEATURE_OPTIONS + FEATURES + c MI_NO_USE_CXX + guarded MI_GUARDED + secure MI_SECURE + override MI_OVERRIDE + optarch MI_OPT_ARCH + nooptarch MI_NO_OPT_ARCH + optsimd MI_OPT_SIMD + xmalloc MI_XMALLOC + asm MI_SEE_ASM +) +string(COMPARE EQUAL "${VCPKG_LIBRARY_LINKAGE}" "static" MI_BUILD_STATIC) +string(COMPARE EQUAL "${VCPKG_LIBRARY_LINKAGE}" "dynamic" MI_BUILD_SHARED) + +vcpkg_cmake_configure( + SOURCE_PATH "${SOURCE_PATH}" + OPTIONS + -DMI_USE_CXX=ON + -DMI_BUILD_TESTS=OFF + -DMI_BUILD_OBJECT=ON + -DMI_BUILD_STATIC=${MI_BUILD_STATIC} + -DMI_BUILD_SHARED=${MI_BUILD_SHARED} + -DMI_INSTALL_TOPLEVEL=ON + ${FEATURE_OPTIONS} +) + +vcpkg_cmake_install() +vcpkg_copy_pdbs() + +file(COPY + "${CMAKE_CURRENT_LIST_DIR}/vcpkg-cmake-wrapper.cmake" + "${CMAKE_CURRENT_LIST_DIR}/usage" + DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}" +) +vcpkg_cmake_config_fixup(CONFIG_PATH lib/cmake/mimalloc) + +if(VCPKG_LIBRARY_LINKAGE STREQUAL "dynamic") + # todo: why is this needed? + vcpkg_replace_string( + "${CURRENT_PACKAGES_DIR}/include/mimalloc.h" + "!defined(MI_SHARED_LIB)" + "0 // !defined(MI_SHARED_LIB)" + ) +endif() +file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/include") +file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/share") + +vcpkg_fixup_pkgconfig() +vcpkg_install_copyright(FILE_LIST "${SOURCE_PATH}/LICENSE") diff --git a/src/dashbls/depends/mimalloc/contrib/vcpkg/readme.md b/src/dashbls/depends/mimalloc/contrib/vcpkg/readme.md new file mode 100644 index 000000000000..014f2867363b --- /dev/null +++ b/src/dashbls/depends/mimalloc/contrib/vcpkg/readme.md @@ -0,0 +1,40 @@ +# Vcpkg support + +This directory is meant to provide the sources for the official [vcpkg port] +of mimalloc, but can also be used to override the official port with +your own variant. + +For example, you can edit the [`portfile.cmake`](portfile.cmake) +to check out a specific commit, version, or branch of mimalloc, or set further options. +You can install such custom port as: + +```sh +$ vcpkg install "mimalloc[override]" --recurse --overlay-ports=./contrib/vcpkg +``` + +This will also show the correct sha512 hash if you use a custom version. +Another way is to refer to the overlay from the [vcpkg-configuration.json](https://learn.microsoft.com/en-us/vcpkg/reference/vcpkg-configuration-json) file. +See also the vcpkg [documentation](https://learn.microsoft.com/en-us/vcpkg/produce/update-package-version) for more information. + + +# Using mimalloc from vcpkg + +When using [cmake with vcpkg](https://learn.microsoft.com/en-us/vcpkg/get_started/get-started?pivots=shell-powershell), +you can use mimalloc from the `CMakeLists.txt` as: + +```cmake +find_package(mimalloc CONFIG REQUIRED) +target_link_libraries(main PRIVATE mimalloc) +``` + +See [`test/CMakeLists.txt](../../test/CMakeLists.txt) for more examples. + + +# Acknowledgements + +The original port for vckpg was contributed by many people, including: @vicroms, @myd7349, @PhoubeHui, @LilyWangL, +@JonLiu1993, @RT2Code, Remy Tassoux, @wangao, @BillyONeal, @jiayuehua, @dg0yt, @gerar-ryan-immersaview, @nickdademo, +and @jimwang118 -- Thank you so much! + + +[vcpkg port]: https://github.com/microsoft/vcpkg/tree/master/ports/mimalloc diff --git a/src/dashbls/depends/mimalloc/contrib/vcpkg/usage b/src/dashbls/depends/mimalloc/contrib/vcpkg/usage new file mode 100644 index 000000000000..7ce649a754f3 --- /dev/null +++ b/src/dashbls/depends/mimalloc/contrib/vcpkg/usage @@ -0,0 +1,20 @@ +Use the following CMake targets to import mimalloc: + + find_package(mimalloc CONFIG REQUIRED) + target_link_libraries(main PRIVATE mimalloc) + +And use mimalloc in your sources as: + + #include + #include + int main(int argc, char** argv) { + int* p = mi_malloc_tp(int); + *p = mi_version(); + printf("mimalloc version: %d\n", *p); + mi_free(p); + return 0; + } + +When dynamically overriding on Windows, ensure `mimalloc.dll` is linked through some call to +mimalloc (e.g. `mi_version()`), and that the `mimalloc-redirect.dll` is in the same directory. +See https://github.com/microsoft/mimalloc/blob/dev/bin/readme.md for detailed information. diff --git a/src/dashbls/depends/mimalloc/contrib/vcpkg/vcpkg-cmake-wrapper.cmake b/src/dashbls/depends/mimalloc/contrib/vcpkg/vcpkg-cmake-wrapper.cmake new file mode 100644 index 000000000000..1b3557226e00 --- /dev/null +++ b/src/dashbls/depends/mimalloc/contrib/vcpkg/vcpkg-cmake-wrapper.cmake @@ -0,0 +1,20 @@ +_find_package(${ARGS}) + +if(CMAKE_CURRENT_LIST_DIR STREQUAL "${MIMALLOC_CMAKE_DIR}/${MIMALLOC_VERSION_DIR}") + set(MIMALLOC_INCLUDE_DIR "${VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/include") + # As in vcpkg.cmake + if(NOT DEFINED CMAKE_BUILD_TYPE OR CMAKE_BUILD_TYPE MATCHES "^[Dd][Ee][Bb][Uu][Gg]$") + set(MIMALLOC_LIBRARY_DIR "${VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/debug/lib") + else() + set(MIMALLOC_LIBRARY_DIR "${VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/lib") + endif() + set(MIMALLOC_OBJECT_DIR "${MIMALLOC_LIBRARY_DIR}") + set(MIMALLOC_TARGET_DIR "${MIMALLOC_LIBRARY_DIR}") +endif() + +# vcpkg always configures either a static or dynamic library. +# ensure to always expose the mimalloc target as either the static or dynamic build. +if(TARGET mimalloc-static AND NOT TARGET mimalloc) + add_library(mimalloc INTERFACE IMPORTED) + set_target_properties(mimalloc PROPERTIES INTERFACE_LINK_LIBRARIES mimalloc-static) +endif() diff --git a/src/dashbls/depends/mimalloc/contrib/vcpkg/vcpkg.json b/src/dashbls/depends/mimalloc/contrib/vcpkg/vcpkg.json new file mode 100644 index 000000000000..65d57d2ef98a --- /dev/null +++ b/src/dashbls/depends/mimalloc/contrib/vcpkg/vcpkg.json @@ -0,0 +1,48 @@ +{ + "name": "mimalloc", + "version": "3.1.4", + "port-version": 2, + "description": "Compact general purpose allocator with excellent performance", + "homepage": "https://github.com/microsoft/mimalloc", + "license": "MIT", + "supports": "!uwp", + "dependencies": [ + { + "name": "vcpkg-cmake", + "host": true + }, + { + "name": "vcpkg-cmake-config", + "host": true + } + ], + "features": { + "c": { + "description": "Use C11 compilation (this can still override new/delete)" + }, + "override": { + "description": "Override the standard malloc/free interface" + }, + "secure": { + "description": "Use full security mitigations (like guard pages and randomization)" + }, + "guarded": { + "description": "Use build that support guard pages after objects controlled with MIMALLOC_GUARDED_SAMPLE_RATE" + }, + "xmalloc": { + "description": "If out-of-memory, call abort() instead of returning NULL" + }, + "optarch": { + "description": "Use architecture specific optimizations (on x64: '-march=haswell;-mavx2', on arm64: '-march=armv8.1-a')" + }, + "nooptarch": { + "description": "Do _not_ use architecture specific optimizations (on x64: '-march=haswell;-mavx2', on arm64: '-march=armv8.1-a')" + }, + "optsimd": { + "description": "Allow use of SIMD instructions (avx2 or neon) (requires 'optarch' to be enabled)" + }, + "asm": { + "description": "Generate assembly files" + } + } +} \ No newline at end of file diff --git a/src/dashbls/depends/mimalloc/doc/doxyfile b/src/dashbls/depends/mimalloc/doc/doxyfile index 73266f4e9be2..53f874cfb27e 100644 --- a/src/dashbls/depends/mimalloc/doc/doxyfile +++ b/src/dashbls/depends/mimalloc/doc/doxyfile @@ -1,4 +1,4 @@ -# Doxyfile 1.9.1 +# Doxyfile 1.11.0 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. @@ -12,6 +12,16 @@ # For lists, items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (\" \"). +# +# Note: +# +# Use doxygen to compare the used configuration file with the template +# configuration file: +# doxygen -x [configFile] +# Use doxygen to compare the used configuration file with the template +# configuration file without replacing the environment variables or CMake type +# replacement variables: +# doxygen -x_noenv [configFile] #--------------------------------------------------------------------------- # Project related configuration options @@ -38,7 +48,7 @@ PROJECT_NAME = mi-malloc # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 1.7/2.0 +PROJECT_NUMBER = 1.8/2.1 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a @@ -53,6 +63,12 @@ PROJECT_BRIEF = PROJECT_LOGO = mimalloc-logo.svg +# With the PROJECT_ICON tag one can specify an icon that is included in the tabs +# when the HTML document is shown. Doxygen will copy the logo to the output +# directory. + +PROJECT_ICON = + # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path # into which the generated documentation will be written. If a relative path is # entered, it will be relative to the location where doxygen was started. If @@ -60,16 +76,28 @@ PROJECT_LOGO = mimalloc-logo.svg OUTPUT_DIRECTORY = .. -# 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 -# will distribute the generated files over these directories. Enabling this +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create up to 4096 +# sub-directories (in 2 levels) under the output directory of each output format +# and will distribute the generated files over these directories. Enabling this # option can be useful when feeding doxygen a huge amount of source files, where # putting all generated files in the same directory would otherwise causes -# performance problems for the file system. +# performance problems for the file system. Adapt CREATE_SUBDIRS_LEVEL to +# control the number of sub-directories. # The default value is: NO. CREATE_SUBDIRS = NO +# Controls the number of sub-directories that will be created when +# CREATE_SUBDIRS tag is set to YES. Level 0 represents 16 directories, and every +# level increment doubles the number of directories, resulting in 4096 +# directories at level 8 which is the default and also the maximum value. The +# sub-directories are organized in 2 levels, the first level always has a fixed +# number of 16 directories. +# Minimum value: 0, maximum value: 8, default value: 8. +# This tag requires that the tag CREATE_SUBDIRS is set to YES. + +CREATE_SUBDIRS_LEVEL = 8 + # If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII # characters to appear in the names of generated files. If set to NO, non-ASCII # characters will be escaped, for example _xE3_x81_x84 will be used for Unicode @@ -81,26 +109,18 @@ ALLOW_UNICODE_NAMES = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. -# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, -# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), -# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, -# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), -# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, -# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, -# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, -# Ukrainian and Vietnamese. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Bulgarian, +# Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, English +# (United States), Esperanto, Farsi (Persian), Finnish, French, German, Greek, +# Hindi, Hungarian, Indonesian, Italian, Japanese, Japanese-en (Japanese with +# English messages), Korean, Korean-en (Korean with English messages), Latvian, +# Lithuanian, Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, +# Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, +# Swedish, Turkish, Ukrainian and Vietnamese. # The default value is: English. OUTPUT_LANGUAGE = English -# The OUTPUT_TEXT_DIRECTION tag is used to specify the direction in which all -# documentation generated by doxygen is written. Doxygen will use this -# information to generate all generated output in the proper direction. -# Possible values are: None, LTR, RTL and Context. -# The default value is: None. - -OUTPUT_TEXT_DIRECTION = None - # If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member # descriptions after the members that are listed in the file and class # documentation (similar to Javadoc). Set to NO to disable this. @@ -258,16 +278,16 @@ TAB_SIZE = 2 # the documentation. An alias has the form: # name=value # For example adding -# "sideeffect=@par Side Effects:\n" +# "sideeffect=@par Side Effects:^^" # will allow you to put the command \sideeffect (or @sideeffect) in the # documentation, which will result in a user-defined paragraph with heading -# "Side Effects:". You can put \n's in the value part of an alias to insert -# newlines (in the resulting output). You can put ^^ in the value part of an -# alias to insert a newline as if a physical newline was in the original file. -# When you need a literal { or } or , in the value part of an alias you have to -# escape them by means of a backslash (\), this can lead to conflicts with the -# commands \{ and \} for these it is advised to use the version @{ and @} or use -# a double escape (\\{ and \\}) +# "Side Effects:". Note that you cannot put \n's in the value part of an alias +# to insert newlines (in the resulting output). You can put ^^ in the value part +# of an alias to insert a newline as if a physical newline was in the original +# file. When you need a literal { or } or , in the value part of an alias you +# have to escape them by means of a backslash (\), this can lead to conflicts +# with the commands \{ and \} for these it is advised to use the version @{ and +# @} or use a double escape (\\{ and \\}) ALIASES = @@ -312,8 +332,8 @@ OPTIMIZE_OUTPUT_SLICE = NO # extension. Doxygen has a built-in mapping, but you can override or extend it # using this tag. The format is ext=language, where ext is a file extension, and # language is one of the parsers supported by doxygen: IDL, Java, JavaScript, -# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice, VHDL, -# Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: +# Csharp (C#), C, C++, Lex, D, PHP, md (Markdown), Objective-C, Python, Slice, +# VHDL, Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: # FortranFree, unknown formatted Fortran: Fortran. In the later case the parser # tries to guess whether the code is fixed or free formatted code, this is the # default for Fortran type files). For instance to make doxygen treat .inc files @@ -344,11 +364,22 @@ MARKDOWN_SUPPORT = YES # to that level are automatically included in the table of contents, even if # they do not have an id attribute. # Note: This feature currently applies only to Markdown headings. -# Minimum value: 0, maximum value: 99, default value: 5. +# Minimum value: 0, maximum value: 99, default value: 6. # This tag requires that the tag MARKDOWN_SUPPORT is set to YES. TOC_INCLUDE_HEADINGS = 0 +# The MARKDOWN_ID_STYLE tag can be used to specify the algorithm used to +# generate identifiers for the Markdown headings. Note: Every identifier is +# unique. +# Possible values are: DOXYGEN use a fixed 'autotoc_md' string followed by a +# sequence number starting at 0 and GITHUB use the lower case version of title +# with any whitespace replaced by '-' and punctuation characters removed. +# The default value is: DOXYGEN. +# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. + +MARKDOWN_ID_STYLE = DOXYGEN + # When enabled doxygen tries to link words that correspond to documented # classes, or namespaces to their corresponding documentation. Such a link can # be prevented in individual cases by putting a % sign in front of the word or @@ -361,8 +392,8 @@ AUTOLINK_SUPPORT = YES # to include (a tag file for) the STL sources as input, then you should set this # tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); -# versus func(std::string) {}). This also make the inheritance and collaboration -# diagrams that involve STL classes more complete and accurate. +# versus func(std::string) {}). This also makes the inheritance and +# collaboration diagrams that involve STL classes more complete and accurate. # The default value is: NO. BUILTIN_STL_SUPPORT = NO @@ -374,9 +405,9 @@ BUILTIN_STL_SUPPORT = NO CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip (see: -# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen -# will parse them like normal C++ but will assume all classes use public instead -# of private inheritance when no explicit protection keyword is present. +# https://www.riverbankcomputing.com/software) sources only. Doxygen will parse +# them like normal C++ but will assume all classes use public instead of private +# inheritance when no explicit protection keyword is present. # The default value is: NO. SIP_SUPPORT = NO @@ -460,19 +491,27 @@ TYPEDEF_HIDES_STRUCT = YES LOOKUP_CACHE_SIZE = 0 -# The NUM_PROC_THREADS specifies the number threads doxygen is allowed to use +# The NUM_PROC_THREADS specifies the number of threads doxygen is allowed to use # during processing. When set to 0 doxygen will based this on the number of # cores available in the system. You can set it explicitly to a value larger # than 0 to get more control over the balance between CPU load and processing # speed. At this moment only the input processing can be done using multiple # threads. Since this is still an experimental feature the default is set to 1, -# which efficively disables parallel processing. Please report any issues you +# which effectively disables parallel processing. Please report any issues you # encounter. Generating dot graphs in parallel is controlled by the # DOT_NUM_THREADS setting. # Minimum value: 0, maximum value: 32, default value: 1. NUM_PROC_THREADS = 1 +# If the TIMESTAMP tag is set different from NO then each generated page will +# contain the date or date and time when the page was generated. Setting this to +# NO can help when comparing the output of multiple runs. +# Possible values are: YES, NO, DATETIME and DATE. +# The default value is: NO. + +TIMESTAMP = NO + #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- @@ -554,7 +593,8 @@ HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. If set # to NO, these classes will be included in the various overviews. This option -# has no effect if EXTRACT_ALL is enabled. +# will also hide undocumented C++ concepts if enabled. This option has no effect +# if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_CLASSES = NO @@ -585,14 +625,15 @@ INTERNAL_DOCS = NO # filesystem is case sensitive (i.e. it supports files in the same directory # whose names only differ in casing), the option must be set to YES to properly # deal with such files in case they appear in the input. For filesystems that -# are not case sensitive the option should be be set to NO to properly deal with +# are not case sensitive the option should be set to NO to properly deal with # output files written for symbols that only differ in casing, such as for two # classes, one named CLASS and the other named Class, and to also support # references to files without having to specify the exact matching casing. On # Windows (including Cygwin) and MacOS, users should typically set this option # to NO, whereas on Linux or other Unix flavors it should typically be set to # YES. -# The default value is: system dependent. +# Possible values are: SYSTEM, NO and YES. +# The default value is: SYSTEM. CASE_SENSE_NAMES = NO @@ -610,6 +651,12 @@ HIDE_SCOPE_NAMES = NO HIDE_COMPOUND_REFERENCE= NO +# If the SHOW_HEADERFILE tag is set to YES then the documentation for a class +# will show which file needs to be included to use the class. +# The default value is: YES. + +SHOW_HEADERFILE = YES + # If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of # the files that are included by a file in the documentation of that file. # The default value is: YES. @@ -767,7 +814,8 @@ FILE_VERSION_FILTER = # output files in an output format independent way. To create the layout file # that represents doxygen's defaults, run doxygen with the -l option. You can # optionally specify a file name after the option, if omitted DoxygenLayout.xml -# will be used as the name of the layout file. +# will be used as the name of the layout file. See also section "Changing the +# layout of pages" for information. # # Note that if you run doxygen from a directory containing a file called # DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE @@ -813,27 +861,50 @@ WARNINGS = YES WARN_IF_UNDOCUMENTED = YES # If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for -# potential errors in the documentation, such as not documenting some parameters -# in a documented function, or documenting parameters that don't exist or using -# markup commands wrongly. +# potential errors in the documentation, such as documenting some parameters in +# a documented function twice, or documenting parameters that don't exist or +# using markup commands wrongly. # The default value is: YES. WARN_IF_DOC_ERROR = YES +# If WARN_IF_INCOMPLETE_DOC is set to YES, doxygen will warn about incomplete +# function parameter documentation. If set to NO, doxygen will accept that some +# parameters have no documentation without warning. +# The default value is: YES. + +WARN_IF_INCOMPLETE_DOC = YES + # This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that # are documented, but have no documentation for their parameters or return -# value. If set to NO, doxygen will only warn about wrong or incomplete -# parameter documentation, but not about the absence of documentation. If -# EXTRACT_ALL is set to YES then this flag will automatically be disabled. +# value. If set to NO, doxygen will only warn about wrong parameter +# documentation, but not about the absence of documentation. If EXTRACT_ALL is +# set to YES then this flag will automatically be disabled. See also +# WARN_IF_INCOMPLETE_DOC # The default value is: NO. WARN_NO_PARAMDOC = NO +# If WARN_IF_UNDOC_ENUM_VAL option is set to YES, doxygen will warn about +# undocumented enumeration values. If set to NO, doxygen will accept +# undocumented enumeration values. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: NO. + +WARN_IF_UNDOC_ENUM_VAL = NO + # If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when # a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS # then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but # at the end of the doxygen process doxygen will return with a non-zero status. -# Possible values are: NO, YES and FAIL_ON_WARNINGS. +# If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS_PRINT then doxygen behaves +# like FAIL_ON_WARNINGS but in case no WARN_LOGFILE is defined doxygen will not +# write the warning messages in between other messages but write them at the end +# of a run, in case a WARN_LOGFILE is defined the warning messages will be +# besides being in the defined file also be shown at the end of a run, unless +# the WARN_LOGFILE is defined as - i.e. standard output (stdout) in that case +# the behavior will remain as with the setting FAIL_ON_WARNINGS. +# Possible values are: NO, YES, FAIL_ON_WARNINGS and FAIL_ON_WARNINGS_PRINT. # The default value is: NO. WARN_AS_ERROR = NO @@ -844,13 +915,27 @@ WARN_AS_ERROR = NO # and the warning text. Optionally the format may contain $version, which will # be replaced by the version of the file (if it could be obtained via # FILE_VERSION_FILTER) +# See also: WARN_LINE_FORMAT # The default value is: $file:$line: $text. WARN_FORMAT = "$file:$line: $text" +# In the $text part of the WARN_FORMAT command it is possible that a reference +# to a more specific place is given. To make it easier to jump to this place +# (outside of doxygen) the user can define a custom "cut" / "paste" string. +# Example: +# WARN_LINE_FORMAT = "'vi $file +$line'" +# See also: WARN_FORMAT +# The default value is: at line $line of file $file. + +WARN_LINE_FORMAT = "at line $line of file $file" + # The WARN_LOGFILE tag can be used to specify a file to which warning and error # messages should be written. If left blank the output is written to standard -# error (stderr). +# error (stderr). In case the file specified cannot be opened for writing the +# warning and error messages are written to standard error. When as file - is +# specified the warning and error messages are written to standard output +# (stdout). WARN_LOGFILE = @@ -871,10 +956,21 @@ INPUT = mimalloc-doc.h # libiconv (or the iconv built into libc) for the transcoding. See the libiconv # documentation (see: # https://www.gnu.org/software/libiconv/) for the list of possible encodings. +# See also: INPUT_FILE_ENCODING # The default value is: UTF-8. INPUT_ENCODING = UTF-8 +# This tag can be used to specify the character encoding of the source files +# that doxygen parses The INPUT_FILE_ENCODING tag can be used to specify +# character encoding on a per file pattern basis. Doxygen will compare the file +# name with each pattern and apply the encoding instead of the default +# INPUT_ENCODING) if there is a match. The character encodings are a list of the +# form: pattern=encoding (like *.php=ISO-8859-1). +# See also: INPUT_ENCODING for further information on supported encodings. + +INPUT_FILE_ENCODING = + # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and # *.h) to filter out the source-files in the directories. @@ -886,12 +982,12 @@ INPUT_ENCODING = UTF-8 # Note the list of default checked file patterns might differ from the list of # default file extension mappings. # -# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, -# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, -# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, -# *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C comment), -# *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd, *.vhdl, -# *.ucf, *.qsf and *.ice. +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cxxm, +# *.cpp, *.cppm, *.ccm, *.c++, *.c++m, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, +# *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, *.h++, *.ixx, *.l, *.cs, *.d, +# *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to +# be provided as doxygen C comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, +# *.f18, *.f, *.for, *.vhd, *.vhdl, *.ucf, *.qsf and *.ice. FILE_PATTERNS = *.c \ *.cc \ @@ -973,10 +1069,7 @@ EXCLUDE_PATTERNS = # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, -# AClass::ANamespace, ANamespace::*Test -# -# Note that the wildcards are matched against the file with absolute path, so to -# exclude all test directories use the pattern */test/* +# ANamespace::AClass, ANamespace::*Test EXCLUDE_SYMBOLS = @@ -1021,6 +1114,11 @@ IMAGE_PATH = # code is scanned, but not when the output code is generated. If lines are added # or removed, the anchors will not be placed correctly. # +# Note that doxygen will use the data processed and written to standard output +# for further processing, therefore nothing else, like debug statements or used +# commands (so in case of a Windows batch file always use @echo OFF), should be +# written to standard output. +# # Note that for custom extensions or not directly supported extensions you also # need to set EXTENSION_MAPPING for the extension otherwise the files are not # properly processed by doxygen. @@ -1062,6 +1160,15 @@ FILTER_SOURCE_PATTERNS = USE_MDFILE_AS_MAINPAGE = +# The Fortran standard specifies that for fixed formatted Fortran code all +# characters from position 72 are to be considered as comment. A common +# extension is to allow longer lines before the automatic comment starts. The +# setting FORTRAN_COMMENT_AFTER will also make it possible that longer lines can +# be processed before the automatic comment starts. +# Minimum value: 7, maximum value: 10000, default value: 72. + +FORTRAN_COMMENT_AFTER = 72 + #--------------------------------------------------------------------------- # Configuration options related to source browsing #--------------------------------------------------------------------------- @@ -1076,7 +1183,8 @@ USE_MDFILE_AS_MAINPAGE = SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body of functions, -# classes and enums directly into the documentation. +# multi-line macros, enums or list initialized variables directly into the +# documentation. # The default value is: NO. INLINE_SOURCES = NO @@ -1159,9 +1267,11 @@ VERBATIM_HEADERS = YES CLANG_ASSISTED_PARSING = NO -# If clang assisted parsing is enabled and the CLANG_ADD_INC_PATHS tag is set to -# YES then doxygen will add the directory of each input to the include path. +# If the CLANG_ASSISTED_PARSING tag is set to YES and the CLANG_ADD_INC_PATHS +# tag is set to YES then doxygen will add the directory of each input to the +# include path. # The default value is: YES. +# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. CLANG_ADD_INC_PATHS = YES @@ -1197,10 +1307,11 @@ CLANG_DATABASE_PATH = ALPHABETICAL_INDEX = YES -# In case all classes in a project start with a common prefix, all classes will -# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag -# can be used to specify a prefix (or a list of prefixes) that should be ignored -# while generating the index headers. +# The IGNORE_PREFIX tag can be used to specify a prefix (or a list of prefixes) +# that should be ignored while generating the index headers. The IGNORE_PREFIX +# tag works for classes, function and member names. The entity will be placed in +# the alphabetical list under the first letter of the entity name that remains +# after removing the prefix. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. IGNORE_PREFIX = @@ -1279,7 +1390,12 @@ HTML_STYLESHEET = # Doxygen will copy the style sheet files to the output directory. # Note: The order of the extra style sheet files is of importance (e.g. the last # style sheet in the list overrules the setting of the previous ones in the -# list). For an example see the documentation. +# list). +# Note: Since the styling of scrollbars can currently not be overruled in +# Webkit/Chromium, the styling will be left out of the default doxygen.css if +# one or more extra stylesheets have been specified. So if scrollbar +# customization is desired it has to be added explicitly. For an example see the +# documentation. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_EXTRA_STYLESHEET = mimalloc-doxygen.css @@ -1294,9 +1410,22 @@ HTML_EXTRA_STYLESHEET = mimalloc-doxygen.css HTML_EXTRA_FILES = +# The HTML_COLORSTYLE tag can be used to specify if the generated HTML output +# should be rendered with a dark or light theme. +# Possible values are: LIGHT always generates light mode output, DARK always +# generates dark mode output, AUTO_LIGHT automatically sets the mode according +# to the user preference, uses light mode if no preference is set (the default), +# AUTO_DARK automatically sets the mode according to the user preference, uses +# dark mode if no preference is set and TOGGLE allows a user to switch between +# light and dark mode via a button. +# The default value is: AUTO_LIGHT. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE = LIGHT + # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen # will adjust the colors in the style sheet and background images according to -# this color. Hue is specified as an angle on a colorwheel, see +# this color. Hue is specified as an angle on a color-wheel, see # https://en.wikipedia.org/wiki/Hue for more information. For instance the value # 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 # purple, and 360 is red again. @@ -1306,7 +1435,7 @@ HTML_EXTRA_FILES = HTML_COLORSTYLE_HUE = 189 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors -# in the HTML output. For a value of 0 the output will use grayscales only. A +# in the HTML output. For a value of 0 the output will use gray-scales only. A # value of 255 will produce the most vivid colors. # Minimum value: 0, maximum value: 255, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. @@ -1324,15 +1453,6 @@ HTML_COLORSTYLE_SAT = 12 HTML_COLORSTYLE_GAMMA = 240 -# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML -# page will contain the date and time when the page was generated. Setting this -# to YES can help to show when doxygen was last run and thus if the -# documentation is up to date. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_TIMESTAMP = NO - # If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML # documentation will contain a main index with vertical navigation menus that # are dynamically created via JavaScript. If disabled, the navigation index will @@ -1352,6 +1472,33 @@ HTML_DYNAMIC_MENUS = NO HTML_DYNAMIC_SECTIONS = NO +# If the HTML_CODE_FOLDING tag is set to YES then classes and functions can be +# dynamically folded and expanded in the generated HTML source code. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_CODE_FOLDING = YES + +# If the HTML_COPY_CLIPBOARD tag is set to YES then doxygen will show an icon in +# the top right corner of code and text fragments that allows the user to copy +# its content to the clipboard. Note this only works if supported by the browser +# and the web page is served via a secure context (see: +# https://www.w3.org/TR/secure-contexts/), i.e. using the https: or file: +# protocol. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COPY_CLIPBOARD = YES + +# Doxygen stores a couple of settings persistently in the browser (via e.g. +# cookies). By default these settings apply to all HTML pages generated by +# doxygen across all projects. The HTML_PROJECT_COOKIE tag can be used to store +# the settings under a project specific key, such that the user preferences will +# be stored separately. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_PROJECT_COOKIE = + # With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries # shown in the various tree structured indices initially; the user can expand # and collapse entries dynamically later on. Doxygen will expand the tree to @@ -1388,6 +1535,13 @@ GENERATE_DOCSET = NO DOCSET_FEEDNAME = "Doxygen generated docs" +# This tag determines the URL of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDURL = + # This tag specifies a string that should uniquely identify the documentation # set bundle. This should be a reverse domain-name style string, e.g. # com.mycompany.MyDocSet. Doxygen will append .docset to the name. @@ -1413,8 +1567,12 @@ DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three # additional HTML index files: index.hhp, index.hhc, and index.hhk. The # index.hhp is a project file that can be read by Microsoft's HTML Help Workshop -# (see: -# https://www.microsoft.com/en-us/download/details.aspx?id=21138) on Windows. +# on Windows. In the beginning of 2021 Microsoft took the original page, with +# a.o. the download links, offline the HTML help workshop was already many years +# in maintenance mode). You can download the HTML help workshop from the web +# archives at Installation executable (see: +# http://web.archive.org/web/20160201063255/http://download.microsoft.com/downlo +# ad/0/A/9/0A939EF6-E31C-430F-A3DF-DFAE7960D564/htmlhelp.exe). # # The HTML Help Workshop contains a compiler that can convert all HTML output # generated by doxygen into a single compiled HTML file (.chm). Compiled HTML @@ -1471,6 +1629,16 @@ BINARY_TOC = NO TOC_EXPAND = NO +# The SITEMAP_URL tag is used to specify the full URL of the place where the +# generated documentation will be placed on the server by the user during the +# deployment of the documentation. The generated sitemap is called sitemap.xml +# and placed on the directory specified by HTML_OUTPUT. In case no SITEMAP_URL +# is specified no sitemap is generated. For information about the sitemap +# protocol see https://www.sitemaps.org +# This tag requires that the tag GENERATE_HTML is set to YES. + +SITEMAP_URL = + # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that # can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help @@ -1573,16 +1741,28 @@ DISABLE_INDEX = YES # to work a browser that supports JavaScript, DHTML, CSS and frames is required # (i.e. any modern browser). Windows users are probably better off using the # HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can -# further fine-tune the look of the index. As an example, the default style -# sheet generated by doxygen has an example that shows how to put an image at -# the root of the tree instead of the PROJECT_NAME. Since the tree basically has -# the same information as the tab index, you could consider setting -# DISABLE_INDEX to YES when enabling this option. +# further fine tune the look of the index (see "Fine-tuning the output"). As an +# example, the default style sheet generated by doxygen has an example that +# shows how to put an image at the root of the tree instead of the PROJECT_NAME. +# Since the tree basically has the same information as the tab index, you could +# consider setting DISABLE_INDEX to YES when enabling this option. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_TREEVIEW = YES +# When both GENERATE_TREEVIEW and DISABLE_INDEX are set to YES, then the +# FULL_SIDEBAR option determines if the side bar is limited to only the treeview +# area (value NO) or if it should extend to the full height of the window (value +# YES). Setting this to YES gives a layout similar to +# https://docs.readthedocs.io with more room for contents, but less room for the +# project logo, title, and description. If either GENERATE_TREEVIEW or +# DISABLE_INDEX is set to NO, this option has no effect. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FULL_SIDEBAR = NO + # The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that # doxygen will group on one line in the generated HTML documentation. # @@ -1607,6 +1787,13 @@ TREEVIEW_WIDTH = 180 EXT_LINKS_IN_WINDOW = NO +# If the OBFUSCATE_EMAILS tag is set to YES, doxygen will obfuscate email +# addresses. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +OBFUSCATE_EMAILS = YES + # If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg # tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see # https://inkscape.org) to generate formulas as SVG images instead of PNGs for @@ -1627,17 +1814,6 @@ HTML_FORMULA_FORMAT = png FORMULA_FONTSIZE = 10 -# Use the FORMULA_TRANSPARENT tag to determine whether or not the images -# generated for formulas are transparent PNGs. Transparent PNGs are not -# supported properly for IE 6.0, but are supported on all modern browsers. -# -# Note that when changing this option you need to delete any form_*.png files in -# the HTML output directory before the changes have effect. -# The default value is: YES. -# This tag requires that the tag GENERATE_HTML is set to YES. - -FORMULA_TRANSPARENT = YES - # The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands # to create new LaTeX commands to be used in formulas as building blocks. See # the section "Including formulas" for details. @@ -1655,11 +1831,29 @@ FORMULA_MACROFILE = USE_MATHJAX = NO +# With MATHJAX_VERSION it is possible to specify the MathJax version to be used. +# Note that the different versions of MathJax have different requirements with +# regards to the different settings, so it is possible that also other MathJax +# settings have to be changed when switching between the different MathJax +# versions. +# Possible values are: MathJax_2 and MathJax_3. +# The default value is: MathJax_2. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_VERSION = MathJax_2 + # When MathJax is enabled you can set the default output format to be used for -# the MathJax output. See the MathJax site (see: -# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. +# the MathJax output. For more details about the output format see MathJax +# version 2 (see: +# http://docs.mathjax.org/en/v2.7-latest/output.html) and MathJax version 3 +# (see: +# http://docs.mathjax.org/en/latest/web/components/output.html). # Possible values are: HTML-CSS (which is slower, but has the best -# compatibility), NativeMML (i.e. MathML) and SVG. +# compatibility. This is the name for Mathjax version 2, for MathJax version 3 +# this will be translated into chtml), NativeMML (i.e. MathML. Only supported +# for MathJax 2. For MathJax version 3 chtml will be used instead.), chtml (This +# is the name for Mathjax version 3, for MathJax version 2 this will be +# translated into HTML-CSS) and SVG. # The default value is: HTML-CSS. # This tag requires that the tag USE_MATHJAX is set to YES. @@ -1672,15 +1866,21 @@ MATHJAX_FORMAT = HTML-CSS # MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax # Content Delivery Network so you can quickly see the result without installing # MathJax. However, it is strongly recommended to install a local copy of -# MathJax from https://www.mathjax.org before deployment. -# The default value is: https://cdn.jsdelivr.net/npm/mathjax@2. +# MathJax from https://www.mathjax.org before deployment. The default value is: +# - in case of MathJax version 2: https://cdn.jsdelivr.net/npm/mathjax@2 +# - in case of MathJax version 3: https://cdn.jsdelivr.net/npm/mathjax@3 # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest # The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax # extension names that should be enabled during MathJax rendering. For example +# for MathJax version 2 (see +# https://docs.mathjax.org/en/v2.7-latest/tex.html#tex-and-latex-extensions): # MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# For example for MathJax version 3 (see +# http://docs.mathjax.org/en/latest/input/tex/extensions/index.html): +# MATHJAX_EXTENSIONS = ams # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_EXTENSIONS = @@ -1860,29 +2060,31 @@ PAPER_TYPE = a4 EXTRA_PACKAGES = -# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the -# generated LaTeX document. The header should contain everything until the first -# chapter. If it is left blank doxygen will generate a standard header. See -# section "Doxygen usage" for information on how to let doxygen write the -# default header to a separate file. +# The LATEX_HEADER tag can be used to specify a user-defined LaTeX header for +# the generated LaTeX document. The header should contain everything until the +# first chapter. If it is left blank doxygen will generate a standard header. It +# is highly recommended to start with a default header using +# doxygen -w latex new_header.tex new_footer.tex new_stylesheet.sty +# and then modify the file new_header.tex. See also section "Doxygen usage" for +# information on how to generate the default header that doxygen normally uses. # -# Note: Only use a user-defined header if you know what you are doing! The -# following commands have a special meaning inside the header: $title, -# $datetime, $date, $doxygenversion, $projectname, $projectnumber, -# $projectbrief, $projectlogo. Doxygen will replace $title with the empty -# string, for the replacement values of the other commands the user is referred -# to HTML_HEADER. +# Note: Only use a user-defined header if you know what you are doing! +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. The following +# commands have a special meaning inside the header (and footer): For a +# description of the possible markers and block names see the documentation. # This tag requires that the tag GENERATE_LATEX is set to YES. LATEX_HEADER = -# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the -# generated LaTeX document. The footer should contain everything after the last -# chapter. If it is left blank doxygen will generate a standard footer. See +# The LATEX_FOOTER tag can be used to specify a user-defined LaTeX footer for +# the generated LaTeX document. The footer should contain everything after the +# last chapter. If it is left blank doxygen will generate a standard footer. See # LATEX_HEADER for more information on how to generate a default footer and what -# special commands can be used inside the footer. -# -# Note: Only use a user-defined footer if you know what you are doing! +# special commands can be used inside the footer. See also section "Doxygen +# usage" for information on how to generate the default footer that doxygen +# normally uses. Note: Only use a user-defined footer if you know what you are +# doing! # This tag requires that the tag GENERATE_LATEX is set to YES. LATEX_FOOTER = @@ -1925,10 +2127,16 @@ PDF_HYPERLINKS = YES USE_PDFLATEX = YES -# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode -# command to the generated LaTeX files. This will instruct LaTeX to keep running -# if errors occur, instead of asking the user for help. This option is also used -# when generating formulas in HTML. +# The LATEX_BATCHMODE tag signals the behavior of LaTeX in case of an error. +# Possible values are: NO same as ERROR_STOP, YES same as BATCH, BATCH In batch +# mode nothing is printed on the terminal, errors are scrolled as if is +# hit at every error; missing files that TeX tries to input or request from +# keyboard input (\read on a not open input stream) cause the job to abort, +# NON_STOP In nonstop mode the diagnostic message will appear on the terminal, +# but there is no possibility of user interaction just like in batch mode, +# SCROLL In scroll mode, TeX will stop only for missing files to input or if +# keyboard input is necessary and ERROR_STOP In errorstop mode, TeX will stop at +# each error, asking for user intervention. # The default value is: NO. # This tag requires that the tag GENERATE_LATEX is set to YES. @@ -1941,16 +2149,6 @@ LATEX_BATCHMODE = NO LATEX_HIDE_INDICES = NO -# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source -# code with syntax highlighting in the LaTeX output. -# -# Note that which sources are shown also depends on other settings such as -# SOURCE_BROWSER. -# The default value is: NO. -# This tag requires that the tag GENERATE_LATEX is set to YES. - -LATEX_SOURCE_CODE = NO - # The LATEX_BIB_STYLE tag can be used to specify the style to use for the # bibliography, e.g. plainnat, or ieeetr. See # https://en.wikipedia.org/wiki/BibTeX and \cite for more info. @@ -1959,14 +2157,6 @@ LATEX_SOURCE_CODE = NO LATEX_BIB_STYLE = plain -# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated -# page will contain the date and time when the page was generated. Setting this -# to NO can help when comparing the output of multiple runs. -# The default value is: NO. -# This tag requires that the tag GENERATE_LATEX is set to YES. - -LATEX_TIMESTAMP = NO - # The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute) # path from which the emoji images will be read. If a relative path is entered, # it will be relative to the LATEX_OUTPUT directory. If left blank the @@ -2031,15 +2221,13 @@ RTF_STYLESHEET_FILE = RTF_EXTENSIONS_FILE = -# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code -# with syntax highlighting in the RTF output. -# -# Note that which sources are shown also depends on other settings such as -# SOURCE_BROWSER. -# The default value is: NO. +# The RTF_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the RTF_OUTPUT output directory. +# Note that the files will be copied as-is; there are no commands or markers +# available. # This tag requires that the tag GENERATE_RTF is set to YES. -RTF_SOURCE_CODE = NO +RTF_EXTRA_FILES = #--------------------------------------------------------------------------- # Configuration options related to the man page output @@ -2137,21 +2325,12 @@ GENERATE_DOCBOOK = NO DOCBOOK_OUTPUT = docbook -# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the -# program listings (including syntax highlighting and cross-referencing -# information) to the DOCBOOK output. Note that enabling this will significantly -# increase the size of the DOCBOOK output. -# The default value is: NO. -# This tag requires that the tag GENERATE_DOCBOOK is set to YES. - -DOCBOOK_PROGRAMLISTING = NO - #--------------------------------------------------------------------------- # Configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an -# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures +# AutoGen Definitions (see https://autogen.sourceforge.net/) file that captures # the structure of the code including all documentation. Note that this feature # is still experimental and incomplete at the moment. # The default value is: NO. @@ -2162,6 +2341,28 @@ GENERATE_AUTOGEN_DEF = NO # Configuration options related to Sqlite3 output #--------------------------------------------------------------------------- +# If the GENERATE_SQLITE3 tag is set to YES doxygen will generate a Sqlite3 +# database with symbols found by doxygen stored in tables. +# The default value is: NO. + +GENERATE_SQLITE3 = NO + +# The SQLITE3_OUTPUT tag is used to specify where the Sqlite3 database will be +# put. If a relative path is entered the value of OUTPUT_DIRECTORY will be put +# in front of it. +# The default directory is: sqlite3. +# This tag requires that the tag GENERATE_SQLITE3 is set to YES. + +SQLITE3_OUTPUT = sqlite3 + +# The SQLITE3_RECREATE_DB tag is set to YES, the existing doxygen_sqlite3.db +# database file will be recreated with each doxygen run. If set to NO, doxygen +# will warn if a database file is already found and not modify it. +# The default value is: YES. +# This tag requires that the tag GENERATE_SQLITE3 is set to YES. + +SQLITE3_RECREATE_DB = YES + #--------------------------------------------------------------------------- # Configuration options related to the Perl module output #--------------------------------------------------------------------------- @@ -2236,7 +2437,8 @@ SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by the -# preprocessor. +# preprocessor. Note that the INCLUDE_PATH is not recursive, so the setting of +# RECURSIVE has no effect here. # This tag requires that the tag SEARCH_INCLUDES is set to YES. INCLUDE_PATH = @@ -2303,15 +2505,15 @@ TAGFILES = GENERATE_TAGFILE = -# If the ALLEXTERNALS tag is set to YES, all external class will be listed in -# the class index. If set to NO, only the inherited external classes will be -# listed. +# If the ALLEXTERNALS tag is set to YES, all external classes and namespaces +# will be listed in the class and namespace index. If set to NO, only the +# inherited external classes will be listed. # The default value is: NO. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed -# in the modules index. If set to NO, only the current project's groups will be +# in the topic index. If set to NO, only the current project's groups will be # listed. # The default value is: YES. @@ -2325,25 +2527,9 @@ EXTERNAL_GROUPS = YES EXTERNAL_PAGES = YES #--------------------------------------------------------------------------- -# Configuration options related to the dot tool +# Configuration options related to diagram generator tools #--------------------------------------------------------------------------- -# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram -# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to -# NO turns the diagrams off. Note that this option also works with HAVE_DOT -# disabled, but it is recommended to install and use dot, since it yields more -# powerful graphs. -# The default value is: YES. - -CLASS_DIAGRAMS = YES - -# You can include diagrams made with dia in doxygen documentation. Doxygen will -# then run dia to produce the diagram and insert it in the documentation. The -# DIA_PATH tag allows you to specify the directory where the dia binary resides. -# If left empty dia is assumed to be found in the default search path. - -DIA_PATH = - # If set to YES the inheritance and collaboration graphs will hide inheritance # and usage relations if the target is undocumented or is not a class. # The default value is: YES. @@ -2352,7 +2538,7 @@ HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz (see: -# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent +# https://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent # Bell Labs. The other options in this section have no effect if this option is # set to NO # The default value is: NO. @@ -2369,49 +2555,77 @@ HAVE_DOT = NO DOT_NUM_THREADS = 0 -# When you want a differently looking font in the dot files that doxygen -# generates you can specify the font name using DOT_FONTNAME. You need to make -# sure dot is able to find the font, which can be done by putting it in a -# standard location or by setting the DOTFONTPATH environment variable or by -# setting DOT_FONTPATH to the directory containing the font. -# The default value is: Helvetica. +# DOT_COMMON_ATTR is common attributes for nodes, edges and labels of +# subgraphs. When you want a differently looking font in the dot files that +# doxygen generates you can specify fontname, fontcolor and fontsize attributes. +# For details please see Node, +# Edge and Graph Attributes specification You need to make sure dot is able +# to find the font, which can be done by putting it in a standard location or by +# setting the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the +# directory containing the font. Default graphviz fontsize is 14. +# The default value is: fontname=Helvetica,fontsize=10. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_FONTNAME = Helvetica +DOT_COMMON_ATTR = "fontname=Helvetica,fontsize=10" -# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of -# dot graphs. -# Minimum value: 4, maximum value: 24, default value: 10. +# DOT_EDGE_ATTR is concatenated with DOT_COMMON_ATTR. For elegant style you can +# add 'arrowhead=open, arrowtail=open, arrowsize=0.5'. Complete documentation about +# arrows shapes. +# The default value is: labelfontname=Helvetica,labelfontsize=10. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_FONTSIZE = 10 +DOT_EDGE_ATTR = "labelfontname=Helvetica,labelfontsize=10" -# By default doxygen will tell dot to use the default font as specified with -# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set -# the path where dot can find it using this tag. +# DOT_NODE_ATTR is concatenated with DOT_COMMON_ATTR. For view without boxes +# around nodes set 'shape=plain' or 'shape=plaintext' Shapes specification +# The default value is: shape=box,height=0.2,width=0.4. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_NODE_ATTR = "shape=box,height=0.2,width=0.4" + +# You can set the path where dot can find font specified with fontname in +# DOT_COMMON_ATTR and others dot attributes. # This tag requires that the tag HAVE_DOT is set to YES. DOT_FONTPATH = -# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for -# each documented class showing the direct and indirect inheritance relations. -# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO. +# If the CLASS_GRAPH tag is set to YES or GRAPH or BUILTIN then doxygen will +# generate a graph for each documented class showing the direct and indirect +# inheritance relations. In case the CLASS_GRAPH tag is set to YES or GRAPH and +# HAVE_DOT is enabled as well, then dot will be used to draw the graph. In case +# the CLASS_GRAPH tag is set to YES and HAVE_DOT is disabled or if the +# CLASS_GRAPH tag is set to BUILTIN, then the built-in generator will be used. +# If the CLASS_GRAPH tag is set to TEXT the direct and indirect inheritance +# relations will be shown as texts / links. Explicit enabling an inheritance +# graph or choosing a different representation for an inheritance graph of a +# specific class, can be accomplished by means of the command \inheritancegraph. +# Disabling an inheritance graph can be accomplished by means of the command +# \hideinheritancegraph. +# Possible values are: NO, YES, TEXT, GRAPH and BUILTIN. # The default value is: YES. -# This tag requires that the tag HAVE_DOT is set to YES. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a # graph for each documented class showing the direct and indirect implementation # dependencies (inheritance, containment, and class references variables) of the -# class with other documented classes. +# class with other documented classes. Explicit enabling a collaboration graph, +# when COLLABORATION_GRAPH is set to NO, can be accomplished by means of the +# command \collaborationgraph. Disabling a collaboration graph can be +# accomplished by means of the command \hidecollaborationgraph. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. COLLABORATION_GRAPH = YES # If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for -# groups, showing the direct groups dependencies. +# groups, showing the direct groups dependencies. Explicit enabling a group +# dependency graph, when GROUP_GRAPHS is set to NO, can be accomplished by means +# of the command \groupgraph. Disabling a directory graph can be accomplished by +# means of the command \hidegroupgraph. See also the chapter Grouping in the +# manual. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2453,8 +2667,8 @@ DOT_UML_DETAILS = NO # The DOT_WRAP_THRESHOLD tag can be used to set the maximum number of characters # to display on a single line. If the actual line length exceeds this threshold -# significantly it will wrapped across multiple lines. Some heuristics are apply -# to avoid ugly line breaks. +# significantly it will be wrapped across multiple lines. Some heuristics are +# applied to avoid ugly line breaks. # Minimum value: 0, maximum value: 1000, default value: 17. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2471,7 +2685,9 @@ TEMPLATE_RELATIONS = NO # If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to # YES then doxygen will generate a graph for each documented file showing the # direct and indirect include dependencies of the file with other documented -# files. +# files. Explicit enabling an include graph, when INCLUDE_GRAPH is is set to NO, +# can be accomplished by means of the command \includegraph. Disabling an +# include graph can be accomplished by means of the command \hideincludegraph. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2480,7 +2696,10 @@ INCLUDE_GRAPH = YES # If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are # set to YES then doxygen will generate a graph for each documented file showing # the direct and indirect include dependencies of the file with other documented -# files. +# files. Explicit enabling an included by graph, when INCLUDED_BY_GRAPH is set +# to NO, can be accomplished by means of the command \includedbygraph. Disabling +# an included by graph can be accomplished by means of the command +# \hideincludedbygraph. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2520,16 +2739,26 @@ GRAPHICAL_HIERARCHY = YES # If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the # dependencies a directory has on other directories in a graphical way. The # dependency relations are determined by the #include relations between the -# files in the directories. +# files in the directories. Explicit enabling a directory graph, when +# DIRECTORY_GRAPH is set to NO, can be accomplished by means of the command +# \directorygraph. Disabling a directory graph can be accomplished by means of +# the command \hidedirectorygraph. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. DIRECTORY_GRAPH = YES +# The DIR_GRAPH_MAX_DEPTH tag can be used to limit the maximum number of levels +# of child directories generated in directory dependency graphs by dot. +# Minimum value: 1, maximum value: 25, default value: 1. +# This tag requires that the tag DIRECTORY_GRAPH is set to YES. + +DIR_GRAPH_MAX_DEPTH = 1 + # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. For an explanation of the image formats see the section # output formats in the documentation of the dot tool (Graphviz (see: -# http://www.graphviz.org/)). +# https://www.graphviz.org/)). # Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order # to make the SVG files visible in IE 9+ (other browsers do not have this # requirement). @@ -2566,11 +2795,12 @@ DOT_PATH = DOTFILE_DIRS = -# The MSCFILE_DIRS tag can be used to specify one or more directories that -# contain msc files that are included in the documentation (see the \mscfile -# command). +# You can include diagrams made with dia in doxygen documentation. Doxygen will +# then run dia to produce the diagram and insert it in the documentation. The +# DIA_PATH tag allows you to specify the directory where the dia binary resides. +# If left empty dia is assumed to be found in the default search path. -MSCFILE_DIRS = +DIA_PATH = # The DIAFILE_DIRS tag can be used to specify one or more directories that # contain dia files that are included in the documentation (see the \diafile @@ -2579,10 +2809,10 @@ MSCFILE_DIRS = DIAFILE_DIRS = # When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the -# path where java can find the plantuml.jar file. If left blank, it is assumed -# PlantUML is not used or called during a preprocessing step. Doxygen will -# generate a warning when it encounters a \startuml command in this case and -# will not generate output for the diagram. +# path where java can find the plantuml.jar file or to the filename of jar file +# to be used. If left blank, it is assumed PlantUML is not used or called during +# a preprocessing step. Doxygen will generate a warning when it encounters a +# \startuml command in this case and will not generate output for the diagram. PLANTUML_JAR_PATH = @@ -2599,7 +2829,7 @@ PLANTUML_INCLUDE_PATH = # The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes # that will be shown in the graph. If the number of nodes in a graph becomes # larger than this value, doxygen will truncate the graph, which is visualized -# by representing a node as a red box. Note that doxygen if the number of direct +# by representing a node as a red box. Note that if the number of direct # children of the root node in a graph is already larger than # DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that # the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. @@ -2620,18 +2850,6 @@ DOT_GRAPH_MAX_NODES = 50 MAX_DOT_GRAPH_DEPTH = 0 -# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent -# background. This is disabled by default, because dot on Windows does not seem -# to support this out of the box. -# -# Warning: Depending on the platform used, enabling this option may lead to -# badly anti-aliased labels on the edges of a graph (i.e. they become hard to -# read). -# The default value is: NO. -# This tag requires that the tag HAVE_DOT is set to YES. - -DOT_TRANSPARENT = NO - # Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) support @@ -2644,6 +2862,8 @@ DOT_MULTI_TARGETS = NO # If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page # explaining the meaning of the various boxes and arrows in the dot generated # graphs. +# Note: This tag requires that UML_LOOK isn't set, i.e. the doxygen internal +# graphical representation for inheritance and collaboration diagrams is used. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2652,8 +2872,24 @@ GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate # files that are used to generate the various graphs. # -# Note: This setting is not only used for dot files but also for msc and -# plantuml temporary files. +# Note: This setting is not only used for dot files but also for msc temporary +# files. # The default value is: YES. DOT_CLEANUP = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. If the MSCGEN_TOOL tag is left empty (the default), then doxygen will +# use a built-in version of mscgen tool to produce the charts. Alternatively, +# the MSCGEN_TOOL tag can also specify the name an external tool. For instance, +# specifying prog as the value, doxygen will call the tool as prog -T +# -o . The external tool should support +# output file formats "png", "eps", "svg", and "ismap". + +MSCGEN_TOOL = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the \mscfile +# command). + +MSCFILE_DIRS = diff --git a/src/dashbls/depends/mimalloc/doc/mimalloc-doc.h b/src/dashbls/depends/mimalloc/doc/mimalloc-doc.h index f435309226bd..7a412852ffe8 100644 --- a/src/dashbls/depends/mimalloc/doc/mimalloc-doc.h +++ b/src/dashbls/depends/mimalloc/doc/mimalloc-doc.h @@ -1,5 +1,5 @@ /* ---------------------------------------------------------------------------- -Copyright (c) 2018-2021, Microsoft Research, Daan Leijen +Copyright (c) 2018-2025, Microsoft Research, Daan Leijen This is free software; you can redistribute it and/or modify it under the terms of the MIT license. A copy of the license can be found in the file "LICENSE" at the root of this distribution. @@ -25,12 +25,15 @@ without code changes, for example, on Unix you can use it as: ``` Notable aspects of the design include: - - __small and consistent__: the library is about 8k LOC using simple and consistent data structures. This makes it very suitable to integrate and adapt in other projects. For runtime systems it provides hooks for a monotonic _heartbeat_ and deferred freeing (for bounded worst-case times with reference counting). + Partly due to its simplicity, mimalloc has been ported to many systems (Windows, macOS, + Linux, WASM, various BSD's, Haiku, MUSL, etc) and has excellent support for dynamic overriding. + At the same time, it is an industrial strength allocator that runs (very) large scale + distributed services on thousands of machines with excellent worst case latencies. - __free list sharding__: instead of one big free list (per size class) we have many smaller lists per "mimalloc page" which reduces fragmentation and increases locality -- @@ -40,28 +43,28 @@ Notable aspects of the design include: per mimalloc page, but for each page we have multiple free lists. In particular, there is one list for thread-local `free` operations, and another one for concurrent `free` operations. Free-ing from another thread can now be a single CAS without needing - sophisticated coordination between threads. Since there will be + sophisticated coordination between threads. Since there will be thousands of separate free lists, contention is naturally distributed over the heap, and the chance of contending on a single location will be low -- this is quite similar to randomized algorithms like skip lists where adding a random oracle removes the need for a more complex algorithm. -- __eager page reset__: when a "page" becomes empty (with increased chance - due to free list sharding) the memory is marked to the OS as unused ("reset" or "purged") +- __eager page purging__: when a "page" becomes empty (with increased chance + due to free list sharding) the memory is marked to the OS as unused (reset or decommitted) reducing (real) memory pressure and fragmentation, especially in long running programs. -- __secure__: _mimalloc_ can be build in secure mode, adding guard pages, +- __secure__: _mimalloc_ can be built in secure mode, adding guard pages, randomized allocation, encrypted free lists, etc. to protect against various - heap vulnerabilities. The performance penalty is only around 5% on average + heap vulnerabilities. The performance penalty is usually around 10% on average over our benchmarks. - __first-class heaps__: efficiently create and use multiple heaps to allocate across different regions. A heap can be destroyed at once instead of deallocating each object separately. - __bounded__: it does not suffer from _blowup_ \[1\], has bounded worst-case allocation - times (_wcat_), bounded space overhead (~0.2% meta-data, with low internal fragmentation), - and has no internal points of contention using only atomic operations. -- __fast__: In our benchmarks (see [below](#performance)), - _mimalloc_ outperforms all other leading allocators (_jemalloc_, _tcmalloc_, _Hoard_, etc), - and usually uses less memory (up to 25% more in the worst case). A nice property - is that it does consistently well over a wide range of benchmarks. + times (_wcat_) (upto OS primitives), bounded space overhead (~0.2% meta-data, with low + internal fragmentation), and has no internal points of contention using only atomic operations. +- __fast__: In our benchmarks (see [below](#bench)), + _mimalloc_ outperforms other leading allocators (_jemalloc_, _tcmalloc_, _Hoard_, etc), + and often uses less memory. A nice property is that it does consistently well over a wide range + of benchmarks. There is also good huge OS page support for larger server programs. You can read more on the design of _mimalloc_ in the [technical report](https://www.microsoft.com/en-us/research/publication/mimalloc-free-list-sharding-in-action) @@ -168,7 +171,7 @@ void* mi_expand(void* p, size_t newsize); /// @returns A pointer to a block of \a count * \a size bytes, or \a NULL /// if out of memory or if \a count * \a size overflows. /// -/// If there is no overflow, it behaves exactly like `mi_malloc(p,count*size)`. +/// If there is no overflow, it behaves exactly like `mi_malloc(count*size)`. /// @see mi_calloc() /// @see mi_zallocn() void* mi_mallocn(size_t count, size_t size); @@ -278,8 +281,7 @@ void* mi_zalloc_small(size_t size); /// The returned size can be /// used to call \a mi_expand successfully. /// The returned size is always at least equal to the -/// allocated size of \a p, and, in the current design, -/// should be less than 16.7% more. +/// allocated size of \a p. /// /// @see [_msize](https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/msize?view=vs-2017) (Windows) /// @see [malloc_usable_size](http://man7.org/linux/man-pages/man3/malloc_usable_size.3.html) (Linux) @@ -304,7 +306,7 @@ size_t mi_good_size(size_t size); /// in very narrow circumstances; in particular, when a long running thread /// allocates a lot of blocks that are freed by other threads it may improve /// resource usage by calling this every once in a while. -void mi_collect(bool force); +void mi_collect(bool force); /// Deprecated /// @param out Ignored, outputs to the registered output function or stderr by default. @@ -414,7 +416,7 @@ void mi_register_error(mi_error_fun* errfun, void* arg); bool mi_is_in_heap_region(const void* p); /// Reserve OS memory for use by mimalloc. Reserved areas are used -/// before allocating from the OS again. By reserving a large area upfront, +/// before allocating from the OS again. By reserving a large area upfront, /// allocation can be more efficient, and can be better managed on systems /// without `mmap`/`VirtualAlloc` (like WASM for example). /// @param size The size to reserve. @@ -423,25 +425,24 @@ bool mi_is_in_heap_region(const void* p); /// @return \a 0 if successful, and an error code otherwise (e.g. `ENOMEM`). int mi_reserve_os_memory(size_t size, bool commit, bool allow_large); -/// Manage a particular memory area for use by mimalloc. +/// Manage a particular memory area for use by mimalloc. /// This is just like `mi_reserve_os_memory` except that the area should already be /// allocated in some manner and available for use my mimalloc. /// @param start Start of the memory area /// @param size The size of the memory area. -/// @param commit Is the area already committed? -/// @param is_large Does it consist of large OS pages? Set this to \a true as well for memory -/// that should not be decommitted or protected (like rdma etc.) +/// @param is_committed Is the area already committed? +/// @param is_pinned Can the memory not be decommitted or reset? (usually the case for large OS pages) /// @param is_zero Does the area consists of zero's? /// @param numa_node Possible associated numa node or `-1`. /// @return \a true if successful, and \a false on error. -bool mi_manage_os_memory(void* start, size_t size, bool is_committed, bool is_large, bool is_zero, int numa_node); +bool mi_manage_os_memory(void* start, size_t size, bool is_committed, bool is_pinned, bool is_zero, int numa_node); /// Reserve \a pages of huge OS pages (1GiB) evenly divided over \a numa_nodes nodes, /// but stops after at most `timeout_msecs` seconds. /// @param pages The number of 1GiB pages to reserve. /// @param numa_nodes The number of nodes do evenly divide the pages over, or 0 for using the actual number of NUMA nodes. /// @param timeout_msecs Maximum number of milli-seconds to try reserving, or 0 for no timeout. -/// @returns 0 if successfull, \a ENOMEM if running out of memory, or \a ETIMEDOUT if timed out. +/// @returns 0 if successful, \a ENOMEM if running out of memory, or \a ETIMEDOUT if timed out. /// /// The reserved memory is used by mimalloc to satisfy allocations. /// May quit before \a timeout_msecs are expired if it estimates it will take more than @@ -453,9 +454,9 @@ int mi_reserve_huge_os_pages_interleave(size_t pages, size_t numa_nodes, size_t /// Reserve \a pages of huge OS pages (1GiB) at a specific \a numa_node, /// but stops after at most `timeout_msecs` seconds. /// @param pages The number of 1GiB pages to reserve. -/// @param numa_node The NUMA node where the memory is reserved (start at 0). +/// @param numa_node The NUMA node where the memory is reserved (start at 0). Use -1 for no affinity. /// @param timeout_msecs Maximum number of milli-seconds to try reserving, or 0 for no timeout. -/// @returns 0 if successfull, \a ENOMEM if running out of memory, or \a ETIMEDOUT if timed out. +/// @returns 0 if successful, \a ENOMEM if running out of memory, or \a ETIMEDOUT if timed out. /// /// The reserved memory is used by mimalloc to satisfy allocations. /// May quit before \a timeout_msecs are expired if it estimates it will take more than @@ -468,7 +469,7 @@ int mi_reserve_huge_os_pages_at(size_t pages, int numa_node, size_t timeout_msec /// Is the C runtime \a malloc API redirected? /// @returns \a true if all malloc API calls are redirected to mimalloc. /// -/// Currenty only used on Windows. +/// Currently only used on Windows. bool mi_is_redirected(); /// Return process information (time and memory usage). @@ -486,6 +487,91 @@ bool mi_is_redirected(); /// on other systems as the amount of read/write accessible memory reserved by mimalloc. void mi_process_info(size_t* elapsed_msecs, size_t* user_msecs, size_t* system_msecs, size_t* current_rss, size_t* peak_rss, size_t* current_commit, size_t* peak_commit, size_t* page_faults); +/// @brief Show all current arena's. +/// @param show_inuse Show the arena blocks that are in use. +/// @param show_abandoned Show the abandoned arena blocks. +/// @param show_purge Show arena blocks scheduled for purging. +void mi_debug_show_arenas(bool show_inuse, bool show_abandoned, bool show_purge); + +/// Mimalloc uses large (virtual) memory areas, called "arena"s, from the OS to manage its memory. +/// Each arena has an associated identifier. +typedef int mi_arena_id_t; + +/// @brief Return the size of an arena. +/// @param arena_id The arena identifier. +/// @param size Returned size in bytes of the (virtual) arena area. +/// @return base address of the arena. +void* mi_arena_area(mi_arena_id_t arena_id, size_t* size); + +/// @brief Reserve huge OS pages (1GiB) into a single arena. +/// @param pages Number of 1GiB pages to reserve. +/// @param numa_node The associated NUMA node, or -1 for no NUMA preference. +/// @param timeout_msecs Max amount of milli-seconds this operation is allowed to take. (0 is infinite) +/// @param exclusive If exclusive, only a heap associated with this arena can allocate in it. +/// @param arena_id The arena identifier. +/// @return 0 if successful, \a ENOMEM if running out of memory, or \a ETIMEDOUT if timed out. +int mi_reserve_huge_os_pages_at_ex(size_t pages, int numa_node, size_t timeout_msecs, bool exclusive, mi_arena_id_t* arena_id); + +/// @brief Reserve OS memory to be managed in an arena. +/// @param size Size the reserve. +/// @param commit Should the memory be initially committed? +/// @param allow_large Allow the use of large OS pages? +/// @param exclusive Is the returned arena exclusive? +/// @param arena_id The new arena identifier. +/// @return Zero on success, an error code otherwise. +int mi_reserve_os_memory_ex(size_t size, bool commit, bool allow_large, bool exclusive, mi_arena_id_t* arena_id); + +/// @brief Manage externally allocated memory as a mimalloc arena. This memory will not be freed by mimalloc. +/// @param start Start address of the area. +/// @param size Size in bytes of the area. +/// @param is_committed Is the memory already committed? +/// @param is_large Does it consist of (pinned) large OS pages? +/// @param is_zero Is the memory zero-initialized? +/// @param numa_node Associated NUMA node, or -1 to have no NUMA preference. +/// @param exclusive Is the arena exclusive (where only heaps associated with the arena can allocate in it) +/// @param arena_id The new arena identifier. +/// @return `true` if successful. +bool mi_manage_os_memory_ex(void* start, size_t size, bool is_committed, bool is_large, bool is_zero, int numa_node, bool exclusive, mi_arena_id_t* arena_id); + +/// @brief Create a new heap that only allocates in the specified arena. +/// @param arena_id The arena identifier. +/// @return The new heap or `NULL`. +mi_heap_t* mi_heap_new_in_arena(mi_arena_id_t arena_id); + +/// @brief Create a new heap +/// @param heap_tag The heap tag associated with this heap; heaps only reclaim memory between heaps with the same tag. +/// @param allow_destroy Is \a mi_heap_destroy allowed? Not allowing this allows the heap to reclaim memory from terminated threads. +/// @param arena_id If not 0, the heap will only allocate from the specified arena. +/// @return A new heap or `NULL` on failure. +/// +/// The \a arena_id can be used by runtimes to allocate only in a specified pre-reserved arena. +/// This is used for example for a compressed pointer heap in Koka. +/// The \a heap_tag enables heaps to keep objects of a certain type isolated to heaps with that tag. +/// This is used for example in the CPython integration. +mi_heap_t* mi_heap_new_ex(int heap_tag, bool allow_destroy, mi_arena_id_t arena_id); + +/// A process can associate threads with sub-processes. +/// A sub-process will not reclaim memory from (abandoned heaps/threads) +/// other subprocesses. +typedef void* mi_subproc_id_t; + +/// @brief Get the main sub-process identifier. +mi_subproc_id_t mi_subproc_main(void); + +/// @brief Create a fresh sub-process (with no associated threads yet). +/// @return The new sub-process identifier. +mi_subproc_id_t mi_subproc_new(void); + +/// @brief Delete a previously created sub-process. +/// @param subproc The sub-process identifier. +/// Only delete sub-processes if all associated threads have terminated. +void mi_subproc_delete(mi_subproc_id_t subproc); + +/// Add the current thread to the given sub-process. +/// This should be called right after a thread is created (and no allocation has taken place yet) +void mi_subproc_add_current_thread(mi_subproc_id_t subproc); + + /// \} // ------------------------------------------------------ @@ -495,20 +581,24 @@ void mi_process_info(size_t* elapsed_msecs, size_t* user_msecs, size_t* system_m /// \defgroup aligned Aligned Allocation /// /// Allocating aligned memory blocks. +/// Note that `alignment` always follows `size` for consistency with the unaligned +/// allocation API, but unfortunately this differs from `posix_memalign` and `aligned_alloc` in the C library. /// /// \{ -/// The maximum supported alignment size (currently 1MiB). -#define MI_ALIGNMENT_MAX (1024*1024UL) - /// Allocate \a size bytes aligned by \a alignment. /// @param size number of bytes to allocate. -/// @param alignment the minimal alignment of the allocated memory. Must be less than #MI_ALIGNMENT_MAX. -/// @returns pointer to the allocated memory or \a NULL if out of memory. -/// The returned pointer is aligned by \a alignment, i.e. -/// `(uintptr_t)p % alignment == 0`. -/// +/// @param alignment the minimal alignment of the allocated memory. +/// @returns pointer to the allocated memory or \a NULL if out of memory, +/// or if the alignment is not a power of 2 (including 0). The \a size is unrestricted +/// (and does not have to be an integral multiple of the \a alignment). +/// The returned pointer is aligned by \a alignment, i.e. `(uintptr_t)p % alignment == 0`. /// Returns a unique pointer if called with \a size 0. +/// +/// Note that `alignment` always follows `size` for consistency with the unaligned +/// allocation API, but unfortunately this differs from `posix_memalign` and `aligned_alloc` in the C library. +/// +/// @see [aligned_alloc](https://en.cppreference.com/w/c/memory/aligned_alloc) (in the standard C11 library, with switched arguments!) /// @see [_aligned_malloc](https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/aligned-malloc?view=vs-2017) (on Windows) /// @see [aligned_alloc](http://man.openbsd.org/reallocarray) (on BSD, with switched arguments!) /// @see [posix_memalign](https://linux.die.net/man/3/posix_memalign) (on Posix, with switched arguments!) @@ -522,11 +612,12 @@ void* mi_realloc_aligned(void* p, size_t newsize, size_t alignment); /// @param size number of bytes to allocate. /// @param alignment the minimal alignment of the allocated memory at \a offset. /// @param offset the offset that should be aligned. -/// @returns pointer to the allocated memory or \a NULL if out of memory. -/// The returned pointer is aligned by \a alignment at \a offset, i.e. -/// `((uintptr_t)p + offset) % alignment == 0`. -/// +/// @returns pointer to the allocated memory or \a NULL if out of memory, +/// or if the alignment is not a power of 2 (including 0). The \a size is unrestricted +/// (and does not have to be an integral multiple of the \a alignment). +/// The returned pointer is aligned by \a alignment, i.e. `(uintptr_t)p % alignment == 0`. /// Returns a unique pointer if called with \a size 0. +/// /// @see [_aligned_offset_malloc](https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/aligned-offset-malloc?view=vs-2017) (on Windows) void* mi_malloc_aligned_at(size_t size, size_t alignment, size_t offset); void* mi_zalloc_aligned_at(size_t size, size_t alignment, size_t offset); @@ -558,7 +649,7 @@ mi_heap_t* mi_heap_new(); /// Delete a previously allocated heap. /// This will release resources and migrate any -/// still allocated blocks in this heap (efficienty) +/// still allocated blocks in this heap (efficiently) /// to the default heap. /// /// If \a heap is the default heap, the default @@ -574,12 +665,12 @@ void mi_heap_delete(mi_heap_t* heap); /// heap is set to the backing heap. void mi_heap_destroy(mi_heap_t* heap); -/// Set the default heap to use for mi_malloc() et al. +/// Set the default heap to use in the current thread for mi_malloc() et al. /// @param heap The new default heap. /// @returns The previous default heap. mi_heap_t* mi_heap_set_default(mi_heap_t* heap); -/// Get the default heap that is used for mi_malloc() et al. +/// Get the default heap that is used for mi_malloc() et al. (for the current thread). /// @returns The current default heap. mi_heap_t* mi_heap_get_default(); @@ -764,6 +855,8 @@ typedef struct mi_heap_area_s { size_t committed; ///< current committed bytes of this area size_t used; ///< bytes in use by allocated blocks size_t block_size; ///< size in bytes of one block + size_t full_block_size; ///< size in bytes of a full block including padding and metadata. + int heap_tag; ///< heap tag associated with this area (see \a mi_heap_new_ex) } mi_heap_area_t; /// Visitor function passed to mi_heap_visit_blocks() @@ -788,6 +881,23 @@ typedef bool (mi_block_visit_fun)(const mi_heap_t* heap, const mi_heap_area_t* a /// @returns \a true if all areas and blocks were visited. bool mi_heap_visit_blocks(const mi_heap_t* heap, bool visit_all_blocks, mi_block_visit_fun* visitor, void* arg); +/// @brief Visit all areas and blocks in abandoned heaps. +/// @param subproc_id The sub-process id associated with the abandoned heaps. +/// @param heap_tag Visit only abandoned memory with the specified heap tag, use -1 to visit all abandoned memory. +/// @param visit_blocks If \a true visits all allocated blocks, otherwise +/// \a visitor is only called for every heap area. +/// @param visitor This function is called for every area in the heap +/// (with \a block as \a NULL). If \a visit_all_blocks is +/// \a true, \a visitor is also called for every allocated +/// block in every area (with `block!=NULL`). +/// return \a false from this function to stop visiting early. +/// @param arg extra argument passed to the \a visitor. +/// @return \a true if all areas and blocks were visited. +/// +/// Note: requires the option `mi_option_visit_abandoned` to be set +/// at the start of the program. +bool mi_abandoned_visit_blocks(mi_subproc_id_t subproc_id, int heap_tag, bool visit_blocks, mi_block_visit_fun* visitor, void* arg); + /// \} /// \defgroup options Runtime Options @@ -799,34 +909,38 @@ bool mi_heap_visit_blocks(const mi_heap_t* heap, bool visit_all_blocks, mi_block /// Runtime options. typedef enum mi_option_e { // stable options - mi_option_show_errors, ///< Print error messages to `stderr`. - mi_option_show_stats, ///< Print statistics to `stderr` when the program is done. - mi_option_verbose, ///< Print verbose messages to `stderr`. - - // the following options are experimental - mi_option_eager_commit, ///< Eagerly commit segments (4MiB) (enabled by default). - mi_option_large_os_pages, ///< Use large OS pages (2MiB in size) if possible - mi_option_reserve_huge_os_pages, ///< The number of huge OS pages (1GiB in size) to reserve at the start of the program. - mi_option_reserve_huge_os_pages_at, ///< Reserve huge OS pages at node N. - mi_option_reserve_os_memory, ///< Reserve specified amount of OS memory at startup, e.g. "1g" or "512m". - mi_option_segment_cache, ///< The number of segments per thread to keep cached (0). - mi_option_page_reset, ///< Reset page memory after \a mi_option_reset_delay milliseconds when it becomes free. - mi_option_abandoned_page_reset, //< Reset free page memory when a thread terminates. - mi_option_use_numa_nodes, ///< Pretend there are at most N NUMA nodes; Use 0 to use the actual detected NUMA nodes at runtime. - mi_option_eager_commit_delay, ///< the first N segments per thread are not eagerly committed (=1). - mi_option_os_tag, ///< OS tag to assign to mimalloc'd memory - mi_option_limit_os_alloc, ///< If set to 1, do not use OS memory for allocation (but only pre-reserved arenas) - - // v1.x specific options - mi_option_eager_region_commit, ///< Eagerly commit large (256MiB) memory regions (enabled by default, except on Windows) - mi_option_segment_reset, ///< Experimental - mi_option_reset_delay, ///< Delay in milli-seconds before resetting a page (100ms by default) - mi_option_reset_decommits, ///< Experimental - - // v2.x specific options - mi_option_allow_decommit, ///< Enable decommitting memory (=on) - mi_option_decommit_delay, ///< Decommit page memory after N milli-seconds delay (25ms). - mi_option_segment_decommit_delay, ///< Decommit large segment memory after N milli-seconds delay (500ms). + mi_option_show_errors, ///< Print error messages. + mi_option_show_stats, ///< Print statistics on termination. + mi_option_verbose, ///< Print verbose messages. + mi_option_max_errors, ///< issue at most N error messages + mi_option_max_warnings, ///< issue at most N warning messages + + // advanced options + mi_option_reserve_huge_os_pages, ///< reserve N huge OS pages (1GiB pages) at startup + mi_option_reserve_huge_os_pages_at, ///< Reserve N huge OS pages at a specific NUMA node N. + mi_option_reserve_os_memory, ///< reserve specified amount of OS memory in an arena at startup (internally, this value is in KiB; use `mi_option_get_size`) + mi_option_allow_large_os_pages, ///< allow large (2 or 4 MiB) OS pages, implies eager commit. If false, also disables THP for the process. + mi_option_purge_decommits, ///< should a memory purge decommit? (=1). Set to 0 to use memory reset on a purge (instead of decommit) + mi_option_arena_reserve, ///< initial memory size for arena reservation (= 1 GiB on 64-bit) (internally, this value is in KiB; use `mi_option_get_size`) + mi_option_os_tag, ///< tag used for OS logging (macOS only for now) (=100) + mi_option_retry_on_oom, ///< retry on out-of-memory for N milli seconds (=400), set to 0 to disable retries. (only on windows) + + // experimental options + mi_option_eager_commit, ///< eager commit segments? (after `eager_commit_delay` segments) (enabled by default). + mi_option_eager_commit_delay, ///< the first N segments per thread are not eagerly committed (but per page in the segment on demand) + mi_option_arena_eager_commit, ///< eager commit arenas? Use 2 to enable just on overcommit systems (=2) + mi_option_abandoned_page_purge, ///< immediately purge delayed purges on thread termination + mi_option_purge_delay, ///< memory purging is delayed by N milli seconds; use 0 for immediate purging or -1 for no purging at all. (=10) + mi_option_use_numa_nodes, ///< 0 = use all available numa nodes, otherwise use at most N nodes. + mi_option_disallow_os_alloc, ///< 1 = do not use OS memory for allocation (but only programmatically reserved arenas) + mi_option_limit_os_alloc, ///< If set to 1, do not use OS memory for allocation (but only pre-reserved arenas) + mi_option_max_segment_reclaim, ///< max. percentage of the abandoned segments can be reclaimed per try (=10%) + mi_option_destroy_on_exit, ///< if set, release all memory on exit; sometimes used for dynamic unloading but can be unsafe + mi_option_arena_purge_mult, ///< multiplier for `purge_delay` for the purging delay for arenas (=10) + mi_option_abandoned_reclaim_on_free, ///< allow to reclaim an abandoned segment on a free (=1) + mi_option_purge_extend_delay, ///< extend purge delay on each subsequent delay (=1) + mi_option_disallow_arena_alloc, ///< 1 = do not use arena's for allocation (except if using specific arena id's) + mi_option_visit_abandoned, ///< allow visiting heap blocks from abandoned threads (=0) _mi_option_last } mi_option_t; @@ -838,7 +952,10 @@ void mi_option_disable(mi_option_t option); void mi_option_set_enabled(mi_option_t option, bool enable); void mi_option_set_enabled_default(mi_option_t option, bool enable); -long mi_option_get(mi_option_t option); +long mi_option_get(mi_option_t option); +long mi_option_get_clamp(mi_option_t option, long min, long max); +size_t mi_option_get_size(mi_option_t option); + void mi_option_set(mi_option_t option, long value); void mi_option_set_default(mi_option_t option, long value); @@ -852,21 +969,27 @@ void mi_option_set_default(mi_option_t option, long value); /// /// \{ +/// Just as `free` but also checks if the pointer `p` belongs to our heap. +void mi_cfree(void* p); +void* mi__expand(void* p, size_t newsize); + void* mi_recalloc(void* p, size_t count, size_t size); size_t mi_malloc_size(const void* p); +size_t mi_malloc_good_size(size_t size); size_t mi_malloc_usable_size(const void *p); -/// Just as `free` but also checks if the pointer `p` belongs to our heap. -void mi_cfree(void* p); - int mi_posix_memalign(void** p, size_t alignment, size_t size); int mi__posix_memalign(void** p, size_t alignment, size_t size); void* mi_memalign(size_t alignment, size_t size); void* mi_valloc(size_t size); - void* mi_pvalloc(size_t size); void* mi_aligned_alloc(size_t alignment, size_t size); +unsigned short* mi_wcsdup(const unsigned short* s); +unsigned char* mi_mbsdup(const unsigned char* s); +int mi_dupenv_s(char** buf, size_t* size, const char* name); +int mi_wdupenv_s(unsigned short** buf, size_t* size, const unsigned short* name); + /// Correspond s to [reallocarray](https://www.freebsd.org/cgi/man.cgi?query=reallocarray&sektion=3&manpath=freebsd-release-ports) /// in FreeBSD. void* mi_reallocarray(void* p, size_t count, size_t size); @@ -874,6 +997,9 @@ void* mi_reallocarray(void* p, size_t count, size_t size); /// Corresponds to [reallocarr](https://man.netbsd.org/reallocarr.3) in NetBSD. int mi_reallocarr(void* p, size_t count, size_t size); +void* mi_aligned_recalloc(void* p, size_t newcount, size_t size, size_t alignment); +void* mi_aligned_offset_recalloc(void* p, size_t newcount, size_t size, size_t alignment, size_t offset); + void mi_free_size(void* p, size_t size); void mi_free_size_aligned(void* p, size_t size, size_t alignment); void mi_free_aligned(void* p, size_t alignment); @@ -888,7 +1014,7 @@ void mi_free_aligned(void* p, size_t alignment); /// /// Note: use the `mimalloc-new-delete.h` header to override the \a new /// and \a delete operators globally. The wrappers here are mostly -/// for convience for library writers that need to interface with +/// for convenience for library writers that need to interface with /// mimalloc from C++. /// /// \{ @@ -927,7 +1053,7 @@ template struct mi_stl_allocator { } /*! \page build Building -Checkout the sources from Github: +Checkout the sources from GitHub: ``` git clone https://github.com/microsoft/mimalloc ``` @@ -998,7 +1124,7 @@ mimalloc uses only safe OS calls (`mmap` and `VirtualAlloc`) and can co-exist with other allocators linked to the same program. If you use `cmake`, you can simply use: ``` -find_package(mimalloc 1.0 REQUIRED) +find_package(mimalloc 2.1 REQUIRED) ``` in your `CMakeLists.txt` to find a locally installed mimalloc. Then use either: ``` @@ -1012,7 +1138,7 @@ to link with the static library. See `test\CMakeLists.txt` for an example. ### C++ For best performance in C++ programs, it is also recommended to override the -global `new` and `delete` operators. For convience, mimalloc provides +global `new` and `delete` operators. For convenience, mimalloc provides [`mimalloc-new-delete.h`](https://github.com/microsoft/mimalloc/blob/master/include/mimalloc-new-delete.h) which does this for you -- just include it in a single(!) source file in your project. In C++, mimalloc also provides the `mi_stl_allocator` struct which implements the `std::allocator` @@ -1071,38 +1197,64 @@ See \ref overrides for more info. /*! \page environment Environment Options -You can set further options either programmatically (using [`mi_option_set`](https://microsoft.github.io/mimalloc/group__options.html)), -or via environment variables. +You can set further options either programmatically (using [`mi_option_set`](https://microsoft.github.io/mimalloc/group__options.html)), or via environment variables: - `MIMALLOC_SHOW_STATS=1`: show statistics when the program terminates. - `MIMALLOC_VERBOSE=1`: show verbose messages. - `MIMALLOC_SHOW_ERRORS=1`: show error and warning messages. -- `MIMALLOC_PAGE_RESET=0`: by default, mimalloc will reset (or purge) OS pages when not in use to signal to the OS - that the underlying physical memory can be reused. This can reduce memory fragmentation in long running (server) - programs. By setting it to `0` no such page resets will be done which can improve performance for programs that are not long - running. As an alternative, the `MIMALLOC_DECOMMIT_DELAY=` can be set higher (100ms by default) to make the page - reset occur less frequently instead of turning it off completely. -- `MIMALLOC_LARGE_OS_PAGES=1`: use large OS pages (2MiB) when available; for some workloads this can significantly - improve performance. Use `MIMALLOC_VERBOSE` to check if the large OS pages are enabled -- usually one needs - to explicitly allow large OS pages (as on [Windows][windows-huge] and [Linux][linux-huge]). However, sometimes + +Advanced options: + +- `MIMALLOC_ARENA_EAGER_COMMIT=2`: turns on eager commit for the large arenas (usually 1GiB) from which mimalloc + allocates segments and pages. Set this to 2 (default) to + only enable this on overcommit systems (e.g. Linux). Set this to 1 to enable explicitly on other systems + as well (like Windows or macOS) which may improve performance (as the whole arena is committed at once). + Note that eager commit only increases the commit but not the actual the peak resident set + (rss) so it is generally ok to enable this. +- `MIMALLOC_PURGE_DELAY=N`: the delay in `N` milli-seconds (by default `10`) after which mimalloc will purge + OS pages that are not in use. This signals to the OS that the underlying physical memory can be reused which + can reduce memory fragmentation especially in long running (server) programs. Setting `N` to `0` purges immediately when + a page becomes unused which can improve memory usage but also decreases performance. Setting `N` to a higher + value like `100` can improve performance (sometimes by a lot) at the cost of potentially using more memory at times. + Setting it to `-1` disables purging completely. +- `MIMALLOC_PURGE_DECOMMITS=1`: By default "purging" memory means unused memory is decommitted (`MEM_DECOMMIT` on Windows, + `MADV_DONTNEED` (which decresease rss immediately) on `mmap` systems). Set this to 0 to instead "reset" unused + memory on a purge (`MEM_RESET` on Windows, generally `MADV_FREE` (which does not decrease rss immediately) on `mmap` systems). + Mimalloc generally does not "free" OS memory but only "purges" OS memory, in other words, it tries to keep virtual + address ranges and decommits within those ranges (to make the underlying physical memory available to other processes). + +Further options for large workloads and services: + +- `MIMALLOC_USE_NUMA_NODES=N`: pretend there are at most `N` NUMA nodes. If not set, the actual NUMA nodes are detected + at runtime. Setting `N` to 1 may avoid problems in some virtual environments. Also, setting it to a lower number than + the actual NUMA nodes is fine and will only cause threads to potentially allocate more memory across actual NUMA + nodes (but this can happen in any case as NUMA local allocation is always a best effort but not guaranteed). +- `MIMALLOC_ALLOW_LARGE_OS_PAGES=1`: use large OS pages (2 or 4MiB) when available; for some workloads this can significantly + improve performance. When this option is disabled (default), it also disables transparent huge pages (THP) for the process + (on Linux and Android). On Linux the default setting is 2 -- this enables the use of large pages through THP only. + Use `MIMALLOC_VERBOSE` to check if the large OS pages are enabled -- usually one needs + to explicitly give permissions for large OS pages (as on [Windows][windows-huge] and [Linux][linux-huge]). However, sometimes the OS is very slow to reserve contiguous physical memory for large OS pages so use with care on systems that - can have fragmented memory (for that reason, we generally recommend to use `MIMALLOC_RESERVE_HUGE_OS_PAGES` instead when possible). -- `MIMALLOC_RESERVE_HUGE_OS_PAGES=N`: where N is the number of 1GiB _huge_ OS pages. This reserves the huge pages at + can have fragmented memory (for that reason, we generally recommend to use `MIMALLOC_RESERVE_HUGE_OS_PAGES` instead whenever possible). +- `MIMALLOC_RESERVE_HUGE_OS_PAGES=N`: where `N` is the number of 1GiB _huge_ OS pages. This reserves the huge pages at startup and sometimes this can give a large (latency) performance improvement on big workloads. - Usually it is better to not use - `MIMALLOC_LARGE_OS_PAGES` in combination with this setting. Just like large OS pages, use with care as reserving + Usually it is better to not use `MIMALLOC_ALLOW_LARGE_OS_PAGES=1` in combination with this setting. Just like large + OS pages, use with care as reserving contiguous physical memory can take a long time when memory is fragmented (but reserving the huge pages is done at startup only once). - Note that we usually need to explicitly enable huge OS pages (as on [Windows][windows-huge] and [Linux][linux-huge])). With huge OS pages, it may be beneficial to set the setting + Note that we usually need to explicitly give permission for huge OS pages (as on [Windows][windows-huge] and [Linux][linux-huge])). + With huge OS pages, it may be beneficial to set the setting `MIMALLOC_EAGER_COMMIT_DELAY=N` (`N` is 1 by default) to delay the initial `N` segments (of 4MiB) of a thread to not allocate in the huge OS pages; this prevents threads that are short lived - and allocate just a little to take up space in the huge OS page area (which cannot be reset). -- `MIMALLOC_RESERVE_HUGE_OS_PAGES_AT=N`: where N is the numa node. This reserves the huge pages at a specific numa node. - (`N` is -1 by default to reserve huge pages evenly among the given number of numa nodes (or use the available ones as detected)) + and allocate just a little to take up space in the huge OS page area (which cannot be purged as huge OS pages are pinned + to physical memory). + The huge pages are usually allocated evenly among NUMA nodes. + We can use `MIMALLOC_RESERVE_HUGE_OS_PAGES_AT=N` where `N` is the numa node (starting at 0) to allocate all + the huge pages at a specific numa node instead. Use caution when using `fork` in combination with either large or huge OS pages: on a fork, the OS uses copy-on-write for all pages in the original process including the huge OS pages. When any memory is now written in that area, the -OS will copy the entire 1GiB huge page (or 2MiB large page) which can cause the memory usage to grow in big increments. +OS will copy the entire 1GiB huge page (or 2MiB large page) which can cause the memory usage to grow in large increments. [linux-huge]: https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/5/html/tuning_and_optimizing_red_hat_enterprise_linux_for_oracle_9i_and_10g_databases/sect-oracle_9i_and_10g_tuning_guide-large_memory_optimization_big_pages_and_huge_pages-configuring_huge_pages_in_red_hat_enterprise_linux_4_or_5 [windows-huge]: https://docs.microsoft.com/en-us/sql/database-engine/configure-windows/enable-the-lock-pages-in-memory-option-windows?view=sql-server-2017 @@ -1111,88 +1263,106 @@ OS will copy the entire 1GiB huge page (or 2MiB large page) which can cause the /*! \page overrides Overriding Malloc -Overriding the standard `malloc` can be done either _dynamically_ or _statically_. +Overriding the standard `malloc` (and `new`) can be done either _dynamically_ or _statically_. ## Dynamic override This is the recommended way to override the standard malloc interface. +### Dynamic Override on Linux, BSD -### Linux, BSD - -On these systems we preload the mimalloc shared +On these ELF-based systems we preload the mimalloc shared library so all calls to the standard `malloc` interface are resolved to the _mimalloc_ library. - -- `env LD_PRELOAD=/usr/lib/libmimalloc.so myprogram` +``` +> env LD_PRELOAD=/usr/lib/libmimalloc.so myprogram +``` You can set extra environment variables to check that mimalloc is running, like: ``` -env MIMALLOC_VERBOSE=1 LD_PRELOAD=/usr/lib/libmimalloc.so myprogram +> env MIMALLOC_VERBOSE=1 LD_PRELOAD=/usr/lib/libmimalloc.so myprogram ``` or run with the debug version to get detailed statistics: ``` -env MIMALLOC_SHOW_STATS=1 LD_PRELOAD=/usr/lib/libmimalloc-debug.so myprogram +> env MIMALLOC_SHOW_STATS=1 LD_PRELOAD=/usr/lib/libmimalloc-debug.so myprogram ``` -### MacOS +### Dynamic Override on MacOS On macOS we can also preload the mimalloc shared library so all calls to the standard `malloc` interface are resolved to the _mimalloc_ library. - -- `env DYLD_FORCE_FLAT_NAMESPACE=1 DYLD_INSERT_LIBRARIES=/usr/lib/libmimalloc.dylib myprogram` +``` +> env DYLD_INSERT_LIBRARIES=/usr/lib/libmimalloc.dylib myprogram +``` Note that certain security restrictions may apply when doing this from the [shell](https://stackoverflow.com/questions/43941322/dyld-insert-libraries-ignored-when-calling-application-through-bash). -(Note: macOS support for dynamic overriding is recent, please report any issues.) +### Dynamic Override on Windows + +Dynamically overriding on mimalloc on Windows +is robust and has the particular advantage to be able to redirect all malloc/free calls +that go through the (dynamic) C runtime allocator, including those from other DLL's or +libraries. As it intercepts all allocation calls on a low level, it can be used reliably +on large programs that include other 3rd party components. +There are four requirements to make the overriding work well: + +1. Use the C-runtime library as a DLL (using the `/MD` or `/MDd` switch). -### Windows +2. Link your program explicitly with the `mimalloc.lib` export library for the `mimalloc.dll`. + (which must be compiled with `-DMI_OVERRIDE=ON`, which is the default though). + To ensure the `mimalloc.dll` is actually loaded at run-time it is easiest + to insert some call to the mimalloc API in the `main` function, like `mi_version()` + (or use the `/include:mi_version` switch on the linker command, or + similarly, `#pragma comment(linker, "/include:mi_version")` in some source file). + See the `mimalloc-test-override` project for an example on how to use this. -Overriding on Windows is robust and has the -particular advantage to be able to redirect all malloc/free calls that go through -the (dynamic) C runtime allocator, including those from other DLL's or libraries. +3. The `mimalloc-redirect.dll` must be put in the same directory as the main + `mimalloc.dll` at runtime (as it is a dependency of that DLL). + The redirection DLL ensures that all calls to the C runtime malloc API get + redirected to mimalloc functions (which reside in `mimalloc.dll`). -The overriding on Windows requires that you link your program explicitly with -the mimalloc DLL and use the C-runtime library as a DLL (using the `/MD` or `/MDd` switch). -Also, the `mimalloc-redirect.dll` (or `mimalloc-redirect32.dll`) must be available -in the same folder as the main `mimalloc-override.dll` at runtime (as it is a dependency). -The redirection DLL ensures that all calls to the C runtime malloc API get redirected to -mimalloc (in `mimalloc-override.dll`). +4. Ensure the `mimalloc.dll` comes as early as possible in the import + list of the final executable (so it can intercept all potential allocations). + You can use `minject -l ` to check this if needed. -To ensure the mimalloc DLL is loaded at run-time it is easiest to insert some -call to the mimalloc API in the `main` function, like `mi_version()` -(or use the `/INCLUDE:mi_version` switch on the linker). See the `mimalloc-override-test` project -for an example on how to use this. For best performance on Windows with C++, it +For best performance on Windows with C++, it is also recommended to also override the `new`/`delete` operations (by including -[`mimalloc-new-delete.h`](https://github.com/microsoft/mimalloc/blob/master/include/mimalloc-new-delete.h) a single(!) source file in your project). +[`mimalloc-new-delete.h`](include/mimalloc-new-delete.h) +a single(!) source file in your project). The environment variable `MIMALLOC_DISABLE_REDIRECT=1` can be used to disable dynamic -overriding at run-time. Use `MIMALLOC_VERBOSE=1` to check if mimalloc was successfully redirected. +overriding at run-time. Use `MIMALLOC_VERBOSE=1` to check if mimalloc was successfully +redirected. -(Note: in principle, it is possible to even patch existing executables without any recompilation -if they are linked with the dynamic C runtime (`ucrtbase.dll`) -- just put the `mimalloc-override.dll` -into the import table (and put `mimalloc-redirect.dll` in the same folder) -Such patching can be done for example with [CFF Explorer](https://ntcore.com/?page_id=388)). +For different platforms than x64, you may need a specific [redirection dll](bin). +Furthermore, we cannot always re-link an executable or ensure `mimalloc.dll` comes +first in the import table. In such cases the [`minject`](bin) tool can be used +to patch the executable's import tables. ## Static override -On Unix systems, you can also statically link with _mimalloc_ to override the standard +On Unix-like systems, you can also statically link with _mimalloc_ to override the standard malloc interface. The recommended way is to link the final program with the -_mimalloc_ single object file (`mimalloc-override.o`). We use +_mimalloc_ single object file (`mimalloc.o`). We use an object file instead of a library file as linkers give preference to that over archives to resolve symbols. To ensure that the standard malloc interface resolves to the _mimalloc_ library, link it as the first object file. For example: - ``` -gcc -o myprogram mimalloc-override.o myfile1.c ... +> gcc -o myprogram mimalloc.o myfile1.c ... ``` +Another way to override statically that works on all platforms, is to +link statically to mimalloc (as shown in the introduction) and include a +header file in each source file that re-defines `malloc` etc. to `mi_malloc`. +This is provided by [`mimalloc-override.h`](https://github.com/microsoft/mimalloc/blob/master/include/mimalloc-override.h). This only works reliably though if all sources are +under your control or otherwise mixing of pointers from different heaps may occur! + ## List of Overrides: The specific functions that get redirected to the _mimalloc_ library are: diff --git a/src/dashbls/depends/mimalloc/doc/mimalloc-doxygen.css b/src/dashbls/depends/mimalloc/doc/mimalloc-doxygen.css index b24f5643268f..c889a8d2c326 100644 --- a/src/dashbls/depends/mimalloc/doc/mimalloc-doxygen.css +++ b/src/dashbls/depends/mimalloc/doc/mimalloc-doxygen.css @@ -47,3 +47,14 @@ div.fragment { #nav-sync img { display: none; } +h1,h2,h3,h4,h5,h6 { + transition:none; +} +.memtitle { + background-image: none; + background-color: #EEE; +} +table.memproto, .memproto { + text-shadow: none; + font-size: 110%; +} diff --git a/src/dashbls/depends/mimalloc/docs/annotated.html b/src/dashbls/depends/mimalloc/docs/annotated.html index f3e392a457a9..fbb3936e234f 100644 --- a/src/dashbls/depends/mimalloc/docs/annotated.html +++ b/src/dashbls/depends/mimalloc/docs/annotated.html @@ -1,24 +1,26 @@ - + - - + + mi-malloc: Data Structures + - + + @@ -29,20 +31,16 @@

- + - -
-
mi-malloc -  1.7/2.0 +
+
mi-malloc 1.8/2.1
+
- -   + @@ -56,10 +54,15 @@
- + + @@ -74,8 +77,8 @@
@@ -88,20 +91,26 @@
- +
+
+
+
+
Loading...
+
Searching...
+
No Matches
+
+
+
-
-
Data Structures
+
Data Structures
Here are the data structures with brief descriptions:
- +
 Cmi_heap_area_tAn area of heap space contains blocks of a single size
 Cmi_stl_allocatorstd::allocator implementation for mimalloc for use in STL containers
 Cmi_stl_allocatorstd::allocator implementation for mimalloc for use in STL containers
@@ -109,7 +118,7 @@ diff --git a/src/dashbls/depends/mimalloc/docs/bench.html b/src/dashbls/depends/mimalloc/docs/bench.html index 6c4728958088..c896e7fcb092 100644 --- a/src/dashbls/depends/mimalloc/docs/bench.html +++ b/src/dashbls/depends/mimalloc/docs/bench.html @@ -1,24 +1,26 @@ - + - - + + mi-malloc: Performance + - + + @@ -29,20 +31,16 @@
- + - -
-
mi-malloc -  1.7/2.0 +
+
mi-malloc 1.8/2.1
+
- -   + @@ -56,10 +54,15 @@
- + +
@@ -74,8 +77,8 @@
@@ -88,14 +91,20 @@
- +
+
+
+
+
Loading...
+
Searching...
+
No Matches
+
+
+
-
-
-
Performance
+
+
Performance

We tested mimalloc against many other top allocators over a wide range of benchmarks, ranging from various real world programs to synthetic benchmarks that see how the allocator behaves under more extreme circumstances.

@@ -107,7 +116,7 @@ diff --git a/src/dashbls/depends/mimalloc/docs/build.html b/src/dashbls/depends/mimalloc/docs/build.html index dbcc0d7521be..9849b055f2b3 100644 --- a/src/dashbls/depends/mimalloc/docs/build.html +++ b/src/dashbls/depends/mimalloc/docs/build.html @@ -1,24 +1,26 @@ - + - - + + mi-malloc: Building + - + + @@ -29,20 +31,16 @@
- + - -
-
mi-malloc -  1.7/2.0 +
+
mi-malloc 1.8/2.1
+
- -   + @@ -56,10 +54,15 @@
- + +
@@ -74,8 +77,8 @@
@@ -88,17 +91,23 @@
- +
+
+
+
+
Loading...
+
Searching...
+
No Matches
+
+
+
-
-
-
Building
+
+
Building
-

Checkout the sources from Github:

git clone https://github.com/microsoft/mimalloc
+

Checkout the sources from GitHub:

git clone https://github.com/microsoft/mimalloc

Windows

Open ide/vs2019/mimalloc.sln in Visual Studio 2019 and build (or ide/vs2017/mimalloc.sln). The mimalloc project builds a static library (in out/msvc-x64), while the mimalloc-override project builds a DLL for overriding malloc in the entire program.

macOS, Linux, BSD, etc.

@@ -130,7 +139,7 @@

macOS, Linux, BSD, etc.

diff --git a/src/dashbls/depends/mimalloc/docs/classes.html b/src/dashbls/depends/mimalloc/docs/classes.html index b744c4d90041..e86cf9f2f1ee 100644 --- a/src/dashbls/depends/mimalloc/docs/classes.html +++ b/src/dashbls/depends/mimalloc/docs/classes.html @@ -1,24 +1,26 @@ - + - - + + mi-malloc: Data Structure Index + - + + @@ -29,20 +31,16 @@
- + - -
-
mi-malloc -  1.7/2.0 +
+
mi-malloc 1.8/2.1
+
- -   + @@ -56,10 +54,15 @@
- + +
@@ -74,8 +77,8 @@
@@ -88,20 +91,26 @@
- +
+
+
+
+
Loading...
+
Searching...
+
No Matches
+
+
+
-
-
Data Structure Index
+
Data Structure Index
@@ -109,7 +118,7 @@ diff --git a/src/dashbls/depends/mimalloc/docs/clipboard.js b/src/dashbls/depends/mimalloc/docs/clipboard.js new file mode 100644 index 000000000000..42c1fb0e02dc --- /dev/null +++ b/src/dashbls/depends/mimalloc/docs/clipboard.js @@ -0,0 +1,61 @@ +/** + +The code below is based on the Doxygen Awesome project, see +https://github.com/jothepro/doxygen-awesome-css + +MIT License + +Copyright (c) 2021 - 2022 jothepro + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +let clipboard_title = "Copy to clipboard" +let clipboard_icon = `` +let clipboard_successIcon = `` +let clipboard_successDuration = 1000 + +$(function() { + if(navigator.clipboard) { + const fragments = document.getElementsByClassName("fragment") + for(const fragment of fragments) { + const clipboard_div = document.createElement("div") + clipboard_div.classList.add("clipboard") + clipboard_div.innerHTML = clipboard_icon + clipboard_div.title = clipboard_title + $(clipboard_div).click(function() { + const content = this.parentNode.cloneNode(true) + // filter out line number and folded fragments from file listings + content.querySelectorAll(".lineno, .ttc, .foldclosed").forEach((node) => { node.remove() }) + let text = content.textContent + // remove trailing newlines and trailing spaces from empty lines + text = text.replace(/^\s*\n/gm,'\n').replace(/\n*$/,'') + navigator.clipboard.writeText(text); + this.classList.add("success") + this.innerHTML = clipboard_successIcon + window.setTimeout(() => { // switch back to normal icon after timeout + this.classList.remove("success") + this.innerHTML = clipboard_icon + }, clipboard_successDuration); + }) + fragment.insertBefore(clipboard_div, fragment.firstChild) + } + } +}) diff --git a/src/dashbls/depends/mimalloc/docs/cookie.js b/src/dashbls/depends/mimalloc/docs/cookie.js new file mode 100644 index 000000000000..53ad21d98119 --- /dev/null +++ b/src/dashbls/depends/mimalloc/docs/cookie.js @@ -0,0 +1,58 @@ +/*! + Cookie helper functions + Copyright (c) 2023 Dimitri van Heesch + Released under MIT license. +*/ +let Cookie = { + cookie_namespace: 'doxygen_', + + readSetting(cookie,defVal) { + if (window.chrome) { + const val = localStorage.getItem(this.cookie_namespace+cookie) || + sessionStorage.getItem(this.cookie_namespace+cookie); + if (val) return val; + } else { + let myCookie = this.cookie_namespace+cookie+"="; + if (document.cookie) { + const index = document.cookie.indexOf(myCookie); + if (index != -1) { + const valStart = index + myCookie.length; + let valEnd = document.cookie.indexOf(";", valStart); + if (valEnd == -1) { + valEnd = document.cookie.length; + } + return document.cookie.substring(valStart, valEnd); + } + } + } + return defVal; + }, + + writeSetting(cookie,val,days=10*365) { // default days='forever', 0=session cookie, -1=delete + if (window.chrome) { + if (days==0) { + sessionStorage.setItem(this.cookie_namespace+cookie,val); + } else { + localStorage.setItem(this.cookie_namespace+cookie,val); + } + } else { + let date = new Date(); + date.setTime(date.getTime()+(days*24*60*60*1000)); + const expiration = days!=0 ? "expires="+date.toGMTString()+";" : ""; + document.cookie = this.cookie_namespace + cookie + "=" + + val + "; SameSite=Lax;" + expiration + "path=/"; + } + }, + + eraseSetting(cookie) { + if (window.chrome) { + if (localStorage.getItem(this.cookie_namespace+cookie)) { + localStorage.removeItem(this.cookie_namespace+cookie); + } else if (sessionStorage.getItem(this.cookie_namespace+cookie)) { + sessionStorage.removeItem(this.cookie_namespace+cookie); + } + } else { + this.writeSetting(cookie,'',-1); + } + }, +} diff --git a/src/dashbls/depends/mimalloc/docs/doxygen.css b/src/dashbls/depends/mimalloc/docs/doxygen.css index f090ef799cc0..0ee13f355c97 100644 --- a/src/dashbls/depends/mimalloc/docs/doxygen.css +++ b/src/dashbls/depends/mimalloc/docs/doxygen.css @@ -1,26 +1,31 @@ -/* The standard CSS for doxygen 1.9.1 */ +/* The standard CSS for doxygen 1.13.1*/ -body, table, div, p, dl { - font: 400 14px/22px Roboto,sans-serif; +body { + background-color: white; + color: black; } -p.reference, p.definition { - font: 400 14px/22px Roboto,sans-serif; +body, table, div, p, dl { + font-weight: 400; + font-size: 14px; + font-family: Roboto,sans-serif; + line-height: 22px; } /* @group Heading Levels */ -h1.groupheader { - font-size: 150%; -} - .title { - font: 400 14px/28px Roboto,sans-serif; + font-family: Roboto,sans-serif; + line-height: 28px; font-size: 150%; font-weight: bold; margin: 10px 2px; } +h1.groupheader { + font-size: 150%; +} + h2.groupheader { border-bottom: 1px solid #474D4E; color: #0A0B0B; @@ -53,15 +58,6 @@ dt { font-weight: bold; } -ul.multicol { - -moz-column-gap: 1em; - -webkit-column-gap: 1em; - column-gap: 1em; - -moz-column-count: 3; - -webkit-column-count: 3; - column-count: 3; -} - p.startli, p.startdd { margin-top: 2px; } @@ -113,7 +109,6 @@ h3.version { } div.navtab { - border-right: 1px solid #636C6D; padding-right: 15px; text-align: right; line-height: 110%; @@ -127,6 +122,7 @@ td.navtab { padding-right: 6px; padding-left: 6px; } + td.navtabHL { background-image: url('tab_a.png'); background-repeat:repeat-x; @@ -135,7 +131,7 @@ td.navtabHL { } td.navtabHL a, td.navtabHL a:visited { - color: #fff; + color: white; text-shadow: 0px 1px 1px rgba(0, 0, 0, 1.0); } @@ -151,6 +147,12 @@ div.qindex{ color: #A0A0A0; } +#main-menu a:focus { + outline: auto; + z-index: 10; + position: relative; +} + dt.alphachar{ font-size: 180%; font-weight: bold; @@ -176,6 +178,10 @@ dt.alphachar{ line-height: 1.15em; } +.classindex dl.even { + background-color: white; +} + .classindex dl.odd { background-color: #F0F1F1; } @@ -206,11 +212,13 @@ a { } a:hover { - text-decoration: underline; + text-decoration: none; + background: linear-gradient(to bottom, transparent 0,transparent calc(100% - 1px), currentColor 100%); } -.contents a.qindexHL:visited { - color: #FFFFFF; +a:hover > span.arrow { + text-decoration: none; + background : #F2F3F3; } a.el { @@ -221,21 +229,75 @@ a.elRef { } a.code, a.code:visited, a.line, a.line:visited { - color: #171919; + color: #171919; } a.codeRef, a.codeRef:visited, a.lineRef, a.lineRef:visited { - color: #171919; + color: #171919; } +a.code.hl_class { /* style for links to class names in code snippets */ } +a.code.hl_struct { /* style for links to struct names in code snippets */ } +a.code.hl_union { /* style for links to union names in code snippets */ } +a.code.hl_interface { /* style for links to interface names in code snippets */ } +a.code.hl_protocol { /* style for links to protocol names in code snippets */ } +a.code.hl_category { /* style for links to category names in code snippets */ } +a.code.hl_exception { /* style for links to exception names in code snippets */ } +a.code.hl_service { /* style for links to service names in code snippets */ } +a.code.hl_singleton { /* style for links to singleton names in code snippets */ } +a.code.hl_concept { /* style for links to concept names in code snippets */ } +a.code.hl_namespace { /* style for links to namespace names in code snippets */ } +a.code.hl_package { /* style for links to package names in code snippets */ } +a.code.hl_define { /* style for links to macro names in code snippets */ } +a.code.hl_function { /* style for links to function names in code snippets */ } +a.code.hl_variable { /* style for links to variable names in code snippets */ } +a.code.hl_typedef { /* style for links to typedef names in code snippets */ } +a.code.hl_enumvalue { /* style for links to enum value names in code snippets */ } +a.code.hl_enumeration { /* style for links to enumeration names in code snippets */ } +a.code.hl_signal { /* style for links to Qt signal names in code snippets */ } +a.code.hl_slot { /* style for links to Qt slot names in code snippets */ } +a.code.hl_friend { /* style for links to friend names in code snippets */ } +a.code.hl_dcop { /* style for links to KDE3 DCOP names in code snippets */ } +a.code.hl_property { /* style for links to property names in code snippets */ } +a.code.hl_event { /* style for links to event names in code snippets */ } +a.code.hl_sequence { /* style for links to sequence names in code snippets */ } +a.code.hl_dictionary { /* style for links to dictionary names in code snippets */ } + /* @end */ dl.el { margin-left: -1cm; } +ul.check { + list-style:none; + text-indent: -16px; + padding-left: 38px; +} +li.unchecked:before { + content: "\2610\A0"; +} +li.checked:before { + content: "\2611\A0"; +} + +ol { + text-indent: 0px; +} + ul { - overflow: hidden; /*Fixed: list item bullets overlap floating elements*/ + text-indent: 0px; + overflow: visible; +} + +ul.multicol { + -moz-column-gap: 1em; + -webkit-column-gap: 1em; + column-gap: 1em; + -moz-column-count: 3; + -webkit-column-count: 3; + column-count: 3; + list-style-type: none; } #side-nav ul { @@ -249,35 +311,70 @@ ul { .fragment { text-align: left; direction: ltr; - overflow-x: auto; /*Fixed: fragment lines overlap floating elements*/ + overflow-x: auto; overflow-y: hidden; + position: relative; + min-height: 12px; + margin: 10px 0px; + padding: 10px 10px; + border: 1px solid #90989A; + border-radius: 4px; + background-color: #F7F8F8; + color: black; } pre.fragment { - border: 1px solid #90989A; - background-color: #F7F8F8; - padding: 4px 6px; - margin: 4px 8px 4px 2px; + word-wrap: break-word; + font-size: 10pt; + line-height: 125%; + font-family: 'JetBrains Mono',Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace,fixed; +} + +.clipboard { + width: 24px; + height: 24px; + right: 5px; + top: 5px; + opacity: 0; + position: absolute; + display: inline; overflow: auto; - word-wrap: break-word; - font-size: 9pt; - line-height: 125%; - font-family: monospace, fixed; - font-size: 105%; + fill: black; + justify-content: center; + align-items: center; + cursor: pointer; +} + +.clipboard.success { + border: 1px solid black; + border-radius: 4px; +} + +.fragment:hover .clipboard, .clipboard.success { + opacity: .28; } -div.fragment { - padding: 0 0 1px 0; /*Fixed: last line underline overlap border*/ - margin: 4px 8px 4px 2px; - background-color: #F7F8F8; - border: 1px solid #90989A; +.clipboard:hover, .clipboard.success { + opacity: 1 !important; +} + +.clipboard:active:not([class~=success]) svg { + transform: scale(.91); +} + +.clipboard.success svg { + fill: #2EC82E; +} + +.clipboard.success { + border-color: #2EC82E; } div.line { - font-family: monospace, fixed; + font-family: 'JetBrains Mono',Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace,fixed; font-size: 13px; min-height: 13px; - line-height: 1.0; + line-height: 1.2; text-wrap: unrestricted; white-space: -moz-pre-wrap; /* Moz */ white-space: -pre-wrap; /* Opera 4-6 */ @@ -310,19 +407,35 @@ div.line.glow { box-shadow: 0 0 10px cyan; } +span.fold { + margin-left: 5px; + margin-right: 1px; + margin-top: 0px; + margin-bottom: 0px; + padding: 0px; + display: inline-block; + width: 12px; + height: 12px; + background-repeat:no-repeat; + background-position:center; +} span.lineno { padding-right: 4px; + margin-right: 9px; text-align: right; - border-right: 2px solid #0F0; + border-right: 2px solid #00FF00; + color: black; background-color: #E8E8E8; white-space: pre; } -span.lineno a { +span.lineno a, span.lineno a:visited { + color: #171919; background-color: #D8D8D8; } span.lineno a:hover { + color: #171919; background-color: #C8C8C8; } @@ -335,24 +448,6 @@ span.lineno a:hover { user-select: none; } -div.ah, span.ah { - background-color: black; - font-weight: bold; - color: #FFFFFF; - margin-bottom: 3px; - margin-top: 3px; - padding: 0.2em; - border: solid thin #333; - border-radius: 0.5em; - -webkit-border-radius: .5em; - -moz-border-radius: .5em; - box-shadow: 2px 2px 3px #999; - -webkit-box-shadow: 2px 2px 3px #999; - -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px; - background-image: -webkit-gradient(linear, left top, left bottom, from(#eee), to(#000),color-stop(0.3, #444)); - background-image: -moz-linear-gradient(center top, #eee 0%, #444 40%, #000 110%); -} - div.classindex ul { list-style: none; padding-left: 0; @@ -374,7 +469,6 @@ div.groupText { } body { - background-color: white; color: black; margin: 0; } @@ -385,33 +479,15 @@ div.contents { margin-right: 8px; } -td.indexkey { - background-color: #D6D9D9; - font-weight: bold; - border: 1px solid #90989A; - margin: 2px 0px 2px 0; - padding: 2px 10px; - white-space: nowrap; - vertical-align: top; -} - -td.indexvalue { - background-color: #D6D9D9; - border: 1px solid #90989A; - padding: 2px 10px; - margin: 2px 0px; -} - -tr.memlist { - background-color: #DADDDE; -} - p.formulaDsp { text-align: center; } -img.formulaDsp { - +img.dark-mode-visible { + display: none; +} +img.light-mode-visible { + display: none; } img.formulaInl, img.inline { @@ -437,52 +513,63 @@ address.footer { img.footer { border: 0px; vertical-align: middle; + width: 104px; +} + +.compoundTemplParams { + color: #171919; + font-size: 80%; + line-height: 120%; } /* @group Code Colorization */ span.keyword { - color: #008000 + color: #008000; } span.keywordtype { - color: #604020 + color: #604020; } span.keywordflow { - color: #e08000 + color: #E08000; } span.comment { - color: #800000 + color: #800000; } span.preprocessor { - color: #806020 + color: #806020; } span.stringliteral { - color: #002080 + color: #002080; } span.charliteral { - color: #008080 + color: #008080; +} + +span.xmlcdata { + color: black; } span.vhdldigit { - color: #ff00ff + color: #FF00FF; } span.vhdlchar { - color: #000000 + color: #000000; } span.vhdlkeyword { - color: #700070 + color: #700070; } span.vhdllogic { - color: #ff0000 + color: #FF0000; } blockquote { @@ -492,34 +579,8 @@ blockquote { padding: 0 12px 0 16px; } -blockquote.DocNodeRTL { - border-left: 0; - border-right: 2px solid #5B6364; - margin: 0 4px 0 24px; - padding: 0 16px 0 12px; -} - /* @end */ -/* -.search { - color: #003399; - font-weight: bold; -} - -form.search { - margin-bottom: 0px; - margin-top: 0px; -} - -input.search { - font-size: 75%; - color: #000080; - font-weight: normal; - background-color: #e8eef2; -} -*/ - td.tiny { font-size: 75%; } @@ -527,11 +588,12 @@ td.tiny { .dirtab { padding: 4px; border-collapse: collapse; - border: 1px solid #636C6D; + border: 1px solid #060606; } th.dirtab { - background: #D6D9D9; + background-color: #0B0C0C; + color: #FFFFFF; font-weight: bold; } @@ -641,15 +703,6 @@ table.memberdecls { margin-left: 9px; } -.memnav { - background-color: #D6D9D9; - border: 1px solid #636C6D; - text-align: center; - margin: 2px; - margin-right: 15px; - padding: 2px; -} - .mempage { width: 100%; } @@ -689,33 +742,24 @@ table.memberdecls { font-weight: bold; text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9); background-color: #BDC2C3; - /* opera specific markup */ box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); border-top-right-radius: 4px; - /* firefox specific markup */ - -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px; - -moz-border-radius-topright: 4px; - /* webkit specific markup */ - -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); - -webkit-border-top-right-radius: 4px; - } .overload { - font-family: "courier new",courier,monospace; + font-family: 'JetBrains Mono',Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace,fixed; font-size: 65%; } .memdoc, dl.reflist dd { - border-bottom: 1px solid #697273; - border-left: 1px solid #697273; - border-right: 1px solid #697273; + border-bottom: 1px solid #697273; + border-left: 1px solid #697273; + border-right: 1px solid #697273; padding: 6px 10px 2px 10px; - background-color: #F7F8F8; border-top-width: 0; background-image:url('nav_g.png'); background-repeat:repeat-x; - background-color: #FFFFFF; + background-color: white; /* opera specific markup */ border-bottom-left-radius: 4px; border-bottom-right-radius: 4px; @@ -745,36 +789,44 @@ dl.reflist dd { .paramtype { white-space: nowrap; + padding: 0px; + padding-bottom: 1px; } .paramname { - color: #602020; white-space: nowrap; + padding: 0px; + padding-bottom: 1px; + margin-left: 2px; } + .paramname em { + color: #602020; font-style: normal; + margin-right: 1px; } -.paramname code { - line-height: 14px; + +.paramname .paramdefval { + font-family: 'JetBrains Mono',Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace,fixed; } .params, .retval, .exception, .tparams { margin-left: 0px; padding-left: 0px; -} +} .params .paramname, .retval .paramname, .tparams .paramname, .exception .paramname { font-weight: bold; vertical-align: top; } - + .params .paramtype, .tparams .paramtype { font-style: italic; vertical-align: top; -} - +} + .params .paramdir, .tparams .paramdir { - font-family: "courier new",courier,monospace; + font-family: 'JetBrains Mono',Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace,fixed; vertical-align: top; } @@ -858,9 +910,14 @@ div.directory { border-left: 1px solid rgba(0,0,0,0.05); } +.directory tr.odd { + padding-left: 6px; + background-color: #F0F1F1; +} + .directory tr.even { padding-left: 6px; - background-color: #EDEFEF; + background-color: white; } .directory img { @@ -896,7 +953,8 @@ div.directory { } .icon { - font-family: Arial, Helvetica; + font-family: Arial,Helvetica; + line-height: normal; font-weight: bold; font-size: 12px; height: 14px; @@ -920,8 +978,7 @@ div.directory { width: 24px; height: 18px; margin-bottom: 4px; - background-image:url('folderopen.png'); - background-position: 0px -4px; + background-image:url('folderopen.svg'); background-repeat: repeat-y; vertical-align:top; display: inline-block; @@ -931,8 +988,7 @@ div.directory { width: 24px; height: 18px; margin-bottom: 4px; - background-image:url('folderclosed.png'); - background-position: 0px -4px; + background-image:url('folderclosed.svg'); background-repeat: repeat-y; vertical-align:top; display: inline-block; @@ -942,17 +998,13 @@ div.directory { width: 24px; height: 18px; margin-bottom: 4px; - background-image:url('doc.png'); + background-image:url('doc.svg'); background-position: 0px -4px; background-repeat: repeat-y; vertical-align:top; display: inline-block; } -table.directory { - font: 400 14px Roboto,sans-serif; -} - /* @end */ div.dynheader { @@ -994,15 +1046,10 @@ table.doxtable th { } table.fieldtable { - /*width: 100%;*/ margin-bottom: 10px; border: 1px solid #697273; border-spacing: 0px; - -moz-border-radius: 4px; - -webkit-border-radius: 4px; border-radius: 4px; - -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px; - -webkit-box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15); box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15); } @@ -1010,7 +1057,7 @@ table.fieldtable { padding: 3px 7px 2px; } -.fieldtable td.fieldtype, .fieldtable td.fieldname { +.fieldtable td.fieldtype, .fieldtable td.fieldname, .fieldtable td.fieldinit { white-space: nowrap; border-right: 1px solid #697273; border-bottom: 1px solid #697273; @@ -1021,15 +1068,20 @@ table.fieldtable { padding-top: 3px; } +.fieldtable td.fieldinit { + padding-top: 3px; + text-align: right; +} + + .fieldtable td.fielddoc { border-bottom: 1px solid #697273; - /*width: 100%;*/ } .fieldtable td.fielddoc p:first-child { margin-top: 0px; -} - +} + .fieldtable td.fielddoc p:last-child { margin-bottom: 2px; } @@ -1039,7 +1091,7 @@ table.fieldtable { } .fieldtable th { - background-image:url('nav_f.png'); + background-image: url('nav_f.png'); background-repeat:repeat-x; background-color: #C4C8C9; font-size: 90%; @@ -1048,10 +1100,6 @@ table.fieldtable { padding-top: 5px; text-align:left; font-weight: 400; - -moz-border-radius-topleft: 4px; - -moz-border-radius-topright: 4px; - -webkit-border-top-left-radius: 4px; - -webkit-border-top-right-radius: 4px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom: 1px solid #697273; @@ -1071,12 +1119,12 @@ table.fieldtable { .navpath ul { font-size: 11px; - background-image:url('tab_b.png'); + background-image: url('tab_b.png'); background-repeat:repeat-x; background-position: 0 -5px; height:30px; line-height:30px; - color:#494F50; + color:#040404; border:solid 1px #8C9596; overflow:hidden; margin:0px; @@ -1092,24 +1140,24 @@ table.fieldtable { background-image:url('bc_s.png'); background-repeat:no-repeat; background-position:right; - color:#0A0B0B; + color: #0A0B0B; } .navpath li.navelem a { height:32px; display:block; - text-decoration: none; outline: none; color: #040404; font-family: 'Lucida Grande',Geneva,Helvetica,Arial,sans-serif; text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9); - text-decoration: none; + text-decoration: none; } .navpath li.navelem a:hover { - color:#2E3233; + color: white; + text-shadow: 0px 1px 1px rgba(0, 0, 0, 1.0); } .navpath li.footer @@ -1121,7 +1169,7 @@ table.fieldtable { background-image:none; background-repeat:no-repeat; background-position:right; - color:#0A0B0B; + color: #050505; font-size: 8pt; } @@ -1133,7 +1181,7 @@ div.summary padding-right: 5px; width: 50%; text-align: right; -} +} div.summary a { @@ -1148,7 +1196,7 @@ table.classindex margin-right: 3%; width: 94%; border: 0; - border-spacing: 0; + border-spacing: 0; padding: 0; } @@ -1166,7 +1214,7 @@ div.ingroups a div.header { - background-image:url('nav_h.png'); + background-image: url('nav_h.png'); background-repeat:repeat-x; background-color: #F2F3F3; margin: 0px; @@ -1187,17 +1235,13 @@ dl { padding: 0 0 0 0; } -/* dl.note, dl.warning, dl.attention, dl.pre, dl.post, dl.invariant, dl.deprecated, dl.todo, dl.test, dl.bug, dl.examples */ +/* + dl.section { margin-left: 0px; padding-left: 0px; } -dl.section.DocNodeRTL { - margin-right: 0px; - padding-right: 0px; -} - dl.note { margin-left: -7px; padding-left: 3px; @@ -1205,33 +1249,13 @@ dl.note { border-color: #D0C000; } -dl.note.DocNodeRTL { - margin-left: 0; - padding-left: 0; - border-left: 0; - margin-right: -7px; - padding-right: 3px; - border-right: 4px solid; - border-color: #D0C000; -} - -dl.warning, dl.attention { +dl.warning, dl.attention, dl.important { margin-left: -7px; padding-left: 3px; border-left: 4px solid; border-color: #FF0000; } -dl.warning.DocNodeRTL, dl.attention.DocNodeRTL { - margin-left: 0; - padding-left: 0; - border-left: 0; - margin-right: -7px; - padding-right: 3px; - border-right: 4px solid; - border-color: #FF0000; -} - dl.pre, dl.post, dl.invariant { margin-left: -7px; padding-left: 3px; @@ -1239,16 +1263,6 @@ dl.pre, dl.post, dl.invariant { border-color: #00D000; } -dl.pre.DocNodeRTL, dl.post.DocNodeRTL, dl.invariant.DocNodeRTL { - margin-left: 0; - padding-left: 0; - border-left: 0; - margin-right: -7px; - padding-right: 3px; - border-right: 4px solid; - border-color: #00D000; -} - dl.deprecated { margin-left: -7px; padding-left: 3px; @@ -1256,16 +1270,6 @@ dl.deprecated { border-color: #505050; } -dl.deprecated.DocNodeRTL { - margin-left: 0; - padding-left: 0; - border-left: 0; - margin-right: -7px; - padding-right: 3px; - border-right: 4px solid; - border-color: #505050; -} - dl.todo { margin-left: -7px; padding-left: 3px; @@ -1273,16 +1277,6 @@ dl.todo { border-color: #00C0E0; } -dl.todo.DocNodeRTL { - margin-left: 0; - padding-left: 0; - border-left: 0; - margin-right: -7px; - padding-right: 3px; - border-right: 4px solid; - border-color: #00C0E0; -} - dl.test { margin-left: -7px; padding-left: 3px; @@ -1290,16 +1284,6 @@ dl.test { border-color: #3030E0; } -dl.test.DocNodeRTL { - margin-left: 0; - padding-left: 0; - border-left: 0; - margin-right: -7px; - padding-right: 3px; - border-right: 4px solid; - border-color: #3030E0; -} - dl.bug { margin-left: -7px; padding-left: 3px; @@ -1307,20 +1291,110 @@ dl.bug { border-color: #C08050; } -dl.bug.DocNodeRTL { - margin-left: 0; - padding-left: 0; - border-left: 0; - margin-right: -7px; - padding-right: 3px; - border-right: 4px solid; - border-color: #C08050; +*/ + +dl.bug dt a, dl.deprecated dt a, dl.todo dt a, dl.test a { + font-weight: bold !important; +} + +dl.warning, dl.attention, dl.important, dl.note, dl.deprecated, dl.bug, +dl.invariant, dl.pre, dl.post, dl.todo, dl.test, dl.remark { + padding: 10px; + margin: 10px 0px; + overflow: hidden; + margin-left: 0; + border-radius: 4px; } dl.section dd { - margin-bottom: 6px; + margin-bottom: 2px; +} + +dl.warning, dl.attention, dl.important { + background: #f8d1cc; + border-left: 8px solid #b61825; + color: #75070f; } +dl.warning dt, dl.attention dt, dl.important dt { + color: #b61825; +} + +dl.note, dl.remark { + background: #faf3d8; + border-left: 8px solid #f3a600; + color: #5f4204; +} + +dl.note dt, dl.remark dt { + color: #f3a600; +} + +dl.todo { + background: #e4f3ff; + border-left: 8px solid #1879C4; + color: #274a5c; +} + +dl.todo dt { + color: #1879C4; +} + +dl.test { + background: #e8e8ff; + border-left: 8px solid #3939C4; + color: #1a1a5c; +} + +dl.test dt { + color: #3939C4; +} + +dl.bug dt a { + color: #5b2bdd !important; +} + +dl.bug { + background: #e4dafd; + border-left: 8px solid #5b2bdd; + color: #2a0d72; +} + +dl.bug dt a { + color: #5b2bdd !important; +} + +dl.deprecated { + background: #ecf0f3; + border-left: 8px solid #5b6269; + color: #43454a; +} + +dl.deprecated dt a { + color: #5b6269 !important; +} + +dl.note dd, dl.warning dd, dl.pre dd, dl.post dd, +dl.remark dd, dl.attention dd, dl.important dd, dl.invariant dd, +dl.bug dd, dl.deprecated dd, dl.todo dd, dl.test dd { + margin-inline-start: 0px; +} + +dl.invariant, dl.pre, dl.post { + background: #d8f1e3; + border-left: 8px solid #44b86f; + color: #265532; +} + +dl.invariant dt, dl.pre dt, dl.post dt { + color: #44b86f; +} + + +#projectrow +{ + height: 56px; +} #projectlogo { @@ -1328,34 +1402,43 @@ dl.section dd { vertical-align: bottom; border-collapse: separate; } - + #projectlogo img -{ +{ border: 0px none; } - + #projectalign { vertical-align: middle; + padding-left: 0.5em; } #projectname { - font: 300% Tahoma, Arial,sans-serif; + font-size: 200%; + font-family: Tahoma,Arial,sans-serif; margin: 0px; padding: 2px 0px; } - + +#side-nav #projectname +{ + font-size: 130%; +} + #projectbrief { - font: 120% Tahoma, Arial,sans-serif; + font-size: 90%; + font-family: Tahoma,Arial,sans-serif; margin: 0px; padding: 0px; } #projectnumber { - font: 50% Tahoma, Arial,sans-serif; + font-size: 50%; + font-family: 50% Tahoma,Arial,sans-serif; margin: 0px; padding: 0px; } @@ -1366,6 +1449,7 @@ dl.section dd { margin: 0px; width: 100%; border-bottom: 1px solid #212425; + background-color: white; } .image @@ -1398,11 +1482,6 @@ dl.section dd { font-weight: bold; } -div.zoom -{ - border: 1px solid #4F5657; -} - dl.citelist { margin-bottom:50px; } @@ -1433,27 +1512,16 @@ div.toc { width: 200px; } -.PageDocRTL-title div.toc { - float: left !important; - text-align: right; -} - div.toc li { - background: url("bdwn.png") no-repeat scroll 0 5px transparent; - font: 10px/1.2 Verdana,DejaVu Sans,Geneva,sans-serif; + background: url("data:image/svg+xml;utf8,&%238595;") no-repeat scroll 0 5px transparent; + font: 10px/1.2 Verdana,'DejaVu Sans',Geneva,sans-serif; margin-top: 5px; padding-left: 10px; padding-top: 2px; } -.PageDocRTL-title div.toc li { - background-position-x: right !important; - padding-left: 0 !important; - padding-right: 10px; -} - div.toc h3 { - font: bold 12px/1.2 Arial,FreeSans,sans-serif; + font: bold 12px/1.2 Verdana,'DejaVu Sans',Geneva,sans-serif; color: #171919; border-bottom: 0 none; margin: 0; @@ -1463,22 +1531,19 @@ div.toc ul { list-style: none outside none; border: medium none; padding: 0px; -} - -div.toc li.level1 { - margin-left: 0px; } -div.toc li.level2 { +div.toc li[class^='level'] { margin-left: 15px; } -div.toc li.level3 { - margin-left: 30px; +div.toc li.level1 { + margin-left: 0px; } -div.toc li.level4 { - margin-left: 45px; +div.toc li.empty { + background-image: none; + margin-top: 0px; } span.emoji { @@ -1487,24 +1552,8 @@ span.emoji { */ } -.PageDocRTL-title div.toc li.level1 { - margin-left: 0 !important; - margin-right: 0; -} - -.PageDocRTL-title div.toc li.level2 { - margin-left: 0 !important; - margin-right: 15px; -} - -.PageDocRTL-title div.toc li.level3 { - margin-left: 0 !important; - margin-right: 30px; -} - -.PageDocRTL-title div.toc li.level4 { - margin-left: 0 !important; - margin-right: 45px; +span.obfuscator { + display: none; } .inherit_header { @@ -1541,7 +1590,8 @@ tr.heading h2 { #powerTip { cursor: default; - white-space: nowrap; + /*white-space: nowrap;*/ + color: black; background-color: white; border: 1px solid gray; border-radius: 4px 4px 4px 4px; @@ -1564,6 +1614,10 @@ tr.heading h2 { font-weight: bold; } +#powerTip a { + color: #171919; +} + #powerTip div.ttname { font-weight: bold; } @@ -1575,7 +1629,9 @@ tr.heading h2 { #powerTip div { margin: 0px; padding: 0px; - font: 12px/16px Roboto,sans-serif; + font-size: 12px; + font-family: Roboto,sans-serif; + line-height: 16px; } #powerTip:before, #powerTip:after { @@ -1620,12 +1676,12 @@ tr.heading h2 { } #powerTip.n:after, #powerTip.ne:after, #powerTip.nw:after { - border-top-color: #FFFFFF; + border-top-color: white; border-width: 10px; margin: 0px -10px; } -#powerTip.n:before { - border-top-color: #808080; +#powerTip.n:before, #powerTip.ne:before, #powerTip.nw:before { + border-top-color: gray; border-width: 11px; margin: 0px -11px; } @@ -1648,13 +1704,13 @@ tr.heading h2 { } #powerTip.s:after, #powerTip.se:after, #powerTip.sw:after { - border-bottom-color: #FFFFFF; + border-bottom-color: white; border-width: 10px; margin: 0px -10px; } #powerTip.s:before, #powerTip.se:before, #powerTip.sw:before { - border-bottom-color: #808080; + border-bottom-color: gray; border-width: 11px; margin: 0px -11px; } @@ -1675,13 +1731,13 @@ tr.heading h2 { left: 100%; } #powerTip.e:after { - border-left-color: #FFFFFF; + border-left-color: gray; border-width: 10px; top: 50%; margin-top: -10px; } #powerTip.e:before { - border-left-color: #808080; + border-left-color: gray; border-width: 11px; top: 50%; margin-top: -11px; @@ -1691,13 +1747,13 @@ tr.heading h2 { right: 100%; } #powerTip.w:after { - border-right-color: #FFFFFF; + border-right-color: gray; border-width: 10px; top: 50%; margin-top: -10px; } #powerTip.w:before { - border-right-color: #808080; + border-right-color: gray; border-width: 11px; top: 50%; margin-top: -11px; @@ -1758,36 +1814,37 @@ th.markdownTableHeadCenter, td.markdownTableBodyCenter { text-align: center } -.DocNodeRTL { - text-align: right; - direction: rtl; +tt, code, kbd +{ + display: inline-block; +} +tt, code, kbd +{ + vertical-align: top; } +/* @end */ -.DocNodeLTR { - text-align: left; - direction: ltr; +u { + text-decoration: underline; } -table.DocNodeRTL { - width: auto; - margin-right: 0; - margin-left: auto; +details>summary { + list-style-type: none; } -table.DocNodeLTR { - width: auto; - margin-right: auto; - margin-left: 0; +details > summary::-webkit-details-marker { + display: none; } -tt, code, kbd, samp -{ - display: inline-block; - direction:ltr; +details>summary::before { + content: "\25ba"; + padding-right:4px; + font-size: 80%; } -/* @end */ -u { - text-decoration: underline; +details[open]>summary::before { + content: "\25bc"; + padding-right:4px; + font-size: 80%; } diff --git a/src/dashbls/depends/mimalloc/docs/doxygen.svg b/src/dashbls/depends/mimalloc/docs/doxygen.svg new file mode 100644 index 000000000000..aeb5facb8198 --- /dev/null +++ b/src/dashbls/depends/mimalloc/docs/doxygen.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/dashbls/depends/mimalloc/docs/dynsections.js b/src/dashbls/depends/mimalloc/docs/dynsections.js index 3174bd7bebbf..3cc426a65adc 100644 --- a/src/dashbls/depends/mimalloc/docs/dynsections.js +++ b/src/dashbls/depends/mimalloc/docs/dynsections.js @@ -22,100 +22,177 @@ @licend The above is the entire license notice for the JavaScript code in this file */ -function toggleVisibility(linkObj) -{ - var base = $(linkObj).attr('id'); - var summary = $('#'+base+'-summary'); - var content = $('#'+base+'-content'); - var trigger = $('#'+base+'-trigger'); - var src=$(trigger).attr('src'); - if (content.is(':visible')===true) { - content.hide(); - summary.show(); - $(linkObj).addClass('closed').removeClass('opened'); - $(trigger).attr('src',src.substring(0,src.length-8)+'closed.png'); - } else { - content.show(); - summary.hide(); - $(linkObj).removeClass('closed').addClass('opened'); - $(trigger).attr('src',src.substring(0,src.length-10)+'open.png'); - } - return false; -} -function updateStripes() -{ - $('table.directory tr'). - removeClass('even').filter(':visible:even').addClass('even'); +function toggleVisibility(linkObj) { + return dynsection.toggleVisibility(linkObj); } -function toggleLevel(level) -{ - $('table.directory tr').each(function() { - var l = this.id.split('_').length-1; - var i = $('#img'+this.id.substring(3)); - var a = $('#arr'+this.id.substring(3)); - if (l'); + // add vertical lines to other rows + $('span[class=lineno]').not(':eq(0)').append(''); + // add toggle controls to lines with fold divs + $('div[class=foldopen]').each(function() { + // extract specific id to use + const id = $(this).attr('id').replace('foldopen',''); + // extract start and end foldable fragment attributes + const start = $(this).attr('data-start'); + const end = $(this).attr('data-end'); + // replace normal fold span with controls for the first line of a foldable fragment + $(this).find('span[class=fold]:first').replaceWith(''); + // append div for folded (closed) representation + $(this).after(''); + // extract the first line from the "open" section to represent closed content + const line = $(this).children().first().clone(); + // remove any glow that might still be active on the original line + $(line).removeClass('glow'); + if (start) { + // if line already ends with a start marker (e.g. trailing {), remove it + $(line).html($(line).html().replace(new RegExp('\\s*'+start+'\\s*$','g'),'')); + } + // replace minus with plus symbol + $(line).find('span[class=fold]').css('background-image',codefold.plusImg[relPath]); + // append ellipsis + $(line).append(' '+start+''+end); + // insert constructed line into closed div + $('#foldclosed'+id).html(line); + }); + }, +}; /* @license-end */ diff --git a/src/dashbls/depends/mimalloc/docs/environment.html b/src/dashbls/depends/mimalloc/docs/environment.html index f571f95f8052..7da7c3053199 100644 --- a/src/dashbls/depends/mimalloc/docs/environment.html +++ b/src/dashbls/depends/mimalloc/docs/environment.html @@ -1,24 +1,26 @@ - + - - + + mi-malloc: Environment Options + - + + @@ -29,20 +31,16 @@
- + - -
-
mi-malloc -  1.7/2.0 +
+
mi-malloc 1.8/2.1
+
- -   + @@ -56,10 +54,15 @@
- + +
@@ -74,8 +77,8 @@
@@ -88,34 +91,48 @@
- +
+
+
+
+
Loading...
+
Searching...
+
No Matches
+
+
+
-
-
-
Environment Options
+
+
Environment Options
-

You can set further options either programmatically (using mi_option_set), or via environment variables.

+

You can set further options either programmatically (using mi_option_set), or via environment variables:

  • MIMALLOC_SHOW_STATS=1: show statistics when the program terminates.
  • MIMALLOC_VERBOSE=1: show verbose messages.
  • MIMALLOC_SHOW_ERRORS=1: show error and warning messages.
  • -
  • MIMALLOC_PAGE_RESET=0: by default, mimalloc will reset (or purge) OS pages when not in use to signal to the OS that the underlying physical memory can be reused. This can reduce memory fragmentation in long running (server) programs. By setting it to 0 no such page resets will be done which can improve performance for programs that are not long running. As an alternative, the MIMALLOC_RESET_DELAY=<msecs> can be set higher (100ms by default) to make the page reset occur less frequently instead of turning it off completely.
  • -
  • MIMALLOC_LARGE_OS_PAGES=1: use large OS pages (2MiB) when available; for some workloads this can significantly improve performance. Use MIMALLOC_VERBOSE to check if the large OS pages are enabled – usually one needs to explicitly allow large OS pages (as on Windows and Linux). However, sometimes the OS is very slow to reserve contiguous physical memory for large OS pages so use with care on systems that can have fragmented memory (for that reason, we generally recommend to use MIMALLOC_RESERVE_HUGE_OS_PAGES instead when possible).
  • -
  • MIMALLOC_RESERVE_HUGE_OS_PAGES=N: where N is the number of 1GiB huge OS pages. This reserves the huge pages at startup and sometimes this can give a large (latency) performance improvement on big workloads. Usually it is better to not use MIMALLOC_LARGE_OS_PAGES in combination with this setting. Just like large OS pages, use with care as reserving contiguous physical memory can take a long time when memory is fragmented (but reserving the huge pages is done at startup only once). Note that we usually need to explicitly enable huge OS pages (as on Windows and Linux)). With huge OS pages, it may be beneficial to set the setting MIMALLOC_EAGER_COMMIT_DELAY=N (N is 1 by default) to delay the initial N segments (of 4MiB) of a thread to not allocate in the huge OS pages; this prevents threads that are short lived and allocate just a little to take up space in the huge OS page area (which cannot be reset).
  • -
  • MIMALLOC_RESERVE_HUGE_OS_PAGES_AT=N: where N is the numa node. This reserves the huge pages at a specific numa node. (N is -1 by default to reserve huge pages evenly among the given number of numa nodes (or use the available ones as detected))
-

Use caution when using fork in combination with either large or huge OS pages: on a fork, the OS uses copy-on-write for all pages in the original process including the huge OS pages. When any memory is now written in that area, the OS will copy the entire 1GiB huge page (or 2MiB large page) which can cause the memory usage to grow in big increments.

+

Advanced options:

+
    +
  • MIMALLOC_ARENA_EAGER_COMMIT=2: turns on eager commit for the large arenas (usually 1GiB) from which mimalloc allocates segments and pages. Set this to 2 (default) to only enable this on overcommit systems (e.g. Linux). Set this to 1 to enable explicitly on other systems as well (like Windows or macOS) which may improve performance (as the whole arena is committed at once). Note that eager commit only increases the commit but not the actual the peak resident set (rss) so it is generally ok to enable this.
  • +
  • MIMALLOC_PURGE_DELAY=N: the delay in N milli-seconds (by default 10) after which mimalloc will purge OS pages that are not in use. This signals to the OS that the underlying physical memory can be reused which can reduce memory fragmentation especially in long running (server) programs. Setting N to 0 purges immediately when a page becomes unused which can improve memory usage but also decreases performance. Setting N to a higher value like 100 can improve performance (sometimes by a lot) at the cost of potentially using more memory at times. Setting it to -1 disables purging completely.
  • +
  • MIMALLOC_PURGE_DECOMMITS=1: By default "purging" memory means unused memory is decommitted (MEM_DECOMMIT on Windows, MADV_DONTNEED (which decresease rss immediately) on mmap systems). Set this to 0 to instead "reset" unused memory on a purge (MEM_RESET on Windows, generally MADV_FREE (which does not decrease rss immediately) on mmap systems). Mimalloc generally does not "free" OS memory but only "purges" OS memory, in other words, it tries to keep virtual address ranges and decommits within those ranges (to make the underlying physical memory available to other processes).
  • +
+

Further options for large workloads and services:

+
    +
  • MIMALLOC_USE_NUMA_NODES=N: pretend there are at most N NUMA nodes. If not set, the actual NUMA nodes are detected at runtime. Setting N to 1 may avoid problems in some virtual environments. Also, setting it to a lower number than the actual NUMA nodes is fine and will only cause threads to potentially allocate more memory across actual NUMA nodes (but this can happen in any case as NUMA local allocation is always a best effort but not guaranteed).
  • +
  • MIMALLOC_ALLOW_LARGE_OS_PAGES=1: use large OS pages (2 or 4MiB) when available; for some workloads this can significantly improve performance. When this option is disabled, it also disables transparent huge pages (THP) for the process (on Linux and Android). Use MIMALLOC_VERBOSE to check if the large OS pages are enabled – usually one needs to explicitly give permissions for large OS pages (as on Windows and Linux). However, sometimes the OS is very slow to reserve contiguous physical memory for large OS pages so use with care on systems that can have fragmented memory (for that reason, we generally recommend to use MIMALLOC_RESERVE_HUGE_OS_PAGES instead whenever possible).
  • +
  • MIMALLOC_RESERVE_HUGE_OS_PAGES=N: where N is the number of 1GiB huge OS pages. This reserves the huge pages at startup and sometimes this can give a large (latency) performance improvement on big workloads. Usually it is better to not use MIMALLOC_ALLOW_LARGE_OS_PAGES=1 in combination with this setting. Just like large OS pages, use with care as reserving contiguous physical memory can take a long time when memory is fragmented (but reserving the huge pages is done at startup only once). Note that we usually need to explicitly give permission for huge OS pages (as on Windows and Linux)). With huge OS pages, it may be beneficial to set the setting MIMALLOC_EAGER_COMMIT_DELAY=N (N is 1 by default) to delay the initial N segments (of 4MiB) of a thread to not allocate in the huge OS pages; this prevents threads that are short lived and allocate just a little to take up space in the huge OS page area (which cannot be purged as huge OS pages are pinned to physical memory). The huge pages are usually allocated evenly among NUMA nodes. We can use MIMALLOC_RESERVE_HUGE_OS_PAGES_AT=N where N is the numa node (starting at 0) to allocate all the huge pages at a specific numa node instead.
  • +
+

Use caution when using fork in combination with either large or huge OS pages: on a fork, the OS uses copy-on-write for all pages in the original process including the huge OS pages. When any memory is now written in that area, the OS will copy the entire 1GiB huge page (or 2MiB large page) which can cause the memory usage to grow in large increments.

diff --git a/src/dashbls/depends/mimalloc/docs/functions.html b/src/dashbls/depends/mimalloc/docs/functions.html index 373fafe2b8b4..043b8621bef0 100644 --- a/src/dashbls/depends/mimalloc/docs/functions.html +++ b/src/dashbls/depends/mimalloc/docs/functions.html @@ -1,24 +1,26 @@ - + - - + + mi-malloc: Data Fields + - + + @@ -29,20 +31,16 @@
- + - -
-
mi-malloc -  1.7/2.0 +
+
mi-malloc 1.8/2.1
+
- -   + @@ -56,10 +54,15 @@
- + +
@@ -74,8 +77,8 @@
@@ -88,35 +91,34 @@
- +
+
+
+
+
Loading...
+
Searching...
+
No Matches
+
+
+
Here is a list of all struct and union fields with links to the structures/unions they belong to:
diff --git a/src/dashbls/depends/mimalloc/docs/functions_vars.html b/src/dashbls/depends/mimalloc/docs/functions_vars.html index a12ef6226574..ec9a4de13482 100644 --- a/src/dashbls/depends/mimalloc/docs/functions_vars.html +++ b/src/dashbls/depends/mimalloc/docs/functions_vars.html @@ -1,24 +1,26 @@ - + - - + + mi-malloc: Data Fields - Variables + - + + @@ -29,20 +31,16 @@
- + - -
-
mi-malloc -  1.7/2.0 +
+
mi-malloc 1.8/2.1
+
- -   + @@ -56,10 +54,15 @@
- + +
@@ -74,8 +77,8 @@
@@ -88,35 +91,34 @@
- +
+
+
+
+
Loading...
+
Searching...
+
No Matches
+
+
+
diff --git a/src/dashbls/depends/mimalloc/docs/group__aligned.html b/src/dashbls/depends/mimalloc/docs/group__aligned.html index bd11f30f2732..f107758e8395 100644 --- a/src/dashbls/depends/mimalloc/docs/group__aligned.html +++ b/src/dashbls/depends/mimalloc/docs/group__aligned.html @@ -1,24 +1,26 @@ - + - - + + mi-malloc: Aligned Allocation + - + + @@ -29,20 +31,16 @@
- + - -
-
mi-malloc -  1.7/2.0 +
+
mi-malloc 1.8/2.1
+
- -   + @@ -56,10 +54,15 @@
- + +
@@ -74,8 +77,8 @@
@@ -88,180 +91,142 @@
- +
+
+
+
+
Loading...
+
Searching...
+
No Matches
+
+
+
-
-
Aligned Allocation
+
Aligned Allocation

Allocating aligned memory blocks. More...

- - - - -

-Macros

#define MI_ALIGNMENT_MAX
 The maximum supported alignment size (currently 1MiB). More...
 
- - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + +

+

Functions

void * mi_malloc_aligned (size_t size, size_t alignment)
 Allocate size bytes aligned by alignment. More...
 
void * mi_zalloc_aligned (size_t size, size_t alignment)
 
void * mi_calloc_aligned (size_t count, size_t size, size_t alignment)
 
void * mi_realloc_aligned (void *p, size_t newsize, size_t alignment)
 
void * mi_malloc_aligned_at (size_t size, size_t alignment, size_t offset)
 Allocate size bytes aligned by alignment at a specified offset. More...
 
void * mi_zalloc_aligned_at (size_t size, size_t alignment, size_t offset)
 
void * mi_calloc_aligned_at (size_t count, size_t size, size_t alignment, size_t offset)
 
void * mi_realloc_aligned_at (void *p, size_t newsize, size_t alignment, size_t offset)
 
void * mi_malloc_aligned (size_t size, size_t alignment)
 Allocate size bytes aligned by alignment.
 
void * mi_zalloc_aligned (size_t size, size_t alignment)
 
void * mi_calloc_aligned (size_t count, size_t size, size_t alignment)
 
void * mi_realloc_aligned (void *p, size_t newsize, size_t alignment)
 
void * mi_malloc_aligned_at (size_t size, size_t alignment, size_t offset)
 Allocate size bytes aligned by alignment at a specified offset.
 
void * mi_zalloc_aligned_at (size_t size, size_t alignment, size_t offset)
 
void * mi_calloc_aligned_at (size_t count, size_t size, size_t alignment, size_t offset)
 
void * mi_realloc_aligned_at (void *p, size_t newsize, size_t alignment, size_t offset)
 

Detailed Description

Allocating aligned memory blocks.

-

Macro Definition Documentation

- -

◆ MI_ALIGNMENT_MAX

- -
-
- - - - -
#define MI_ALIGNMENT_MAX
-
- -

The maximum supported alignment size (currently 1MiB).

- -
-
+

Note that alignment always follows size for consistency with the unaligned allocation API, but unfortunately this differs from posix_memalign and aligned_alloc in the C library.

Function Documentation

- -

◆ mi_calloc_aligned()

+ +

◆ mi_calloc_aligned()

- + - - + - - + - - - - - - - +
void* mi_calloc_aligned void * mi_calloc_aligned (size_t count, size_t count,
size_t size, size_t size,
size_t alignment 
)size_t alignment )
- -

◆ mi_calloc_aligned_at()

+ +

◆ mi_calloc_aligned_at()

- + - - + - - + - - + - - - - - - - +
void* mi_calloc_aligned_at void * mi_calloc_aligned_at (size_t count, size_t count,
size_t size, size_t size,
size_t alignment, size_t alignment,
size_t offset 
)size_t offset )
- -

◆ mi_malloc_aligned()

+ +

◆ mi_malloc_aligned()

- + - - + - - - - - - - +
void* mi_malloc_aligned void * mi_malloc_aligned (size_t size, size_t size,
size_t alignment 
)size_t alignment )
-

Allocate size bytes aligned by alignment.

+

Allocate size bytes aligned by alignment.

Parameters
- +
sizenumber of bytes to allocate.
alignmentthe minimal alignment of the allocated memory. Must be less than MI_ALIGNMENT_MAX.
alignmentthe minimal alignment of the allocated memory.
-
Returns
pointer to the allocated memory or NULL if out of memory. The returned pointer is aligned by alignment, i.e. (uintptr_t)p % alignment == 0.
-

Returns a unique pointer if called with size 0.

See also
_aligned_malloc (on Windows)
+
Returns
pointer to the allocated memory or NULL if out of memory, or if the alignment is not a power of 2 (including 0). The size is unrestricted (and does not have to be an integral multiple of the alignment). The returned pointer is aligned by alignment, i.e. (uintptr_t)p % alignment == 0. Returns a unique pointer if called with size 0.
+

Note that alignment always follows size for consistency with the unaligned allocation API, but unfortunately this differs from posix_memalign and aligned_alloc in the C library.

+
See also
aligned_alloc (in the standard C11 library, with switched arguments!)
+
+_aligned_malloc (on Windows)
aligned_alloc (on BSD, with switched arguments!)
@@ -271,182 +236,142 @@

-

◆ mi_malloc_aligned_at()

+ +

◆ mi_malloc_aligned_at()

- + - - + - - + - - - - - - - +
void* mi_malloc_aligned_at void * mi_malloc_aligned_at (size_t size, size_t size,
size_t alignment, size_t alignment,
size_t offset 
)size_t offset )
-

Allocate size bytes aligned by alignment at a specified offset.

+

Allocate size bytes aligned by alignment at a specified offset.

Parameters
- +
sizenumber of bytes to allocate.
alignmentthe minimal alignment of the allocated memory at offset.
alignmentthe minimal alignment of the allocated memory at offset.
offsetthe offset that should be aligned.
-
Returns
pointer to the allocated memory or NULL if out of memory. The returned pointer is aligned by alignment at offset, i.e. ((uintptr_t)p + offset) % alignment == 0.
-

Returns a unique pointer if called with size 0.

See also
_aligned_offset_malloc (on Windows)
+
Returns
pointer to the allocated memory or NULL if out of memory, or if the alignment is not a power of 2 (including 0). The size is unrestricted (and does not have to be an integral multiple of the alignment). The returned pointer is aligned by alignment, i.e. (uintptr_t)p % alignment == 0. Returns a unique pointer if called with size 0.
+
See also
_aligned_offset_malloc (on Windows)
- -

◆ mi_realloc_aligned()

+ +

◆ mi_realloc_aligned()

- + - - + - - + - - - - - - - +
void* mi_realloc_aligned void * mi_realloc_aligned (void * p, void * p,
size_t newsize, size_t newsize,
size_t alignment 
)size_t alignment )
- -

◆ mi_realloc_aligned_at()

+ +

◆ mi_realloc_aligned_at()

- + - - + - - + - - + - - - - - - - +
void* mi_realloc_aligned_at void * mi_realloc_aligned_at (void * p, void * p,
size_t newsize, size_t newsize,
size_t alignment, size_t alignment,
size_t offset 
)size_t offset )
- -

◆ mi_zalloc_aligned()

+ +

◆ mi_zalloc_aligned()

- + - - + - - - - - - - +
void* mi_zalloc_aligned void * mi_zalloc_aligned (size_t size, size_t size,
size_t alignment 
)size_t alignment )
- -

◆ mi_zalloc_aligned_at()

+ +

◆ mi_zalloc_aligned_at()

- + - - + - - + - - - - - - - +
void* mi_zalloc_aligned_at void * mi_zalloc_aligned_at (size_t size, size_t size,
size_t alignment, size_t alignment,
size_t offset 
)size_t offset )
@@ -458,7 +383,7 @@

diff --git a/src/dashbls/depends/mimalloc/docs/group__aligned.js b/src/dashbls/depends/mimalloc/docs/group__aligned.js index 06ccb0c370bb..d77e5036c311 100644 --- a/src/dashbls/depends/mimalloc/docs/group__aligned.js +++ b/src/dashbls/depends/mimalloc/docs/group__aligned.js @@ -1,12 +1,11 @@ var group__aligned = [ - [ "MI_ALIGNMENT_MAX", "group__aligned.html#ga83c03016066b438f51a8095e9140be06", null ], - [ "mi_calloc_aligned", "group__aligned.html#ga53dddb4724042a90315b94bc268fb4c9", null ], - [ "mi_calloc_aligned_at", "group__aligned.html#ga08647c4593f3b2eef24a919a73eba3a3", null ], - [ "mi_malloc_aligned", "group__aligned.html#ga68930196751fa2cca9e1fd0d71bade56", null ], - [ "mi_malloc_aligned_at", "group__aligned.html#ga5850da130c936bd77db039dcfbc8295d", null ], - [ "mi_realloc_aligned", "group__aligned.html#ga4028d1cf4aa4c87c880747044a8322ae", null ], - [ "mi_realloc_aligned_at", "group__aligned.html#gaf66a9ae6c6f08bd6be6fb6ea771faffb", null ], - [ "mi_zalloc_aligned", "group__aligned.html#ga0cadbcf5b89a7b6fb171bc8df8734819", null ], - [ "mi_zalloc_aligned_at", "group__aligned.html#ga5f8c2353766db522565e642fafd8a3f8", null ] + [ "mi_calloc_aligned", "group__aligned.html#ga424ef386fb1f9f8e0a86ab53f16eaaf1", null ], + [ "mi_calloc_aligned_at", "group__aligned.html#ga977f96bd2c5c141bcd70e6685c90d6c3", null ], + [ "mi_malloc_aligned", "group__aligned.html#ga69578ff1a98ca16e1dcd02c0995cd65c", null ], + [ "mi_malloc_aligned_at", "group__aligned.html#ga2022f71b95a7cd6cce1b6e07752ae8ca", null ], + [ "mi_realloc_aligned", "group__aligned.html#ga5d7a46d054b4d7abe9d8d2474add2edf", null ], + [ "mi_realloc_aligned_at", "group__aligned.html#gad06dcf2bb8faadb2c8ea61ee5d24bbf6", null ], + [ "mi_zalloc_aligned", "group__aligned.html#gaac7d0beb782f9b9ac31f47492b130f82", null ], + [ "mi_zalloc_aligned_at", "group__aligned.html#ga7c1778805ce50ebbf02ccbd5e39d5dba", null ] ]; \ No newline at end of file diff --git a/src/dashbls/depends/mimalloc/docs/group__analysis.html b/src/dashbls/depends/mimalloc/docs/group__analysis.html index 883099fe50a7..882830ebb5b4 100644 --- a/src/dashbls/depends/mimalloc/docs/group__analysis.html +++ b/src/dashbls/depends/mimalloc/docs/group__analysis.html @@ -1,24 +1,26 @@ - + - - + + mi-malloc: Heap Introspection + - + + @@ -29,20 +31,16 @@
- + - -
-
mi-malloc -  1.7/2.0 +
+
mi-malloc 1.8/2.1
+
- -   + @@ -56,10 +54,15 @@
- + +
@@ -74,8 +77,8 @@

@@ -88,9 +91,16 @@
- +
+
+
+
+
Loading...
+
Searching...
+
No Matches
+
+
+
@@ -98,46 +108,48 @@ Data Structures | Typedefs | Functions
-
-
Heap Introspection
+
Heap Introspection

Inspect the heap at runtime. More...

- - - + +

+

Data Structures

struct  mi_heap_area_t
 An area of heap space contains blocks of a single size. More...
struct  mi_heap_area_t
 An area of heap space contains blocks of a single size. More...
 
- - - - + + +

+

Typedefs

typedef bool() mi_block_visit_fun(const mi_heap_t *heap, const mi_heap_area_t *area, void *block, size_t block_size, void *arg)
 Visitor function passed to mi_heap_visit_blocks() More...
 
typedef bool mi_block_visit_fun(const mi_heap_t *heap, const mi_heap_area_t *area, void *block, size_t block_size, void *arg)
 Visitor function passed to mi_heap_visit_blocks()
 
- - - + + - - + + - - + + - - + + + + +

+

Functions

bool mi_heap_contains_block (mi_heap_t *heap, const void *p)
 Does a heap contain a pointer to a previously allocated block? More...
bool mi_heap_contains_block (mi_heap_t *heap, const void *p)
 Does a heap contain a pointer to a previously allocated block?
 
bool mi_heap_check_owned (mi_heap_t *heap, const void *p)
 Check safely if any pointer is part of a heap. More...
bool mi_heap_check_owned (mi_heap_t *heap, const void *p)
 Check safely if any pointer is part of a heap.
 
bool mi_check_owned (const void *p)
 Check safely if any pointer is part of the default heap of this thread. More...
bool mi_check_owned (const void *p)
 Check safely if any pointer is part of the default heap of this thread.
 
bool mi_heap_visit_blocks (const mi_heap_t *heap, bool visit_all_blocks, mi_block_visit_fun *visitor, void *arg)
 Visit all areas and blocks in a heap. More...
bool mi_heap_visit_blocks (const mi_heap_t *heap, bool visit_all_blocks, mi_block_visit_fun *visitor, void *arg)
 Visit all areas and blocks in a heap.
 
bool mi_abandoned_visit_blocks (mi_subproc_id_t subproc_id, int heap_tag, bool visit_blocks, mi_block_visit_fun *visitor, void *arg)
 Visit all areas and blocks in abandoned heaps.
 

Detailed Description

Inspect the heap at runtime.


Data Structure Documentation

-

◆ mi_heap_area_t

+

◆ mi_heap_area_t

@@ -152,31 +164,43 @@

+size_t +void * +size_t +size_t + + + + + + +size_t - - +
Data Fields
-size_t block_size size in bytes of one block
-void * blocks start of the area containing heap blocks
-size_t committed current committed bytes of this area
-size_t +full_block_size +size in bytes of a full block including padding and metadata.
+int +heap_tag +heap tag associated with this area (see mi_heap_new_ex)
+size_t reserved bytes reserved for this area
-size_t used @@ -186,27 +210,77 @@

Typedef Documentation

-
-

◆ mi_block_visit_fun

+ +

◆ mi_block_visit_fun

- +
typedef bool() mi_block_visit_fun(const mi_heap_t *heap, const mi_heap_area_t *area, void *block, size_t block_size, void *arg)typedef bool mi_block_visit_fun(const mi_heap_t *heap, const mi_heap_area_t *area, void *block, size_t block_size, void *arg)
-

Visitor function passed to mi_heap_visit_blocks()

-
Returns
true if ok, false to stop visiting (i.e. break)
-

This function is always first called for every area with block as a NULL pointer. If visit_all_blocks was true, the function is then called for every allocated block in that area.

+

Visitor function passed to mi_heap_visit_blocks()

+
Returns
true if ok, false to stop visiting (i.e. break)
+

This function is always first called for every area with block as a NULL pointer. If visit_all_blocks was true, the function is then called for every allocated block in that area.

Function Documentation

- -

◆ mi_check_owned()

+ +

◆ mi_abandoned_visit_blocks()

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
bool mi_abandoned_visit_blocks (mi_subproc_id_t subproc_id,
int heap_tag,
bool visit_blocks,
mi_block_visit_fun * visitor,
void * arg )
+
+ +

Visit all areas and blocks in abandoned heaps.

+
Parameters
+ + + + + + +
subproc_idThe sub-process id associated with the abandoned heaps.
heap_tagVisit only abandoned memory with the specified heap tag, use -1 to visit all abandoned memory.
visit_blocksIf true visits all allocated blocks, otherwise visitor is only called for every heap area.
visitorThis function is called for every area in the heap (with block as NULL). If visit_all_blocks is true, visitor is also called for every allocated block in every area (with block!=NULL). return false from this function to stop visiting early.
argextra argument passed to the visitor.
+
+
+
Returns
true if all areas and blocks were visited.
+

Note: requires the option mi_option_visit_abandoned to be set at the start of the program.

+ +
+
+ +

◆ mi_check_owned()

@@ -214,8 +288,7 @@

bool mi_check_owned

(const void * p)const void * p)
@@ -228,15 +301,15 @@

Returns
true if p points to a block in default heap of this thread.
-

Note: expensive function, linear in the pages in the heap.

See also
mi_heap_contains_block()
+
Returns
true if p points to a block in default heap of this thread.
+

Note: expensive function, linear in the pages in the heap.

See also
mi_heap_contains_block()
-mi_heap_get_default()
+mi_heap_get_default()

- -

◆ mi_heap_check_owned()

+ +

◆ mi_heap_check_owned()

@@ -244,19 +317,12 @@

bool mi_heap_check_owned ( - mi_heap_t *  - heap, + mi_heap_t * heap, - const void *  - p  - - - - ) - + const void * p )

@@ -269,15 +335,15 @@

Returns
true if p points to a block in heap.
-

Note: expensive function, linear in the pages in the heap.

See also
mi_heap_contains_block()
+
Returns
true if p points to a block in heap.
+

Note: expensive function, linear in the pages in the heap.

See also
mi_heap_contains_block()
-mi_heap_get_default()
+mi_heap_get_default()

- -

◆ mi_heap_contains_block()

+ +

◆ mi_heap_contains_block()

@@ -285,19 +351,12 @@

bool mi_heap_contains_block ( - mi_heap_t *  - heap, + mi_heap_t * heap, - const void *  - p  - - - - ) - + const void * p )

@@ -310,13 +369,13 @@

Returns
true if the block pointed to by p is in the heap.
-
See also
mi_heap_check_owned()
+
Returns
true if the block pointed to by p is in the heap.
+
See also
mi_heap_check_owned()

- -

◆ mi_heap_visit_blocks()

+ +

◆ mi_heap_visit_blocks()

@@ -372,7 +422,7 @@

diff --git a/src/dashbls/depends/mimalloc/docs/group__analysis.js b/src/dashbls/depends/mimalloc/docs/group__analysis.js index 351783628ddf..5e72b94a5e4f 100644 --- a/src/dashbls/depends/mimalloc/docs/group__analysis.js +++ b/src/dashbls/depends/mimalloc/docs/group__analysis.js @@ -4,10 +4,13 @@ var group__analysis = [ "block_size", "group__analysis.html#a332a6c14d736a99699d5453a1cb04b41", null ], [ "blocks", "group__analysis.html#ae0085e6e1cf059a4eb7767e30e9991b8", null ], [ "committed", "group__analysis.html#ab47526df656d8837ec3e97f11b83f835", null ], + [ "full_block_size", "group__analysis.html#ab53664e31d7fe2564f8d42041ef75cb3", null ], + [ "heap_tag", "group__analysis.html#a2b7a0c92ece8daf46b558efc990ebdc1", null ], [ "reserved", "group__analysis.html#ae848a3e6840414891035423948ca0383", null ], [ "used", "group__analysis.html#ab820302c5cd0df133eb8e51650a008b4", null ] ] ], - [ "mi_block_visit_fun", "group__analysis.html#gadfa01e2900f0e5d515ad5506b26f6d65", null ], + [ "mi_block_visit_fun", "group__analysis.html#ga8255dc9371e6b299d9802a610c4e34ec", null ], + [ "mi_abandoned_visit_blocks", "group__analysis.html#ga6a4865a887b2ec5247854af61562503c", null ], [ "mi_check_owned", "group__analysis.html#ga628c237489c2679af84a4d0d143b3dd5", null ], [ "mi_heap_check_owned", "group__analysis.html#ga0d67c1789faaa15ff366c024fcaf6377", null ], [ "mi_heap_contains_block", "group__analysis.html#gaa862aa8ed8d57d84cae41fc1022d71af", null ], diff --git a/src/dashbls/depends/mimalloc/docs/group__analysis_structmi__heap__area__t.js b/src/dashbls/depends/mimalloc/docs/group__analysis_structmi__heap__area__t.js index 2dbabc5cde17..41a8e77abecc 100644 --- a/src/dashbls/depends/mimalloc/docs/group__analysis_structmi__heap__area__t.js +++ b/src/dashbls/depends/mimalloc/docs/group__analysis_structmi__heap__area__t.js @@ -3,6 +3,8 @@ var group__analysis_structmi__heap__area__t = [ "block_size", "group__analysis.html#a332a6c14d736a99699d5453a1cb04b41", null ], [ "blocks", "group__analysis.html#ae0085e6e1cf059a4eb7767e30e9991b8", null ], [ "committed", "group__analysis.html#ab47526df656d8837ec3e97f11b83f835", null ], + [ "full_block_size", "group__analysis.html#ab53664e31d7fe2564f8d42041ef75cb3", null ], + [ "heap_tag", "group__analysis.html#a2b7a0c92ece8daf46b558efc990ebdc1", null ], [ "reserved", "group__analysis.html#ae848a3e6840414891035423948ca0383", null ], [ "used", "group__analysis.html#ab820302c5cd0df133eb8e51650a008b4", null ] ]; \ No newline at end of file diff --git a/src/dashbls/depends/mimalloc/docs/group__cpp.html b/src/dashbls/depends/mimalloc/docs/group__cpp.html index e81179feb643..d998433469de 100644 --- a/src/dashbls/depends/mimalloc/docs/group__cpp.html +++ b/src/dashbls/depends/mimalloc/docs/group__cpp.html @@ -1,24 +1,26 @@ - + - - + + mi-malloc: C++ wrappers + - + + @@ -29,20 +31,16 @@
- + - -
-
mi-malloc -  1.7/2.0 +
+
mi-malloc 1.8/2.1
+
- -   + @@ -56,10 +54,15 @@
- + +
@@ -74,8 +77,8 @@
@@ -88,59 +91,65 @@
- +
+
+
+
+
Loading...
+
Searching...
+
No Matches
+
+
+
-
-
C++ wrappers
+
C++ wrappers

mi_ prefixed implementations of various allocation functions that use C++ semantics on out-of-memory, generally calling std::get_new_handler and raising a std::bad_alloc exception on failure. More...

- - - + +

+

Data Structures

struct  mi_stl_allocator< T >
 std::allocator implementation for mimalloc for use in STL containers. More...
struct  mi_stl_allocator< T >
 std::allocator implementation for mimalloc for use in STL containers. More...
 
- - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + +

+

Functions

void * mi_new (std::size_t n) noexcept(false)
 like mi_malloc(), but when out of memory, use std::get_new_handler and raise std::bad_alloc exception on failure. More...
 
void * mi_new_n (size_t count, size_t size) noexcept(false)
 like mi_mallocn(), but when out of memory, use std::get_new_handler and raise std::bad_alloc exception on failure. More...
 
void * mi_new_aligned (std::size_t n, std::align_val_t alignment) noexcept(false)
 like mi_malloc_aligned(), but when out of memory, use std::get_new_handler and raise std::bad_alloc exception on failure. More...
 
void * mi_new_nothrow (size_t n)
 like mi_malloc, but when out of memory, use std::get_new_handler but return NULL on failure. More...
 
void * mi_new_aligned_nothrow (size_t n, size_t alignment)
 like mi_malloc_aligned, but when out of memory, use std::get_new_handler but return NULL on failure. More...
 
void * mi_new_realloc (void *p, size_t newsize)
 like mi_realloc(), but when out of memory, use std::get_new_handler and raise std::bad_alloc exception on failure. More...
 
void * mi_new_reallocn (void *p, size_t newcount, size_t size)
 like mi_reallocn(), but when out of memory, use std::get_new_handler and raise std::bad_alloc exception on failure. More...
 
void * mi_new (std::size_t n) noexcept(false)
 like mi_malloc(), but when out of memory, use std::get_new_handler and raise std::bad_alloc exception on failure.
 
void * mi_new_n (size_t count, size_t size) noexcept(false)
 like mi_mallocn(), but when out of memory, use std::get_new_handler and raise std::bad_alloc exception on failure.
 
void * mi_new_aligned (std::size_t n, std::align_val_t alignment) noexcept(false)
 like mi_malloc_aligned(), but when out of memory, use std::get_new_handler and raise std::bad_alloc exception on failure.
 
void * mi_new_nothrow (size_t n)
 like mi_malloc, but when out of memory, use std::get_new_handler but return NULL on failure.
 
void * mi_new_aligned_nothrow (size_t n, size_t alignment)
 like mi_malloc_aligned, but when out of memory, use std::get_new_handler but return NULL on failure.
 
void * mi_new_realloc (void *p, size_t newsize)
 like mi_realloc(), but when out of memory, use std::get_new_handler and raise std::bad_alloc exception on failure.
 
void * mi_new_reallocn (void *p, size_t newcount, size_t size)
 like mi_reallocn(), but when out of memory, use std::get_new_handler and raise std::bad_alloc exception on failure.
 

Detailed Description

mi_ prefixed implementations of various allocation functions that use C++ semantics on out-of-memory, generally calling std::get_new_handler and raising a std::bad_alloc exception on failure.

-

Note: use the mimalloc-new-delete.h header to override the new and delete operators globally. The wrappers here are mostly for convience for library writers that need to interface with mimalloc from C++.

+

Note: use the mimalloc-new-delete.h header to override the new and delete operators globally. The wrappers here are mostly for convenience for library writers that need to interface with mimalloc from C++.


Data Structure Documentation

-

◆ mi_stl_allocator

+

◆ mi_stl_allocator

@@ -150,10 +159,8 @@

-

template<class T>
-struct mi_stl_allocator< T >

- -

std::allocator implementation for mimalloc for use in STL containers.

+
template<class T>
+struct mi_stl_allocator< T >

std::allocator implementation for mimalloc for use in STL containers.

For example:

Function Documentation

-
-

◆ mi_new()

+ +

◆ mi_new()

- - - - - -
- + - - +
void* mi_new void * mi_new (std::size_t n)std::size_t n)
-
-noexcept
-

like mi_malloc(), but when out of memory, use std::get_new_handler and raise std::bad_alloc exception on failure.

+

like mi_malloc(), but when out of memory, use std::get_new_handler and raise std::bad_alloc exception on failure.

- -

◆ mi_new_aligned()

+ +

◆ mi_new_aligned()

- - - - - -
- + - - + - - - - - - - +
void* mi_new_aligned void * mi_new_aligned (std::size_t n, std::size_t n,
std::align_val_t alignment 
)std::align_val_t alignment )
-
-noexcept
-

like mi_malloc_aligned(), but when out of memory, use std::get_new_handler and raise std::bad_alloc exception on failure.

+

like mi_malloc_aligned(), but when out of memory, use std::get_new_handler and raise std::bad_alloc exception on failure.

- -

◆ mi_new_aligned_nothrow()

+ +

◆ mi_new_aligned_nothrow()

- + - - + - - - - - - - +
void* mi_new_aligned_nothrow void * mi_new_aligned_nothrow (size_t n, size_t n,
size_t alignment 
)size_t alignment )
-

like mi_malloc_aligned, but when out of memory, use std::get_new_handler but return NULL on failure.

+

like mi_malloc_aligned, but when out of memory, use std::get_new_handler but return NULL on failure.

- -

◆ mi_new_n()

+ +

◆ mi_new_n()

- - - - - -
- + - - + - - - - - - - +
void* mi_new_n void * mi_new_n (size_t count, size_t count,
size_t size 
)size_t size )
-
-noexcept
-

like mi_mallocn(), but when out of memory, use std::get_new_handler and raise std::bad_alloc exception on failure.

+

like mi_mallocn(), but when out of memory, use std::get_new_handler and raise std::bad_alloc exception on failure.

- -

◆ mi_new_nothrow()

+ +

◆ mi_new_nothrow()

- + - - +
void* mi_new_nothrow void * mi_new_nothrow (size_t n)size_t n)
-

like mi_malloc, but when out of memory, use std::get_new_handler but return NULL on failure.

+

like mi_malloc, but when out of memory, use std::get_new_handler but return NULL on failure.

- -

◆ mi_new_realloc()

+ +

◆ mi_new_realloc()

- + - - + - - - - - - - +
void* mi_new_realloc void * mi_new_realloc (void * p, void * p,
size_t newsize 
)size_t newsize )
-

like mi_realloc(), but when out of memory, use std::get_new_handler and raise std::bad_alloc exception on failure.

+

like mi_realloc(), but when out of memory, use std::get_new_handler and raise std::bad_alloc exception on failure.

- -

◆ mi_new_reallocn()

+ +

◆ mi_new_reallocn()

- + - - + - - + - - - - - - - +
void* mi_new_reallocn void * mi_new_reallocn (void * p, void * p,
size_t newcount, size_t newcount,
size_t size 
)size_t size )
-

like mi_reallocn(), but when out of memory, use std::get_new_handler and raise std::bad_alloc exception on failure.

+

like mi_reallocn(), but when out of memory, use std::get_new_handler and raise std::bad_alloc exception on failure.

@@ -386,7 +331,7 @@

diff --git a/src/dashbls/depends/mimalloc/docs/group__cpp.js b/src/dashbls/depends/mimalloc/docs/group__cpp.js index 207066468529..355f1ac6d053 100644 --- a/src/dashbls/depends/mimalloc/docs/group__cpp.js +++ b/src/dashbls/depends/mimalloc/docs/group__cpp.js @@ -1,11 +1,11 @@ var group__cpp = [ - [ "mi_stl_allocator", "group__cpp.html#structmi__stl__allocator", null ], - [ "mi_new", "group__cpp.html#gaad048a9fce3d02c5909cd05c6ec24545", null ], - [ "mi_new_aligned", "group__cpp.html#gaef2c2bdb4f70857902d3c8903ac095f3", null ], - [ "mi_new_aligned_nothrow", "group__cpp.html#gab5e29558926d934c3f1cae8c815f942c", null ], - [ "mi_new_n", "group__cpp.html#gae7bc4f56cd57ed3359060ff4f38bda81", null ], - [ "mi_new_nothrow", "group__cpp.html#gaeaded64eda71ed6b1d569d3e723abc4a", null ], - [ "mi_new_realloc", "group__cpp.html#gaab78a32f55149e9fbf432d5288e38e1e", null ], - [ "mi_new_reallocn", "group__cpp.html#ga756f4b2bc6a7ecd0a90baea8e90c7907", null ] + [ "mi_stl_allocator< T >", "group__cpp.html#structmi__stl__allocator", null ], + [ "mi_new", "group__cpp.html#ga633d96e3bc7011f960df9f3b2731fc6a", null ], + [ "mi_new_aligned", "group__cpp.html#ga79c54da0b4b4ce9fcc11d2f6ef6675f8", null ], + [ "mi_new_aligned_nothrow", "group__cpp.html#ga92ae00b6dd64406c7e64557711ec04b7", null ], + [ "mi_new_n", "group__cpp.html#gadd11b85c15d21d308386844b5233856c", null ], + [ "mi_new_nothrow", "group__cpp.html#ga5cb4f120d1f7296074256215aa9a9e54", null ], + [ "mi_new_realloc", "group__cpp.html#ga6867d89baf992728e0cc20a1f47db4d0", null ], + [ "mi_new_reallocn", "group__cpp.html#gaace912ce086682d56f3ce9f7638d9d67", null ] ]; \ No newline at end of file diff --git a/src/dashbls/depends/mimalloc/docs/group__extended.html b/src/dashbls/depends/mimalloc/docs/group__extended.html index e54991180272..4eea7c69bc5e 100644 --- a/src/dashbls/depends/mimalloc/docs/group__extended.html +++ b/src/dashbls/depends/mimalloc/docs/group__extended.html @@ -1,24 +1,26 @@ - + - - + + mi-malloc: Extended Functions + - + + @@ -29,20 +31,16 @@
- + - -
-
mi-malloc -  1.7/2.0 +
+
mi-malloc 1.8/2.1
+
- -   + @@ -56,10 +54,15 @@
- + +
@@ -74,8 +77,8 @@
@@ -88,9 +91,16 @@
- +
+
+
+
+
Loading...
+
Searching...
+
No Matches
+
+
+
@@ -98,106 +108,144 @@ Macros | Typedefs | Functions
-
-
Extended Functions
+
Extended Functions

Extended functionality. More...

- - - + +

+

Macros

#define MI_SMALL_SIZE_MAX
 Maximum size allowed for small allocations in mi_malloc_small and mi_zalloc_small (usually 128*sizeof(void*) (= 1KB on 64-bit systems)) More...
#define MI_SMALL_SIZE_MAX
 Maximum size allowed for small allocations in mi_malloc_small and mi_zalloc_small (usually 128*sizeof(void*) (= 1KB on 64-bit systems))
 
- - - - - - - - - - + + + + + + + + + + + + + + +

+

Typedefs

typedef void() mi_deferred_free_fun(bool force, unsigned long long heartbeat, void *arg)
 Type of deferred free functions. More...
 
typedef void() mi_output_fun(const char *msg, void *arg)
 Type of output functions. More...
 
typedef void() mi_error_fun(int err, void *arg)
 Type of error callback functions. More...
 
typedef void mi_deferred_free_fun(bool force, unsigned long long heartbeat, void *arg)
 Type of deferred free functions.
 
typedef void mi_output_fun(const char *msg, void *arg)
 Type of output functions.
 
typedef void mi_error_fun(int err, void *arg)
 Type of error callback functions.
 
typedef int mi_arena_id_t
 Mimalloc uses large (virtual) memory areas, called "arena"s, from the OS to manage its memory.
 
typedef void * mi_subproc_id_t
 A process can associate threads with sub-processes.
 
- - - - - - - - - + + + + + + + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+

Functions

void * mi_malloc_small (size_t size)
 Allocate a small object. More...
 
void * mi_zalloc_small (size_t size)
 Allocate a zero initialized small object. More...
 
size_t mi_usable_size (void *p)
 Return the available bytes in a memory block. More...
void * mi_malloc_small (size_t size)
 Allocate a small object.
 
void * mi_zalloc_small (size_t size)
 Allocate a zero initialized small object.
 
size_t mi_usable_size (void *p)
 Return the available bytes in a memory block.
 
size_t mi_good_size (size_t size)
 Return the used allocation size. More...
size_t mi_good_size (size_t size)
 Return the used allocation size.
 
void mi_collect (bool force)
 Eagerly free memory. More...
void mi_collect (bool force)
 Eagerly free memory.
 
void mi_stats_print (void *out)
 Deprecated. More...
void mi_stats_print (void *out)
 Deprecated.
 
void mi_stats_print_out (mi_output_fun *out, void *arg)
 Print the main statistics. More...
void mi_stats_print_out (mi_output_fun *out, void *arg)
 Print the main statistics.
 
void mi_stats_reset (void)
 Reset statistics. More...
void mi_stats_reset (void)
 Reset statistics.
 
void mi_stats_merge (void)
 Merge thread local statistics with the main statistics and reset. More...
void mi_stats_merge (void)
 Merge thread local statistics with the main statistics and reset.
 
void mi_thread_init (void)
 Initialize mimalloc on a thread. More...
void mi_thread_init (void)
 Initialize mimalloc on a thread.
 
void mi_thread_done (void)
 Uninitialize mimalloc on a thread. More...
void mi_thread_done (void)
 Uninitialize mimalloc on a thread.
 
void mi_thread_stats_print_out (mi_output_fun *out, void *arg)
 Print out heap statistics for this thread. More...
void mi_thread_stats_print_out (mi_output_fun *out, void *arg)
 Print out heap statistics for this thread.
 
void mi_register_deferred_free (mi_deferred_free_fun *deferred_free, void *arg)
 Register a deferred free function. More...
void mi_register_deferred_free (mi_deferred_free_fun *deferred_free, void *arg)
 Register a deferred free function.
 
void mi_register_output (mi_output_fun *out, void *arg)
 Register an output function. More...
void mi_register_output (mi_output_fun *out, void *arg)
 Register an output function.
 
void mi_register_error (mi_error_fun *errfun, void *arg)
 Register an error callback function. More...
void mi_register_error (mi_error_fun *errfun, void *arg)
 Register an error callback function.
 
bool mi_is_in_heap_region (const void *p)
 Is a pointer part of our heap? More...
bool mi_is_in_heap_region (const void *p)
 Is a pointer part of our heap?
 
int mi_reserve_os_memory (size_t size, bool commit, bool allow_large)
 Reserve OS memory for use by mimalloc. More...
int mi_reserve_os_memory (size_t size, bool commit, bool allow_large)
 Reserve OS memory for use by mimalloc.
 
bool mi_manage_os_memory (void *start, size_t size, bool is_committed, bool is_large, bool is_zero, int numa_node)
 Manage a particular memory area for use by mimalloc. More...
bool mi_manage_os_memory (void *start, size_t size, bool is_committed, bool is_large, bool is_zero, int numa_node)
 Manage a particular memory area for use by mimalloc.
 
int mi_reserve_huge_os_pages_interleave (size_t pages, size_t numa_nodes, size_t timeout_msecs)
 Reserve pages of huge OS pages (1GiB) evenly divided over numa_nodes nodes, but stops after at most timeout_msecs seconds. More...
int mi_reserve_huge_os_pages_interleave (size_t pages, size_t numa_nodes, size_t timeout_msecs)
 Reserve pages of huge OS pages (1GiB) evenly divided over numa_nodes nodes, but stops after at most timeout_msecs seconds.
 
int mi_reserve_huge_os_pages_at (size_t pages, int numa_node, size_t timeout_msecs)
 Reserve pages of huge OS pages (1GiB) at a specific numa_node, but stops after at most timeout_msecs seconds. More...
int mi_reserve_huge_os_pages_at (size_t pages, int numa_node, size_t timeout_msecs)
 Reserve pages of huge OS pages (1GiB) at a specific numa_node, but stops after at most timeout_msecs seconds.
 
bool mi_is_redirected ()
 Is the C runtime malloc API redirected? More...
bool mi_is_redirected ()
 Is the C runtime malloc API redirected?
 
void mi_process_info (size_t *elapsed_msecs, size_t *user_msecs, size_t *system_msecs, size_t *current_rss, size_t *peak_rss, size_t *current_commit, size_t *peak_commit, size_t *page_faults)
 Return process information (time and memory usage). More...
void mi_process_info (size_t *elapsed_msecs, size_t *user_msecs, size_t *system_msecs, size_t *current_rss, size_t *peak_rss, size_t *current_commit, size_t *peak_commit, size_t *page_faults)
 Return process information (time and memory usage).
 
void mi_debug_show_arenas (bool show_inuse, bool show_abandoned, bool show_purge)
 Show all current arena's.
 
void * mi_arena_area (mi_arena_id_t arena_id, size_t *size)
 Return the size of an arena.
 
int mi_reserve_huge_os_pages_at_ex (size_t pages, int numa_node, size_t timeout_msecs, bool exclusive, mi_arena_id_t *arena_id)
 Reserve huge OS pages (1GiB) into a single arena.
 
int mi_reserve_os_memory_ex (size_t size, bool commit, bool allow_large, bool exclusive, mi_arena_id_t *arena_id)
 Reserve OS memory to be managed in an arena.
 
bool mi_manage_os_memory_ex (void *start, size_t size, bool is_committed, bool is_large, bool is_zero, int numa_node, bool exclusive, mi_arena_id_t *arena_id)
 Manage externally allocated memory as a mimalloc arena.
 
mi_heap_tmi_heap_new_in_arena (mi_arena_id_t arena_id)
 Create a new heap that only allocates in the specified arena.
 
mi_heap_tmi_heap_new_ex (int heap_tag, bool allow_destroy, mi_arena_id_t arena_id)
 Create a new heap.
 
mi_subproc_id_t mi_subproc_main (void)
 Get the main sub-process identifier.
 
mi_subproc_id_t mi_subproc_new (void)
 Create a fresh sub-process (with no associated threads yet).
 
void mi_subproc_delete (mi_subproc_id_t subproc)
 Delete a previously created sub-process.
 
void mi_subproc_add_current_thread (mi_subproc_id_t subproc)
 Add the current thread to the given sub-process.
 

Detailed Description

Extended functionality.

Macro Definition Documentation

- -

◆ MI_SMALL_SIZE_MAX

+ +

◆ MI_SMALL_SIZE_MAX

@@ -208,19 +256,36 @@

-

Maximum size allowed for small allocations in mi_malloc_small and mi_zalloc_small (usually 128*sizeof(void*) (= 1KB on 64-bit systems))

+

Maximum size allowed for small allocations in mi_malloc_small and mi_zalloc_small (usually 128*sizeof(void*) (= 1KB on 64-bit systems))

Typedef Documentation

- -

◆ mi_deferred_free_fun

+ +

◆ mi_arena_id_t

- + + +
typedef void() mi_deferred_free_fun(bool force, unsigned long long heartbeat, void *arg)typedef int mi_arena_id_t
+
+ +

Mimalloc uses large (virtual) memory areas, called "arena"s, from the OS to manage its memory.

+

Each arena has an associated identifier.

+ +
+
+ +

◆ mi_deferred_free_fun

+ + - -

◆ mi_error_fun

+ +

◆ mi_error_fun

- -

◆ mi_output_fun

+ +

◆ mi_output_fun

- +
typedef void() mi_output_fun(const char *msg, void *arg)typedef void mi_output_fun(const char *msg, void *arg)
@@ -282,13 +347,61 @@

See also
mi_register_output()
+
See also
mi_register_output()
+ +

+
+ +

◆ mi_subproc_id_t

+ +
+
+ + + + +
typedef void* mi_subproc_id_t
+
+ +

A process can associate threads with sub-processes.

+

A sub-process will not reclaim memory from (abandoned heaps/threads) other subprocesses.

Function Documentation

- -

◆ mi_collect()

+ +

◆ mi_arena_area()

+ +
+
+ + + + + + + + + + + +
void * mi_arena_area (mi_arena_id_t arena_id,
size_t * size )
+
+ +

Return the size of an arena.

+
Parameters
+ + + +
arena_idThe arena identifier.
sizeReturned size in bytes of the (virtual) arena area.
+
+
+
Returns
base address of the arena.
+ +
+
+ +

◆ mi_collect()

@@ -296,8 +409,7 @@

void mi_collect ( - bool  - force) + bool force) @@ -306,7 +418,7 @@

Parameters
- +
forceIf true, aggressively return memory to the OS (can be expensive!)
forceIf true, aggressively return memory to the OS (can be expensive!)
@@ -314,8 +426,44 @@

-

◆ mi_good_size()

+ +

◆ mi_debug_show_arenas()

+ +
+
+ + + + + + + + + + + + + + + + +
void mi_debug_show_arenas (bool show_inuse,
bool show_abandoned,
bool show_purge )
+
+ +

Show all current arena's.

+
Parameters
+ + + + +
show_inuseShow the arena blocks that are in use.
show_abandonedShow the abandoned arena blocks.
show_purgeShow arena blocks scheduled for purging.
+
+
+ +
+
+ +

◆ mi_good_size()

- -

◆ mi_is_in_heap_region()

+ +

◆ mi_heap_new_ex()

+ +
+
+ + + + + + + + + + + + + + + + +
mi_heap_t * mi_heap_new_ex (int heap_tag,
bool allow_destroy,
mi_arena_id_t arena_id )
+
+ +

Create a new heap.

+
Parameters
+ + + + +
heap_tagThe heap tag associated with this heap; heaps only reclaim memory between heaps with the same tag.
allow_destroyIs mi_heap_destroy allowed? Not allowing this allows the heap to reclaim memory from terminated threads.
arena_idIf not 0, the heap will only allocate from the specified arena.
+
+
+
Returns
A new heap or NULL on failure.
+

The arena_id can be used by runtimes to allocate only in a specified pre-reserved arena. This is used for example for a compressed pointer heap in Koka. The heap_tag enables heaps to keep objects of a certain type isolated to heaps with that tag. This is used for example in the CPython integration.

+ +
+
+ +

◆ mi_heap_new_in_arena()

+ +
+
+ + + + + + + +
mi_heap_t * mi_heap_new_in_arena (mi_arena_id_t arena_id)
+
+ +

Create a new heap that only allocates in the specified arena.

+
Parameters
+ + +
arena_idThe arena identifier.
+
+
+
Returns
The new heap or NULL.
+ +
+
+ +

◆ mi_is_in_heap_region()

- -

◆ mi_is_redirected()

+ +

◆ mi_is_redirected()

- -

◆ mi_malloc_small()

+ +

◆ mi_malloc_small()

- -

◆ mi_manage_os_memory()

+ +

◆ mi_manage_os_memory()

- -

◆ mi_process_info()

+ +

◆ mi_manage_os_memory_ex()

- + - - + + + + + + + + + + + + + + + + - - + - - + - - + - - + + +
void mi_process_info bool mi_manage_os_memory_ex (size_t * elapsed_msecs, void * start,
size_t size,
bool is_committed,
bool is_large,
size_t * user_msecs, bool is_zero,
size_t * system_msecs, int numa_node,
size_t * current_rss, bool exclusive,
size_t * peak_rss, mi_arena_id_t * arena_id )
+
+ +

Manage externally allocated memory as a mimalloc arena.

+

This memory will not be freed by mimalloc.

Parameters
+ + + + + + + + + +
startStart address of the area.
sizeSize in bytes of the area.
is_committedIs the memory already committed?
is_largeDoes it consist of (pinned) large OS pages?
is_zeroIs the memory zero-initialized?
numa_nodeAssociated NUMA node, or -1 to have no NUMA preference.
exclusiveIs the arena exclusive (where only heaps associated with the arena can allocate in it)
arena_idThe new arena identifier.
+
+
+
Returns
true if successful.
+ +
+
+ +

◆ mi_process_info()

+ +
+
+ + + + + - - + - - + - - + + - - + + + + + + + + + + + + + + + +
void mi_process_info (size_t * elapsed_msecs,
size_t * current_commit, size_t * user_msecs,
size_t * peak_commit, size_t * system_msecs,
size_t * page_faults size_t * current_rss,
)size_t * peak_rss,
size_t * current_commit,
size_t * peak_commit,
size_t * page_faults )
- -

◆ mi_register_deferred_free()

+ +

◆ mi_register_deferred_free()

@@ -573,19 +825,12 @@

void mi_register_deferred_free ( - mi_deferred_free_fun *  - deferred_free, + mi_deferred_free_fun * deferred_free, - void *  - arg  - - - - ) - + void * arg )

@@ -593,17 +838,17 @@

Parameters
- +
deferred_freeAddress of a deferred free-ing function or NULL to unregister.
deferred_freeAddress of a deferred free-ing function or NULL to unregister.
argArgument that will be passed on to the deferred free function.
-

Some runtime systems use deferred free-ing, for example when using reference counting to limit the worst case free time. Such systems can register (re-entrant) deferred free function to free more memory on demand. When the force parameter is true all possible memory should be freed. The per-thread heartbeat parameter is monotonically increasing and guaranteed to be deterministic if the program allocates deterministically. The deferred_free function is guaranteed to be called deterministically after some number of allocations (regardless of freeing or available free memory). At most one deferred_free function can be active.

+

Some runtime systems use deferred free-ing, for example when using reference counting to limit the worst case free time. Such systems can register (re-entrant) deferred free function to free more memory on demand. When the force parameter is true all possible memory should be freed. The per-thread heartbeat parameter is monotonically increasing and guaranteed to be deterministic if the program allocates deterministically. The deferred_free function is guaranteed to be called deterministically after some number of allocations (regardless of freeing or available free memory). At most one deferred_free function can be active.

- -

◆ mi_register_error()

+ +

◆ mi_register_error()

@@ -611,19 +856,12 @@

void mi_register_error ( - mi_error_fun *  - errfun, + mi_error_fun * errfun, - void *  - arg  - - - - ) - + void * arg )

@@ -631,23 +869,23 @@

Parameters
- +
errfunThe error function that is called on an error (use NULL for default)
errfunThe error function that is called on an error (use NULL for default)
argExtra argument that will be passed on to the error function.
-

The errfun function is called on an error in mimalloc after emitting an error message (through the output function). It as always legal to just return from the errfun function in which case allocation functions generally return NULL or ignore the condition. The default function only calls abort() when compiled in secure mode with an EFAULT error. The possible error codes are:

- -

◆ mi_register_output()

+ +

◆ mi_register_output()

@@ -655,19 +893,12 @@

void mi_register_output ( - mi_output_fun *  - out, + mi_output_fun * out, - void *  - arg  - - - - ) - + void * arg )

@@ -684,8 +915,8 @@

-

◆ mi_reserve_huge_os_pages_at()

+ +

◆ mi_reserve_huge_os_pages_at()

- -

◆ mi_reserve_huge_os_pages_interleave()

+ +

◆ mi_reserve_huge_os_pages_at_ex()

- + - - + + + + + + + + + + + + + + + + - - + + +
int mi_reserve_huge_os_pages_interleave int mi_reserve_huge_os_pages_at_ex (size_t pages, size_t pages,
int numa_node,
size_t timeout_msecs,
bool exclusive,
size_t numa_nodes, mi_arena_id_t * arena_id )
+
+ +

Reserve huge OS pages (1GiB) into a single arena.

+
Parameters
+ + + + + + +
pagesNumber of 1GiB pages to reserve.
numa_nodeThe associated NUMA node, or -1 for no NUMA preference.
timeout_msecsMax amount of milli-seconds this operation is allowed to take. (0 is infinite)
exclusiveIf exclusive, only a heap associated with this arena can allocate in it.
arena_idThe arena identifier.
+
+
+
Returns
0 if successful, ENOMEM if running out of memory, or ETIMEDOUT if timed out.
+ +
+
+ +

◆ mi_reserve_huge_os_pages_interleave()

+ +
+
+ + + + + - - + + - - +
int mi_reserve_huge_os_pages_interleave (size_t pages,
size_t timeout_msecs size_t numa_nodes,
)size_t timeout_msecs )
+
+ +

◆ mi_reserve_os_memory_ex()

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
int mi_reserve_os_memory_ex (size_t size,
bool commit,
bool allow_large,
bool exclusive,
mi_arena_id_t * arena_id )
+
+ +

Reserve OS memory to be managed in an arena.

+
Parameters
+ + + + + + +
sizeSize the reserve.
commitShould the memory be initially committed?
allow_largeAllow the use of large OS pages?
exclusiveIs the returned arena exclusive?
arena_idThe new arena identifier.
+
+
+
Returns
Zero on success, an error code otherwise.
- -

◆ mi_stats_merge()

+ +

◆ mi_stats_merge()

@@ -830,8 +1135,7 @@

void mi_stats_merge ( - void  - ) + void ) @@ -841,8 +1145,8 @@

-

◆ mi_stats_print()

+ +

◆ mi_stats_print()

@@ -850,8 +1154,7 @@

void mi_stats_print ( - void *  - out) + void * out) @@ -868,8 +1171,8 @@

-

◆ mi_stats_print_out()

+ +

◆ mi_stats_print_out()

@@ -877,19 +1180,12 @@

void mi_stats_print_out ( - mi_output_fun *  - out, + mi_output_fun * out, - void *  - arg  - - - - ) - + void * arg )

@@ -897,8 +1193,8 @@

Parameters
- - + +
outAn output function or NULL for the default.
argOptional argument passed to out (if not NULL)
outAn output function or NULL for the default.
argOptional argument passed to out (if not NULL)
@@ -906,8 +1202,8 @@

-

◆ mi_stats_reset()

+ +

◆ mi_stats_reset()

@@ -915,8 +1211,7 @@

void mi_stats_reset ( - void  - ) + void ) @@ -926,8 +1221,92 @@

-

◆ mi_thread_done()

+ +

◆ mi_subproc_add_current_thread()

+ +
+
+ + + + + + + +
void mi_subproc_add_current_thread (mi_subproc_id_t subproc)
+
+ +

Add the current thread to the given sub-process.

+

This should be called right after a thread is created (and no allocation has taken place yet)

+ +
+
+ +

◆ mi_subproc_delete()

+ +
+
+ + + + + + + +
void mi_subproc_delete (mi_subproc_id_t subproc)
+
+ +

Delete a previously created sub-process.

+
Parameters
+ + +
subprocThe sub-process identifier. Only delete sub-processes if all associated threads have terminated.
+
+
+ +
+
+ +

◆ mi_subproc_main()

+ +
+
+ + + + + + + +
mi_subproc_id_t mi_subproc_main (void )
+
+ +

Get the main sub-process identifier.

+ +
+
+ +

◆ mi_subproc_new()

+ +
+
+ + + + + + + +
mi_subproc_id_t mi_subproc_new (void )
+
+ +

Create a fresh sub-process (with no associated threads yet).

+
Returns
The new sub-process identifier.
+ +
+
+ +

◆ mi_thread_done()

@@ -935,8 +1314,7 @@

void mi_thread_done ( - void  - ) + void ) @@ -947,8 +1325,8 @@

-

◆ mi_thread_init()

+ +

◆ mi_thread_init()

@@ -956,8 +1334,7 @@

void mi_thread_init ( - void  - ) + void ) @@ -968,8 +1345,8 @@

-

◆ mi_thread_stats_print_out()

+ +

◆ mi_thread_stats_print_out()

@@ -977,19 +1354,12 @@

void mi_thread_stats_print_out ( - mi_output_fun *  - out, + mi_output_fun * out, - void *  - arg  - - - - ) - + void * arg )

@@ -997,8 +1367,8 @@

Parameters
- - + +
outAn output function or NULL for the default.
argOptional argument passed to out (if not NULL)
outAn output function or NULL for the default.
argOptional argument passed to out (if not NULL)
@@ -1006,8 +1376,8 @@

-

◆ mi_usable_size()

+ +

◆ mi_usable_size()

- -

◆ mi_zalloc_small()

+ +

◆ mi_zalloc_small()

@@ -1071,7 +1439,7 @@

diff --git a/src/dashbls/depends/mimalloc/docs/group__extended.js b/src/dashbls/depends/mimalloc/docs/group__extended.js index c217aaca76b6..43d6378fb097 100644 --- a/src/dashbls/depends/mimalloc/docs/group__extended.js +++ b/src/dashbls/depends/mimalloc/docs/group__extended.js @@ -1,29 +1,42 @@ var group__extended = [ [ "MI_SMALL_SIZE_MAX", "group__extended.html#ga1ea64283508718d9d645c38efc2f4305", null ], - [ "mi_deferred_free_fun", "group__extended.html#ga299dae78d25ce112e384a98b7309c5be", null ], - [ "mi_error_fun", "group__extended.html#ga251d369cda3f1c2a955c555486ed90e5", null ], - [ "mi_output_fun", "group__extended.html#gad823d23444a4b77a40f66bf075a98a0c", null ], + [ "mi_arena_id_t", "group__extended.html#ga99fe38650d0b02e0e0f89ee024db91d3", null ], + [ "mi_deferred_free_fun", "group__extended.html#ga292a45f7dbc7cd23c5352ce1f0002816", null ], + [ "mi_error_fun", "group__extended.html#ga83fc6a688b322261e1c2deab000b0591", null ], + [ "mi_output_fun", "group__extended.html#gadf31cea7d0332a81c8b882cbbdbadb8d", null ], + [ "mi_subproc_id_t", "group__extended.html#ga8c0bcd1fee27c7641e9c3c0d991b3b7d", null ], + [ "mi_arena_area", "group__extended.html#ga9a25a00a22151619a0be91a10af7787f", null ], [ "mi_collect", "group__extended.html#ga421430e2226d7d468529cec457396756", null ], + [ "mi_debug_show_arenas", "group__extended.html#gad7439207f8f71fb6c382a9ea20b997e7", null ], [ "mi_good_size", "group__extended.html#gac057927cd06c854b45fe7847e921bd47", null ], + [ "mi_heap_new_ex", "group__extended.html#ga3ae360583f4351aa5267ee7e43008faf", null ], + [ "mi_heap_new_in_arena", "group__extended.html#gaaf2d9976576d5efd5544be12848af949", null ], [ "mi_is_in_heap_region", "group__extended.html#ga5f071b10d4df1c3658e04e7fd67a94e6", null ], [ "mi_is_redirected", "group__extended.html#gaad25050b19f30cd79397b227e0157a3f", null ], - [ "mi_malloc_small", "group__extended.html#ga7136c2e55cb22c98ecf95d08d6debb99", null ], + [ "mi_malloc_small", "group__extended.html#ga7f050bc6b897da82692174f5fce59cde", null ], [ "mi_manage_os_memory", "group__extended.html#ga4c6486a1fdcd7a423b5f25fe4be8e0cf", null ], + [ "mi_manage_os_memory_ex", "group__extended.html#ga41ce8525d77bbb60f618fa1029994f6e", null ], [ "mi_process_info", "group__extended.html#ga7d862c2affd5790381da14eb102a364d", null ], [ "mi_register_deferred_free", "group__extended.html#ga3460a6ca91af97be4058f523d3cb8ece", null ], [ "mi_register_error", "group__extended.html#gaa1d55e0e894be240827e5d87ec3a1f45", null ], [ "mi_register_output", "group__extended.html#gae5b17ff027cd2150b43a33040250cf3f", null ], [ "mi_reserve_huge_os_pages_at", "group__extended.html#ga7795a13d20087447281858d2c771cca1", null ], + [ "mi_reserve_huge_os_pages_at_ex", "group__extended.html#ga591aab1c2bc2ca920e33f0f9f9cb5c52", null ], [ "mi_reserve_huge_os_pages_interleave", "group__extended.html#ga3132f521fb756fc0e8ec0b74fb58df50", null ], [ "mi_reserve_os_memory", "group__extended.html#ga00ec3324b6b2591c7fe3677baa30a767", null ], + [ "mi_reserve_os_memory_ex", "group__extended.html#ga32f519797fd9a81acb4f52d36e6d751b", null ], [ "mi_stats_merge", "group__extended.html#ga854b1de8cb067c7316286c28b2fcd3d1", null ], [ "mi_stats_print", "group__extended.html#ga2d126e5c62d3badc35445e5d84166df2", null ], [ "mi_stats_print_out", "group__extended.html#ga537f13b299ddf801e49a5a94fde02c79", null ], [ "mi_stats_reset", "group__extended.html#ga3bb8468b8cfcc6e2a61d98aee85c5f99", null ], + [ "mi_subproc_add_current_thread", "group__extended.html#gadbc53414eb68b275588ec001ce1ddc7c", null ], + [ "mi_subproc_delete", "group__extended.html#gaa7d263e9429bac9ac8345c9d25de610e", null ], + [ "mi_subproc_main", "group__extended.html#ga2ecba0d7ebdc99e71bb985c4a1609806", null ], + [ "mi_subproc_new", "group__extended.html#ga8068cac328e41fa2170faef707315243", null ], [ "mi_thread_done", "group__extended.html#ga0ae4581e85453456a0d658b2b98bf7bf", null ], [ "mi_thread_init", "group__extended.html#gaf8e73efc2cbca9ebfdfb166983a04c17", null ], [ "mi_thread_stats_print_out", "group__extended.html#gab1dac8476c46cb9eecab767eb40c1525", null ], [ "mi_usable_size", "group__extended.html#ga089c859d9eddc5f9b4bd946cd53cebee", null ], - [ "mi_zalloc_small", "group__extended.html#ga220f29f40a44404b0061c15bc1c31152", null ] + [ "mi_zalloc_small", "group__extended.html#ga51c47637e81df0e2f13a2d7a2dec123e", null ] ]; \ No newline at end of file diff --git a/src/dashbls/depends/mimalloc/docs/group__heap.html b/src/dashbls/depends/mimalloc/docs/group__heap.html index 0f21ea42c122..c01a9e54c1e2 100644 --- a/src/dashbls/depends/mimalloc/docs/group__heap.html +++ b/src/dashbls/depends/mimalloc/docs/group__heap.html @@ -1,24 +1,26 @@ - + - - + + mi-malloc: Heap Allocation + - + + @@ -29,20 +31,16 @@
- + - -
-
mi-malloc -  1.7/2.0 +
+
mi-malloc 1.8/2.1
+
- -   + @@ -56,10 +54,15 @@
- + +
@@ -74,8 +77,8 @@

@@ -88,110 +91,116 @@
- +
+
+
+
+
Loading...
+
Searching...
+
No Matches
+
+
+
-
-
Heap Allocation
+
Heap Allocation

First-class heaps that can be destroyed in one go. More...

- - - + +

+

Typedefs

typedef struct mi_heap_s mi_heap_t
 Type of first-class heaps. More...
typedef struct mi_heap_s mi_heap_t
 Type of first-class heaps.
 
- - - - - - + + + + + - - + + - - - - - - - - - - - + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+

Functions

mi_heap_tmi_heap_new ()
 Create a new heap that can be used for allocation. More...
 
void mi_heap_delete (mi_heap_t *heap)
 Delete a previously allocated heap. More...
mi_heap_tmi_heap_new ()
 Create a new heap that can be used for allocation.
 
void mi_heap_delete (mi_heap_t *heap)
 Delete a previously allocated heap.
 
void mi_heap_destroy (mi_heap_t *heap)
 Destroy a heap, freeing all its still allocated blocks. More...
void mi_heap_destroy (mi_heap_t *heap)
 Destroy a heap, freeing all its still allocated blocks.
 
mi_heap_tmi_heap_set_default (mi_heap_t *heap)
 Set the default heap to use for mi_malloc() et al. More...
 
mi_heap_tmi_heap_get_default ()
 Get the default heap that is used for mi_malloc() et al. More...
 
mi_heap_tmi_heap_get_backing ()
 Get the backing heap. More...
 
void mi_heap_collect (mi_heap_t *heap, bool force)
 Release outstanding resources in a specific heap. More...
mi_heap_tmi_heap_set_default (mi_heap_t *heap)
 Set the default heap to use in the current thread for mi_malloc() et al.
 
mi_heap_tmi_heap_get_default ()
 Get the default heap that is used for mi_malloc() et al.
 
mi_heap_tmi_heap_get_backing ()
 Get the backing heap.
 
void mi_heap_collect (mi_heap_t *heap, bool force)
 Release outstanding resources in a specific heap.
 
void * mi_heap_malloc (mi_heap_t *heap, size_t size)
 Allocate in a specific heap. More...
 
void * mi_heap_malloc_small (mi_heap_t *heap, size_t size)
 Allocate a small object in a specific heap. More...
 
void * mi_heap_zalloc (mi_heap_t *heap, size_t size)
 Allocate zero-initialized in a specific heap. More...
 
void * mi_heap_calloc (mi_heap_t *heap, size_t count, size_t size)
 Allocate count zero-initialized elements in a specific heap. More...
 
void * mi_heap_mallocn (mi_heap_t *heap, size_t count, size_t size)
 Allocate count elements in a specific heap. More...
 
char * mi_heap_strdup (mi_heap_t *heap, const char *s)
 Duplicate a string in a specific heap. More...
 
char * mi_heap_strndup (mi_heap_t *heap, const char *s, size_t n)
 Duplicate a string of at most length n in a specific heap. More...
 
char * mi_heap_realpath (mi_heap_t *heap, const char *fname, char *resolved_name)
 Resolve a file path name using a specific heap to allocate the result. More...
 
void * mi_heap_realloc (mi_heap_t *heap, void *p, size_t newsize)
 
void * mi_heap_reallocn (mi_heap_t *heap, void *p, size_t count, size_t size)
 
void * mi_heap_reallocf (mi_heap_t *heap, void *p, size_t newsize)
 
void * mi_heap_malloc_aligned (mi_heap_t *heap, size_t size, size_t alignment)
 
void * mi_heap_malloc_aligned_at (mi_heap_t *heap, size_t size, size_t alignment, size_t offset)
 
void * mi_heap_zalloc_aligned (mi_heap_t *heap, size_t size, size_t alignment)
 
void * mi_heap_zalloc_aligned_at (mi_heap_t *heap, size_t size, size_t alignment, size_t offset)
 
void * mi_heap_calloc_aligned (mi_heap_t *heap, size_t count, size_t size, size_t alignment)
 
void * mi_heap_calloc_aligned_at (mi_heap_t *heap, size_t count, size_t size, size_t alignment, size_t offset)
 
void * mi_heap_realloc_aligned (mi_heap_t *heap, void *p, size_t newsize, size_t alignment)
 
void * mi_heap_realloc_aligned_at (mi_heap_t *heap, void *p, size_t newsize, size_t alignment, size_t offset)
 
void * mi_heap_malloc (mi_heap_t *heap, size_t size)
 Allocate in a specific heap.
 
void * mi_heap_malloc_small (mi_heap_t *heap, size_t size)
 Allocate a small object in a specific heap.
 
void * mi_heap_zalloc (mi_heap_t *heap, size_t size)
 Allocate zero-initialized in a specific heap.
 
void * mi_heap_calloc (mi_heap_t *heap, size_t count, size_t size)
 Allocate count zero-initialized elements in a specific heap.
 
void * mi_heap_mallocn (mi_heap_t *heap, size_t count, size_t size)
 Allocate count elements in a specific heap.
 
char * mi_heap_strdup (mi_heap_t *heap, const char *s)
 Duplicate a string in a specific heap.
 
char * mi_heap_strndup (mi_heap_t *heap, const char *s, size_t n)
 Duplicate a string of at most length n in a specific heap.
 
char * mi_heap_realpath (mi_heap_t *heap, const char *fname, char *resolved_name)
 Resolve a file path name using a specific heap to allocate the result.
 
void * mi_heap_realloc (mi_heap_t *heap, void *p, size_t newsize)
 
void * mi_heap_reallocn (mi_heap_t *heap, void *p, size_t count, size_t size)
 
void * mi_heap_reallocf (mi_heap_t *heap, void *p, size_t newsize)
 
void * mi_heap_malloc_aligned (mi_heap_t *heap, size_t size, size_t alignment)
 
void * mi_heap_malloc_aligned_at (mi_heap_t *heap, size_t size, size_t alignment, size_t offset)
 
void * mi_heap_zalloc_aligned (mi_heap_t *heap, size_t size, size_t alignment)
 
void * mi_heap_zalloc_aligned_at (mi_heap_t *heap, size_t size, size_t alignment, size_t offset)
 
void * mi_heap_calloc_aligned (mi_heap_t *heap, size_t count, size_t size, size_t alignment)
 
void * mi_heap_calloc_aligned_at (mi_heap_t *heap, size_t count, size_t size, size_t alignment, size_t offset)
 
void * mi_heap_realloc_aligned (mi_heap_t *heap, void *p, size_t newsize, size_t alignment)
 
void * mi_heap_realloc_aligned_at (mi_heap_t *heap, void *p, size_t newsize, size_t alignment, size_t offset)
 

Detailed Description

First-class heaps that can be destroyed in one go.

Typedef Documentation

- -

◆ mi_heap_t

+ +

◆ mi_heap_t

- +
typedef struct mi_heap_s mi_heap_ttypedef struct mi_heap_s mi_heap_t
@@ -202,131 +211,104 @@

Function Documentation

- -

◆ mi_heap_calloc()

+ +

◆ mi_heap_calloc()

- + - - + - - + - - - - - - - +
void* mi_heap_calloc void * mi_heap_calloc (mi_heap_theap, mi_heap_t * heap,
size_t count, size_t count,
size_t size 
)size_t size )
-

Allocate count zero-initialized elements in a specific heap.

-
See also
mi_calloc()
+

Allocate count zero-initialized elements in a specific heap.

+
See also
mi_calloc()
- -

◆ mi_heap_calloc_aligned()

+ +

◆ mi_heap_calloc_aligned()

- + - - + - - + - - + - - - - - - - +
void* mi_heap_calloc_aligned void * mi_heap_calloc_aligned (mi_heap_theap, mi_heap_t * heap,
size_t count, size_t count,
size_t size, size_t size,
size_t alignment 
)size_t alignment )
- -

◆ mi_heap_calloc_aligned_at()

+ +

◆ mi_heap_calloc_aligned_at()

- + - - + - - + - - + - - + - - - - - - - +
void* mi_heap_calloc_aligned_at void * mi_heap_calloc_aligned_at (mi_heap_theap, mi_heap_t * heap,
size_t count, size_t count,
size_t size, size_t size,
size_t alignment, size_t alignment,
size_t offset 
)size_t offset )
- -

◆ mi_heap_collect()

+ +

◆ mi_heap_collect()

@@ -334,19 +316,12 @@

void mi_heap_collect ( - mi_heap_t *  - heap, + mi_heap_t * heap, - bool  - force  - - - - ) - + bool force )

@@ -355,8 +330,8 @@

-

◆ mi_heap_delete()

+ +

◆ mi_heap_delete()

@@ -364,21 +339,20 @@

void mi_heap_delete ( - mi_heap_t *  - heap) + mi_heap_t * heap)

Delete a previously allocated heap.

-

This will release resources and migrate any still allocated blocks in this heap (efficienty) to the default heap.

-

If heap is the default heap, the default heap is set to the backing heap.

+

This will release resources and migrate any still allocated blocks in this heap (efficiently) to the default heap.

+

If heap is the default heap, the default heap is set to the backing heap.

- -

◆ mi_heap_destroy()

+ +

◆ mi_heap_destroy()

- -

◆ mi_heap_get_backing()

+ +

◆ mi_heap_get_backing()

- + - +
mi_heap_t* mi_heap_get_backing mi_heap_t * mi_heap_get_backing ())
@@ -419,209 +392,170 @@

-

◆ mi_heap_get_default()

+ +

◆ mi_heap_get_default()

- + - +
mi_heap_t* mi_heap_get_default mi_heap_t * mi_heap_get_default ())
-

Get the default heap that is used for mi_malloc() et al.

-
Returns
The current default heap.
+

Get the default heap that is used for mi_malloc() et al.

+

(for the current thread).

Returns
The current default heap.
- -

◆ mi_heap_malloc()

+ +

◆ mi_heap_malloc()

- + - - + - - - - - - - +
void* mi_heap_malloc void * mi_heap_malloc (mi_heap_theap, mi_heap_t * heap,
size_t size 
)size_t size )

Allocate in a specific heap.

-
See also
mi_malloc()
+
See also
mi_malloc()
- -

◆ mi_heap_malloc_aligned()

+ +

◆ mi_heap_malloc_aligned()

- + - - + - - + - - - - - - - +
void* mi_heap_malloc_aligned void * mi_heap_malloc_aligned (mi_heap_theap, mi_heap_t * heap,
size_t size, size_t size,
size_t alignment 
)size_t alignment )
- -

◆ mi_heap_malloc_aligned_at()

+ +

◆ mi_heap_malloc_aligned_at()

- + - - + - - + - - + - - - - - - - +
void* mi_heap_malloc_aligned_at void * mi_heap_malloc_aligned_at (mi_heap_theap, mi_heap_t * heap,
size_t size, size_t size,
size_t alignment, size_t alignment,
size_t offset 
)size_t offset )
- -

◆ mi_heap_malloc_small()

+ +

◆ mi_heap_malloc_small()

- + - - + - - - - - - - +
void* mi_heap_malloc_small void * mi_heap_malloc_small (mi_heap_theap, mi_heap_t * heap,
size_t size 
)size_t size )

Allocate a small object in a specific heap.

-

size must be smaller or equal to MI_SMALL_SIZE_MAX().

See also
mi_malloc()
+

size must be smaller or equal to MI_SMALL_SIZE_MAX().

See also
mi_malloc()
- -

◆ mi_heap_mallocn()

+ +

◆ mi_heap_mallocn()

- + - - + - - + - - - - - - - +
void* mi_heap_mallocn void * mi_heap_mallocn (mi_heap_theap, mi_heap_t * heap,
size_t count, size_t count,
size_t size 
)size_t size )
-

Allocate count elements in a specific heap.

-
See also
mi_mallocn()
+

Allocate count elements in a specific heap.

+
See also
mi_mallocn()
- -

◆ mi_heap_new()

+ +

◆ mi_heap_new()

- + - +
mi_heap_t* mi_heap_new mi_heap_t * mi_heap_new ())
@@ -631,254 +565,201 @@

-

◆ mi_heap_realloc()

+ +

◆ mi_heap_realloc()

- + - - + - - + - - - - - - - +
void* mi_heap_realloc void * mi_heap_realloc (mi_heap_theap, mi_heap_t * heap,
void * p, void * p,
size_t newsize 
)size_t newsize )
- -

◆ mi_heap_realloc_aligned()

+ +

◆ mi_heap_realloc_aligned()

- + - - + - - + - - + - - - - - - - +
void* mi_heap_realloc_aligned void * mi_heap_realloc_aligned (mi_heap_theap, mi_heap_t * heap,
void * p, void * p,
size_t newsize, size_t newsize,
size_t alignment 
)size_t alignment )
- -

◆ mi_heap_realloc_aligned_at()

+ +

◆ mi_heap_realloc_aligned_at()

- + - - + - - + - - + - - + - - - - - - - +
void* mi_heap_realloc_aligned_at void * mi_heap_realloc_aligned_at (mi_heap_theap, mi_heap_t * heap,
void * p, void * p,
size_t newsize, size_t newsize,
size_t alignment, size_t alignment,
size_t offset 
)size_t offset )
- -

◆ mi_heap_reallocf()

+ +

◆ mi_heap_reallocf()

- + - - + - - + - - - - - - - +
void* mi_heap_reallocf void * mi_heap_reallocf (mi_heap_theap, mi_heap_t * heap,
void * p, void * p,
size_t newsize 
)size_t newsize )
- -

◆ mi_heap_reallocn()

+ +

◆ mi_heap_reallocn()

- + - - + - - + - - + - - - - - - - +
void* mi_heap_reallocn void * mi_heap_reallocn (mi_heap_theap, mi_heap_t * heap,
void * p, void * p,
size_t count, size_t count,
size_t size 
)size_t size )
- -

◆ mi_heap_realpath()

+ +

◆ mi_heap_realpath()

- + - - + - - + - - - - - - - +
char* mi_heap_realpath char * mi_heap_realpath (mi_heap_theap, mi_heap_t * heap,
const char * fname, const char * fname,
char * resolved_name 
)char * resolved_name )
-

Resolve a file path name using a specific heap to allocate the result.

-
See also
mi_realpath()
+

Resolve a file path name using a specific heap to allocate the result.

+
See also
mi_realpath()
- -

◆ mi_heap_set_default()

+ +

◆ mi_heap_set_default()

- + - - +
mi_heap_t* mi_heap_set_default mi_heap_t * mi_heap_set_default (mi_heap_theap)mi_heap_t * heap)
-

Set the default heap to use for mi_malloc() et al.

+

Set the default heap to use in the current thread for mi_malloc() et al.

Parameters
@@ -889,173 +770,134 @@

-

◆ mi_heap_strdup()

+ +

◆ mi_heap_strdup()

heapThe new default heap.
- + - - + - - - - - - - +
char* mi_heap_strdup char * mi_heap_strdup (mi_heap_theap, mi_heap_t * heap,
const char * s 
)const char * s )

Duplicate a string in a specific heap.

-
See also
mi_strdup()
+
See also
mi_strdup()
- -

◆ mi_heap_strndup()

+ +

◆ mi_heap_strndup()

- + - - + - - + - - - - - - - +
char* mi_heap_strndup char * mi_heap_strndup (mi_heap_theap, mi_heap_t * heap,
const char * s, const char * s,
size_t n 
)size_t n )
-

Duplicate a string of at most length n in a specific heap.

-
See also
mi_strndup()
+

Duplicate a string of at most length n in a specific heap.

+
See also
mi_strndup()
- -

◆ mi_heap_zalloc()

+ +

◆ mi_heap_zalloc()

- + - - + - - - - - - - +
void* mi_heap_zalloc void * mi_heap_zalloc (mi_heap_theap, mi_heap_t * heap,
size_t size 
)size_t size )

Allocate zero-initialized in a specific heap.

-
See also
mi_zalloc()
+
See also
mi_zalloc()
- -

◆ mi_heap_zalloc_aligned()

+ +

◆ mi_heap_zalloc_aligned()

- + - - + - - + - - - - - - - +
void* mi_heap_zalloc_aligned void * mi_heap_zalloc_aligned (mi_heap_theap, mi_heap_t * heap,
size_t size, size_t size,
size_t alignment 
)size_t alignment )
- -

◆ mi_heap_zalloc_aligned_at()

+ +

◆ mi_heap_zalloc_aligned_at()

- + - - + - - + - - + - - - - - - - +
void* mi_heap_zalloc_aligned_at void * mi_heap_zalloc_aligned_at (mi_heap_theap, mi_heap_t * heap,
size_t size, size_t size,
size_t alignment, size_t alignment,
size_t offset 
)size_t offset )
@@ -1067,7 +909,7 @@

diff --git a/src/dashbls/depends/mimalloc/docs/group__heap.js b/src/dashbls/depends/mimalloc/docs/group__heap.js index 13d13778865b..8b6118d56b34 100644 --- a/src/dashbls/depends/mimalloc/docs/group__heap.js +++ b/src/dashbls/depends/mimalloc/docs/group__heap.js @@ -1,30 +1,30 @@ var group__heap = [ [ "mi_heap_t", "group__heap.html#ga34a47cde5a5b38c29f1aa3c5e76943c2", null ], - [ "mi_heap_calloc", "group__heap.html#gaa6702b3c48e9e53e50e81b36f5011d55", null ], - [ "mi_heap_calloc_aligned", "group__heap.html#ga4af03a6e2b93fae77424d93f889705c3", null ], - [ "mi_heap_calloc_aligned_at", "group__heap.html#ga08ca6419a5c057a4d965868998eef487", null ], + [ "mi_heap_calloc", "group__heap.html#gac0098aaf231d3e9586c73136d5df95da", null ], + [ "mi_heap_calloc_aligned", "group__heap.html#gacafcc26df827c7a7de5e850217566108", null ], + [ "mi_heap_calloc_aligned_at", "group__heap.html#gaa42ec2079989c4374f2c331d9b35f4e4", null ], [ "mi_heap_collect", "group__heap.html#ga7922f7495cde30b1984d0e6072419298", null ], [ "mi_heap_delete", "group__heap.html#ga2ab1af8d438819b55319c7ef51d1e409", null ], [ "mi_heap_destroy", "group__heap.html#ga9f9c0844edb9717f4feacd79116b8e0d", null ], - [ "mi_heap_get_backing", "group__heap.html#ga5d03fbe062ffcf38f0f417fd968357fc", null ], - [ "mi_heap_get_default", "group__heap.html#ga8db4cbb87314a989a9a187464d6b5e05", null ], - [ "mi_heap_malloc", "group__heap.html#ga9cbed01e42c0647907295de92c3fa296", null ], - [ "mi_heap_malloc_aligned", "group__heap.html#gab5b87e1805306f70df38789fcfcf6653", null ], - [ "mi_heap_malloc_aligned_at", "group__heap.html#ga23acd7680fb0976dde3783254c6c874b", null ], - [ "mi_heap_malloc_small", "group__heap.html#gaa1a1c7a1f4da6826b5a25b70ef878368", null ], - [ "mi_heap_mallocn", "group__heap.html#ga851da6c43fe0b71c1376cee8aef90db0", null ], - [ "mi_heap_new", "group__heap.html#ga766f672ba56f2fbfeb9d9dbb0b7f6b11", null ], - [ "mi_heap_realloc", "group__heap.html#gaaef3395f66be48f37bdc8322509c5d81", null ], - [ "mi_heap_realloc_aligned", "group__heap.html#gafc603b696bd14cae6da28658f950d98c", null ], - [ "mi_heap_realloc_aligned_at", "group__heap.html#gaf96c788a1bf553fe2d371de9365e047c", null ], - [ "mi_heap_reallocf", "group__heap.html#ga4a21070eb4e7cce018133c8d5f4b0527", null ], - [ "mi_heap_reallocn", "group__heap.html#gac74e94ad9b0c9b57c1c4d88b8825b7a8", null ], - [ "mi_heap_realpath", "group__heap.html#ga00e95ba1e01acac3cfd95bb7a357a6f0", null ], - [ "mi_heap_set_default", "group__heap.html#gab8631ec88c8d26641b68b5d25dcd4422", null ], - [ "mi_heap_strdup", "group__heap.html#ga139d6b09dbf50c3c2523d0f4d1cfdeb5", null ], - [ "mi_heap_strndup", "group__heap.html#ga8e3dbd46650dd26573cf307a2c8f1f5a", null ], - [ "mi_heap_zalloc", "group__heap.html#ga903104592c8ed53417a3762da6241133", null ], - [ "mi_heap_zalloc_aligned", "group__heap.html#gaa450a59c6c7ae5fdbd1c2b80a8329ef0", null ], - [ "mi_heap_zalloc_aligned_at", "group__heap.html#ga45fb43a62776fbebbdf1edd99b527954", null ] + [ "mi_heap_get_backing", "group__heap.html#gac6ac9f0e7be9ab4ff70acfc8dad1235a", null ], + [ "mi_heap_get_default", "group__heap.html#ga14c667a6e2c5d28762d8cb7d4e057909", null ], + [ "mi_heap_malloc", "group__heap.html#gab374e206c7034e0d899fb934e4f4a863", null ], + [ "mi_heap_malloc_aligned", "group__heap.html#ga33f4f05b7fea7af2113c62a4bf882cc5", null ], + [ "mi_heap_malloc_aligned_at", "group__heap.html#gae7ffc045c3996497a7f3a5f6fe7b8aaa", null ], + [ "mi_heap_malloc_small", "group__heap.html#ga012c5c8abe22b10043de39ff95909541", null ], + [ "mi_heap_mallocn", "group__heap.html#gab0f755c0b21c387fe8e9024200faa372", null ], + [ "mi_heap_new", "group__heap.html#gaa718bb226ec0546ba6d1b6cb32179f3a", null ], + [ "mi_heap_realloc", "group__heap.html#gac5252d6a2e510bd349e4fcb452e6a93a", null ], + [ "mi_heap_realloc_aligned", "group__heap.html#gaccf8c249872f30bf1c2493a09197d734", null ], + [ "mi_heap_realloc_aligned_at", "group__heap.html#ga6df988a7219d5707f010d5f3eb0dc3f5", null ], + [ "mi_heap_reallocf", "group__heap.html#gae7cd171425bee04c683c65a3701f0b4a", null ], + [ "mi_heap_reallocn", "group__heap.html#gaccf7bfe10ce510a000d3547d9cf7fa29", null ], + [ "mi_heap_realpath", "group__heap.html#ga55545a3ec6da29c5b4f62e540ecac1e2", null ], + [ "mi_heap_set_default", "group__heap.html#ga349b677dec7da5eacdbc7a385bd62a4a", null ], + [ "mi_heap_strdup", "group__heap.html#ga5754e09ccc51dd6bc73885bb6ea21b7a", null ], + [ "mi_heap_strndup", "group__heap.html#gad224df78f1fbee942df8adf023e12cf3", null ], + [ "mi_heap_zalloc", "group__heap.html#gabebc796399619d964d8db77aa835e8c1", null ], + [ "mi_heap_zalloc_aligned", "group__heap.html#ga6466bde8b5712aa34e081a8317f9f471", null ], + [ "mi_heap_zalloc_aligned_at", "group__heap.html#ga484e3d01cd174f78c7e53370e5a7c819", null ] ]; \ No newline at end of file diff --git a/src/dashbls/depends/mimalloc/docs/group__malloc.html b/src/dashbls/depends/mimalloc/docs/group__malloc.html index 2dc16656728f..3694d2b2a824 100644 --- a/src/dashbls/depends/mimalloc/docs/group__malloc.html +++ b/src/dashbls/depends/mimalloc/docs/group__malloc.html @@ -1,24 +1,26 @@ - + - - + + mi-malloc: Basic Allocation + - + + @@ -29,20 +31,16 @@
- + - -
-
mi-malloc -  1.7/2.0 +
+
mi-malloc 1.8/2.1
+
- -   + @@ -56,10 +54,15 @@
- + +
@@ -74,8 +77,8 @@

@@ -88,94 +91,93 @@
- +
+
+
+
+
Loading...
+
Searching...
+
No Matches
+
+
+
-
-
Basic Allocation
+
Basic Allocation

The basic allocation interface. More...

- - - + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + +

+

Functions

void mi_free (void *p)
 Free previously allocated memory. More...
void mi_free (void *p)
 Free previously allocated memory.
 
void * mi_malloc (size_t size)
 Allocate size bytes. More...
 
void * mi_zalloc (size_t size)
 Allocate zero-initialized size bytes. More...
 
void * mi_calloc (size_t count, size_t size)
 Allocate zero-initialized count elements of size bytes. More...
 
void * mi_realloc (void *p, size_t newsize)
 Re-allocate memory to newsize bytes. More...
 
void * mi_recalloc (void *p, size_t count, size_t size)
 Re-allocate memory to count elements of size bytes, with extra memory initialized to zero. More...
void * mi_malloc (size_t size)
 Allocate size bytes.
 
void * mi_zalloc (size_t size)
 Allocate zero-initialized size bytes.
 
void * mi_calloc (size_t count, size_t size)
 Allocate zero-initialized count elements of size bytes.
 
void * mi_realloc (void *p, size_t newsize)
 Re-allocate memory to newsize bytes.
 
void * mi_recalloc (void *p, size_t count, size_t size)
 Re-allocate memory to count elements of size bytes, with extra memory initialized to zero.
 
void * mi_expand (void *p, size_t newsize)
 Try to re-allocate memory to newsize bytes in place. More...
 
void * mi_mallocn (size_t count, size_t size)
 Allocate count elements of size bytes. More...
 
void * mi_reallocn (void *p, size_t count, size_t size)
 Re-allocate memory to count elements of size bytes. More...
 
void * mi_reallocf (void *p, size_t newsize)
 Re-allocate memory to newsize bytes,. More...
 
char * mi_strdup (const char *s)
 Allocate and duplicate a string. More...
 
char * mi_strndup (const char *s, size_t n)
 Allocate and duplicate a string up to n bytes. More...
 
char * mi_realpath (const char *fname, char *resolved_name)
 Resolve a file path name. More...
 
void * mi_expand (void *p, size_t newsize)
 Try to re-allocate memory to newsize bytes in place.
 
void * mi_mallocn (size_t count, size_t size)
 Allocate count elements of size bytes.
 
void * mi_reallocn (void *p, size_t count, size_t size)
 Re-allocate memory to count elements of size bytes.
 
void * mi_reallocf (void *p, size_t newsize)
 Re-allocate memory to newsize bytes,.
 
char * mi_strdup (const char *s)
 Allocate and duplicate a string.
 
char * mi_strndup (const char *s, size_t n)
 Allocate and duplicate a string up to n bytes.
 
char * mi_realpath (const char *fname, char *resolved_name)
 Resolve a file path name.
 

Detailed Description

The basic allocation interface.

Function Documentation

- -

◆ mi_calloc()

+ +

◆ mi_calloc()

- + - - + - - - - - - - +
void* mi_calloc void * mi_calloc (size_t count, size_t count,
size_t size 
)size_t size )
-

Allocate zero-initialized count elements of size bytes.

+

Allocate zero-initialized count elements of size bytes.

Parameters
@@ -183,51 +185,44 @@

Returns
pointer to the allocated memory of size*count bytes, or NULL if either out of memory or when count*size overflows.
-

Returns a unique pointer if called with either size or count of 0.

See also
mi_zalloc()
+
Returns
pointer to the allocated memory of size*count bytes, or NULL if either out of memory or when count*size overflows.
+

Returns a unique pointer if called with either size or count of 0.

See also
mi_zalloc()
- -

◆ mi_expand()

+ +

◆ mi_expand()

countnumber of elements.
- + - - + - - - - - - - +
void* mi_expand void * mi_expand (void * p, void * p,
size_t newsize 
)size_t newsize )
-

Try to re-allocate memory to newsize bytes in place.

+

Try to re-allocate memory to newsize bytes in place.

Parameters
- +
ppointer to previously allocated memory (or NULL).
ppointer to previously allocated memory (or NULL).
newsizethe new required size in bytes.
-
Returns
pointer to the re-allocated memory of newsize bytes (always equal to p), or NULL if either out of memory or if the memory could not be expanded in place. If NULL is returned, the pointer p is not freed. Otherwise the original pointer is returned as the reallocated result since it fits in-place with the new size. If newsize is larger than the original size allocated for p, the bytes after size are uninitialized.
+
Returns
pointer to the re-allocated memory of newsize bytes (always equal to p), or NULL if either out of memory or if the memory could not be expanded in place. If NULL is returned, the pointer p is not freed. Otherwise the original pointer is returned as the reallocated result since it fits in-place with the new size. If newsize is larger than the original size allocated for p, the bytes after size are uninitialized.
- -

◆ mi_free()

+ +

◆ mi_free()

- -

◆ mi_malloc()

+ +

◆ mi_malloc()

- + - - +
void* mi_malloc void * mi_malloc (size_t size)size_t size)
-

Allocate size bytes.

+

Allocate size bytes.

Parameters
sizenumber of bytes to allocate.
-
Returns
pointer to the allocated memory or NULL if out of memory. Returns a unique pointer if called with size 0.
+
Returns
pointer to the allocated memory or NULL if out of memory. Returns a unique pointer if called with size 0.
- -

◆ mi_mallocn()

+ +

◆ mi_mallocn()

- + - - + - - - - - - - +
void* mi_mallocn void * mi_mallocn (size_t count, size_t count,
size_t size 
)size_t size )
-

Allocate count elements of size bytes.

+

Allocate count elements of size bytes.

Parameters
@@ -313,159 +299,130 @@

Returns
A pointer to a block of count * size bytes, or NULL if out of memory or if count * size overflows.
-

If there is no overflow, it behaves exactly like mi_malloc(p,count*size).

See also
mi_calloc()
+
Returns
A pointer to a block of count * size bytes, or NULL if out of memory or if count * size overflows.
+

If there is no overflow, it behaves exactly like mi_malloc(count*size).

See also
mi_calloc()
mi_zallocn()
- -

◆ mi_realloc()

+ +

◆ mi_realloc()

countThe number of elements.
- + - - + - - - - - - - +
void* mi_realloc void * mi_realloc (void * p, void * p,
size_t newsize 
)size_t newsize )
-

Re-allocate memory to newsize bytes.

+

Re-allocate memory to newsize bytes.

Parameters
- +
ppointer to previously allocated memory (or NULL).
ppointer to previously allocated memory (or NULL).
newsizethe new required size in bytes.
-
Returns
pointer to the re-allocated memory of newsize bytes, or NULL if out of memory. If NULL is returned, the pointer p is not freed. Otherwise the original pointer is either freed or returned as the reallocated result (in case it fits in-place with the new size). If the pointer p is NULL, it behaves as mi_malloc(newsize). If newsize is larger than the original size allocated for p, the bytes after size are uninitialized.
+
Returns
pointer to the re-allocated memory of newsize bytes, or NULL if out of memory. If NULL is returned, the pointer p is not freed. Otherwise the original pointer is either freed or returned as the reallocated result (in case it fits in-place with the new size). If the pointer p is NULL, it behaves as mi_malloc(newsize). If newsize is larger than the original size allocated for p, the bytes after size are uninitialized.
- -

◆ mi_reallocf()

+ +

◆ mi_reallocf()

- + - - + - - - - - - - +
void* mi_reallocf void * mi_reallocf (void * p, void * p,
size_t newsize 
)size_t newsize )
-

Re-allocate memory to newsize bytes,.

+

Re-allocate memory to newsize bytes,.

Parameters
- +
ppointer to previously allocated memory (or NULL).
ppointer to previously allocated memory (or NULL).
newsizethe new required size in bytes.
-
Returns
pointer to the re-allocated memory of newsize bytes, or NULL if out of memory.
-

In contrast to mi_realloc(), if NULL is returned, the original pointer p is freed (if it was not NULL itself). Otherwise the original pointer is either freed or returned as the reallocated result (in case it fits in-place with the new size). If the pointer p is NULL, it behaves as mi_malloc(newsize). If newsize is larger than the original size allocated for p, the bytes after size are uninitialized.

+
Returns
pointer to the re-allocated memory of newsize bytes, or NULL if out of memory.
+

In contrast to mi_realloc(), if NULL is returned, the original pointer p is freed (if it was not NULL itself). Otherwise the original pointer is either freed or returned as the reallocated result (in case it fits in-place with the new size). If the pointer p is NULL, it behaves as mi_malloc(newsize). If newsize is larger than the original size allocated for p, the bytes after size are uninitialized.

See also
reallocf (on BSD)
- -

◆ mi_reallocn()

+ +

◆ mi_reallocn()

- + - - + - - + - - - - - - - +
void* mi_reallocn void * mi_reallocn (void * p, void * p,
size_t count, size_t count,
size_t size 
)size_t size )
-

Re-allocate memory to count elements of size bytes.

+

Re-allocate memory to count elements of size bytes.

Parameters
- +
pPointer to a previously allocated block (or NULL).
pPointer to a previously allocated block (or NULL).
countThe number of elements.
sizeThe size of each element.
-
Returns
A pointer to a re-allocated block of count * size bytes, or NULL if out of memory or if count * size overflows.
+
Returns
A pointer to a re-allocated block of count * size bytes, or NULL if out of memory or if count * size overflows.

If there is no overflow, it behaves exactly like mi_realloc(p,count*size).

See also
reallocarray() (on BSD)
- -

◆ mi_realpath()

+ +

◆ mi_realpath()

- + - - + - - - - - - - +
char* mi_realpath char * mi_realpath (const char * fname, const char * fname,
char * resolved_name 
)char * resolved_name )
@@ -474,18 +431,18 @@

Parameters
- +
fnameFile name.
resolved_nameShould be NULL (but can also point to a buffer of at least PATH_MAX bytes).
resolved_nameShould be NULL (but can also point to a buffer of at least PATH_MAX bytes).
-
Returns
If successful a pointer to the resolved absolute file name, or NULL on failure (with errno set to the error code).
-

If resolved_name was NULL, the returned result should be freed with mi_free().

-

Replacement for the standard realpath() such that mi_free() can be used on the returned result (if resolved_name was NULL).

+
Returns
If successful a pointer to the resolved absolute file name, or NULL on failure (with errno set to the error code).
+

If resolved_name was NULL, the returned result should be freed with mi_free().

+

Replacement for the standard realpath() such that mi_free() can be used on the returned result (if resolved_name was NULL).

- -

◆ mi_recalloc()

+ +

◆ mi_recalloc()

- -

◆ mi_strdup()

+ +

◆ mi_strdup()

- + - - +
char* mi_strdup char * mi_strdup (const char * s)const char * s)
@@ -551,65 +499,57 @@

Parameters
- +
sstring to duplicate (or NULL).
sstring to duplicate (or NULL).
-
Returns
a pointer to newly allocated memory initialized to string s, or NULL if either out of memory or if s is NULL.
-

Replacement for the standard strdup() such that mi_free() can be used on the returned result.

+
Returns
a pointer to newly allocated memory initialized to string s, or NULL if either out of memory or if s is NULL.
+

Replacement for the standard strdup() such that mi_free() can be used on the returned result.

- -

◆ mi_strndup()

+ +

◆ mi_strndup()

- + - - + - - - - - - - +
char* mi_strndup char * mi_strndup (const char * s, const char * s,
size_t n 
)size_t n )
-

Allocate and duplicate a string up to n bytes.

+

Allocate and duplicate a string up to n bytes.

Parameters
- +
sstring to duplicate (or NULL).
sstring to duplicate (or NULL).
nmaximum number of bytes to copy (excluding the terminating zero).
-
Returns
a pointer to newly allocated memory initialized to string s up to the first n bytes (and always zero terminated), or NULL if either out of memory or if s is NULL.
-

Replacement for the standard strndup() such that mi_free() can be used on the returned result.

+
Returns
a pointer to newly allocated memory initialized to string s up to the first n bytes (and always zero terminated), or NULL if either out of memory or if s is NULL.
+

Replacement for the standard strndup() such that mi_free() can be used on the returned result.

- -

◆ mi_zalloc()

+ +

◆ mi_zalloc()

@@ -631,7 +571,7 @@

diff --git a/src/dashbls/depends/mimalloc/docs/group__malloc.js b/src/dashbls/depends/mimalloc/docs/group__malloc.js index 7293ffafd19a..5b0765205350 100644 --- a/src/dashbls/depends/mimalloc/docs/group__malloc.js +++ b/src/dashbls/depends/mimalloc/docs/group__malloc.js @@ -1,16 +1,16 @@ var group__malloc = [ - [ "mi_calloc", "group__malloc.html#ga97fedb4f7107c592fd7f0f0a8949a57d", null ], - [ "mi_expand", "group__malloc.html#gaaee66a1d483c3e28f585525fb96707e4", null ], + [ "mi_calloc", "group__malloc.html#ga6686568014b54d1e6c7ac64a076e4f56", null ], + [ "mi_expand", "group__malloc.html#ga19299856216cfbb08e2628593654dfb0", null ], [ "mi_free", "group__malloc.html#gaf2c7b89c327d1f60f59e68b9ea644d95", null ], - [ "mi_malloc", "group__malloc.html#ga3406e8b168bc74c8637b11571a6da83a", null ], - [ "mi_mallocn", "group__malloc.html#ga0b05e2bf0f73e7401ae08597ff782ac6", null ], - [ "mi_realloc", "group__malloc.html#gaf11eb497da57bdfb2de65eb191c69db6", null ], - [ "mi_reallocf", "group__malloc.html#gafe68ac7c5e24a65cd55c9d6b152211a0", null ], - [ "mi_reallocn", "group__malloc.html#ga61d57b4144ba24fba5c1e9b956d13853", null ], - [ "mi_realpath", "group__malloc.html#ga08cec32dd5bbe7da91c78d19f1b5bebe", null ], + [ "mi_malloc", "group__malloc.html#gae1dd97b542420c87ae085e822b1229e8", null ], + [ "mi_mallocn", "group__malloc.html#ga61f46bade3db76ca24aaafedc40de7b6", null ], + [ "mi_realloc", "group__malloc.html#ga0621af6a5e3aa384e6a1b548958bf583", null ], + [ "mi_reallocf", "group__malloc.html#ga4dc3a4067037b151a64629fe8a332641", null ], + [ "mi_reallocn", "group__malloc.html#ga8bddfb4a1270a0854bbcf44cb3980467", null ], + [ "mi_realpath", "group__malloc.html#ga94c3afcc086e85d75a57e9f76b9b71dd", null ], [ "mi_recalloc", "group__malloc.html#ga23a0fbb452b5dce8e31fab1a1958cacc", null ], - [ "mi_strdup", "group__malloc.html#gac7cffe13f1f458ed16789488bf92b9b2", null ], - [ "mi_strndup", "group__malloc.html#gaaabf971c2571891433477e2d21a35266", null ], - [ "mi_zalloc", "group__malloc.html#gafdd9d8bb2986e668ba9884f28af38000", null ] + [ "mi_strdup", "group__malloc.html#ga245ac90ebc2cfdd17de599e5fea59889", null ], + [ "mi_strndup", "group__malloc.html#ga486d0d26b3b3794f6d1cdb41a9aed92d", null ], + [ "mi_zalloc", "group__malloc.html#gae6e38c4403247a7b40d80419e093bfb8", null ] ]; \ No newline at end of file diff --git a/src/dashbls/depends/mimalloc/docs/group__options.html b/src/dashbls/depends/mimalloc/docs/group__options.html index f92905d42f51..1092afcb7002 100644 --- a/src/dashbls/depends/mimalloc/docs/group__options.html +++ b/src/dashbls/depends/mimalloc/docs/group__options.html @@ -1,24 +1,26 @@ - + - - + + mi-malloc: Runtime Options + - + + @@ -29,20 +31,16 @@
- + - -
-
mi-malloc -  1.7/2.0 +
+
mi-malloc 1.8/2.1
+
- -   + @@ -56,10 +54,15 @@
- + +
@@ -74,8 +77,8 @@

@@ -88,128 +91,177 @@
- +
+
+
+
+
Loading...
+
Searching...
+
No Matches
+
+
+
-
-
Runtime Options
+
Runtime Options

Set runtime behavior. More...

- - - +

+

Enumerations

enum  mi_option_t {
-  mi_option_show_errors -, mi_option_show_stats -, mi_option_verbose -, mi_option_eager_commit +
enum  mi_option_t {
+  mi_option_show_errors +, mi_option_show_stats +, mi_option_verbose +, mi_option_max_errors +,
+  mi_option_max_warnings +, mi_option_reserve_huge_os_pages +, mi_option_reserve_huge_os_pages_at +, mi_option_reserve_os_memory ,
-  mi_option_eager_region_commit -, mi_option_large_os_pages -, mi_option_reserve_huge_os_pages -, mi_option_reserve_huge_os_pages_at +  mi_option_allow_large_os_pages +, mi_option_purge_decommits +, mi_option_arena_reserve +, mi_option_os_tag ,
-  mi_option_segment_cache -, mi_option_page_reset -, mi_option_segment_reset -, mi_option_reset_delay +  mi_option_retry_on_oom +, mi_option_eager_commit +, mi_option_eager_commit_delay +, mi_option_arena_eager_commit ,
-  mi_option_use_numa_nodes -, mi_option_reset_decommits -, mi_option_eager_commit_delay -, mi_option_os_tag +  mi_option_abandoned_page_purge +, mi_option_purge_delay +, mi_option_use_numa_nodes +, mi_option_disallow_os_alloc ,
-  _mi_option_last +  mi_option_limit_os_alloc +, mi_option_max_segment_reclaim +, mi_option_destroy_on_exit +, mi_option_arena_purge_mult +,
+  mi_option_abandoned_reclaim_on_free +, mi_option_purge_extend_delay +, mi_option_disallow_arena_alloc +, mi_option_visit_abandoned +,
+  _mi_option_last
}
 Runtime options. More...
 Runtime options. More...
 
- - + - + - + - + - + - + - + + + + + - +

+

Functions

bool mi_option_is_enabled (mi_option_t option)
bool mi_option_is_enabled (mi_option_t option)
 
void mi_option_enable (mi_option_t option)
void mi_option_enable (mi_option_t option)
 
void mi_option_disable (mi_option_t option)
void mi_option_disable (mi_option_t option)
 
void mi_option_set_enabled (mi_option_t option, bool enable)
void mi_option_set_enabled (mi_option_t option, bool enable)
 
void mi_option_set_enabled_default (mi_option_t option, bool enable)
void mi_option_set_enabled_default (mi_option_t option, bool enable)
 
long mi_option_get (mi_option_t option)
long mi_option_get (mi_option_t option)
 
void mi_option_set (mi_option_t option, long value)
long mi_option_get_clamp (mi_option_t option, long min, long max)
 
size_t mi_option_get_size (mi_option_t option)
 
void mi_option_set (mi_option_t option, long value)
 
void mi_option_set_default (mi_option_t option, long value)
void mi_option_set_default (mi_option_t option, long value)
 

Detailed Description

Set runtime behavior.

Enumeration Type Documentation

- -

◆ mi_option_t

+ +

◆ mi_option_t

- +
enum mi_option_tenum mi_option_t

Runtime options.

- + + + + + + - - - - - - - - - - - - - - - - + + + + + + +
Enumerator
mi_option_show_errors 

Print error messages to stderr.

+
Enumerator
mi_option_show_errors 

Print error messages.

+
mi_option_show_stats 

Print statistics on termination.

+
mi_option_verbose 

Print verbose messages.

+
mi_option_max_errors 

issue at most N error messages

+
mi_option_max_warnings 

issue at most N warning messages

+
mi_option_reserve_huge_os_pages 

reserve N huge OS pages (1GiB pages) at startup

+
mi_option_reserve_huge_os_pages_at 

Reserve N huge OS pages at a specific NUMA node N.

mi_option_show_stats 

Print statistics to stderr when the program is done.

+
mi_option_reserve_os_memory 

reserve specified amount of OS memory in an arena at startup (internally, this value is in KiB; use mi_option_get_size)

mi_option_verbose 

Print verbose messages to stderr.

+
mi_option_allow_large_os_pages 

allow large (2 or 4 MiB) OS pages, implies eager commit. If false, also disables THP for the process.

mi_option_eager_commit 

Eagerly commit segments (4MiB) (enabled by default).

+
mi_option_purge_decommits 

should a memory purge decommit? (=1). Set to 0 to use memory reset on a purge (instead of decommit)

mi_option_eager_region_commit 

Eagerly commit large (256MiB) memory regions (enabled by default, except on Windows)

+
mi_option_arena_reserve 

initial memory size for arena reservation (= 1 GiB on 64-bit) (internally, this value is in KiB; use mi_option_get_size)

mi_option_large_os_pages 

Use large OS pages (2MiB in size) if possible.

+
mi_option_os_tag 

tag used for OS logging (macOS only for now) (=100)

mi_option_reserve_huge_os_pages 

The number of huge OS pages (1GiB in size) to reserve at the start of the program.

+
mi_option_retry_on_oom 

retry on out-of-memory for N milli seconds (=400), set to 0 to disable retries. (only on windows)

mi_option_reserve_huge_os_pages_at 

Reserve huge OS pages at node N.

+
mi_option_eager_commit 

eager commit segments? (after eager_commit_delay segments) (enabled by default).

mi_option_segment_cache 

The number of segments per thread to keep cached.

+
mi_option_eager_commit_delay 

the first N segments per thread are not eagerly committed (but per page in the segment on demand)

mi_option_page_reset 

Reset page memory after mi_option_reset_delay milliseconds when it becomes free.

+
mi_option_arena_eager_commit 

eager commit arenas? Use 2 to enable just on overcommit systems (=2)

mi_option_segment_reset 

Experimental.

+
mi_option_abandoned_page_purge 

immediately purge delayed purges on thread termination

mi_option_reset_delay 

Delay in milli-seconds before resetting a page (100ms by default)

+
mi_option_purge_delay 

memory purging is delayed by N milli seconds; use 0 for immediate purging or -1 for no purging at all. (=10)

mi_option_use_numa_nodes 

Pretend there are at most N NUMA nodes.

+
mi_option_use_numa_nodes 

0 = use all available numa nodes, otherwise use at most N nodes.

mi_option_reset_decommits 

Experimental.

+
mi_option_disallow_os_alloc 

1 = do not use OS memory for allocation (but only programmatically reserved arenas)

mi_option_eager_commit_delay 

Experimental.

+
mi_option_limit_os_alloc 

If set to 1, do not use OS memory for allocation (but only pre-reserved arenas)

mi_option_os_tag 

OS tag to assign to mimalloc'd memory.

+
mi_option_max_segment_reclaim 

max. percentage of the abandoned segments can be reclaimed per try (=10%)

_mi_option_last 
mi_option_destroy_on_exit 

if set, release all memory on exit; sometimes used for dynamic unloading but can be unsafe

+
mi_option_arena_purge_mult 

multiplier for purge_delay for the purging delay for arenas (=10)

+
mi_option_abandoned_reclaim_on_free 

allow to reclaim an abandoned segment on a free (=1)

+
mi_option_purge_extend_delay 

extend purge delay on each subsequent delay (=1)

+
mi_option_disallow_arena_alloc 

1 = do not use arena's for allocation (except if using specific arena id's)

+
mi_option_visit_abandoned 

allow visiting heap blocks from abandoned threads (=0)

+
_mi_option_last 

Function Documentation

- -

◆ mi_option_disable()

+ +

◆ mi_option_disable()

@@ -217,8 +269,7 @@

void mi_option_disable ( - mi_option_t  - option) + mi_option_t option) @@ -226,8 +277,8 @@

-

◆ mi_option_enable()

+ +

◆ mi_option_enable()

@@ -235,8 +286,7 @@

void mi_option_enable ( - mi_option_t  - option) + mi_option_t option) @@ -244,8 +294,8 @@

-

◆ mi_option_get()

+ +

◆ mi_option_get()

@@ -253,8 +303,7 @@

long mi_option_get ( - mi_option_t  - option) + mi_option_t option) @@ -262,82 +311,110 @@

-

◆ mi_option_is_enabled()

+ +

◆ mi_option_get_clamp()

- + - - + + + + + + + + + +
bool mi_option_is_enabled long mi_option_get_clamp (mi_option_t option)mi_option_t option,
long min,
long max )
- -

◆ mi_option_set()

+ +

◆ mi_option_get_size()

- + - - - - - + - - +
void mi_option_set size_t mi_option_get_size (mi_option_t option,
mi_option_t option) long value 
+
+ +
+
+ +

◆ mi_option_is_enabled()

+ +
+
+ + + + - -
bool mi_option_is_enabled (mi_option_t option) )
- -

◆ mi_option_set_default()

+ +

◆ mi_option_set()

- + - - + - - + + +
void mi_option_set_default void mi_option_set (mi_option_t option, mi_option_t option,
long value long value )
+
+ +
+
+ +

◆ mi_option_set_default()

+ +
+
+ + + + + + - - +
void mi_option_set_default (mi_option_t option,
)long value )
- -

◆ mi_option_set_enabled()

+ +

◆ mi_option_set_enabled()

@@ -345,27 +422,20 @@

void mi_option_set_enabled ( - mi_option_t  - option, + mi_option_t option, - bool  - enable  - - - - ) - + bool enable )

- -

◆ mi_option_set_enabled_default()

+ +

◆ mi_option_set_enabled_default()

@@ -373,19 +443,12 @@

void mi_option_set_enabled_default ( - mi_option_t  - option, + mi_option_t option, - bool  - enable  - - - - ) - + bool enable )

@@ -397,7 +460,7 @@

diff --git a/src/dashbls/depends/mimalloc/docs/group__options.js b/src/dashbls/depends/mimalloc/docs/group__options.js index c8836cdc1c0d..b152f7bc33ce 100644 --- a/src/dashbls/depends/mimalloc/docs/group__options.js +++ b/src/dashbls/depends/mimalloc/docs/group__options.js @@ -4,24 +4,38 @@ var group__options = [ "mi_option_show_errors", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cafbf4822e5c00732c5984b32a032837f0", null ], [ "mi_option_show_stats", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca0957ef73b2550764b4840edf48422fda", null ], [ "mi_option_verbose", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca7c8b7bf5281c581bad64f5daa6442777", null ], - [ "mi_option_eager_commit", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca1e8de72c93da7ff22d91e1e27b52ac2b", null ], - [ "mi_option_eager_region_commit", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca32ce97ece29f69e82579679cf8a307ad", null ], - [ "mi_option_large_os_pages", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca4192d491200d0055df0554d4cf65054e", null ], + [ "mi_option_max_errors", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caec6ecbe29d46a48205ed8823a8a52a6a", null ], + [ "mi_option_max_warnings", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caf9595921087e942602ee079158762665", null ], [ "mi_option_reserve_huge_os_pages", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caca7ed041be3b0b9d0b82432c7bf41af2", null ], [ "mi_option_reserve_huge_os_pages_at", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caa13e7926d4339d2aa6fbf61d4473fd5c", null ], - [ "mi_option_segment_cache", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca2ecbe7ef32f5c84de3739aa4f0b805a1", null ], - [ "mi_option_page_reset", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cada854dd272c66342f18a93ee254a2968", null ], - [ "mi_option_segment_reset", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cafb121d30d87591850d5410ccc3a95c6d", null ], - [ "mi_option_reset_delay", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca154fe170131d5212cff57e22b99523c5", null ], - [ "mi_option_use_numa_nodes", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca0ac33a18f6b659fcfaf44efb0bab1b74", null ], - [ "mi_option_reset_decommits", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cac81ee965b130fa81238913a3c239d536", null ], - [ "mi_option_eager_commit_delay", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca17a190c25be381142d87e0468c4c068c", null ], + [ "mi_option_reserve_os_memory", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cafbf4999c828cf79a0fb2de65d23f7333", null ], + [ "mi_option_allow_large_os_pages", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca7cc4804ced69004fa42a9a136a9ba556", null ], + [ "mi_option_purge_decommits", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca9d15c5e3d2115eef681c17e4dd5ab9a4", null ], + [ "mi_option_arena_reserve", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cab1c88e23ae290bbeec824038a97959de", null ], [ "mi_option_os_tag", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca4b74ae2a69e445de6c2361b73c1d14bf", null ], + [ "mi_option_retry_on_oom", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca8f51df355bf6651db899e6085b54865e", null ], + [ "mi_option_eager_commit", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca1e8de72c93da7ff22d91e1e27b52ac2b", null ], + [ "mi_option_eager_commit_delay", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca17a190c25be381142d87e0468c4c068c", null ], + [ "mi_option_arena_eager_commit", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cafd0c5ddbc4b59fd8b5216871728167a5", null ], + [ "mi_option_abandoned_page_purge", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca11e62ed69200a489a5be955582078c0c", null ], + [ "mi_option_purge_delay", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cadd351e615acd8563529c20a347be7290", null ], + [ "mi_option_use_numa_nodes", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca0ac33a18f6b659fcfaf44efb0bab1b74", null ], + [ "mi_option_disallow_os_alloc", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cadcfb5a09580361b1be65901d2d812de6", null ], + [ "mi_option_limit_os_alloc", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca9fa61bd9668479f8452d2195759444cc", null ], + [ "mi_option_max_segment_reclaim", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caa9ad9005d7017c8c30ad2d6ba31db909", null ], + [ "mi_option_destroy_on_exit", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca6364331e305e7d3c0218b058ff3afc88", null ], + [ "mi_option_arena_purge_mult", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca8236501f1ab45d26e6fd885d191a2b5e", null ], + [ "mi_option_abandoned_reclaim_on_free", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca009e4b5684922ce664d73d2a8e1698d9", null ], + [ "mi_option_purge_extend_delay", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca02005f164bdf03f5f00c5be726adf487", null ], + [ "mi_option_disallow_arena_alloc", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caeae1696100e4057ffc4182730cc04e40", null ], + [ "mi_option_visit_abandoned", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca38c67733a3956a1f4eeaca89fab9e78e", null ], [ "_mi_option_last", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca5b4357b74be0d87568036c32eb1a2e4a", null ] ] ], [ "mi_option_disable", "group__options.html#gaebf6ff707a2e688ebb1a2296ca564054", null ], [ "mi_option_enable", "group__options.html#ga04180ae41b0d601421dd62ced40ca050", null ], [ "mi_option_get", "group__options.html#ga7e8af195cc81d3fa64ccf2662caa565a", null ], + [ "mi_option_get_clamp", "group__options.html#ga96ad9c406338bd314cfe878cfc9bf723", null ], + [ "mi_option_get_size", "group__options.html#ga274db5a6ac87cc24ef0b23e7006ed02c", null ], [ "mi_option_is_enabled", "group__options.html#ga459ad98f18b3fc9275474807fe0ca188", null ], [ "mi_option_set", "group__options.html#gaf84921c32375e25754dc2ee6a911fa60", null ], [ "mi_option_set_default", "group__options.html#ga7ef623e440e6e5545cb08c94e71e4b90", null ], diff --git a/src/dashbls/depends/mimalloc/docs/group__posix.html b/src/dashbls/depends/mimalloc/docs/group__posix.html index 539f7ec68300..27351449ffe0 100644 --- a/src/dashbls/depends/mimalloc/docs/group__posix.html +++ b/src/dashbls/depends/mimalloc/docs/group__posix.html @@ -1,24 +1,26 @@ - + - - + + mi-malloc: Posix + - + + @@ -29,20 +31,16 @@
- + - -
-
mi-malloc -  1.7/2.0 +
+
mi-malloc 1.8/2.1
+
- -   + @@ -56,10 +54,15 @@
- + +
@@ -74,8 +77,8 @@

@@ -88,62 +91,105 @@
- +
+
+
+
+
Loading...
+
Searching...
+
No Matches
+
+
+
-
-
Posix
+
Posix

mi_ prefixed implementations of various Posix, Unix, and C++ allocation functions. More...

- - + + + + + + - + + + - - - - + - + - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - + + + + + - + - +

+

Functions

size_t mi_malloc_size (const void *p)
void mi_cfree (void *p)
 Just as free but also checks if the pointer p belongs to our heap.
 
void * mi__expand (void *p, size_t newsize)
 
size_t mi_malloc_size (const void *p)
 
size_t mi_malloc_usable_size (const void *p)
size_t mi_malloc_good_size (size_t size)
 
size_t mi_malloc_usable_size (const void *p)
 
void mi_cfree (void *p)
 Just as free but also checks if the pointer p belongs to our heap. More...
 
int mi_posix_memalign (void **p, size_t alignment, size_t size)
int mi_posix_memalign (void **p, size_t alignment, size_t size)
 
int mi__posix_memalign (void **p, size_t alignment, size_t size)
int mi__posix_memalign (void **p, size_t alignment, size_t size)
 
void * mi_memalign (size_t alignment, size_t size)
 
void * mi_valloc (size_t size)
 
void * mi_pvalloc (size_t size)
 
void * mi_aligned_alloc (size_t alignment, size_t size)
 
void * mi_reallocarray (void *p, size_t count, size_t size)
 Correspond s to reallocarray in FreeBSD. More...
 
int mi_reallocarr (void *p, size_t count, size_t size)
 Corresponds to reallocarr in NetBSD. More...
void * mi_memalign (size_t alignment, size_t size)
 
void * mi_valloc (size_t size)
 
void * mi_pvalloc (size_t size)
 
void * mi_aligned_alloc (size_t alignment, size_t size)
 
unsigned short * mi_wcsdup (const unsigned short *s)
 
unsigned char * mi_mbsdup (const unsigned char *s)
 
int mi_dupenv_s (char **buf, size_t *size, const char *name)
 
int mi_wdupenv_s (unsigned short **buf, size_t *size, const unsigned short *name)
 
void * mi_reallocarray (void *p, size_t count, size_t size)
 Correspond s to reallocarray in FreeBSD.
 
int mi_reallocarr (void *p, size_t count, size_t size)
 Corresponds to reallocarr in NetBSD.
 
void mi_free_size (void *p, size_t size)
void * mi_aligned_recalloc (void *p, size_t newcount, size_t size, size_t alignment)
 
void * mi_aligned_offset_recalloc (void *p, size_t newcount, size_t size, size_t alignment, size_t offset)
 
void mi_free_size (void *p, size_t size)
 
void mi_free_size_aligned (void *p, size_t size, size_t alignment)
void mi_free_size_aligned (void *p, size_t size, size_t alignment)
 
void mi_free_aligned (void *p, size_t alignment)
void mi_free_aligned (void *p, size_t alignment)
 

Detailed Description

mi_ prefixed implementations of various Posix, Unix, and C++ allocation functions.

Defined for convenience as all redirect to the regular mimalloc API.

Function Documentation

- -

◆ mi__posix_memalign()

+ +

◆ mi__expand()

+ +
+
+ + + + + + + + + + + +
void * mi__expand (void * p,
size_t newsize )
+
+ +
+
+ +

◆ mi__posix_memalign()

+ +

◆ mi_aligned_alloc()

+ +
+
+ + + + + + + + + + + +
void * mi_aligned_alloc (size_t alignment,
size_t size )
+
+ +
+
+ +

◆ mi_aligned_offset_recalloc()

+ +
+
+ + + + + - - + - - + + + + + + + - - +
void * mi_aligned_offset_recalloc (void * p,
size_t alignment, size_t newcount,
size_t size size_t size,
size_t alignment,
)size_t offset )
- -

◆ mi_aligned_alloc()

+ +

◆ mi_aligned_recalloc()

- + - - + - - + + + + + + + - - +
void* mi_aligned_alloc void * mi_aligned_recalloc (size_t alignment, void * p,
size_t size size_t newcount,
size_t size,
)size_t alignment )
- -

◆ mi_cfree()

+ +

◆ mi_cfree()

@@ -213,8 +311,7 @@

void mi_cfree ( - void *  - p) + void * p) @@ -224,64 +321,76 @@

-

◆ mi_free_aligned()

+ +

◆ mi_dupenv_s()

- + - - + - - + + - - +
void mi_free_aligned int mi_dupenv_s (void * p, char ** buf,
size_t alignment size_t * size,
)const char * name )
- -

◆ mi_free_size()

+ +

◆ mi_free_aligned()

- + - - + - - + +
void mi_free_size void mi_free_aligned (void * p, void * p,
size_t size size_t alignment )
+
+ +
+
+ +

◆ mi_free_size()

+ +
+
+ + + + + + + - - +
void mi_free_size (void * p,
)size_t size )
- -

◆ mi_free_size_aligned()

+ +

◆ mi_free_size_aligned()

+ +

◆ mi_malloc_good_size()

+ +
+
+ + + + - -
size_t mi_malloc_good_size (size_t size) )
- -

◆ mi_malloc_size()

+ +

◆ mi_malloc_size()

@@ -323,8 +441,7 @@

size_t mi_malloc_size ( - const void *  - p) + const void * p) @@ -332,8 +449,8 @@

-

◆ mi_malloc_usable_size()

+ +

◆ mi_malloc_usable_size()

@@ -341,8 +458,7 @@

size_t mi_malloc_usable_size ( - const void *  - p) + const void * p) @@ -350,36 +466,46 @@

-

◆ mi_memalign()

+ +

◆ mi_mbsdup()

- + - - + + +
void* mi_memalign unsigned char * mi_mbsdup (size_t alignment, const unsigned char * s)
+
+ +
+
+ +

◆ mi_memalign()

+ +
+
+ - - - - + + + + - - +
size_t size void * mi_memalign (size_t alignment,
)size_t size )
- -

◆ mi_posix_memalign()

+ +

◆ mi_posix_memalign()

- -

◆ mi_pvalloc()

+ +

◆ mi_pvalloc()

- + - - +
void* mi_pvalloc void * mi_pvalloc (size_t size)size_t size)
@@ -430,8 +547,8 @@

-

◆ mi_reallocarr()

+ +

◆ mi_reallocarr()

@@ -466,54 +575,88 @@

-

◆ mi_reallocarray()

+ +

◆ mi_reallocarray()

- + - - + - - + - - + +
void* mi_reallocarray void * mi_reallocarray (void * p, void * p,
size_t count, size_t count,
size_t size size_t size )
+
+ +

Correspond s to reallocarray in FreeBSD.

+ +
+
+ +

◆ mi_valloc()

+ +
+
+ + + + - -
void * mi_valloc (size_t size) )
-

Correspond s to reallocarray in FreeBSD.

+
+
+ +

◆ mi_wcsdup()

+ +
+
+ + + + + + + +
unsigned short * mi_wcsdup (const unsigned short * s)
+
- -

◆ mi_valloc()

+ +

◆ mi_wdupenv_s()

- + - - + + + + + + + + + +
void* mi_valloc int mi_wdupenv_s (size_t size)unsigned short ** buf,
size_t * size,
const unsigned short * name )
@@ -525,7 +668,7 @@

diff --git a/src/dashbls/depends/mimalloc/docs/group__posix.js b/src/dashbls/depends/mimalloc/docs/group__posix.js index 50c248c80dac..ea4ed269ed5d 100644 --- a/src/dashbls/depends/mimalloc/docs/group__posix.js +++ b/src/dashbls/depends/mimalloc/docs/group__posix.js @@ -1,17 +1,25 @@ var group__posix = [ + [ "mi__expand", "group__posix.html#ga66bcfeb4faedbb42b796bc680821ef84", null ], [ "mi__posix_memalign", "group__posix.html#gad5a69c8fea96aa2b7a7c818c2130090a", null ], - [ "mi_aligned_alloc", "group__posix.html#ga1326d2e4388630b5f81ca7206318b8e5", null ], + [ "mi_aligned_alloc", "group__posix.html#ga430ed1513f0571ff83be00ec58a98ee0", null ], + [ "mi_aligned_offset_recalloc", "group__posix.html#ga16570deddd559001b44953eedbad0084", null ], + [ "mi_aligned_recalloc", "group__posix.html#gaf82cbb4b4f24acf723348628451798d3", null ], [ "mi_cfree", "group__posix.html#ga705dc7a64bffacfeeb0141501a5c35d7", null ], + [ "mi_dupenv_s", "group__posix.html#gab41369c1a1da7504013a7a0b1d4dd958", null ], [ "mi_free_aligned", "group__posix.html#ga0d28d5cf61e6bfbb18c63092939fe5c9", null ], [ "mi_free_size", "group__posix.html#gae01389eedab8d67341ff52e2aad80ebb", null ], [ "mi_free_size_aligned", "group__posix.html#ga72e9d7ffb5fe94d69bc722c8506e27bc", null ], + [ "mi_malloc_good_size", "group__posix.html#ga9d23ac7885fed7413c11d8e0ffa31071", null ], [ "mi_malloc_size", "group__posix.html#ga4531c9e775bb3ae12db57c1ba8a5d7de", null ], [ "mi_malloc_usable_size", "group__posix.html#ga06d07cf357bbac5c73ba5d0c0c421e17", null ], - [ "mi_memalign", "group__posix.html#gaab7fa71ea93b96873f5d9883db57d40e", null ], + [ "mi_mbsdup", "group__posix.html#ga7b82a44094fdec4d2084eb4288a979b0", null ], + [ "mi_memalign", "group__posix.html#ga726867f13fd29ca36064954c0285b1d8", null ], [ "mi_posix_memalign", "group__posix.html#gacff84f226ba9feb2031b8992e5579447", null ], - [ "mi_pvalloc", "group__posix.html#gaeb325c39b887d3b90d85d1eb1712fb1e", null ], + [ "mi_pvalloc", "group__posix.html#ga644bebccdbb2821542dd8c7e7641f476", null ], [ "mi_reallocarr", "group__posix.html#ga7e1934d60a3e697950eeb48e042bfad5", null ], - [ "mi_reallocarray", "group__posix.html#ga48fad8648a2f1dab9c87ea9448a52088", null ], - [ "mi_valloc", "group__posix.html#ga73baaf5951f5165ba0763d0c06b6a93b", null ] + [ "mi_reallocarray", "group__posix.html#gadfeccb72748a2f6305474a37d9d57bce", null ], + [ "mi_valloc", "group__posix.html#ga50cafb9722020402f065de93799f64ca", null ], + [ "mi_wcsdup", "group__posix.html#gaa9fd7f25c9ac3a20e89b33bd6e383fcf", null ], + [ "mi_wdupenv_s", "group__posix.html#ga6ac6a6a8f3c96f1af24bb8d0439cbbd1", null ] ]; \ No newline at end of file diff --git a/src/dashbls/depends/mimalloc/docs/group__typed.html b/src/dashbls/depends/mimalloc/docs/group__typed.html index c19c7f4adbb7..0d3203e9279f 100644 --- a/src/dashbls/depends/mimalloc/docs/group__typed.html +++ b/src/dashbls/depends/mimalloc/docs/group__typed.html @@ -1,24 +1,26 @@ - + - - + + mi-malloc: Typed Macros + - + + @@ -29,20 +31,16 @@
- + - -
-
mi-malloc -  1.7/2.0 +
+
mi-malloc 1.8/2.1
+
- -   + @@ -56,10 +54,15 @@
- + +
@@ -74,8 +77,8 @@
@@ -88,65 +91,71 @@
- +
+
+
+
+
Loading...
+
Searching...
+
No Matches
+
+
+
-
-
Typed Macros
+
Typed Macros

Typed allocation macros. More...

- - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + +

+

Macros

#define mi_malloc_tp(tp)
 Allocate a block of type tp. More...
#define mi_malloc_tp(tp)
 Allocate a block of type tp.
 
#define mi_zalloc_tp(tp)
 Allocate a zero-initialized block of type tp. More...
#define mi_zalloc_tp(tp)
 Allocate a zero-initialized block of type tp.
 
#define mi_calloc_tp(tp, count)
 Allocate count zero-initialized blocks of type tp. More...
#define mi_calloc_tp(tp, count)
 Allocate count zero-initialized blocks of type tp.
 
#define mi_mallocn_tp(tp, count)
 Allocate count blocks of type tp. More...
#define mi_mallocn_tp(tp, count)
 Allocate count blocks of type tp.
 
#define mi_reallocn_tp(p, tp, count)
 Re-allocate to count blocks of type tp. More...
#define mi_reallocn_tp(p, tp, count)
 Re-allocate to count blocks of type tp.
 
#define mi_heap_malloc_tp(hp, tp)
 Allocate a block of type tp in a heap hp. More...
#define mi_heap_malloc_tp(hp, tp)
 Allocate a block of type tp in a heap hp.
 
#define mi_heap_zalloc_tp(hp, tp)
 Allocate a zero-initialized block of type tp in a heap hp. More...
#define mi_heap_zalloc_tp(hp, tp)
 Allocate a zero-initialized block of type tp in a heap hp.
 
#define mi_heap_calloc_tp(hp, tp, count)
 Allocate count zero-initialized blocks of type tp in a heap hp. More...
#define mi_heap_calloc_tp(hp, tp, count)
 Allocate count zero-initialized blocks of type tp in a heap hp.
 
#define mi_heap_mallocn_tp(hp, tp, count)
 Allocate count blocks of type tp in a heap hp. More...
#define mi_heap_mallocn_tp(hp, tp, count)
 Allocate count blocks of type tp in a heap hp.
 
#define mi_heap_reallocn_tp(hp, p, tp, count)
 Re-allocate to count blocks of type tp in a heap hp. More...
#define mi_heap_reallocn_tp(hp, p, tp, count)
 Re-allocate to count blocks of type tp in a heap hp.
 
#define mi_heap_recalloc_tp(hp, p, tp, count)
 Re-allocate to count zero initialized blocks of type tp in a heap hp. More...
#define mi_heap_recalloc_tp(hp, p, tp, count)
 Re-allocate to count zero initialized blocks of type tp in a heap hp.
 

Detailed Description

Typed allocation macros.

-

For example:

int* p = mi_malloc_tp(int)
-
#define mi_malloc_tp(tp)
Allocate a block of type tp.
Definition: mimalloc-doc.h:692
+

For example:

int* p = mi_malloc_tp(int)
+
#define mi_malloc_tp(tp)
Allocate a block of type tp.
Definition mimalloc-doc.h:784

Macro Definition Documentation

- -

◆ mi_calloc_tp

+ +

◆ mi_calloc_tp

- -

◆ mi_heap_calloc_tp

+ +

◆ mi_heap_calloc_tp

- -

◆ mi_heap_malloc_tp

+ +

◆ mi_heap_malloc_tp

- -

◆ mi_heap_mallocn_tp

+ +

◆ mi_heap_mallocn_tp

- -

◆ mi_heap_reallocn_tp

+ +

◆ mi_heap_reallocn_tp

- -

◆ mi_heap_recalloc_tp

+ +

◆ mi_heap_recalloc_tp

- -

◆ mi_heap_zalloc_tp

+ +

◆ mi_heap_zalloc_tp

- -

◆ mi_malloc_tp

+ +

◆ mi_malloc_tp

- -

◆ mi_mallocn_tp

+ +

◆ mi_mallocn_tp

- -

◆ mi_reallocn_tp

+ +

◆ mi_reallocn_tp

- -

◆ mi_zalloc_tp

+ +

◆ mi_zalloc_tp

@@ -511,7 +448,7 @@

diff --git a/src/dashbls/depends/mimalloc/docs/group__zeroinit.html b/src/dashbls/depends/mimalloc/docs/group__zeroinit.html index 329a7739d207..6ae8ff87ea9b 100644 --- a/src/dashbls/depends/mimalloc/docs/group__zeroinit.html +++ b/src/dashbls/depends/mimalloc/docs/group__zeroinit.html @@ -1,24 +1,26 @@ - + - - + + mi-malloc: Zero initialized re-allocation + - + + @@ -29,20 +31,16 @@
- + - -
-
mi-malloc -  1.7/2.0 +
+
mi-malloc 1.8/2.1
+
- -   + @@ -56,10 +54,15 @@
- + +
@@ -74,8 +77,8 @@

@@ -88,491 +91,397 @@
- +
+
+
+
+
Loading...
+
Searching...
+
No Matches
+
+
+
-
-
Zero initialized re-allocation
+
Zero initialized re-allocation

The zero-initialized re-allocations are only valid on memory that was originally allocated with zero initialization too. More...

- - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + +

+

Functions

void * mi_rezalloc (void *p, size_t newsize)
 
void * mi_rezalloc_aligned (void *p, size_t newsize, size_t alignment)
 
void * mi_rezalloc_aligned_at (void *p, size_t newsize, size_t alignment, size_t offset)
 
void * mi_recalloc_aligned (void *p, size_t newcount, size_t size, size_t alignment)
 
void * mi_recalloc_aligned_at (void *p, size_t newcount, size_t size, size_t alignment, size_t offset)
 
void * mi_heap_rezalloc (mi_heap_t *heap, void *p, size_t newsize)
 
void * mi_heap_recalloc (mi_heap_t *heap, void *p, size_t newcount, size_t size)
 
void * mi_heap_rezalloc_aligned (mi_heap_t *heap, void *p, size_t newsize, size_t alignment)
 
void * mi_heap_rezalloc_aligned_at (mi_heap_t *heap, void *p, size_t newsize, size_t alignment, size_t offset)
 
void * mi_heap_recalloc_aligned (mi_heap_t *heap, void *p, size_t newcount, size_t size, size_t alignment)
 
void * mi_heap_recalloc_aligned_at (mi_heap_t *heap, void *p, size_t newcount, size_t size, size_t alignment, size_t offset)
 
void * mi_rezalloc (void *p, size_t newsize)
 
void * mi_rezalloc_aligned (void *p, size_t newsize, size_t alignment)
 
void * mi_rezalloc_aligned_at (void *p, size_t newsize, size_t alignment, size_t offset)
 
void * mi_recalloc_aligned (void *p, size_t newcount, size_t size, size_t alignment)
 
void * mi_recalloc_aligned_at (void *p, size_t newcount, size_t size, size_t alignment, size_t offset)
 
void * mi_heap_rezalloc (mi_heap_t *heap, void *p, size_t newsize)
 
void * mi_heap_recalloc (mi_heap_t *heap, void *p, size_t newcount, size_t size)
 
void * mi_heap_rezalloc_aligned (mi_heap_t *heap, void *p, size_t newsize, size_t alignment)
 
void * mi_heap_rezalloc_aligned_at (mi_heap_t *heap, void *p, size_t newsize, size_t alignment, size_t offset)
 
void * mi_heap_recalloc_aligned (mi_heap_t *heap, void *p, size_t newcount, size_t size, size_t alignment)
 
void * mi_heap_recalloc_aligned_at (mi_heap_t *heap, void *p, size_t newcount, size_t size, size_t alignment, size_t offset)
 

Detailed Description

The zero-initialized re-allocations are only valid on memory that was originally allocated with zero initialization too.

e.g. mi_calloc, mi_zalloc, mi_zalloc_aligned etc. see https://github.com/microsoft/mimalloc/issues/63#issuecomment-508272992

Function Documentation

- -

◆ mi_heap_recalloc()

+ +

◆ mi_heap_recalloc()

- + - - + - - + - - + - - - - - - - +
void* mi_heap_recalloc void * mi_heap_recalloc (mi_heap_theap, mi_heap_t * heap,
void * p, void * p,
size_t newcount, size_t newcount,
size_t size 
)size_t size )
- -

◆ mi_heap_recalloc_aligned()

+ +

◆ mi_heap_recalloc_aligned()

- + - - + - - + - - + - - + - - - - - - - +
void* mi_heap_recalloc_aligned void * mi_heap_recalloc_aligned (mi_heap_theap, mi_heap_t * heap,
void * p, void * p,
size_t newcount, size_t newcount,
size_t size, size_t size,
size_t alignment 
)size_t alignment )
- -

◆ mi_heap_recalloc_aligned_at()

+ +

◆ mi_heap_recalloc_aligned_at()

- + - - + - - + - - + - - + - - + - - - - - - - +
void* mi_heap_recalloc_aligned_at void * mi_heap_recalloc_aligned_at (mi_heap_theap, mi_heap_t * heap,
void * p, void * p,
size_t newcount, size_t newcount,
size_t size, size_t size,
size_t alignment, size_t alignment,
size_t offset 
)size_t offset )
- -

◆ mi_heap_rezalloc()

+ +

◆ mi_heap_rezalloc()

- + - - + - - + - - - - - - - +
void* mi_heap_rezalloc void * mi_heap_rezalloc (mi_heap_theap, mi_heap_t * heap,
void * p, void * p,
size_t newsize 
)size_t newsize )
- -

◆ mi_heap_rezalloc_aligned()

+ +

◆ mi_heap_rezalloc_aligned()

- + - - + - - + - - + - - - - - - - +
void* mi_heap_rezalloc_aligned void * mi_heap_rezalloc_aligned (mi_heap_theap, mi_heap_t * heap,
void * p, void * p,
size_t newsize, size_t newsize,
size_t alignment 
)size_t alignment )
- -

◆ mi_heap_rezalloc_aligned_at()

+ +

◆ mi_heap_rezalloc_aligned_at()

- + - - + - - + - - + - - + - - - - - - - +
void* mi_heap_rezalloc_aligned_at void * mi_heap_rezalloc_aligned_at (mi_heap_theap, mi_heap_t * heap,
void * p, void * p,
size_t newsize, size_t newsize,
size_t alignment, size_t alignment,
size_t offset 
)size_t offset )
- -

◆ mi_recalloc_aligned()

+ +

◆ mi_recalloc_aligned()

- + - - + - - + - - + - - - - - - - +
void* mi_recalloc_aligned void * mi_recalloc_aligned (void * p, void * p,
size_t newcount, size_t newcount,
size_t size, size_t size,
size_t alignment 
)size_t alignment )
- -

◆ mi_recalloc_aligned_at()

+ +

◆ mi_recalloc_aligned_at()

- + - - + - - + - - + - - + - - - - - - - +
void* mi_recalloc_aligned_at void * mi_recalloc_aligned_at (void * p, void * p,
size_t newcount, size_t newcount,
size_t size, size_t size,
size_t alignment, size_t alignment,
size_t offset 
)size_t offset )
- -

◆ mi_rezalloc()

+ +

◆ mi_rezalloc()

- + - - + - - - - - - - +
void* mi_rezalloc void * mi_rezalloc (void * p, void * p,
size_t newsize 
)size_t newsize )
- -

◆ mi_rezalloc_aligned()

+ +

◆ mi_rezalloc_aligned()

- + - - + - - + - - - - - - - +
void* mi_rezalloc_aligned void * mi_rezalloc_aligned (void * p, void * p,
size_t newsize, size_t newsize,
size_t alignment 
)size_t alignment )
- -

◆ mi_rezalloc_aligned_at()

+ +

◆ mi_rezalloc_aligned_at()

- + - - + - - + - - + - - - - - - - +
void* mi_rezalloc_aligned_at void * mi_rezalloc_aligned_at (void * p, void * p,
size_t newsize, size_t newsize,
size_t alignment, size_t alignment,
size_t offset 
)size_t offset )
@@ -584,7 +493,7 @@

diff --git a/src/dashbls/depends/mimalloc/docs/group__zeroinit.js b/src/dashbls/depends/mimalloc/docs/group__zeroinit.js index b9297d2123f8..505df60222d2 100644 --- a/src/dashbls/depends/mimalloc/docs/group__zeroinit.js +++ b/src/dashbls/depends/mimalloc/docs/group__zeroinit.js @@ -1,14 +1,14 @@ var group__zeroinit = [ - [ "mi_heap_recalloc", "group__zeroinit.html#ga8648c5fbb22a80f0262859099f06dfbd", null ], - [ "mi_heap_recalloc_aligned", "group__zeroinit.html#ga9f3f999396c8f77ca5e80e7b40ac29e3", null ], - [ "mi_heap_recalloc_aligned_at", "group__zeroinit.html#ga496452c96f1de8c500be9fddf52edaf7", null ], - [ "mi_heap_rezalloc", "group__zeroinit.html#gacfad83f14eb5d6a42a497a898e19fc76", null ], - [ "mi_heap_rezalloc_aligned", "group__zeroinit.html#ga375fa8a611c51905e592d5d467c49664", null ], - [ "mi_heap_rezalloc_aligned_at", "group__zeroinit.html#gac90da54fa7e5d10bdc97ce0b51dce2eb", null ], - [ "mi_recalloc_aligned", "group__zeroinit.html#ga3e7e5c291acf1c7fd7ffd9914a9f945f", null ], - [ "mi_recalloc_aligned_at", "group__zeroinit.html#ga4ff5e92ad73585418a072c9d059e5cf9", null ], - [ "mi_rezalloc", "group__zeroinit.html#ga8c292e142110229a2980b37ab036dbc6", null ], - [ "mi_rezalloc_aligned", "group__zeroinit.html#gacd71a7bce96aab38ae6de17af2eb2cf0", null ], - [ "mi_rezalloc_aligned_at", "group__zeroinit.html#gae8b358c417e61d5307da002702b0a8e1", null ] + [ "mi_heap_recalloc", "group__zeroinit.html#gad1a0d325d930eeb80f25e3fea37aacde", null ], + [ "mi_heap_recalloc_aligned", "group__zeroinit.html#ga87ddd674bf1c67237d780d0b9e0f0f32", null ], + [ "mi_heap_recalloc_aligned_at", "group__zeroinit.html#ga07b5bcbaf00d0d2e598c232982588496", null ], + [ "mi_heap_rezalloc", "group__zeroinit.html#ga8d8b7ebb24b513cd84d1a696048da60d", null ], + [ "mi_heap_rezalloc_aligned", "group__zeroinit.html#ga5129f6dc46ee1613d918820a8a0533a7", null ], + [ "mi_heap_rezalloc_aligned_at", "group__zeroinit.html#ga2bafa79c3f98ea74882349d44cffa5d9", null ], + [ "mi_recalloc_aligned", "group__zeroinit.html#ga3e2169b48683aa0ab64f813fd68d839e", null ], + [ "mi_recalloc_aligned_at", "group__zeroinit.html#gaae25e4ddedd4e0fb61b1a8bd5d452750", null ], + [ "mi_rezalloc", "group__zeroinit.html#gadfd34cd7b4f2bbda7ae06367a6360756", null ], + [ "mi_rezalloc_aligned", "group__zeroinit.html#ga4d02404fe1e7db00beb65f185e012caa", null ], + [ "mi_rezalloc_aligned_at", "group__zeroinit.html#ga6843a88285bbfcc3bdfccc60aafd1270", null ] ]; \ No newline at end of file diff --git a/src/dashbls/depends/mimalloc/docs/index.html b/src/dashbls/depends/mimalloc/docs/index.html index 2ea91215ea9e..b3c8a630ad72 100644 --- a/src/dashbls/depends/mimalloc/docs/index.html +++ b/src/dashbls/depends/mimalloc/docs/index.html @@ -1,24 +1,26 @@ - + - - + + -mi-malloc: Main Page +mi-malloc: mi-malloc + - + + @@ -29,20 +31,16 @@
- + - -
-
mi-malloc -  1.7/2.0 +
+
mi-malloc 1.8/2.1
+
- -   + @@ -56,10 +54,15 @@
- + +
@@ -74,8 +77,8 @@
@@ -88,28 +91,33 @@
- +
+
+
+
+
Loading...
+
Searching...
+
No Matches
+
+
+
-
-
-
mi-malloc Documentation
+
+
mi-malloc

This is the API documentation of the mimalloc allocator (pronounced "me-malloc") – a general purpose allocator with excellent performance characteristics. Initially developed by Daan Leijen for the run-time systems of the Koka and Lean languages.

It is a drop-in replacement for malloc and can be used in other programs without code changes, for example, on Unix you can use it as:

> LD_PRELOAD=/usr/bin/libmimalloc.so myprogram
-

Notable aspects of the design include:

-
    -
  • small and consistent: the library is about 8k LOC using simple and consistent data structures. This makes it very suitable to integrate and adapt in other projects. For runtime systems it provides hooks for a monotonic heartbeat and deferred freeing (for bounded worst-case times with reference counting).
  • +

Notable aspects of the design include:

    +
  • small and consistent: the library is about 8k LOC using simple and consistent data structures. This makes it very suitable to integrate and adapt in other projects. For runtime systems it provides hooks for a monotonic heartbeat and deferred freeing (for bounded worst-case times with reference counting). Partly due to its simplicity, mimalloc has been ported to many systems (Windows, macOS, Linux, WASM, various BSD's, Haiku, MUSL, etc) and has excellent support for dynamic overriding. At the same time, it is an industrial strength allocator that runs (very) large scale distributed services on thousands of machines with excellent worst case latencies.
  • free list sharding: instead of one big free list (per size class) we have many smaller lists per "mimalloc page" which reduces fragmentation and increases locality – things that are allocated close in time get allocated close in memory. (A mimalloc page contains blocks of one size class and is usually 64KiB on a 64-bit system).
  • free list multi-sharding: the big idea! Not only do we shard the free list per mimalloc page, but for each page we have multiple free lists. In particular, there is one list for thread-local free operations, and another one for concurrent free operations. Free-ing from another thread can now be a single CAS without needing sophisticated coordination between threads. Since there will be thousands of separate free lists, contention is naturally distributed over the heap, and the chance of contending on a single location will be low – this is quite similar to randomized algorithms like skip lists where adding a random oracle removes the need for a more complex algorithm.
  • -
  • eager page reset: when a "page" becomes empty (with increased chance due to free list sharding) the memory is marked to the OS as unused ("reset" or "purged") reducing (real) memory pressure and fragmentation, especially in long running programs.
  • -
  • secure: mimalloc can be build in secure mode, adding guard pages, randomized allocation, encrypted free lists, etc. to protect against various heap vulnerabilities. The performance penalty is only around 5% on average over our benchmarks.
  • +
  • eager page purging: when a "page" becomes empty (with increased chance due to free list sharding) the memory is marked to the OS as unused (reset or decommitted) reducing (real) memory pressure and fragmentation, especially in long running programs.
  • +
  • secure: mimalloc can be built in secure mode, adding guard pages, randomized allocation, encrypted free lists, etc. to protect against various heap vulnerabilities. The performance penalty is usually around 10% on average over our benchmarks.
  • first-class heaps: efficiently create and use multiple heaps to allocate across different regions. A heap can be destroyed at once instead of deallocating each object separately.
  • -
  • bounded: it does not suffer from blowup [1], has bounded worst-case allocation times (wcat), bounded space overhead (~0.2% meta-data, with at most 12.5% waste in allocation sizes), and has no internal points of contention using only atomic operations.
  • -
  • fast: In our benchmarks (see below), mimalloc outperforms all other leading allocators (jemalloc, tcmalloc, Hoard, etc), and usually uses less memory (up to 25% more in the worst case). A nice property is that it does consistently well over a wide range of benchmarks.
  • +
  • bounded: it does not suffer from blowup [1], has bounded worst-case allocation times (wcat) (upto OS primitives), bounded space overhead (~0.2% meta-data, with low internal fragmentation), and has no internal points of contention using only atomic operations.
  • +
  • fast: In our benchmarks (see below), mimalloc outperforms other leading allocators (jemalloc, tcmalloc, Hoard, etc), and often uses less memory. A nice property is that it does consistently well over a wide range of benchmarks. There is also good huge OS page support for larger server programs.

You can read more on the design of mimalloc in the technical report which also has detailed benchmark results.

Further information:

@@ -130,12 +138,13 @@
  • C++ wrappers
  • +
    diff --git a/src/dashbls/depends/mimalloc/docs/jquery.js b/src/dashbls/depends/mimalloc/docs/jquery.js index 103c32d79b74..875ada738f09 100644 --- a/src/dashbls/depends/mimalloc/docs/jquery.js +++ b/src/dashbls/depends/mimalloc/docs/jquery.js @@ -1,18 +1,143 @@ -/*! jQuery v3.4.1 | (c) JS Foundation and other contributors | jquery.org/license */ -!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],E=C.document,r=Object.getPrototypeOf,s=t.slice,g=t.concat,u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType},x=function(e){return null!=e&&e===e.window},c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.4.1",k=function(e,t){return new k.fn.init(e,t)},p=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;function d(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp($),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+$),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),ne=function(e,t,n){var r="0x"+t-65536;return r!=r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(m.childNodes),m.childNodes),t[m.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&((e?e.ownerDocument||e:m)!==C&&T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!A[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&U.test(t)){(s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=k),o=(l=h(t)).length;while(o--)l[o]="#"+s+" "+xe(l[o]);c=l.join(","),f=ee.test(t)&&ye(e.parentNode)||e}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){A(t,!0)}finally{s===k&&e.removeAttribute("id")}}}return g(t.replace(B,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[k]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:m;return r!==C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),m!==C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=k,!C.getElementsByName||!C.getElementsByName(k).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+k+"-]").length||v.push("~="),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+k+"+*").length||v.push(".#.+[+~]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",$)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e===C||e.ownerDocument===m&&y(m,e)?-1:t===C||t.ownerDocument===m&&y(m,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e===C?-1:t===C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]===m?-1:s[r]===m?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if((e.ownerDocument||e)!==C&&T(e),d.matchesSelector&&E&&!A[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){A(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=p[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&p(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?k.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?k.grep(e,function(e){return e===n!==r}):"string"!=typeof n?k.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(k.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||q,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:L.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof k?t[0]:t,k.merge(this,k.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),D.test(r[1])&&k.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(k):k.makeArray(e,this)}).prototype=k.fn,q=k(E);var H=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}k.fn.extend({has:function(e){var t=k(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i,ge={option:[1,""],thead:[1,"","
    "],col:[2,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?k.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;nx",y.noCloneChecked=!!me.cloneNode(!0).lastChild.defaultValue;var Te=/^key/,Ce=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Ee=/^([^.]*)(?:\.(.+)|)/;function ke(){return!0}function Se(){return!1}function Ne(e,t){return e===function(){try{return E.activeElement}catch(e){}}()==("focus"===t)}function Ae(e,t,n,r,i,o){var a,s;if("object"==typeof t){for(s in"string"!=typeof n&&(r=r||n,n=void 0),t)Ae(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=Se;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return k().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=k.guid++)),e.each(function(){k.event.add(this,t,i,r,n)})}function De(e,i,o){o?(Q.set(e,i,!1),k.event.add(e,i,{namespace:!1,handler:function(e){var t,n,r=Q.get(this,i);if(1&e.isTrigger&&this[i]){if(r.length)(k.event.special[i]||{}).delegateType&&e.stopPropagation();else if(r=s.call(arguments),Q.set(this,i,r),t=o(this,i),this[i](),r!==(n=Q.get(this,i))||t?Q.set(this,i,!1):n={},r!==n)return e.stopImmediatePropagation(),e.preventDefault(),n.value}else r.length&&(Q.set(this,i,{value:k.event.trigger(k.extend(r[0],k.Event.prototype),r.slice(1),this)}),e.stopImmediatePropagation())}})):void 0===Q.get(e,i)&&k.event.add(e,i,ke)}k.event={global:{},add:function(t,e,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.get(t);if(v){n.handler&&(n=(o=n).handler,i=o.selector),i&&k.find.matchesSelector(ie,i),n.guid||(n.guid=k.guid++),(u=v.events)||(u=v.events={}),(a=v.handle)||(a=v.handle=function(e){return"undefined"!=typeof k&&k.event.triggered!==e.type?k.event.dispatch.apply(t,arguments):void 0}),l=(e=(e||"").match(R)||[""]).length;while(l--)d=g=(s=Ee.exec(e[l])||[])[1],h=(s[2]||"").split(".").sort(),d&&(f=k.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=k.event.special[d]||{},c=k.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&k.expr.match.needsContext.test(i),namespace:h.join(".")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(t,r,h,a)||t.addEventListener&&t.addEventListener(d,a)),f.add&&(f.add.call(t,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),k.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.hasData(e)&&Q.get(e);if(v&&(u=v.events)){l=(t=(t||"").match(R)||[""]).length;while(l--)if(d=g=(s=Ee.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),d){f=k.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,v.handle)||k.removeEvent(e,d,v.handle),delete u[d])}else for(d in u)k.event.remove(e,d+t[l],n,r,!0);k.isEmptyObject(u)&&Q.remove(e,"handle events")}},dispatch:function(e){var t,n,r,i,o,a,s=k.event.fix(e),u=new Array(arguments.length),l=(Q.get(this,"events")||{})[s.type]||[],c=k.event.special[s.type]||{};for(u[0]=s,t=1;t\x20\t\r\n\f]*)[^>]*)\/>/gi,qe=/\s*$/g;function Oe(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&k(e).children("tbody")[0]||e}function Pe(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function Re(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Me(e,t){var n,r,i,o,a,s,u,l;if(1===t.nodeType){if(Q.hasData(e)&&(o=Q.access(e),a=Q.set(t,o),l=o.events))for(i in delete a.handle,a.events={},l)for(n=0,r=l[i].length;n")},clone:function(e,t,n){var r,i,o,a,s,u,l,c=e.cloneNode(!0),f=oe(e);if(!(y.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||k.isXMLDoc(e)))for(a=ve(c),r=0,i=(o=ve(e)).length;r").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var Vt,Gt=[],Yt=/(=)\?(?=&|$)|\?\?/;k.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Gt.pop()||k.expando+"_"+kt++;return this[e]=!0,e}}),k.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Yt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Yt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Yt,"$1"+r):!1!==e.jsonp&&(e.url+=(St.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||k.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?k(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Gt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((Vt=E.implementation.createHTMLDocument("").body).innerHTML="
    ",2===Vt.childNodes.length),k.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=D.exec(e))?[t.createElement(i[1])]:(i=we([e],t,o),o&&o.length&&k(o).remove(),k.merge([],i.childNodes)));var r,i,o},k.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(k.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},k.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){k.fn[t]=function(e){return this.on(t,e)}}),k.expr.pseudos.animated=function(t){return k.grep(k.timers,function(e){return t===e.elem}).length},k.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=k.css(e,"position"),c=k(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=k.css(e,"top"),u=k.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,k.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},k.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){k.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===k.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===k.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=k(e).offset()).top+=k.css(e,"borderTopWidth",!0),i.left+=k.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-k.css(r,"marginTop",!0),left:t.left-i.left-k.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===k.css(e,"position"))e=e.offsetParent;return e||ie})}}),k.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;k.fn[t]=function(e){return _(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),k.each(["top","left"],function(e,n){k.cssHooks[n]=ze(y.pixelPosition,function(e,t){if(t)return t=_e(e,n),$e.test(t)?k(e).position()[n]+"px":t})}),k.each({Height:"height",Width:"width"},function(a,s){k.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){k.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return _(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?k.css(e,t,i):k.style(e,t,n,i)},s,n?e:void 0,n)}})}),k.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){k.fn[n]=function(e,t){return 0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp( +"^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"�":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType +}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c +)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){ +return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll( +":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id") +)&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push( +"\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test( +a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},j=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null, +null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne +).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||D,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,D=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for( +var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="",y.option=!!ce.lastChild;var ge={thead:[1,"","
    "],col:[2,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],_default:[0,"",""]};function ve(e,t){var n; +return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n",""]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function je(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function De(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Le(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0, +r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var _t,zt=[],Ut=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=zt.pop()||S.expando+"_"+wt.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Ut.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Ut.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Ut,"$1"+r):!1!==e.jsonp&&(e.url+=(Tt.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r] +,C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,zt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((_t=E.implementation.createHTMLDocument("").body).innerHTML="
    ",2===_t.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each( +function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r, +"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=Fe(y.pixelPosition,function(e,t){if(t)return t=We(e,n),Pe.test(t)?S(e).position()[n]+"px":t})} +),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each( +"blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0a;a++)for(i in o[a])n=o[a][i],o[a].hasOwnProperty(i)&&void 0!==n&&(e[i]=t.isPlainObject(n)?t.isPlainObject(e[i])?t.widget.extend({},e[i],n):t.widget.extend({},n):n);return e},t.widget.bridge=function(e,i){var n=i.prototype.widgetFullName||e;t.fn[e]=function(o){var a="string"==typeof o,r=s.call(arguments,1),h=this;return a?this.length||"instance"!==o?this.each(function(){var i,s=t.data(this,n);return"instance"===o?(h=s,!1):s?t.isFunction(s[o])&&"_"!==o.charAt(0)?(i=s[o].apply(s,r),i!==s&&void 0!==i?(h=i&&i.jquery?h.pushStack(i.get()):i,!1):void 0):t.error("no such method '"+o+"' for "+e+" widget instance"):t.error("cannot call methods on "+e+" prior to initialization; "+"attempted to call method '"+o+"'")}):h=void 0:(r.length&&(o=t.widget.extend.apply(null,[o].concat(r))),this.each(function(){var e=t.data(this,n);e?(e.option(o||{}),e._init&&e._init()):t.data(this,n,new i(o,this))})),h}},t.Widget=function(){},t.Widget._childConstructors=[],t.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",defaultElement:"
    ",options:{classes:{},disabled:!1,create:null},_createWidget:function(e,s){s=t(s||this.defaultElement||this)[0],this.element=t(s),this.uuid=i++,this.eventNamespace="."+this.widgetName+this.uuid,this.bindings=t(),this.hoverable=t(),this.focusable=t(),this.classesElementLookup={},s!==this&&(t.data(s,this.widgetFullName,this),this._on(!0,this.element,{remove:function(t){t.target===s&&this.destroy()}}),this.document=t(s.style?s.ownerDocument:s.document||s),this.window=t(this.document[0].defaultView||this.document[0].parentWindow)),this.options=t.widget.extend({},this.options,this._getCreateOptions(),e),this._create(),this.options.disabled&&this._setOptionDisabled(this.options.disabled),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:function(){return{}},_getCreateEventData:t.noop,_create:t.noop,_init:t.noop,destroy:function(){var e=this;this._destroy(),t.each(this.classesElementLookup,function(t,i){e._removeClass(i,t)}),this.element.off(this.eventNamespace).removeData(this.widgetFullName),this.widget().off(this.eventNamespace).removeAttr("aria-disabled"),this.bindings.off(this.eventNamespace)},_destroy:t.noop,widget:function(){return this.element},option:function(e,i){var s,n,o,a=e;if(0===arguments.length)return t.widget.extend({},this.options);if("string"==typeof e)if(a={},s=e.split("."),e=s.shift(),s.length){for(n=a[e]=t.widget.extend({},this.options[e]),o=0;s.length-1>o;o++)n[s[o]]=n[s[o]]||{},n=n[s[o]];if(e=s.pop(),1===arguments.length)return void 0===n[e]?null:n[e];n[e]=i}else{if(1===arguments.length)return void 0===this.options[e]?null:this.options[e];a[e]=i}return this._setOptions(a),this},_setOptions:function(t){var e;for(e in t)this._setOption(e,t[e]);return this},_setOption:function(t,e){return"classes"===t&&this._setOptionClasses(e),this.options[t]=e,"disabled"===t&&this._setOptionDisabled(e),this},_setOptionClasses:function(e){var i,s,n;for(i in e)n=this.classesElementLookup[i],e[i]!==this.options.classes[i]&&n&&n.length&&(s=t(n.get()),this._removeClass(n,i),s.addClass(this._classes({element:s,keys:i,classes:e,add:!0})))},_setOptionDisabled:function(t){this._toggleClass(this.widget(),this.widgetFullName+"-disabled",null,!!t),t&&(this._removeClass(this.hoverable,null,"ui-state-hover"),this._removeClass(this.focusable,null,"ui-state-focus"))},enable:function(){return this._setOptions({disabled:!1})},disable:function(){return this._setOptions({disabled:!0})},_classes:function(e){function i(i,o){var a,r;for(r=0;i.length>r;r++)a=n.classesElementLookup[i[r]]||t(),a=e.add?t(t.unique(a.get().concat(e.element.get()))):t(a.not(e.element).get()),n.classesElementLookup[i[r]]=a,s.push(i[r]),o&&e.classes[i[r]]&&s.push(e.classes[i[r]])}var s=[],n=this;return e=t.extend({element:this.element,classes:this.options.classes||{}},e),this._on(e.element,{remove:"_untrackClassesElement"}),e.keys&&i(e.keys.match(/\S+/g)||[],!0),e.extra&&i(e.extra.match(/\S+/g)||[]),s.join(" ")},_untrackClassesElement:function(e){var i=this;t.each(i.classesElementLookup,function(s,n){-1!==t.inArray(e.target,n)&&(i.classesElementLookup[s]=t(n.not(e.target).get()))})},_removeClass:function(t,e,i){return this._toggleClass(t,e,i,!1)},_addClass:function(t,e,i){return this._toggleClass(t,e,i,!0)},_toggleClass:function(t,e,i,s){s="boolean"==typeof s?s:i;var n="string"==typeof t||null===t,o={extra:n?e:i,keys:n?t:e,element:n?this.element:t,add:s};return o.element.toggleClass(this._classes(o),s),this},_on:function(e,i,s){var n,o=this;"boolean"!=typeof e&&(s=i,i=e,e=!1),s?(i=n=t(i),this.bindings=this.bindings.add(i)):(s=i,i=this.element,n=this.widget()),t.each(s,function(s,a){function r(){return e||o.options.disabled!==!0&&!t(this).hasClass("ui-state-disabled")?("string"==typeof a?o[a]:a).apply(o,arguments):void 0}"string"!=typeof a&&(r.guid=a.guid=a.guid||r.guid||t.guid++);var h=s.match(/^([\w:-]*)\s*(.*)$/),l=h[1]+o.eventNamespace,c=h[2];c?n.on(l,c,r):i.on(l,r)})},_off:function(e,i){i=(i||"").split(" ").join(this.eventNamespace+" ")+this.eventNamespace,e.off(i).off(i),this.bindings=t(this.bindings.not(e).get()),this.focusable=t(this.focusable.not(e).get()),this.hoverable=t(this.hoverable.not(e).get())},_delay:function(t,e){function i(){return("string"==typeof t?s[t]:t).apply(s,arguments)}var s=this;return setTimeout(i,e||0)},_hoverable:function(e){this.hoverable=this.hoverable.add(e),this._on(e,{mouseenter:function(e){this._addClass(t(e.currentTarget),null,"ui-state-hover")},mouseleave:function(e){this._removeClass(t(e.currentTarget),null,"ui-state-hover")}})},_focusable:function(e){this.focusable=this.focusable.add(e),this._on(e,{focusin:function(e){this._addClass(t(e.currentTarget),null,"ui-state-focus")},focusout:function(e){this._removeClass(t(e.currentTarget),null,"ui-state-focus")}})},_trigger:function(e,i,s){var n,o,a=this.options[e];if(s=s||{},i=t.Event(i),i.type=(e===this.widgetEventPrefix?e:this.widgetEventPrefix+e).toLowerCase(),i.target=this.element[0],o=i.originalEvent)for(n in o)n in i||(i[n]=o[n]);return this.element.trigger(i,s),!(t.isFunction(a)&&a.apply(this.element[0],[i].concat(s))===!1||i.isDefaultPrevented())}},t.each({show:"fadeIn",hide:"fadeOut"},function(e,i){t.Widget.prototype["_"+e]=function(s,n,o){"string"==typeof n&&(n={effect:n});var a,r=n?n===!0||"number"==typeof n?i:n.effect||i:e;n=n||{},"number"==typeof n&&(n={duration:n}),a=!t.isEmptyObject(n),n.complete=o,n.delay&&s.delay(n.delay),a&&t.effects&&t.effects.effect[r]?s[e](n):r!==e&&s[r]?s[r](n.duration,n.easing,o):s.queue(function(i){t(this)[e](),o&&o.call(s[0]),i()})}}),t.widget,function(){function e(t,e,i){return[parseFloat(t[0])*(u.test(t[0])?e/100:1),parseFloat(t[1])*(u.test(t[1])?i/100:1)]}function i(e,i){return parseInt(t.css(e,i),10)||0}function s(e){var i=e[0];return 9===i.nodeType?{width:e.width(),height:e.height(),offset:{top:0,left:0}}:t.isWindow(i)?{width:e.width(),height:e.height(),offset:{top:e.scrollTop(),left:e.scrollLeft()}}:i.preventDefault?{width:0,height:0,offset:{top:i.pageY,left:i.pageX}}:{width:e.outerWidth(),height:e.outerHeight(),offset:e.offset()}}var n,o=Math.max,a=Math.abs,r=/left|center|right/,h=/top|center|bottom/,l=/[\+\-]\d+(\.[\d]+)?%?/,c=/^\w+/,u=/%$/,d=t.fn.position;t.position={scrollbarWidth:function(){if(void 0!==n)return n;var e,i,s=t("
    "),o=s.children()[0];return t("body").append(s),e=o.offsetWidth,s.css("overflow","scroll"),i=o.offsetWidth,e===i&&(i=s[0].clientWidth),s.remove(),n=e-i},getScrollInfo:function(e){var i=e.isWindow||e.isDocument?"":e.element.css("overflow-x"),s=e.isWindow||e.isDocument?"":e.element.css("overflow-y"),n="scroll"===i||"auto"===i&&e.widthi?"left":e>0?"right":"center",vertical:0>r?"top":s>0?"bottom":"middle"};l>p&&p>a(e+i)&&(u.horizontal="center"),c>f&&f>a(s+r)&&(u.vertical="middle"),u.important=o(a(e),a(i))>o(a(s),a(r))?"horizontal":"vertical",n.using.call(this,t,u)}),h.offset(t.extend(D,{using:r}))})},t.ui.position={fit:{left:function(t,e){var i,s=e.within,n=s.isWindow?s.scrollLeft:s.offset.left,a=s.width,r=t.left-e.collisionPosition.marginLeft,h=n-r,l=r+e.collisionWidth-a-n;e.collisionWidth>a?h>0&&0>=l?(i=t.left+h+e.collisionWidth-a-n,t.left+=h-i):t.left=l>0&&0>=h?n:h>l?n+a-e.collisionWidth:n:h>0?t.left+=h:l>0?t.left-=l:t.left=o(t.left-r,t.left)},top:function(t,e){var i,s=e.within,n=s.isWindow?s.scrollTop:s.offset.top,a=e.within.height,r=t.top-e.collisionPosition.marginTop,h=n-r,l=r+e.collisionHeight-a-n;e.collisionHeight>a?h>0&&0>=l?(i=t.top+h+e.collisionHeight-a-n,t.top+=h-i):t.top=l>0&&0>=h?n:h>l?n+a-e.collisionHeight:n:h>0?t.top+=h:l>0?t.top-=l:t.top=o(t.top-r,t.top)}},flip:{left:function(t,e){var i,s,n=e.within,o=n.offset.left+n.scrollLeft,r=n.width,h=n.isWindow?n.scrollLeft:n.offset.left,l=t.left-e.collisionPosition.marginLeft,c=l-h,u=l+e.collisionWidth-r-h,d="left"===e.my[0]?-e.elemWidth:"right"===e.my[0]?e.elemWidth:0,p="left"===e.at[0]?e.targetWidth:"right"===e.at[0]?-e.targetWidth:0,f=-2*e.offset[0];0>c?(i=t.left+d+p+f+e.collisionWidth-r-o,(0>i||a(c)>i)&&(t.left+=d+p+f)):u>0&&(s=t.left-e.collisionPosition.marginLeft+d+p+f-h,(s>0||u>a(s))&&(t.left+=d+p+f))},top:function(t,e){var i,s,n=e.within,o=n.offset.top+n.scrollTop,r=n.height,h=n.isWindow?n.scrollTop:n.offset.top,l=t.top-e.collisionPosition.marginTop,c=l-h,u=l+e.collisionHeight-r-h,d="top"===e.my[1],p=d?-e.elemHeight:"bottom"===e.my[1]?e.elemHeight:0,f="top"===e.at[1]?e.targetHeight:"bottom"===e.at[1]?-e.targetHeight:0,m=-2*e.offset[1];0>c?(s=t.top+p+f+m+e.collisionHeight-r-o,(0>s||a(c)>s)&&(t.top+=p+f+m)):u>0&&(i=t.top-e.collisionPosition.marginTop+p+f+m-h,(i>0||u>a(i))&&(t.top+=p+f+m))}},flipfit:{left:function(){t.ui.position.flip.left.apply(this,arguments),t.ui.position.fit.left.apply(this,arguments)},top:function(){t.ui.position.flip.top.apply(this,arguments),t.ui.position.fit.top.apply(this,arguments)}}}}(),t.ui.position,t.extend(t.expr[":"],{data:t.expr.createPseudo?t.expr.createPseudo(function(e){return function(i){return!!t.data(i,e)}}):function(e,i,s){return!!t.data(e,s[3])}}),t.fn.extend({disableSelection:function(){var t="onselectstart"in document.createElement("div")?"selectstart":"mousedown";return function(){return this.on(t+".ui-disableSelection",function(t){t.preventDefault()})}}(),enableSelection:function(){return this.off(".ui-disableSelection")}}),t.ui.focusable=function(i,s){var n,o,a,r,h,l=i.nodeName.toLowerCase();return"area"===l?(n=i.parentNode,o=n.name,i.href&&o&&"map"===n.nodeName.toLowerCase()?(a=t("img[usemap='#"+o+"']"),a.length>0&&a.is(":visible")):!1):(/^(input|select|textarea|button|object)$/.test(l)?(r=!i.disabled,r&&(h=t(i).closest("fieldset")[0],h&&(r=!h.disabled))):r="a"===l?i.href||s:s,r&&t(i).is(":visible")&&e(t(i)))},t.extend(t.expr[":"],{focusable:function(e){return t.ui.focusable(e,null!=t.attr(e,"tabindex"))}}),t.ui.focusable,t.fn.form=function(){return"string"==typeof this[0].form?this.closest("form"):t(this[0].form)},t.ui.formResetMixin={_formResetHandler:function(){var e=t(this);setTimeout(function(){var i=e.data("ui-form-reset-instances");t.each(i,function(){this.refresh()})})},_bindFormResetHandler:function(){if(this.form=this.element.form(),this.form.length){var t=this.form.data("ui-form-reset-instances")||[];t.length||this.form.on("reset.ui-form-reset",this._formResetHandler),t.push(this),this.form.data("ui-form-reset-instances",t)}},_unbindFormResetHandler:function(){if(this.form.length){var e=this.form.data("ui-form-reset-instances");e.splice(t.inArray(this,e),1),e.length?this.form.data("ui-form-reset-instances",e):this.form.removeData("ui-form-reset-instances").off("reset.ui-form-reset")}}},"1.7"===t.fn.jquery.substring(0,3)&&(t.each(["Width","Height"],function(e,i){function s(e,i,s,o){return t.each(n,function(){i-=parseFloat(t.css(e,"padding"+this))||0,s&&(i-=parseFloat(t.css(e,"border"+this+"Width"))||0),o&&(i-=parseFloat(t.css(e,"margin"+this))||0)}),i}var n="Width"===i?["Left","Right"]:["Top","Bottom"],o=i.toLowerCase(),a={innerWidth:t.fn.innerWidth,innerHeight:t.fn.innerHeight,outerWidth:t.fn.outerWidth,outerHeight:t.fn.outerHeight};t.fn["inner"+i]=function(e){return void 0===e?a["inner"+i].call(this):this.each(function(){t(this).css(o,s(this,e)+"px")})},t.fn["outer"+i]=function(e,n){return"number"!=typeof e?a["outer"+i].call(this,e):this.each(function(){t(this).css(o,s(this,e,!0,n)+"px")})}}),t.fn.addBack=function(t){return this.add(null==t?this.prevObject:this.prevObject.filter(t))}),t.ui.keyCode={BACKSPACE:8,COMMA:188,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,LEFT:37,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SPACE:32,TAB:9,UP:38},t.ui.escapeSelector=function(){var t=/([!"#$%&'()*+,./:;<=>?@[\]^`{|}~])/g;return function(e){return e.replace(t,"\\$1")}}(),t.fn.labels=function(){var e,i,s,n,o;return this[0].labels&&this[0].labels.length?this.pushStack(this[0].labels):(n=this.eq(0).parents("label"),s=this.attr("id"),s&&(e=this.eq(0).parents().last(),o=e.add(e.length?e.siblings():this.siblings()),i="label[for='"+t.ui.escapeSelector(s)+"']",n=n.add(o.find(i).addBack(i))),this.pushStack(n))},t.fn.scrollParent=function(e){var i=this.css("position"),s="absolute"===i,n=e?/(auto|scroll|hidden)/:/(auto|scroll)/,o=this.parents().filter(function(){var e=t(this);return s&&"static"===e.css("position")?!1:n.test(e.css("overflow")+e.css("overflow-y")+e.css("overflow-x"))}).eq(0);return"fixed"!==i&&o.length?o:t(this[0].ownerDocument||document)},t.extend(t.expr[":"],{tabbable:function(e){var i=t.attr(e,"tabindex"),s=null!=i;return(!s||i>=0)&&t.ui.focusable(e,s)}}),t.fn.extend({uniqueId:function(){var t=0;return function(){return this.each(function(){this.id||(this.id="ui-id-"+ ++t)})}}(),removeUniqueId:function(){return this.each(function(){/^ui-id-\d+$/.test(this.id)&&t(this).removeAttr("id")})}}),t.ui.ie=!!/msie [\w.]+/.exec(navigator.userAgent.toLowerCase());var n=!1;t(document).on("mouseup",function(){n=!1}),t.widget("ui.mouse",{version:"1.12.1",options:{cancel:"input, textarea, button, select, option",distance:1,delay:0},_mouseInit:function(){var e=this;this.element.on("mousedown."+this.widgetName,function(t){return e._mouseDown(t)}).on("click."+this.widgetName,function(i){return!0===t.data(i.target,e.widgetName+".preventClickEvent")?(t.removeData(i.target,e.widgetName+".preventClickEvent"),i.stopImmediatePropagation(),!1):void 0}),this.started=!1},_mouseDestroy:function(){this.element.off("."+this.widgetName),this._mouseMoveDelegate&&this.document.off("mousemove."+this.widgetName,this._mouseMoveDelegate).off("mouseup."+this.widgetName,this._mouseUpDelegate)},_mouseDown:function(e){if(!n){this._mouseMoved=!1,this._mouseStarted&&this._mouseUp(e),this._mouseDownEvent=e;var i=this,s=1===e.which,o="string"==typeof this.options.cancel&&e.target.nodeName?t(e.target).closest(this.options.cancel).length:!1;return s&&!o&&this._mouseCapture(e)?(this.mouseDelayMet=!this.options.delay,this.mouseDelayMet||(this._mouseDelayTimer=setTimeout(function(){i.mouseDelayMet=!0},this.options.delay)),this._mouseDistanceMet(e)&&this._mouseDelayMet(e)&&(this._mouseStarted=this._mouseStart(e)!==!1,!this._mouseStarted)?(e.preventDefault(),!0):(!0===t.data(e.target,this.widgetName+".preventClickEvent")&&t.removeData(e.target,this.widgetName+".preventClickEvent"),this._mouseMoveDelegate=function(t){return i._mouseMove(t)},this._mouseUpDelegate=function(t){return i._mouseUp(t)},this.document.on("mousemove."+this.widgetName,this._mouseMoveDelegate).on("mouseup."+this.widgetName,this._mouseUpDelegate),e.preventDefault(),n=!0,!0)):!0}},_mouseMove:function(e){if(this._mouseMoved){if(t.ui.ie&&(!document.documentMode||9>document.documentMode)&&!e.button)return this._mouseUp(e);if(!e.which)if(e.originalEvent.altKey||e.originalEvent.ctrlKey||e.originalEvent.metaKey||e.originalEvent.shiftKey)this.ignoreMissingWhich=!0;else if(!this.ignoreMissingWhich)return this._mouseUp(e)}return(e.which||e.button)&&(this._mouseMoved=!0),this._mouseStarted?(this._mouseDrag(e),e.preventDefault()):(this._mouseDistanceMet(e)&&this._mouseDelayMet(e)&&(this._mouseStarted=this._mouseStart(this._mouseDownEvent,e)!==!1,this._mouseStarted?this._mouseDrag(e):this._mouseUp(e)),!this._mouseStarted)},_mouseUp:function(e){this.document.off("mousemove."+this.widgetName,this._mouseMoveDelegate).off("mouseup."+this.widgetName,this._mouseUpDelegate),this._mouseStarted&&(this._mouseStarted=!1,e.target===this._mouseDownEvent.target&&t.data(e.target,this.widgetName+".preventClickEvent",!0),this._mouseStop(e)),this._mouseDelayTimer&&(clearTimeout(this._mouseDelayTimer),delete this._mouseDelayTimer),this.ignoreMissingWhich=!1,n=!1,e.preventDefault()},_mouseDistanceMet:function(t){return Math.max(Math.abs(this._mouseDownEvent.pageX-t.pageX),Math.abs(this._mouseDownEvent.pageY-t.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return!0}}),t.ui.plugin={add:function(e,i,s){var n,o=t.ui[e].prototype;for(n in s)o.plugins[n]=o.plugins[n]||[],o.plugins[n].push([i,s[n]])},call:function(t,e,i,s){var n,o=t.plugins[e];if(o&&(s||t.element[0].parentNode&&11!==t.element[0].parentNode.nodeType))for(n=0;o.length>n;n++)t.options[o[n][0]]&&o[n][1].apply(t.element,i)}},t.widget("ui.resizable",t.ui.mouse,{version:"1.12.1",widgetEventPrefix:"resize",options:{alsoResize:!1,animate:!1,animateDuration:"slow",animateEasing:"swing",aspectRatio:!1,autoHide:!1,classes:{"ui-resizable-se":"ui-icon ui-icon-gripsmall-diagonal-se"},containment:!1,ghost:!1,grid:!1,handles:"e,s,se",helper:!1,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:90,resize:null,start:null,stop:null},_num:function(t){return parseFloat(t)||0},_isNumber:function(t){return!isNaN(parseFloat(t))},_hasScroll:function(e,i){if("hidden"===t(e).css("overflow"))return!1;var s=i&&"left"===i?"scrollLeft":"scrollTop",n=!1;return e[s]>0?!0:(e[s]=1,n=e[s]>0,e[s]=0,n)},_create:function(){var e,i=this.options,s=this;this._addClass("ui-resizable"),t.extend(this,{_aspectRatio:!!i.aspectRatio,aspectRatio:i.aspectRatio,originalElement:this.element,_proportionallyResizeElements:[],_helper:i.helper||i.ghost||i.animate?i.helper||"ui-resizable-helper":null}),this.element[0].nodeName.match(/^(canvas|textarea|input|select|button|img)$/i)&&(this.element.wrap(t("
    ").css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")})),this.element=this.element.parent().data("ui-resizable",this.element.resizable("instance")),this.elementIsWrapper=!0,e={marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom"),marginLeft:this.originalElement.css("marginLeft")},this.element.css(e),this.originalElement.css("margin",0),this.originalResizeStyle=this.originalElement.css("resize"),this.originalElement.css("resize","none"),this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"})),this.originalElement.css(e),this._proportionallyResize()),this._setupHandles(),i.autoHide&&t(this.element).on("mouseenter",function(){i.disabled||(s._removeClass("ui-resizable-autohide"),s._handles.show())}).on("mouseleave",function(){i.disabled||s.resizing||(s._addClass("ui-resizable-autohide"),s._handles.hide())}),this._mouseInit()},_destroy:function(){this._mouseDestroy();var e,i=function(e){t(e).removeData("resizable").removeData("ui-resizable").off(".resizable").find(".ui-resizable-handle").remove()};return this.elementIsWrapper&&(i(this.element),e=this.element,this.originalElement.css({position:e.css("position"),width:e.outerWidth(),height:e.outerHeight(),top:e.css("top"),left:e.css("left")}).insertAfter(e),e.remove()),this.originalElement.css("resize",this.originalResizeStyle),i(this.originalElement),this},_setOption:function(t,e){switch(this._super(t,e),t){case"handles":this._removeHandles(),this._setupHandles();break;default:}},_setupHandles:function(){var e,i,s,n,o,a=this.options,r=this;if(this.handles=a.handles||(t(".ui-resizable-handle",this.element).length?{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"}:"e,s,se"),this._handles=t(),this.handles.constructor===String)for("all"===this.handles&&(this.handles="n,e,s,w,se,sw,ne,nw"),s=this.handles.split(","),this.handles={},i=0;s.length>i;i++)e=t.trim(s[i]),n="ui-resizable-"+e,o=t("
    "),this._addClass(o,"ui-resizable-handle "+n),o.css({zIndex:a.zIndex}),this.handles[e]=".ui-resizable-"+e,this.element.append(o);this._renderAxis=function(e){var i,s,n,o;e=e||this.element;for(i in this.handles)this.handles[i].constructor===String?this.handles[i]=this.element.children(this.handles[i]).first().show():(this.handles[i].jquery||this.handles[i].nodeType)&&(this.handles[i]=t(this.handles[i]),this._on(this.handles[i],{mousedown:r._mouseDown})),this.elementIsWrapper&&this.originalElement[0].nodeName.match(/^(textarea|input|select|button)$/i)&&(s=t(this.handles[i],this.element),o=/sw|ne|nw|se|n|s/.test(i)?s.outerHeight():s.outerWidth(),n=["padding",/ne|nw|n/.test(i)?"Top":/se|sw|s/.test(i)?"Bottom":/^e$/.test(i)?"Right":"Left"].join(""),e.css(n,o),this._proportionallyResize()),this._handles=this._handles.add(this.handles[i])},this._renderAxis(this.element),this._handles=this._handles.add(this.element.find(".ui-resizable-handle")),this._handles.disableSelection(),this._handles.on("mouseover",function(){r.resizing||(this.className&&(o=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i)),r.axis=o&&o[1]?o[1]:"se")}),a.autoHide&&(this._handles.hide(),this._addClass("ui-resizable-autohide"))},_removeHandles:function(){this._handles.remove()},_mouseCapture:function(e){var i,s,n=!1;for(i in this.handles)s=t(this.handles[i])[0],(s===e.target||t.contains(s,e.target))&&(n=!0);return!this.options.disabled&&n},_mouseStart:function(e){var i,s,n,o=this.options,a=this.element;return this.resizing=!0,this._renderProxy(),i=this._num(this.helper.css("left")),s=this._num(this.helper.css("top")),o.containment&&(i+=t(o.containment).scrollLeft()||0,s+=t(o.containment).scrollTop()||0),this.offset=this.helper.offset(),this.position={left:i,top:s},this.size=this._helper?{width:this.helper.width(),height:this.helper.height()}:{width:a.width(),height:a.height()},this.originalSize=this._helper?{width:a.outerWidth(),height:a.outerHeight()}:{width:a.width(),height:a.height()},this.sizeDiff={width:a.outerWidth()-a.width(),height:a.outerHeight()-a.height()},this.originalPosition={left:i,top:s},this.originalMousePosition={left:e.pageX,top:e.pageY},this.aspectRatio="number"==typeof o.aspectRatio?o.aspectRatio:this.originalSize.width/this.originalSize.height||1,n=t(".ui-resizable-"+this.axis).css("cursor"),t("body").css("cursor","auto"===n?this.axis+"-resize":n),this._addClass("ui-resizable-resizing"),this._propagate("start",e),!0},_mouseDrag:function(e){var i,s,n=this.originalMousePosition,o=this.axis,a=e.pageX-n.left||0,r=e.pageY-n.top||0,h=this._change[o];return this._updatePrevProperties(),h?(i=h.apply(this,[e,a,r]),this._updateVirtualBoundaries(e.shiftKey),(this._aspectRatio||e.shiftKey)&&(i=this._updateRatio(i,e)),i=this._respectSize(i,e),this._updateCache(i),this._propagate("resize",e),s=this._applyChanges(),!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize(),t.isEmptyObject(s)||(this._updatePrevProperties(),this._trigger("resize",e,this.ui()),this._applyChanges()),!1):!1},_mouseStop:function(e){this.resizing=!1;var i,s,n,o,a,r,h,l=this.options,c=this;return this._helper&&(i=this._proportionallyResizeElements,s=i.length&&/textarea/i.test(i[0].nodeName),n=s&&this._hasScroll(i[0],"left")?0:c.sizeDiff.height,o=s?0:c.sizeDiff.width,a={width:c.helper.width()-o,height:c.helper.height()-n},r=parseFloat(c.element.css("left"))+(c.position.left-c.originalPosition.left)||null,h=parseFloat(c.element.css("top"))+(c.position.top-c.originalPosition.top)||null,l.animate||this.element.css(t.extend(a,{top:h,left:r})),c.helper.height(c.size.height),c.helper.width(c.size.width),this._helper&&!l.animate&&this._proportionallyResize()),t("body").css("cursor","auto"),this._removeClass("ui-resizable-resizing"),this._propagate("stop",e),this._helper&&this.helper.remove(),!1},_updatePrevProperties:function(){this.prevPosition={top:this.position.top,left:this.position.left},this.prevSize={width:this.size.width,height:this.size.height}},_applyChanges:function(){var t={};return this.position.top!==this.prevPosition.top&&(t.top=this.position.top+"px"),this.position.left!==this.prevPosition.left&&(t.left=this.position.left+"px"),this.size.width!==this.prevSize.width&&(t.width=this.size.width+"px"),this.size.height!==this.prevSize.height&&(t.height=this.size.height+"px"),this.helper.css(t),t},_updateVirtualBoundaries:function(t){var e,i,s,n,o,a=this.options;o={minWidth:this._isNumber(a.minWidth)?a.minWidth:0,maxWidth:this._isNumber(a.maxWidth)?a.maxWidth:1/0,minHeight:this._isNumber(a.minHeight)?a.minHeight:0,maxHeight:this._isNumber(a.maxHeight)?a.maxHeight:1/0},(this._aspectRatio||t)&&(e=o.minHeight*this.aspectRatio,s=o.minWidth/this.aspectRatio,i=o.maxHeight*this.aspectRatio,n=o.maxWidth/this.aspectRatio,e>o.minWidth&&(o.minWidth=e),s>o.minHeight&&(o.minHeight=s),o.maxWidth>i&&(o.maxWidth=i),o.maxHeight>n&&(o.maxHeight=n)),this._vBoundaries=o},_updateCache:function(t){this.offset=this.helper.offset(),this._isNumber(t.left)&&(this.position.left=t.left),this._isNumber(t.top)&&(this.position.top=t.top),this._isNumber(t.height)&&(this.size.height=t.height),this._isNumber(t.width)&&(this.size.width=t.width)},_updateRatio:function(t){var e=this.position,i=this.size,s=this.axis;return this._isNumber(t.height)?t.width=t.height*this.aspectRatio:this._isNumber(t.width)&&(t.height=t.width/this.aspectRatio),"sw"===s&&(t.left=e.left+(i.width-t.width),t.top=null),"nw"===s&&(t.top=e.top+(i.height-t.height),t.left=e.left+(i.width-t.width)),t},_respectSize:function(t){var e=this._vBoundaries,i=this.axis,s=this._isNumber(t.width)&&e.maxWidth&&e.maxWidtht.width,a=this._isNumber(t.height)&&e.minHeight&&e.minHeight>t.height,r=this.originalPosition.left+this.originalSize.width,h=this.originalPosition.top+this.originalSize.height,l=/sw|nw|w/.test(i),c=/nw|ne|n/.test(i);return o&&(t.width=e.minWidth),a&&(t.height=e.minHeight),s&&(t.width=e.maxWidth),n&&(t.height=e.maxHeight),o&&l&&(t.left=r-e.minWidth),s&&l&&(t.left=r-e.maxWidth),a&&c&&(t.top=h-e.minHeight),n&&c&&(t.top=h-e.maxHeight),t.width||t.height||t.left||!t.top?t.width||t.height||t.top||!t.left||(t.left=null):t.top=null,t},_getPaddingPlusBorderDimensions:function(t){for(var e=0,i=[],s=[t.css("borderTopWidth"),t.css("borderRightWidth"),t.css("borderBottomWidth"),t.css("borderLeftWidth")],n=[t.css("paddingTop"),t.css("paddingRight"),t.css("paddingBottom"),t.css("paddingLeft")];4>e;e++)i[e]=parseFloat(s[e])||0,i[e]+=parseFloat(n[e])||0;return{height:i[0]+i[2],width:i[1]+i[3]}},_proportionallyResize:function(){if(this._proportionallyResizeElements.length)for(var t,e=0,i=this.helper||this.element;this._proportionallyResizeElements.length>e;e++)t=this._proportionallyResizeElements[e],this.outerDimensions||(this.outerDimensions=this._getPaddingPlusBorderDimensions(t)),t.css({height:i.height()-this.outerDimensions.height||0,width:i.width()-this.outerDimensions.width||0})},_renderProxy:function(){var e=this.element,i=this.options;this.elementOffset=e.offset(),this._helper?(this.helper=this.helper||t("
    "),this._addClass(this.helper,this._helper),this.helper.css({width:this.element.outerWidth(),height:this.element.outerHeight(),position:"absolute",left:this.elementOffset.left+"px",top:this.elementOffset.top+"px",zIndex:++i.zIndex}),this.helper.appendTo("body").disableSelection()):this.helper=this.element -},_change:{e:function(t,e){return{width:this.originalSize.width+e}},w:function(t,e){var i=this.originalSize,s=this.originalPosition;return{left:s.left+e,width:i.width-e}},n:function(t,e,i){var s=this.originalSize,n=this.originalPosition;return{top:n.top+i,height:s.height-i}},s:function(t,e,i){return{height:this.originalSize.height+i}},se:function(e,i,s){return t.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[e,i,s]))},sw:function(e,i,s){return t.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[e,i,s]))},ne:function(e,i,s){return t.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[e,i,s]))},nw:function(e,i,s){return t.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[e,i,s]))}},_propagate:function(e,i){t.ui.plugin.call(this,e,[i,this.ui()]),"resize"!==e&&this._trigger(e,i,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}}),t.ui.plugin.add("resizable","animate",{stop:function(e){var i=t(this).resizable("instance"),s=i.options,n=i._proportionallyResizeElements,o=n.length&&/textarea/i.test(n[0].nodeName),a=o&&i._hasScroll(n[0],"left")?0:i.sizeDiff.height,r=o?0:i.sizeDiff.width,h={width:i.size.width-r,height:i.size.height-a},l=parseFloat(i.element.css("left"))+(i.position.left-i.originalPosition.left)||null,c=parseFloat(i.element.css("top"))+(i.position.top-i.originalPosition.top)||null;i.element.animate(t.extend(h,c&&l?{top:c,left:l}:{}),{duration:s.animateDuration,easing:s.animateEasing,step:function(){var s={width:parseFloat(i.element.css("width")),height:parseFloat(i.element.css("height")),top:parseFloat(i.element.css("top")),left:parseFloat(i.element.css("left"))};n&&n.length&&t(n[0]).css({width:s.width,height:s.height}),i._updateCache(s),i._propagate("resize",e)}})}}),t.ui.plugin.add("resizable","containment",{start:function(){var e,i,s,n,o,a,r,h=t(this).resizable("instance"),l=h.options,c=h.element,u=l.containment,d=u instanceof t?u.get(0):/parent/.test(u)?c.parent().get(0):u;d&&(h.containerElement=t(d),/document/.test(u)||u===document?(h.containerOffset={left:0,top:0},h.containerPosition={left:0,top:0},h.parentData={element:t(document),left:0,top:0,width:t(document).width(),height:t(document).height()||document.body.parentNode.scrollHeight}):(e=t(d),i=[],t(["Top","Right","Left","Bottom"]).each(function(t,s){i[t]=h._num(e.css("padding"+s))}),h.containerOffset=e.offset(),h.containerPosition=e.position(),h.containerSize={height:e.innerHeight()-i[3],width:e.innerWidth()-i[1]},s=h.containerOffset,n=h.containerSize.height,o=h.containerSize.width,a=h._hasScroll(d,"left")?d.scrollWidth:o,r=h._hasScroll(d)?d.scrollHeight:n,h.parentData={element:d,left:s.left,top:s.top,width:a,height:r}))},resize:function(e){var i,s,n,o,a=t(this).resizable("instance"),r=a.options,h=a.containerOffset,l=a.position,c=a._aspectRatio||e.shiftKey,u={top:0,left:0},d=a.containerElement,p=!0;d[0]!==document&&/static/.test(d.css("position"))&&(u=h),l.left<(a._helper?h.left:0)&&(a.size.width=a.size.width+(a._helper?a.position.left-h.left:a.position.left-u.left),c&&(a.size.height=a.size.width/a.aspectRatio,p=!1),a.position.left=r.helper?h.left:0),l.top<(a._helper?h.top:0)&&(a.size.height=a.size.height+(a._helper?a.position.top-h.top:a.position.top),c&&(a.size.width=a.size.height*a.aspectRatio,p=!1),a.position.top=a._helper?h.top:0),n=a.containerElement.get(0)===a.element.parent().get(0),o=/relative|absolute/.test(a.containerElement.css("position")),n&&o?(a.offset.left=a.parentData.left+a.position.left,a.offset.top=a.parentData.top+a.position.top):(a.offset.left=a.element.offset().left,a.offset.top=a.element.offset().top),i=Math.abs(a.sizeDiff.width+(a._helper?a.offset.left-u.left:a.offset.left-h.left)),s=Math.abs(a.sizeDiff.height+(a._helper?a.offset.top-u.top:a.offset.top-h.top)),i+a.size.width>=a.parentData.width&&(a.size.width=a.parentData.width-i,c&&(a.size.height=a.size.width/a.aspectRatio,p=!1)),s+a.size.height>=a.parentData.height&&(a.size.height=a.parentData.height-s,c&&(a.size.width=a.size.height*a.aspectRatio,p=!1)),p||(a.position.left=a.prevPosition.left,a.position.top=a.prevPosition.top,a.size.width=a.prevSize.width,a.size.height=a.prevSize.height)},stop:function(){var e=t(this).resizable("instance"),i=e.options,s=e.containerOffset,n=e.containerPosition,o=e.containerElement,a=t(e.helper),r=a.offset(),h=a.outerWidth()-e.sizeDiff.width,l=a.outerHeight()-e.sizeDiff.height;e._helper&&!i.animate&&/relative/.test(o.css("position"))&&t(this).css({left:r.left-n.left-s.left,width:h,height:l}),e._helper&&!i.animate&&/static/.test(o.css("position"))&&t(this).css({left:r.left-n.left-s.left,width:h,height:l})}}),t.ui.plugin.add("resizable","alsoResize",{start:function(){var e=t(this).resizable("instance"),i=e.options;t(i.alsoResize).each(function(){var e=t(this);e.data("ui-resizable-alsoresize",{width:parseFloat(e.width()),height:parseFloat(e.height()),left:parseFloat(e.css("left")),top:parseFloat(e.css("top"))})})},resize:function(e,i){var s=t(this).resizable("instance"),n=s.options,o=s.originalSize,a=s.originalPosition,r={height:s.size.height-o.height||0,width:s.size.width-o.width||0,top:s.position.top-a.top||0,left:s.position.left-a.left||0};t(n.alsoResize).each(function(){var e=t(this),s=t(this).data("ui-resizable-alsoresize"),n={},o=e.parents(i.originalElement[0]).length?["width","height"]:["width","height","top","left"];t.each(o,function(t,e){var i=(s[e]||0)+(r[e]||0);i&&i>=0&&(n[e]=i||null)}),e.css(n)})},stop:function(){t(this).removeData("ui-resizable-alsoresize")}}),t.ui.plugin.add("resizable","ghost",{start:function(){var e=t(this).resizable("instance"),i=e.size;e.ghost=e.originalElement.clone(),e.ghost.css({opacity:.25,display:"block",position:"relative",height:i.height,width:i.width,margin:0,left:0,top:0}),e._addClass(e.ghost,"ui-resizable-ghost"),t.uiBackCompat!==!1&&"string"==typeof e.options.ghost&&e.ghost.addClass(this.options.ghost),e.ghost.appendTo(e.helper)},resize:function(){var e=t(this).resizable("instance");e.ghost&&e.ghost.css({position:"relative",height:e.size.height,width:e.size.width})},stop:function(){var e=t(this).resizable("instance");e.ghost&&e.helper&&e.helper.get(0).removeChild(e.ghost.get(0))}}),t.ui.plugin.add("resizable","grid",{resize:function(){var e,i=t(this).resizable("instance"),s=i.options,n=i.size,o=i.originalSize,a=i.originalPosition,r=i.axis,h="number"==typeof s.grid?[s.grid,s.grid]:s.grid,l=h[0]||1,c=h[1]||1,u=Math.round((n.width-o.width)/l)*l,d=Math.round((n.height-o.height)/c)*c,p=o.width+u,f=o.height+d,m=s.maxWidth&&p>s.maxWidth,g=s.maxHeight&&f>s.maxHeight,_=s.minWidth&&s.minWidth>p,v=s.minHeight&&s.minHeight>f;s.grid=h,_&&(p+=l),v&&(f+=c),m&&(p-=l),g&&(f-=c),/^(se|s|e)$/.test(r)?(i.size.width=p,i.size.height=f):/^(ne)$/.test(r)?(i.size.width=p,i.size.height=f,i.position.top=a.top-d):/^(sw)$/.test(r)?(i.size.width=p,i.size.height=f,i.position.left=a.left-u):((0>=f-c||0>=p-l)&&(e=i._getPaddingPlusBorderDimensions(this)),f-c>0?(i.size.height=f,i.position.top=a.top-d):(f=c-e.height,i.size.height=f,i.position.top=a.top+o.height-f),p-l>0?(i.size.width=p,i.position.left=a.left-u):(p=l-e.width,i.size.width=p,i.position.left=a.left+o.width-p))}}),t.ui.resizable});/** +* Includes: widget.js, position.js, data.js, disable-selection.js, focusable.js, form-reset-mixin.js, jquery-patch.js, keycode.js, labels.js, scroll-parent.js, tabbable.js, unique-id.js, widgets/resizable.js, widgets/mouse.js +* Copyright jQuery Foundation and other contributors; Licensed MIT */!function(t){"use strict";"function"==typeof define&&define.amd?define(["jquery"],t):t(jQuery)}(function(y){"use strict";y.ui=y.ui||{};y.ui.version="1.13.2";var n,i=0,h=Array.prototype.hasOwnProperty,a=Array.prototype.slice;y.cleanData=(n=y.cleanData,function(t){for(var e,i,s=0;null!=(i=t[s]);s++)(e=y._data(i,"events"))&&e.remove&&y(i).triggerHandler("remove");n(t)}),y.widget=function(t,i,e){var s,n,o,h={},a=t.split(".")[0],r=a+"-"+(t=t.split(".")[1]);return e||(e=i,i=y.Widget),Array.isArray(e)&&(e=y.extend.apply(null,[{}].concat(e))),y.expr.pseudos[r.toLowerCase()]=function(t){return!!y.data(t,r)},y[a]=y[a]||{},s=y[a][t],n=y[a][t]=function(t,e){if(!this||!this._createWidget)return new n(t,e);arguments.length&&this._createWidget(t,e)},y.extend(n,s,{version:e.version,_proto:y.extend({},e),_childConstructors:[]}),(o=new i).options=y.widget.extend({},o.options),y.each(e,function(e,s){function n(){return i.prototype[e].apply(this,arguments)} +function o(t){return i.prototype[e].apply(this,t)}h[e]="function"==typeof s?function(){var t,e=this._super,i=this._superApply;return this._super=n,this._superApply=o,t=s.apply(this,arguments),this._super=e,this._superApply=i,t}:s}),n.prototype=y.widget.extend(o,{widgetEventPrefix:s&&o.widgetEventPrefix||t},h,{constructor:n,namespace:a,widgetName:t,widgetFullName:r}),s?(y.each(s._childConstructors,function(t,e){var i=e.prototype;y.widget(i.namespace+"."+i.widgetName,n,e._proto)}),delete s._childConstructors):i._childConstructors.push(n),y.widget.bridge(t,n),n},y.widget.extend=function(t){for(var e,i,s=a.call(arguments,1),n=0,o=s.length;n",options:{classes:{},disabled:!1,create:null},_createWidget:function(t,e){e=y(e||this.defaultElement||this)[0],this.element=y(e),this.uuid=i++,this.eventNamespace="."+this.widgetName+this.uuid,this.bindings=y(),this.hoverable=y(),this.focusable=y(),this.classesElementLookup={},e!==this&&(y.data(e,this.widgetFullName,this),this._on(!0,this.element,{remove:function(t +){t.target===e&&this.destroy()}}),this.document=y(e.style?e.ownerDocument:e.document||e),this.window=y(this.document[0].defaultView||this.document[0].parentWindow)),this.options=y.widget.extend({},this.options,this._getCreateOptions(),t),this._create(),this.options.disabled&&this._setOptionDisabled(this.options.disabled),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:function(){return{}},_getCreateEventData:y.noop,_create:y.noop,_init:y.noop,destroy:function(){var i=this;this._destroy(),y.each(this.classesElementLookup,function(t,e){i._removeClass(e,t)}),this.element.off(this.eventNamespace).removeData(this.widgetFullName),this.widget().off(this.eventNamespace).removeAttr("aria-disabled"),this.bindings.off(this.eventNamespace)},_destroy:y.noop,widget:function(){return this.element},option:function(t,e){var i,s,n,o=t;if(0===arguments.length)return y.widget.extend({},this.options);if("string"==typeof t)if(o={},t=(i=t.split(".")).shift(),i.length){for(s=o[t +]=y.widget.extend({},this.options[t]),n=0;n
    "),i=e.children()[0];return y("body").append(e),t=i.offsetWidth,e.css("overflow","scroll"),t===(i=i.offsetWidth)&&(i=e[0].clientWidth),e.remove(),s=t-i}, +getScrollInfo:function(t){var e=t.isWindow||t.isDocument?"":t.element.css("overflow-x"),i=t.isWindow||t.isDocument?"":t.element.css("overflow-y"),e="scroll"===e||"auto"===e&&t.widthx(D(s),D(n))?o.important="horizontal":o.important="vertical",p.using.call(this,t,o)}),h.offset(y.extend(l,{using:t}))})},y.ui.position={fit:{left:function(t,e){var i=e.within, +s=i.isWindow?i.scrollLeft:i.offset.left,n=i.width,o=t.left-e.collisionPosition.marginLeft,h=s-o,a=o+e.collisionWidth-n-s;e.collisionWidth>n?0n?0=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return!0}}),y.ui.plugin={add:function(t,e,i){var s,n=y.ui[t].prototype;for(s in i)n.plugins[s]=n.plugins[s]||[],n.plugins[s].push([e,i[s]])},call:function(t,e,i,s){var n,o=t.plugins[e];if(o&&(s||t.element[0].parentNode&&11!==t.element[0].parentNode.nodeType))for(n=0;n
    ").css({overflow:"hidden",position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")})), +this.element=this.element.parent().data("ui-resizable",this.element.resizable("instance")),this.elementIsWrapper=!0,t={marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom"),marginLeft:this.originalElement.css("marginLeft")},this.element.css(t),this.originalElement.css("margin",0),this.originalResizeStyle=this.originalElement.css("resize"),this.originalElement.css("resize","none"),this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"})),this.originalElement.css(t),this._proportionallyResize()),this._setupHandles(),e.autoHide&&y(this.element).on("mouseenter",function(){e.disabled||(i._removeClass("ui-resizable-autohide"),i._handles.show())}).on("mouseleave",function(){e.disabled||i.resizing||(i._addClass("ui-resizable-autohide"),i._handles.hide())}),this._mouseInit()},_destroy:function(){this._mouseDestroy(),this._addedHandles.remove();function t(t){y(t +).removeData("resizable").removeData("ui-resizable").off(".resizable")}var e;return this.elementIsWrapper&&(t(this.element),e=this.element,this.originalElement.css({position:e.css("position"),width:e.outerWidth(),height:e.outerHeight(),top:e.css("top"),left:e.css("left")}).insertAfter(e),e.remove()),this.originalElement.css("resize",this.originalResizeStyle),t(this.originalElement),this},_setOption:function(t,e){switch(this._super(t,e),t){case"handles":this._removeHandles(),this._setupHandles();break;case"aspectRatio":this._aspectRatio=!!e}},_setupHandles:function(){var t,e,i,s,n,o=this.options,h=this;if(this.handles=o.handles||(y(".ui-resizable-handle",this.element).length?{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"}:"e,s,se"),this._handles=y(),this._addedHandles=y(),this.handles.constructor===String)for("all"===this.handles&&(this.handles="n,e,s,w,se,sw,ne,nw"),i=this.handles.split( +","),this.handles={},e=0;e"),this._addClass(n,"ui-resizable-handle "+s),n.css({zIndex:o.zIndex}),this.handles[t]=".ui-resizable-"+t,this.element.children(this.handles[t]).length||(this.element.append(n),this._addedHandles=this._addedHandles.add(n));this._renderAxis=function(t){var e,i,s;for(e in t=t||this.element,this.handles)this.handles[e].constructor===String?this.handles[e]=this.element.children(this.handles[e]).first().show():(this.handles[e].jquery||this.handles[e].nodeType)&&(this.handles[e]=y(this.handles[e]),this._on(this.handles[e],{mousedown:h._mouseDown})),this.elementIsWrapper&&this.originalElement[0].nodeName.match(/^(textarea|input|select|button)$/i)&&(i=y(this.handles[e],this.element),s=/sw|ne|nw|se|n|s/.test(e)?i.outerHeight():i.outerWidth(),i=["padding",/ne|nw|n/.test(e)?"Top":/se|sw|s/.test(e)?"Bottom":/^e$/.test(e)?"Right":"Left"].join(""),t.css(i,s),this._proportionallyResize()),this._handles=this._handles.add( +this.handles[e])},this._renderAxis(this.element),this._handles=this._handles.add(this.element.find(".ui-resizable-handle")),this._handles.disableSelection(),this._handles.on("mouseover",function(){h.resizing||(this.className&&(n=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i)),h.axis=n&&n[1]?n[1]:"se")}),o.autoHide&&(this._handles.hide(),this._addClass("ui-resizable-autohide"))},_removeHandles:function(){this._addedHandles.remove()},_mouseCapture:function(t){var e,i,s=!1;for(e in this.handles)(i=y(this.handles[e])[0])!==t.target&&!y.contains(i,t.target)||(s=!0);return!this.options.disabled&&s},_mouseStart:function(t){var e,i,s=this.options,n=this.element;return this.resizing=!0,this._renderProxy(),e=this._num(this.helper.css("left")),i=this._num(this.helper.css("top")),s.containment&&(e+=y(s.containment).scrollLeft()||0,i+=y(s.containment).scrollTop()||0),this.offset=this.helper.offset(),this.position={left:e,top:i},this.size=this._helper?{width:this.helper.width(),height:this.helper.height()}:{ +width:n.width(),height:n.height()},this.originalSize=this._helper?{width:n.outerWidth(),height:n.outerHeight()}:{width:n.width(),height:n.height()},this.sizeDiff={width:n.outerWidth()-n.width(),height:n.outerHeight()-n.height()},this.originalPosition={left:e,top:i},this.originalMousePosition={left:t.pageX,top:t.pageY},this.aspectRatio="number"==typeof s.aspectRatio?s.aspectRatio:this.originalSize.width/this.originalSize.height||1,s=y(".ui-resizable-"+this.axis).css("cursor"),y("body").css("cursor","auto"===s?this.axis+"-resize":s),this._addClass("ui-resizable-resizing"),this._propagate("start",t),!0},_mouseDrag:function(t){var e=this.originalMousePosition,i=this.axis,s=t.pageX-e.left||0,e=t.pageY-e.top||0,i=this._change[i];return this._updatePrevProperties(),i&&(e=i.apply(this,[t,s,e]),this._updateVirtualBoundaries(t.shiftKey),(this._aspectRatio||t.shiftKey)&&(e=this._updateRatio(e,t)),e=this._respectSize(e,t),this._updateCache(e),this._propagate("resize",t),e=this._applyChanges(), +!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize(),y.isEmptyObject(e)||(this._updatePrevProperties(),this._trigger("resize",t,this.ui()),this._applyChanges())),!1},_mouseStop:function(t){this.resizing=!1;var e,i,s,n=this.options,o=this;return this._helper&&(s=(e=(i=this._proportionallyResizeElements).length&&/textarea/i.test(i[0].nodeName))&&this._hasScroll(i[0],"left")?0:o.sizeDiff.height,i=e?0:o.sizeDiff.width,e={width:o.helper.width()-i,height:o.helper.height()-s},i=parseFloat(o.element.css("left"))+(o.position.left-o.originalPosition.left)||null,s=parseFloat(o.element.css("top"))+(o.position.top-o.originalPosition.top)||null,n.animate||this.element.css(y.extend(e,{top:s,left:i})),o.helper.height(o.size.height),o.helper.width(o.size.width),this._helper&&!n.animate&&this._proportionallyResize()),y("body").css("cursor","auto"),this._removeClass("ui-resizable-resizing"),this._propagate("stop",t),this._helper&&this.helper.remove(),!1},_updatePrevProperties:function(){ +this.prevPosition={top:this.position.top,left:this.position.left},this.prevSize={width:this.size.width,height:this.size.height}},_applyChanges:function(){var t={};return this.position.top!==this.prevPosition.top&&(t.top=this.position.top+"px"),this.position.left!==this.prevPosition.left&&(t.left=this.position.left+"px"),this.size.width!==this.prevSize.width&&(t.width=this.size.width+"px"),this.size.height!==this.prevSize.height&&(t.height=this.size.height+"px"),this.helper.css(t),t},_updateVirtualBoundaries:function(t){var e,i,s=this.options,n={minWidth:this._isNumber(s.minWidth)?s.minWidth:0,maxWidth:this._isNumber(s.maxWidth)?s.maxWidth:1/0,minHeight:this._isNumber(s.minHeight)?s.minHeight:0,maxHeight:this._isNumber(s.maxHeight)?s.maxHeight:1/0};(this._aspectRatio||t)&&(e=n.minHeight*this.aspectRatio,i=n.minWidth/this.aspectRatio,s=n.maxHeight*this.aspectRatio,t=n.maxWidth/this.aspectRatio,e>n.minWidth&&(n.minWidth=e),i>n.minHeight&&(n.minHeight=i),st.width,h=this._isNumber(t.height)&&e.minHeight&&e.minHeight>t.height,a=this.originalPosition.left+this.originalSize.width,r=this.originalPosition.top+this.originalSize.height +,l=/sw|nw|w/.test(i),i=/nw|ne|n/.test(i);return o&&(t.width=e.minWidth),h&&(t.height=e.minHeight),s&&(t.width=e.maxWidth),n&&(t.height=e.maxHeight),o&&l&&(t.left=a-e.minWidth),s&&l&&(t.left=a-e.maxWidth),h&&i&&(t.top=r-e.minHeight),n&&i&&(t.top=r-e.maxHeight),t.width||t.height||t.left||!t.top?t.width||t.height||t.top||!t.left||(t.left=null):t.top=null,t},_getPaddingPlusBorderDimensions:function(t){for(var e=0,i=[],s=[t.css("borderTopWidth"),t.css("borderRightWidth"),t.css("borderBottomWidth"),t.css("borderLeftWidth")],n=[t.css("paddingTop"),t.css("paddingRight"),t.css("paddingBottom"),t.css("paddingLeft")];e<4;e++)i[e]=parseFloat(s[e])||0,i[e]+=parseFloat(n[e])||0;return{height:i[0]+i[2],width:i[1]+i[3]}},_proportionallyResize:function(){if(this._proportionallyResizeElements.length)for(var t,e=0,i=this.helper||this.element;e
    ").css({overflow:"hidden"}),this._addClass(this.helper,this._helper),this.helper.css({width:this.element.outerWidth(),height:this.element.outerHeight(),position:"absolute",left:this.elementOffset.left+"px",top:this.elementOffset.top+"px",zIndex:++e.zIndex}),this.helper.appendTo("body").disableSelection()):this.helper=this.element},_change:{e:function(t,e){return{width:this.originalSize.width+e}},w:function(t,e){var i=this.originalSize;return{left:this.originalPosition.left+e,width:i.width-e}},n:function(t,e,i){var s=this.originalSize;return{top:this.originalPosition.top+i,height:s.height-i}},s:function(t,e,i){return{height:this.originalSize.height+i}},se:function(t,e,i){return y.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[t,e,i]))},sw:function(t,e, +i){return y.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[t,e,i]))},ne:function(t,e,i){return y.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[t,e,i]))},nw:function(t,e,i){return y.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[t,e,i]))}},_propagate:function(t,e){y.ui.plugin.call(this,t,[e,this.ui()]),"resize"!==t&&this._trigger(t,e,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}}),y.ui.plugin.add("resizable","animate",{stop:function(e){var i=y(this).resizable("instance"),t=i.options,s=i._proportionallyResizeElements,n=s.length&&/textarea/i.test(s[0].nodeName),o=n&&i._hasScroll(s[0],"left")?0:i.sizeDiff.height,h=n?0:i.sizeDiff.width,n={width:i.size.width-h,height:i.size.height-o},h=parseFloat(i.element.css("left"))+(i.position.left-i.originalPosition.left +)||null,o=parseFloat(i.element.css("top"))+(i.position.top-i.originalPosition.top)||null;i.element.animate(y.extend(n,o&&h?{top:o,left:h}:{}),{duration:t.animateDuration,easing:t.animateEasing,step:function(){var t={width:parseFloat(i.element.css("width")),height:parseFloat(i.element.css("height")),top:parseFloat(i.element.css("top")),left:parseFloat(i.element.css("left"))};s&&s.length&&y(s[0]).css({width:t.width,height:t.height}),i._updateCache(t),i._propagate("resize",e)}})}}),y.ui.plugin.add("resizable","containment",{start:function(){var i,s,n=y(this).resizable("instance"),t=n.options,e=n.element,o=t.containment,h=o instanceof y?o.get(0):/parent/.test(o)?e.parent().get(0):o;h&&(n.containerElement=y(h),/document/.test(o)||o===document?(n.containerOffset={left:0,top:0},n.containerPosition={left:0,top:0},n.parentData={element:y(document),left:0,top:0,width:y(document).width(),height:y(document).height()||document.body.parentNode.scrollHeight}):(i=y(h),s=[],y(["Top","Right","Left","Bottom"]).each(function(t,e +){s[t]=n._num(i.css("padding"+e))}),n.containerOffset=i.offset(),n.containerPosition=i.position(),n.containerSize={height:i.innerHeight()-s[3],width:i.innerWidth()-s[1]},t=n.containerOffset,e=n.containerSize.height,o=n.containerSize.width,o=n._hasScroll(h,"left")?h.scrollWidth:o,e=n._hasScroll(h)?h.scrollHeight:e,n.parentData={element:h,left:t.left,top:t.top,width:o,height:e}))},resize:function(t){var e=y(this).resizable("instance"),i=e.options,s=e.containerOffset,n=e.position,o=e._aspectRatio||t.shiftKey,h={top:0,left:0},a=e.containerElement,t=!0;a[0]!==document&&/static/.test(a.css("position"))&&(h=s),n.left<(e._helper?s.left:0)&&(e.size.width=e.size.width+(e._helper?e.position.left-s.left:e.position.left-h.left),o&&(e.size.height=e.size.width/e.aspectRatio,t=!1),e.position.left=i.helper?s.left:0),n.top<(e._helper?s.top:0)&&(e.size.height=e.size.height+(e._helper?e.position.top-s.top:e.position.top),o&&(e.size.width=e.size.height*e.aspectRatio,t=!1),e.position.top=e._helper?s.top:0), +i=e.containerElement.get(0)===e.element.parent().get(0),n=/relative|absolute/.test(e.containerElement.css("position")),i&&n?(e.offset.left=e.parentData.left+e.position.left,e.offset.top=e.parentData.top+e.position.top):(e.offset.left=e.element.offset().left,e.offset.top=e.element.offset().top),n=Math.abs(e.sizeDiff.width+(e._helper?e.offset.left-h.left:e.offset.left-s.left)),s=Math.abs(e.sizeDiff.height+(e._helper?e.offset.top-h.top:e.offset.top-s.top)),n+e.size.width>=e.parentData.width&&(e.size.width=e.parentData.width-n,o&&(e.size.height=e.size.width/e.aspectRatio,t=!1)),s+e.size.height>=e.parentData.height&&(e.size.height=e.parentData.height-s,o&&(e.size.width=e.size.height*e.aspectRatio,t=!1)),t||(e.position.left=e.prevPosition.left,e.position.top=e.prevPosition.top,e.size.width=e.prevSize.width,e.size.height=e.prevSize.height)},stop:function(){var t=y(this).resizable("instance"),e=t.options,i=t.containerOffset,s=t.containerPosition,n=t.containerElement,o=y(t.helper),h=o.offset(),a=o.outerWidth( +)-t.sizeDiff.width,o=o.outerHeight()-t.sizeDiff.height;t._helper&&!e.animate&&/relative/.test(n.css("position"))&&y(this).css({left:h.left-s.left-i.left,width:a,height:o}),t._helper&&!e.animate&&/static/.test(n.css("position"))&&y(this).css({left:h.left-s.left-i.left,width:a,height:o})}}),y.ui.plugin.add("resizable","alsoResize",{start:function(){var t=y(this).resizable("instance").options;y(t.alsoResize).each(function(){var t=y(this);t.data("ui-resizable-alsoresize",{width:parseFloat(t.width()),height:parseFloat(t.height()),left:parseFloat(t.css("left")),top:parseFloat(t.css("top"))})})},resize:function(t,i){var e=y(this).resizable("instance"),s=e.options,n=e.originalSize,o=e.originalPosition,h={height:e.size.height-n.height||0,width:e.size.width-n.width||0,top:e.position.top-o.top||0,left:e.position.left-o.left||0};y(s.alsoResize).each(function(){var t=y(this),s=y(this).data("ui-resizable-alsoresize"),n={},e=t.parents(i.originalElement[0]).length?["width","height"]:["width","height","top","left"];y.each(e, +function(t,e){var i=(s[e]||0)+(h[e]||0);i&&0<=i&&(n[e]=i||null)}),t.css(n)})},stop:function(){y(this).removeData("ui-resizable-alsoresize")}}),y.ui.plugin.add("resizable","ghost",{start:function(){var t=y(this).resizable("instance"),e=t.size;t.ghost=t.originalElement.clone(),t.ghost.css({opacity:.25,display:"block",position:"relative",height:e.height,width:e.width,margin:0,left:0,top:0}),t._addClass(t.ghost,"ui-resizable-ghost"),!1!==y.uiBackCompat&&"string"==typeof t.options.ghost&&t.ghost.addClass(this.options.ghost),t.ghost.appendTo(t.helper)},resize:function(){var t=y(this).resizable("instance");t.ghost&&t.ghost.css({position:"relative",height:t.size.height,width:t.size.width})},stop:function(){var t=y(this).resizable("instance");t.ghost&&t.helper&&t.helper.get(0).removeChild(t.ghost.get(0))}}),y.ui.plugin.add("resizable","grid",{resize:function(){var t,e=y(this).resizable("instance"),i=e.options,s=e.size,n=e.originalSize,o=e.originalPosition,h=e.axis,a="number"==typeof i.grid?[i.grid,i.grid]:i.grid,r=a[0 +]||1,l=a[1]||1,u=Math.round((s.width-n.width)/r)*r,p=Math.round((s.height-n.height)/l)*l,d=n.width+u,c=n.height+p,f=i.maxWidth&&i.maxWidthd,s=i.minHeight&&i.minHeight>c;i.grid=a,m&&(d+=r),s&&(c+=l),f&&(d-=r),g&&(c-=l),/^(se|s|e)$/.test(h)?(e.size.width=d,e.size.height=c):/^(ne)$/.test(h)?(e.size.width=d,e.size.height=c,e.position.top=o.top-p):/^(sw)$/.test(h)?(e.size.width=d,e.size.height=c,e.position.left=o.left-u):((c-l<=0||d-r<=0)&&(t=e._getPaddingPlusBorderDimensions(this)),0=f[g]?0:Math.min(f[g],n));!a&&1=f[g]?0:Math.min(f[g],n));!a&&1-1){targetElements.on(evt+EVENT_NAMESPACE,function elementToggle(event){$.powerTip.toggle(this,event)})}else{targetElements.on(evt+EVENT_NAMESPACE,function elementOpen(event){$.powerTip.show(this,event)})}});$.each(options.closeEvents,function(idx,evt){if($.inArray(evt,options.openEvents)<0){targetElements.on(evt+EVENT_NAMESPACE,function elementClose(event){$.powerTip.hide(this,!isMouseEvent(event))})}});targetElements.on("keydown"+EVENT_NAMESPACE,function elementKeyDown(event){if(event.keyCode===27){$.powerTip.hide(this,true)}})}return targetElements};$.fn.powerTip.defaults={fadeInTime:200,fadeOutTime:100,followMouse:false,popupId:"powerTip",popupClass:null,intentSensitivity:7,intentPollInterval:100,closeDelay:100,placement:"n",smartPlacement:false,offset:10,mouseOnToPopup:false,manual:false,openEvents:["mouseenter","focus"],closeEvents:["mouseleave","blur"]};$.fn.powerTip.smartPlacementLists={n:["n","ne","nw","s"],e:["e","ne","se","w","nw","sw","n","s","e"],s:["s","se","sw","n"],w:["w","nw","sw","e","ne","se","n","s","w"],nw:["nw","w","sw","n","s","se","nw"],ne:["ne","e","se","n","s","sw","ne"],sw:["sw","w","nw","s","n","ne","sw"],se:["se","e","ne","s","n","nw","se"],"nw-alt":["nw-alt","n","ne-alt","sw-alt","s","se-alt","w","e"],"ne-alt":["ne-alt","n","nw-alt","se-alt","s","sw-alt","e","w"],"sw-alt":["sw-alt","s","se-alt","nw-alt","n","ne-alt","w","e"],"se-alt":["se-alt","s","sw-alt","ne-alt","n","nw-alt","e","w"]};$.powerTip={show:function apiShowTip(element,event){if(isMouseEvent(event)){trackMouse(event);session.previousX=event.pageX;session.previousY=event.pageY;$(element).data(DATA_DISPLAYCONTROLLER).show()}else{$(element).first().data(DATA_DISPLAYCONTROLLER).show(true,true)}return element},reposition:function apiResetPosition(element){$(element).first().data(DATA_DISPLAYCONTROLLER).resetPosition();return element},hide:function apiCloseTip(element,immediate){var displayController;immediate=element?immediate:true;if(element){displayController=$(element).first().data(DATA_DISPLAYCONTROLLER)}else if(session.activeHover){displayController=session.activeHover.data(DATA_DISPLAYCONTROLLER)}if(displayController){displayController.hide(immediate)}return element},toggle:function apiToggle(element,event){if(session.activeHover&&session.activeHover.is(element)){$.powerTip.hide(element,!isMouseEvent(event))}else{$.powerTip.show(element,event)}return element}};$.powerTip.showTip=$.powerTip.show;$.powerTip.closeTip=$.powerTip.hide;function CSSCoordinates(){var me=this;me.top="auto";me.left="auto";me.right="auto";me.bottom="auto";me.set=function(property,value){if($.isNumeric(value)){me[property]=Math.round(value)}}}function DisplayController(element,options,tipController){var hoverTimer=null,myCloseDelay=null;function openTooltip(immediate,forceOpen){cancelTimer();if(!element.data(DATA_HASACTIVEHOVER)){if(!immediate){session.tipOpenImminent=true;hoverTimer=setTimeout(function intentDelay(){hoverTimer=null;checkForIntent()},options.intentPollInterval)}else{if(forceOpen){element.data(DATA_FORCEDOPEN,true)}closeAnyDelayed();tipController.showTip(element)}}else{cancelClose()}}function closeTooltip(disableDelay){if(myCloseDelay){myCloseDelay=session.closeDelayTimeout=clearTimeout(myCloseDelay);session.delayInProgress=false}cancelTimer();session.tipOpenImminent=false;if(element.data(DATA_HASACTIVEHOVER)){element.data(DATA_FORCEDOPEN,false);if(!disableDelay){session.delayInProgress=true;session.closeDelayTimeout=setTimeout(function closeDelay(){session.closeDelayTimeout=null;tipController.hideTip(element);session.delayInProgress=false;myCloseDelay=null},options.closeDelay);myCloseDelay=session.closeDelayTimeout}else{tipController.hideTip(element)}}}function checkForIntent(){var xDifference=Math.abs(session.previousX-session.currentX),yDifference=Math.abs(session.previousY-session.currentY),totalDifference=xDifference+yDifference;if(totalDifference",{id:options.popupId});if($body.length===0){$body=$("body")}$body.append(tipElement);session.tooltips=session.tooltips?session.tooltips.add(tipElement):tipElement}if(options.followMouse){if(!tipElement.data(DATA_HASMOUSEMOVE)){$document.on("mousemove"+EVENT_NAMESPACE,positionTipOnCursor);$window.on("scroll"+EVENT_NAMESPACE,positionTipOnCursor);tipElement.data(DATA_HASMOUSEMOVE,true)}}function beginShowTip(element){element.data(DATA_HASACTIVEHOVER,true);tipElement.queue(function queueTipInit(next){showTip(element);next()})}function showTip(element){var tipContent;if(!element.data(DATA_HASACTIVEHOVER)){return}if(session.isTipOpen){if(!session.isClosing){hideTip(session.activeHover)}tipElement.delay(100).queue(function queueTipAgain(next){showTip(element);next()});return}element.trigger("powerTipPreRender");tipContent=getTooltipContent(element);if(tipContent){tipElement.empty().append(tipContent)}else{return}element.trigger("powerTipRender");session.activeHover=element;session.isTipOpen=true;tipElement.data(DATA_MOUSEONTOTIP,options.mouseOnToPopup);tipElement.addClass(options.popupClass);if(!options.followMouse||element.data(DATA_FORCEDOPEN)){positionTipOnElement(element);session.isFixedTipOpen=true}else{positionTipOnCursor()}if(!element.data(DATA_FORCEDOPEN)&&!options.followMouse){$document.on("click"+EVENT_NAMESPACE,function documentClick(event){var target=event.target;if(target!==element[0]){if(options.mouseOnToPopup){if(target!==tipElement[0]&&!$.contains(tipElement[0],target)){$.powerTip.hide()}}else{$.powerTip.hide()}}})}if(options.mouseOnToPopup&&!options.manual){tipElement.on("mouseenter"+EVENT_NAMESPACE,function tipMouseEnter(){if(session.activeHover){session.activeHover.data(DATA_DISPLAYCONTROLLER).cancel()}});tipElement.on("mouseleave"+EVENT_NAMESPACE,function tipMouseLeave(){if(session.activeHover){session.activeHover.data(DATA_DISPLAYCONTROLLER).hide()}})}tipElement.fadeIn(options.fadeInTime,function fadeInCallback(){if(!session.desyncTimeout){session.desyncTimeout=setInterval(closeDesyncedTip,500)}element.trigger("powerTipOpen")})}function hideTip(element){session.isClosing=true;session.isTipOpen=false;session.desyncTimeout=clearInterval(session.desyncTimeout);element.data(DATA_HASACTIVEHOVER,false);element.data(DATA_FORCEDOPEN,false);$document.off("click"+EVENT_NAMESPACE);tipElement.off(EVENT_NAMESPACE);tipElement.fadeOut(options.fadeOutTime,function fadeOutCallback(){var coords=new CSSCoordinates;session.activeHover=null;session.isClosing=false;session.isFixedTipOpen=false;tipElement.removeClass();coords.set("top",session.currentY+options.offset);coords.set("left",session.currentX+options.offset);tipElement.css(coords);element.trigger("powerTipClose")})}function positionTipOnCursor(){var tipWidth,tipHeight,coords,collisions,collisionCount;if(!session.isFixedTipOpen&&(session.isTipOpen||session.tipOpenImminent&&tipElement.data(DATA_HASMOUSEMOVE))){tipWidth=tipElement.outerWidth();tipHeight=tipElement.outerHeight();coords=new CSSCoordinates;coords.set("top",session.currentY+options.offset);coords.set("left",session.currentX+options.offset);collisions=getViewportCollisions(coords,tipWidth,tipHeight);if(collisions!==Collision.none){collisionCount=countFlags(collisions);if(collisionCount===1){if(collisions===Collision.right){coords.set("left",session.scrollLeft+session.windowWidth-tipWidth)}else if(collisions===Collision.bottom){coords.set("top",session.scrollTop+session.windowHeight-tipHeight)}}else{coords.set("left",session.currentX-tipWidth-options.offset);coords.set("top",session.currentY-tipHeight-options.offset)}}tipElement.css(coords)}}function positionTipOnElement(element){var priorityList,finalPlacement;if(options.smartPlacement||options.followMouse&&element.data(DATA_FORCEDOPEN)){priorityList=$.fn.powerTip.smartPlacementLists[options.placement];$.each(priorityList,function(idx,pos){var collisions=getViewportCollisions(placeTooltip(element,pos),tipElement.outerWidth(),tipElement.outerHeight());finalPlacement=pos;return collisions!==Collision.none})}else{placeTooltip(element,options.placement);finalPlacement=options.placement}tipElement.removeClass("w nw sw e ne se n s w se-alt sw-alt ne-alt nw-alt");tipElement.addClass(finalPlacement)}function placeTooltip(element,placement){var iterationCount=0,tipWidth,tipHeight,coords=new CSSCoordinates;coords.set("top",0);coords.set("left",0);tipElement.css(coords);do{tipWidth=tipElement.outerWidth();tipHeight=tipElement.outerHeight();coords=placementCalculator.compute(element,placement,tipWidth,tipHeight,options.offset);tipElement.css(coords)}while(++iterationCount<=5&&(tipWidth!==tipElement.outerWidth()||tipHeight!==tipElement.outerHeight()));return coords}function closeDesyncedTip(){var isDesynced=false,hasDesyncableCloseEvent=$.grep(["mouseleave","mouseout","blur","focusout"],function(eventType){return $.inArray(eventType,options.closeEvents)!==-1}).length>0;if(session.isTipOpen&&!session.isClosing&&!session.delayInProgress&&hasDesyncableCloseEvent){if(session.activeHover.data(DATA_HASACTIVEHOVER)===false||session.activeHover.is(":disabled")){isDesynced=true}else if(!isMouseOver(session.activeHover)&&!session.activeHover.is(":focus")&&!session.activeHover.data(DATA_FORCEDOPEN)){if(tipElement.data(DATA_MOUSEONTOTIP)){if(!isMouseOver(tipElement)){isDesynced=true}}else{isDesynced=true}}if(isDesynced){hideTip(session.activeHover)}}}this.showTip=beginShowTip;this.hideTip=hideTip;this.resetPosition=positionTipOnElement}function isSvgElement(element){return Boolean(window.SVGElement&&element[0]instanceof SVGElement)}function isMouseEvent(event){return Boolean(event&&$.inArray(event.type,MOUSE_EVENTS)>-1&&typeof event.pageX==="number")}function initTracking(){if(!session.mouseTrackingActive){session.mouseTrackingActive=true;getViewportDimensions();$(getViewportDimensions);$document.on("mousemove"+EVENT_NAMESPACE,trackMouse);$window.on("resize"+EVENT_NAMESPACE,trackResize);$window.on("scroll"+EVENT_NAMESPACE,trackScroll)}}function getViewportDimensions(){session.scrollLeft=$window.scrollLeft();session.scrollTop=$window.scrollTop();session.windowWidth=$window.width();session.windowHeight=$window.height()}function trackResize(){session.windowWidth=$window.width();session.windowHeight=$window.height()}function trackScroll(){var x=$window.scrollLeft(),y=$window.scrollTop();if(x!==session.scrollLeft){session.currentX+=x-session.scrollLeft;session.scrollLeft=x}if(y!==session.scrollTop){session.currentY+=y-session.scrollTop;session.scrollTop=y}}function trackMouse(event){session.currentX=event.pageX;session.currentY=event.pageY}function isMouseOver(element){var elementPosition=element.offset(),elementBox=element[0].getBoundingClientRect(),elementWidth=elementBox.right-elementBox.left,elementHeight=elementBox.bottom-elementBox.top;return session.currentX>=elementPosition.left&&session.currentX<=elementPosition.left+elementWidth&&session.currentY>=elementPosition.top&&session.currentY<=elementPosition.top+elementHeight}function getTooltipContent(element){var tipText=element.data(DATA_POWERTIP),tipObject=element.data(DATA_POWERTIPJQ),tipTarget=element.data(DATA_POWERTIPTARGET),targetElement,content;if(tipText){if($.isFunction(tipText)){tipText=tipText.call(element[0])}content=tipText}else if(tipObject){if($.isFunction(tipObject)){tipObject=tipObject.call(element[0])}if(tipObject.length>0){content=tipObject.clone(true,true)}}else if(tipTarget){targetElement=$("#"+tipTarget);if(targetElement.length>0){content=targetElement.html()}}return content}function getViewportCollisions(coords,elementWidth,elementHeight){var viewportTop=session.scrollTop,viewportLeft=session.scrollLeft,viewportBottom=viewportTop+session.windowHeight,viewportRight=viewportLeft+session.windowWidth,collisions=Collision.none;if(coords.topviewportBottom||Math.abs(coords.bottom-session.windowHeight)>viewportBottom){collisions|=Collision.bottom}if(coords.leftviewportRight){collisions|=Collision.left}if(coords.left+elementWidth>viewportRight||coords.right-1){ +targetElements.on(evt+EVENT_NAMESPACE,function elementToggle(event){$.powerTip.toggle(this,event)})}else{targetElements.on(evt+EVENT_NAMESPACE,function elementOpen(event){$.powerTip.show(this,event)})}});$.each(options.closeEvents,function(idx,evt){if($.inArray(evt,options.openEvents)<0){targetElements.on(evt+EVENT_NAMESPACE,function elementClose(event){$.powerTip.hide(this,!isMouseEvent(event))})}});targetElements.on("keydown"+EVENT_NAMESPACE,function elementKeyDown(event){if(event.keyCode===27){$.powerTip.hide(this,true)}})}return targetElements};$.fn.powerTip.defaults={fadeInTime:200,fadeOutTime:100,followMouse:false,popupId:"powerTip",popupClass:null,intentSensitivity:7,intentPollInterval:100,closeDelay:100,placement:"n",smartPlacement:false,offset:10,mouseOnToPopup:false,manual:false,openEvents:["mouseenter","focus"],closeEvents:["mouseleave","blur"]};$.fn.powerTip.smartPlacementLists={n:["n","ne","nw","s"],e:["e","ne","se","w","nw","sw","n","s","e"],s:["s","se","sw","n"],w:["w","nw","sw","e","ne","se", +"n","s","w"],nw:["nw","w","sw","n","s","se","nw"],ne:["ne","e","se","n","s","sw","ne"],sw:["sw","w","nw","s","n","ne","sw"],se:["se","e","ne","s","n","nw","se"],"nw-alt":["nw-alt","n","ne-alt","sw-alt","s","se-alt","w","e"],"ne-alt":["ne-alt","n","nw-alt","se-alt","s","sw-alt","e","w"],"sw-alt":["sw-alt","s","se-alt","nw-alt","n","ne-alt","w","e"],"se-alt":["se-alt","s","sw-alt","ne-alt","n","nw-alt","e","w"]};$.powerTip={show:function apiShowTip(element,event){if(isMouseEvent(event)){trackMouse(event);session.previousX=event.pageX;session.previousY=event.pageY;$(element).data(DATA_DISPLAYCONTROLLER).show()}else{$(element).first().data(DATA_DISPLAYCONTROLLER).show(true,true)}return element},reposition:function apiResetPosition(element){$(element).first().data(DATA_DISPLAYCONTROLLER).resetPosition();return element},hide:function apiCloseTip(element,immediate){var displayController;immediate=element?immediate:true;if(element){displayController=$(element).first().data(DATA_DISPLAYCONTROLLER)}else if( +session.activeHover){displayController=session.activeHover.data(DATA_DISPLAYCONTROLLER)}if(displayController){displayController.hide(immediate)}return element},toggle:function apiToggle(element,event){if(session.activeHover&&session.activeHover.is(element)){$.powerTip.hide(element,!isMouseEvent(event))}else{$.powerTip.show(element,event)}return element}};$.powerTip.showTip=$.powerTip.show;$.powerTip.closeTip=$.powerTip.hide;function CSSCoordinates(){var me=this;me.top="auto";me.left="auto";me.right="auto";me.bottom="auto";me.set=function(property,value){if($.isNumeric(value)){me[property]=Math.round(value)}}}function DisplayController(element,options,tipController){var hoverTimer=null,myCloseDelay=null;function openTooltip(immediate,forceOpen){cancelTimer();if(!element.data(DATA_HASACTIVEHOVER)){if(!immediate){session.tipOpenImminent=true;hoverTimer=setTimeout(function intentDelay(){hoverTimer=null;checkForIntent()},options.intentPollInterval)}else{if(forceOpen){element.data(DATA_FORCEDOPEN,true)} +closeAnyDelayed();tipController.showTip(element)}}else{cancelClose()}}function closeTooltip(disableDelay){if(myCloseDelay){myCloseDelay=session.closeDelayTimeout=clearTimeout(myCloseDelay);session.delayInProgress=false}cancelTimer();session.tipOpenImminent=false;if(element.data(DATA_HASACTIVEHOVER)){element.data(DATA_FORCEDOPEN,false);if(!disableDelay){session.delayInProgress=true;session.closeDelayTimeout=setTimeout(function closeDelay(){session.closeDelayTimeout=null;tipController.hideTip(element);session.delayInProgress=false;myCloseDelay=null},options.closeDelay);myCloseDelay=session.closeDelayTimeout}else{tipController.hideTip(element)}}}function checkForIntent(){var xDifference=Math.abs(session.previousX-session.currentX),yDifference=Math.abs(session.previousY-session.currentY),totalDifference=xDifference+yDifference;if(totalDifference",{id:options.popupId});if($body.length===0){$body=$("body")}$body.append(tipElement);session.tooltips=session.tooltips?session.tooltips.add(tipElement):tipElement}if(options.followMouse){if(!tipElement.data(DATA_HASMOUSEMOVE)){$document.on("mousemove"+EVENT_NAMESPACE,positionTipOnCursor);$window.on("scroll"+EVENT_NAMESPACE,positionTipOnCursor);tipElement.data(DATA_HASMOUSEMOVE,true)}}function beginShowTip(element){element.data(DATA_HASACTIVEHOVER,true);tipElement.queue(function queueTipInit(next){showTip(element);next()})}function showTip(element){var tipContent;if(!element.data(DATA_HASACTIVEHOVER)){return}if( +session.isTipOpen){if(!session.isClosing){hideTip(session.activeHover)}tipElement.delay(100).queue(function queueTipAgain(next){showTip(element);next()});return}element.trigger("powerTipPreRender");tipContent=getTooltipContent(element);if(tipContent){tipElement.empty().append(tipContent)}else{return}element.trigger("powerTipRender");session.activeHover=element;session.isTipOpen=true;tipElement.data(DATA_MOUSEONTOTIP,options.mouseOnToPopup);tipElement.addClass(options.popupClass);if(!options.followMouse||element.data(DATA_FORCEDOPEN)){positionTipOnElement(element);session.isFixedTipOpen=true}else{positionTipOnCursor()}if(!element.data(DATA_FORCEDOPEN)&&!options.followMouse){$document.on("click"+EVENT_NAMESPACE,function documentClick(event){var target=event.target;if(target!==element[0]){if(options.mouseOnToPopup){if(target!==tipElement[0]&&!$.contains(tipElement[0],target)){$.powerTip.hide()}}else{$.powerTip.hide()}}})}if(options.mouseOnToPopup&&!options.manual){tipElement.on("mouseenter"+EVENT_NAMESPACE, +function tipMouseEnter(){if(session.activeHover){session.activeHover.data(DATA_DISPLAYCONTROLLER).cancel()}});tipElement.on("mouseleave"+EVENT_NAMESPACE,function tipMouseLeave(){if(session.activeHover){session.activeHover.data(DATA_DISPLAYCONTROLLER).hide()}})}tipElement.fadeIn(options.fadeInTime,function fadeInCallback(){if(!session.desyncTimeout){session.desyncTimeout=setInterval(closeDesyncedTip,500)}element.trigger("powerTipOpen")})}function hideTip(element){session.isClosing=true;session.isTipOpen=false;session.desyncTimeout=clearInterval(session.desyncTimeout);element.data(DATA_HASACTIVEHOVER,false);element.data(DATA_FORCEDOPEN,false);$document.off("click"+EVENT_NAMESPACE);tipElement.off(EVENT_NAMESPACE);tipElement.fadeOut(options.fadeOutTime,function fadeOutCallback(){var coords=new CSSCoordinates;session.activeHover=null;session.isClosing=false;session.isFixedTipOpen=false;tipElement.removeClass();coords.set("top",session.currentY+options.offset);coords.set("left",session.currentX+options.offset); +tipElement.css(coords);element.trigger("powerTipClose")})}function positionTipOnCursor(){var tipWidth,tipHeight,coords,collisions,collisionCount;if(!session.isFixedTipOpen&&(session.isTipOpen||session.tipOpenImminent&&tipElement.data(DATA_HASMOUSEMOVE))){tipWidth=tipElement.outerWidth();tipHeight=tipElement.outerHeight();coords=new CSSCoordinates;coords.set("top",session.currentY+options.offset);coords.set("left",session.currentX+options.offset);collisions=getViewportCollisions(coords,tipWidth,tipHeight);if(collisions!==Collision.none){collisionCount=countFlags(collisions);if(collisionCount===1){if(collisions===Collision.right){coords.set("left",session.scrollLeft+session.windowWidth-tipWidth)}else if(collisions===Collision.bottom){coords.set("top",session.scrollTop+session.windowHeight-tipHeight)}}else{coords.set("left",session.currentX-tipWidth-options.offset);coords.set("top",session.currentY-tipHeight-options.offset)}}tipElement.css(coords)}}function positionTipOnElement(element){var priorityList, +finalPlacement;if(options.smartPlacement||options.followMouse&&element.data(DATA_FORCEDOPEN)){priorityList=$.fn.powerTip.smartPlacementLists[options.placement];$.each(priorityList,function(idx,pos){var collisions=getViewportCollisions(placeTooltip(element,pos),tipElement.outerWidth(),tipElement.outerHeight());finalPlacement=pos;return collisions!==Collision.none})}else{placeTooltip(element,options.placement);finalPlacement=options.placement}tipElement.removeClass("w nw sw e ne se n s w se-alt sw-alt ne-alt nw-alt");tipElement.addClass(finalPlacement)}function placeTooltip(element,placement){var iterationCount=0,tipWidth,tipHeight,coords=new CSSCoordinates;coords.set("top",0);coords.set("left",0);tipElement.css(coords);do{tipWidth=tipElement.outerWidth();tipHeight=tipElement.outerHeight();coords=placementCalculator.compute(element,placement,tipWidth,tipHeight,options.offset);tipElement.css(coords)}while(++iterationCount<=5&&(tipWidth!==tipElement.outerWidth()||tipHeight!==tipElement.outerHeight())); +return coords}function closeDesyncedTip(){var isDesynced=false,hasDesyncableCloseEvent=$.grep(["mouseleave","mouseout","blur","focusout"],function(eventType){return $.inArray(eventType,options.closeEvents)!==-1}).length>0;if(session.isTipOpen&&!session.isClosing&&!session.delayInProgress&&hasDesyncableCloseEvent){if(session.activeHover.data(DATA_HASACTIVEHOVER)===false||session.activeHover.is(":disabled")){isDesynced=true}else if(!isMouseOver(session.activeHover)&&!session.activeHover.is(":focus")&&!session.activeHover.data(DATA_FORCEDOPEN)){if(tipElement.data(DATA_MOUSEONTOTIP)){if(!isMouseOver(tipElement)){isDesynced=true}}else{isDesynced=true}}if(isDesynced){hideTip(session.activeHover)}}}this.showTip=beginShowTip;this.hideTip=hideTip;this.resetPosition=positionTipOnElement}function isSvgElement(element){return Boolean(window.SVGElement&&element[0]instanceof SVGElement)}function isMouseEvent(event){return Boolean(event&&$.inArray(event.type,MOUSE_EVENTS)>-1&&typeof event.pageX==="number")} +function initTracking(){if(!session.mouseTrackingActive){session.mouseTrackingActive=true;getViewportDimensions();$(getViewportDimensions);$document.on("mousemove"+EVENT_NAMESPACE,trackMouse);$window.on("resize"+EVENT_NAMESPACE,trackResize);$window.on("scroll"+EVENT_NAMESPACE,trackScroll)}}function getViewportDimensions(){session.scrollLeft=$window.scrollLeft();session.scrollTop=$window.scrollTop();session.windowWidth=$window.width();session.windowHeight=$window.height()}function trackResize(){session.windowWidth=$window.width();session.windowHeight=$window.height()}function trackScroll(){var x=$window.scrollLeft(),y=$window.scrollTop();if(x!==session.scrollLeft){session.currentX+=x-session.scrollLeft;session.scrollLeft=x}if(y!==session.scrollTop){session.currentY+=y-session.scrollTop;session.scrollTop=y}}function trackMouse(event){session.currentX=event.pageX;session.currentY=event.pageY}function isMouseOver(element){var elementPosition=element.offset(),elementBox=element[0].getBoundingClientRect(), +elementWidth=elementBox.right-elementBox.left,elementHeight=elementBox.bottom-elementBox.top;return session.currentX>=elementPosition.left&&session.currentX<=elementPosition.left+elementWidth&&session.currentY>=elementPosition.top&&session.currentY<=elementPosition.top+elementHeight}function getTooltipContent(element){var tipText=element.data(DATA_POWERTIP),tipObject=element.data(DATA_POWERTIPJQ),tipTarget=element.data(DATA_POWERTIPTARGET),targetElement,content;if(tipText){if($.isFunction(tipText)){tipText=tipText.call(element[0])}content=tipText}else if(tipObject){if($.isFunction(tipObject)){tipObject=tipObject.call(element[0])}if(tipObject.length>0){content=tipObject.clone(true,true)}}else if(tipTarget){targetElement=$("#"+tipTarget);if(targetElement.length>0){content=targetElement.html()}}return content}function getViewportCollisions(coords,elementWidth,elementHeight){var viewportTop=session.scrollTop,viewportLeft=session.scrollLeft,viewportBottom=viewportTop+session.windowHeight, +viewportRight=viewportLeft+session.windowWidth,collisions=Collision.none;if(coords.topviewportBottom||Math.abs(coords.bottom-session.windowHeight)>viewportBottom){collisions|=Collision.bottom}if(coords.leftviewportRight){collisions|=Collision.left}if(coords.left+elementWidth>viewportRight||coords.right1)){a.preventDefault();var c=a.originalEvent.changedTouches[0],d=document.createEvent("MouseEvents");d.initMouseEvent(b,!0,!0,window,1,c.screenX,c.screenY,c.clientX,c.clientY,!1,!1,!1,!1,0,null),a.target.dispatchEvent(d)}}if(a.support.touch="ontouchend"in document,a.support.touch){var e,b=a.ui.mouse.prototype,c=b._mouseInit,d=b._mouseDestroy;b._touchStart=function(a){var b=this;!e&&b._mouseCapture(a.originalEvent.changedTouches[0])&&(e=!0,b._touchMoved=!1,f(a,"mouseover"),f(a,"mousemove"),f(a,"mousedown"))},b._touchMove=function(a){e&&(this._touchMoved=!0,f(a,"mousemove"))},b._touchEnd=function(a){e&&(f(a,"mouseup"),f(a,"mouseout"),this._touchMoved||f(a,"click"),e=!1)},b._mouseInit=function(){var b=this;b.element.bind({touchstart:a.proxy(b,"_touchStart"),touchmove:a.proxy(b,"_touchMove"),touchend:a.proxy(b,"_touchEnd")}),c.call(b)},b._mouseDestroy=function(){var b=this;b.element.unbind({touchstart:a.proxy(b,"_touchStart"),touchmove:a.proxy(b,"_touchMove"),touchend:a.proxy(b,"_touchEnd")}),d.call(b)}}}(jQuery);/*! SmartMenus jQuery Plugin - v1.1.0 - September 17, 2017 + */!function(a){function f(a,b){if(!(a.originalEvent.touches.length>1)){a.preventDefault();var c=a.originalEvent.changedTouches[0],d=document.createEvent("MouseEvents");d.initMouseEvent(b,!0,!0,window,1,c.screenX,c.screenY,c.clientX,c.clientY,!1,!1,!1,!1,0,null),a.target.dispatchEvent(d)}}if(a.support.touch="ontouchend"in document,a.support.touch){var e,b=a.ui.mouse.prototype,c=b._mouseInit,d=b._mouseDestroy;b._touchStart=function(a){var b=this;!e&&b._mouseCapture(a.originalEvent.changedTouches[0])&&(e=!0,b._touchMoved=!1,f(a,"mouseover"),f(a,"mousemove"),f(a,"mousedown"))},b._touchMove=function(a){e&&(this._touchMoved=!0,f(a,"mousemove"))},b._touchEnd=function(a){e&&(f(a,"mouseup"),f(a,"mouseout"),this._touchMoved||f(a,"click"),e=!1)},b._mouseInit=function(){var b=this;b.element.bind({touchstart:a.proxy(b,"_touchStart"),touchmove:a.proxy(b,"_touchMove"),touchend:a.proxy(b,"_touchEnd")}),c.call(b)},b._mouseDestroy=function(){var b=this;b.element.unbind({touchstart:a.proxy(b,"_touchStart"),touchmove:a.proxy(b, +"_touchMove"),touchend:a.proxy(b,"_touchEnd")}),d.call(b)}}}(jQuery); +/*! SmartMenus jQuery Plugin - v1.1.0 - September 17, 2017 * http://www.smartmenus.org/ - * Copyright Vasil Dinkov, Vadikom Web Ltd. http://vadikom.com; Licensed MIT */(function(t){"function"==typeof define&&define.amd?define(["jquery"],t):"object"==typeof module&&"object"==typeof module.exports?module.exports=t(require("jquery")):t(jQuery)})(function($){function initMouseDetection(t){var e=".smartmenus_mouse";if(mouseDetectionEnabled||t)mouseDetectionEnabled&&t&&($(document).off(e),mouseDetectionEnabled=!1);else{var i=!0,s=null,o={mousemove:function(t){var e={x:t.pageX,y:t.pageY,timeStamp:(new Date).getTime()};if(s){var o=Math.abs(s.x-e.x),a=Math.abs(s.y-e.y);if((o>0||a>0)&&2>=o&&2>=a&&300>=e.timeStamp-s.timeStamp&&(mouse=!0,i)){var n=$(t.target).closest("a");n.is("a")&&$.each(menuTrees,function(){return $.contains(this.$root[0],n[0])?(this.itemEnter({currentTarget:n[0]}),!1):void 0}),i=!1}}s=e}};o[touchEvents?"touchstart":"pointerover pointermove pointerout MSPointerOver MSPointerMove MSPointerOut"]=function(t){isTouchEvent(t.originalEvent)&&(mouse=!1)},$(document).on(getEventsNS(o,e)),mouseDetectionEnabled=!0}}function isTouchEvent(t){return!/^(4|mouse)$/.test(t.pointerType)}function getEventsNS(t,e){e||(e="");var i={};for(var s in t)i[s.split(" ").join(e+" ")+e]=t[s];return i}var menuTrees=[],mouse=!1,touchEvents="ontouchstart"in window,mouseDetectionEnabled=!1,requestAnimationFrame=window.requestAnimationFrame||function(t){return setTimeout(t,1e3/60)},cancelAnimationFrame=window.cancelAnimationFrame||function(t){clearTimeout(t)},canAnimate=!!$.fn.animate;return $.SmartMenus=function(t,e){this.$root=$(t),this.opts=e,this.rootId="",this.accessIdPrefix="",this.$subArrow=null,this.activatedItems=[],this.visibleSubMenus=[],this.showTimeout=0,this.hideTimeout=0,this.scrollTimeout=0,this.clickActivated=!1,this.focusActivated=!1,this.zIndexInc=0,this.idInc=0,this.$firstLink=null,this.$firstSub=null,this.disabled=!1,this.$disableOverlay=null,this.$touchScrollingSub=null,this.cssTransforms3d="perspective"in t.style||"webkitPerspective"in t.style,this.wasCollapsible=!1,this.init()},$.extend($.SmartMenus,{hideAll:function(){$.each(menuTrees,function(){this.menuHideAll()})},destroy:function(){for(;menuTrees.length;)menuTrees[0].destroy();initMouseDetection(!0)},prototype:{init:function(t){var e=this;if(!t){menuTrees.push(this),this.rootId=((new Date).getTime()+Math.random()+"").replace(/\D/g,""),this.accessIdPrefix="sm-"+this.rootId+"-",this.$root.hasClass("sm-rtl")&&(this.opts.rightToLeftSubMenus=!0);var i=".smartmenus";this.$root.data("smartmenus",this).attr("data-smartmenus-id",this.rootId).dataSM("level",1).on(getEventsNS({"mouseover focusin":$.proxy(this.rootOver,this),"mouseout focusout":$.proxy(this.rootOut,this),keydown:$.proxy(this.rootKeyDown,this)},i)).on(getEventsNS({mouseenter:$.proxy(this.itemEnter,this),mouseleave:$.proxy(this.itemLeave,this),mousedown:$.proxy(this.itemDown,this),focus:$.proxy(this.itemFocus,this),blur:$.proxy(this.itemBlur,this),click:$.proxy(this.itemClick,this)},i),"a"),i+=this.rootId,this.opts.hideOnClick&&$(document).on(getEventsNS({touchstart:$.proxy(this.docTouchStart,this),touchmove:$.proxy(this.docTouchMove,this),touchend:$.proxy(this.docTouchEnd,this),click:$.proxy(this.docClick,this)},i)),$(window).on(getEventsNS({"resize orientationchange":$.proxy(this.winResize,this)},i)),this.opts.subIndicators&&(this.$subArrow=$("").addClass("sub-arrow"),this.opts.subIndicatorsText&&this.$subArrow.html(this.opts.subIndicatorsText)),initMouseDetection()}if(this.$firstSub=this.$root.find("ul").each(function(){e.menuInit($(this))}).eq(0),this.$firstLink=this.$root.find("a").eq(0),this.opts.markCurrentItem){var s=/(index|default)\.[^#\?\/]*/i,o=/#.*/,a=window.location.href.replace(s,""),n=a.replace(o,"");this.$root.find("a").each(function(){var t=this.href.replace(s,""),i=$(this);(t==a||t==n)&&(i.addClass("current"),e.opts.markCurrentTree&&i.parentsUntil("[data-smartmenus-id]","ul").each(function(){$(this).dataSM("parent-a").addClass("current")}))})}this.wasCollapsible=this.isCollapsible()},destroy:function(t){if(!t){var e=".smartmenus";this.$root.removeData("smartmenus").removeAttr("data-smartmenus-id").removeDataSM("level").off(e),e+=this.rootId,$(document).off(e),$(window).off(e),this.opts.subIndicators&&(this.$subArrow=null)}this.menuHideAll();var i=this;this.$root.find("ul").each(function(){var t=$(this);t.dataSM("scroll-arrows")&&t.dataSM("scroll-arrows").remove(),t.dataSM("shown-before")&&((i.opts.subMenusMinWidth||i.opts.subMenusMaxWidth)&&t.css({width:"",minWidth:"",maxWidth:""}).removeClass("sm-nowrap"),t.dataSM("scroll-arrows")&&t.dataSM("scroll-arrows").remove(),t.css({zIndex:"",top:"",left:"",marginLeft:"",marginTop:"",display:""})),0==(t.attr("id")||"").indexOf(i.accessIdPrefix)&&t.removeAttr("id")}).removeDataSM("in-mega").removeDataSM("shown-before").removeDataSM("scroll-arrows").removeDataSM("parent-a").removeDataSM("level").removeDataSM("beforefirstshowfired").removeAttr("role").removeAttr("aria-hidden").removeAttr("aria-labelledby").removeAttr("aria-expanded"),this.$root.find("a.has-submenu").each(function(){var t=$(this);0==t.attr("id").indexOf(i.accessIdPrefix)&&t.removeAttr("id")}).removeClass("has-submenu").removeDataSM("sub").removeAttr("aria-haspopup").removeAttr("aria-controls").removeAttr("aria-expanded").closest("li").removeDataSM("sub"),this.opts.subIndicators&&this.$root.find("span.sub-arrow").remove(),this.opts.markCurrentItem&&this.$root.find("a.current").removeClass("current"),t||(this.$root=null,this.$firstLink=null,this.$firstSub=null,this.$disableOverlay&&(this.$disableOverlay.remove(),this.$disableOverlay=null),menuTrees.splice($.inArray(this,menuTrees),1))},disable:function(t){if(!this.disabled){if(this.menuHideAll(),!t&&!this.opts.isPopup&&this.$root.is(":visible")){var e=this.$root.offset();this.$disableOverlay=$('
    ').css({position:"absolute",top:e.top,left:e.left,width:this.$root.outerWidth(),height:this.$root.outerHeight(),zIndex:this.getStartZIndex(!0),opacity:0}).appendTo(document.body)}this.disabled=!0}},docClick:function(t){return this.$touchScrollingSub?(this.$touchScrollingSub=null,void 0):((this.visibleSubMenus.length&&!$.contains(this.$root[0],t.target)||$(t.target).closest("a").length)&&this.menuHideAll(),void 0)},docTouchEnd:function(){if(this.lastTouch){if(!(!this.visibleSubMenus.length||void 0!==this.lastTouch.x2&&this.lastTouch.x1!=this.lastTouch.x2||void 0!==this.lastTouch.y2&&this.lastTouch.y1!=this.lastTouch.y2||this.lastTouch.target&&$.contains(this.$root[0],this.lastTouch.target))){this.hideTimeout&&(clearTimeout(this.hideTimeout),this.hideTimeout=0);var t=this;this.hideTimeout=setTimeout(function(){t.menuHideAll()},350)}this.lastTouch=null}},docTouchMove:function(t){if(this.lastTouch){var e=t.originalEvent.touches[0];this.lastTouch.x2=e.pageX,this.lastTouch.y2=e.pageY}},docTouchStart:function(t){var e=t.originalEvent.touches[0];this.lastTouch={x1:e.pageX,y1:e.pageY,target:e.target}},enable:function(){this.disabled&&(this.$disableOverlay&&(this.$disableOverlay.remove(),this.$disableOverlay=null),this.disabled=!1)},getClosestMenu:function(t){for(var e=$(t).closest("ul");e.dataSM("in-mega");)e=e.parent().closest("ul");return e[0]||null},getHeight:function(t){return this.getOffset(t,!0)},getOffset:function(t,e){var i;"none"==t.css("display")&&(i={position:t[0].style.position,visibility:t[0].style.visibility},t.css({position:"absolute",visibility:"hidden"}).show());var s=t[0].getBoundingClientRect&&t[0].getBoundingClientRect(),o=s&&(e?s.height||s.bottom-s.top:s.width||s.right-s.left);return o||0===o||(o=e?t[0].offsetHeight:t[0].offsetWidth),i&&t.hide().css(i),o},getStartZIndex:function(t){var e=parseInt(this[t?"$root":"$firstSub"].css("z-index"));return!t&&isNaN(e)&&(e=parseInt(this.$root.css("z-index"))),isNaN(e)?1:e},getTouchPoint:function(t){return t.touches&&t.touches[0]||t.changedTouches&&t.changedTouches[0]||t},getViewport:function(t){var e=t?"Height":"Width",i=document.documentElement["client"+e],s=window["inner"+e];return s&&(i=Math.min(i,s)),i},getViewportHeight:function(){return this.getViewport(!0)},getViewportWidth:function(){return this.getViewport()},getWidth:function(t){return this.getOffset(t)},handleEvents:function(){return!this.disabled&&this.isCSSOn()},handleItemEvents:function(t){return this.handleEvents()&&!this.isLinkInMegaMenu(t)},isCollapsible:function(){return"static"==this.$firstSub.css("position")},isCSSOn:function(){return"inline"!=this.$firstLink.css("display")},isFixed:function(){var t="fixed"==this.$root.css("position");return t||this.$root.parentsUntil("body").each(function(){return"fixed"==$(this).css("position")?(t=!0,!1):void 0}),t},isLinkInMegaMenu:function(t){return $(this.getClosestMenu(t[0])).hasClass("mega-menu")},isTouchMode:function(){return!mouse||this.opts.noMouseOver||this.isCollapsible()},itemActivate:function(t,e){var i=t.closest("ul"),s=i.dataSM("level");if(s>1&&(!this.activatedItems[s-2]||this.activatedItems[s-2][0]!=i.dataSM("parent-a")[0])){var o=this;$(i.parentsUntil("[data-smartmenus-id]","ul").get().reverse()).add(i).each(function(){o.itemActivate($(this).dataSM("parent-a"))})}if((!this.isCollapsible()||e)&&this.menuHideSubMenus(this.activatedItems[s-1]&&this.activatedItems[s-1][0]==t[0]?s:s-1),this.activatedItems[s-1]=t,this.$root.triggerHandler("activate.smapi",t[0])!==!1){var a=t.dataSM("sub");a&&(this.isTouchMode()||!this.opts.showOnClick||this.clickActivated)&&this.menuShow(a)}},itemBlur:function(t){var e=$(t.currentTarget);this.handleItemEvents(e)&&this.$root.triggerHandler("blur.smapi",e[0])},itemClick:function(t){var e=$(t.currentTarget);if(this.handleItemEvents(e)){if(this.$touchScrollingSub&&this.$touchScrollingSub[0]==e.closest("ul")[0])return this.$touchScrollingSub=null,t.stopPropagation(),!1;if(this.$root.triggerHandler("click.smapi",e[0])===!1)return!1;var i=$(t.target).is(".sub-arrow"),s=e.dataSM("sub"),o=s?2==s.dataSM("level"):!1,a=this.isCollapsible(),n=/toggle$/.test(this.opts.collapsibleBehavior),r=/link$/.test(this.opts.collapsibleBehavior),h=/^accordion/.test(this.opts.collapsibleBehavior);if(s&&!s.is(":visible")){if((!r||!a||i)&&(this.opts.showOnClick&&o&&(this.clickActivated=!0),this.itemActivate(e,h),s.is(":visible")))return this.focusActivated=!0,!1}else if(a&&(n||i))return this.itemActivate(e,h),this.menuHide(s),n&&(this.focusActivated=!1),!1;return this.opts.showOnClick&&o||e.hasClass("disabled")||this.$root.triggerHandler("select.smapi",e[0])===!1?!1:void 0}},itemDown:function(t){var e=$(t.currentTarget);this.handleItemEvents(e)&&e.dataSM("mousedown",!0)},itemEnter:function(t){var e=$(t.currentTarget);if(this.handleItemEvents(e)){if(!this.isTouchMode()){this.showTimeout&&(clearTimeout(this.showTimeout),this.showTimeout=0);var i=this;this.showTimeout=setTimeout(function(){i.itemActivate(e)},this.opts.showOnClick&&1==e.closest("ul").dataSM("level")?1:this.opts.showTimeout)}this.$root.triggerHandler("mouseenter.smapi",e[0])}},itemFocus:function(t){var e=$(t.currentTarget);this.handleItemEvents(e)&&(!this.focusActivated||this.isTouchMode()&&e.dataSM("mousedown")||this.activatedItems.length&&this.activatedItems[this.activatedItems.length-1][0]==e[0]||this.itemActivate(e,!0),this.$root.triggerHandler("focus.smapi",e[0]))},itemLeave:function(t){var e=$(t.currentTarget);this.handleItemEvents(e)&&(this.isTouchMode()||(e[0].blur(),this.showTimeout&&(clearTimeout(this.showTimeout),this.showTimeout=0)),e.removeDataSM("mousedown"),this.$root.triggerHandler("mouseleave.smapi",e[0]))},menuHide:function(t){if(this.$root.triggerHandler("beforehide.smapi",t[0])!==!1&&(canAnimate&&t.stop(!0,!0),"none"!=t.css("display"))){var e=function(){t.css("z-index","")};this.isCollapsible()?canAnimate&&this.opts.collapsibleHideFunction?this.opts.collapsibleHideFunction.call(this,t,e):t.hide(this.opts.collapsibleHideDuration,e):canAnimate&&this.opts.hideFunction?this.opts.hideFunction.call(this,t,e):t.hide(this.opts.hideDuration,e),t.dataSM("scroll")&&(this.menuScrollStop(t),t.css({"touch-action":"","-ms-touch-action":"","-webkit-transform":"",transform:""}).off(".smartmenus_scroll").removeDataSM("scroll").dataSM("scroll-arrows").hide()),t.dataSM("parent-a").removeClass("highlighted").attr("aria-expanded","false"),t.attr({"aria-expanded":"false","aria-hidden":"true"});var i=t.dataSM("level");this.activatedItems.splice(i-1,1),this.visibleSubMenus.splice($.inArray(t,this.visibleSubMenus),1),this.$root.triggerHandler("hide.smapi",t[0])}},menuHideAll:function(){this.showTimeout&&(clearTimeout(this.showTimeout),this.showTimeout=0);for(var t=this.opts.isPopup?1:0,e=this.visibleSubMenus.length-1;e>=t;e--)this.menuHide(this.visibleSubMenus[e]);this.opts.isPopup&&(canAnimate&&this.$root.stop(!0,!0),this.$root.is(":visible")&&(canAnimate&&this.opts.hideFunction?this.opts.hideFunction.call(this,this.$root):this.$root.hide(this.opts.hideDuration))),this.activatedItems=[],this.visibleSubMenus=[],this.clickActivated=!1,this.focusActivated=!1,this.zIndexInc=0,this.$root.triggerHandler("hideAll.smapi")},menuHideSubMenus:function(t){for(var e=this.activatedItems.length-1;e>=t;e--){var i=this.activatedItems[e].dataSM("sub");i&&this.menuHide(i)}},menuInit:function(t){if(!t.dataSM("in-mega")){t.hasClass("mega-menu")&&t.find("ul").dataSM("in-mega",!0);for(var e=2,i=t[0];(i=i.parentNode.parentNode)!=this.$root[0];)e++;var s=t.prevAll("a").eq(-1);s.length||(s=t.prevAll().find("a").eq(-1)),s.addClass("has-submenu").dataSM("sub",t),t.dataSM("parent-a",s).dataSM("level",e).parent().dataSM("sub",t);var o=s.attr("id")||this.accessIdPrefix+ ++this.idInc,a=t.attr("id")||this.accessIdPrefix+ ++this.idInc;s.attr({id:o,"aria-haspopup":"true","aria-controls":a,"aria-expanded":"false"}),t.attr({id:a,role:"group","aria-hidden":"true","aria-labelledby":o,"aria-expanded":"false"}),this.opts.subIndicators&&s[this.opts.subIndicatorsPos](this.$subArrow.clone())}},menuPosition:function(t){var e,i,s=t.dataSM("parent-a"),o=s.closest("li"),a=o.parent(),n=t.dataSM("level"),r=this.getWidth(t),h=this.getHeight(t),u=s.offset(),l=u.left,c=u.top,d=this.getWidth(s),m=this.getHeight(s),p=$(window),f=p.scrollLeft(),v=p.scrollTop(),b=this.getViewportWidth(),S=this.getViewportHeight(),g=a.parent().is("[data-sm-horizontal-sub]")||2==n&&!a.hasClass("sm-vertical"),M=this.opts.rightToLeftSubMenus&&!o.is("[data-sm-reverse]")||!this.opts.rightToLeftSubMenus&&o.is("[data-sm-reverse]"),w=2==n?this.opts.mainMenuSubOffsetX:this.opts.subMenusSubOffsetX,T=2==n?this.opts.mainMenuSubOffsetY:this.opts.subMenusSubOffsetY;if(g?(e=M?d-r-w:w,i=this.opts.bottomToTopSubMenus?-h-T:m+T):(e=M?w-r:d-w,i=this.opts.bottomToTopSubMenus?m-T-h:T),this.opts.keepInViewport){var y=l+e,I=c+i;if(M&&f>y?e=g?f-y+e:d-w:!M&&y+r>f+b&&(e=g?f+b-r-y+e:w-r),g||(S>h&&I+h>v+S?i+=v+S-h-I:(h>=S||v>I)&&(i+=v-I)),g&&(I+h>v+S+.49||v>I)||!g&&h>S+.49){var x=this;t.dataSM("scroll-arrows")||t.dataSM("scroll-arrows",$([$('')[0],$('')[0]]).on({mouseenter:function(){t.dataSM("scroll").up=$(this).hasClass("scroll-up"),x.menuScroll(t)},mouseleave:function(e){x.menuScrollStop(t),x.menuScrollOut(t,e)},"mousewheel DOMMouseScroll":function(t){t.preventDefault()}}).insertAfter(t));var A=".smartmenus_scroll";if(t.dataSM("scroll",{y:this.cssTransforms3d?0:i-m,step:1,itemH:m,subH:h,arrowDownH:this.getHeight(t.dataSM("scroll-arrows").eq(1))}).on(getEventsNS({mouseover:function(e){x.menuScrollOver(t,e)},mouseout:function(e){x.menuScrollOut(t,e)},"mousewheel DOMMouseScroll":function(e){x.menuScrollMousewheel(t,e)}},A)).dataSM("scroll-arrows").css({top:"auto",left:"0",marginLeft:e+(parseInt(t.css("border-left-width"))||0),width:r-(parseInt(t.css("border-left-width"))||0)-(parseInt(t.css("border-right-width"))||0),zIndex:t.css("z-index")}).eq(g&&this.opts.bottomToTopSubMenus?0:1).show(),this.isFixed()){var C={};C[touchEvents?"touchstart touchmove touchend":"pointerdown pointermove pointerup MSPointerDown MSPointerMove MSPointerUp"]=function(e){x.menuScrollTouch(t,e)},t.css({"touch-action":"none","-ms-touch-action":"none"}).on(getEventsNS(C,A))}}}t.css({top:"auto",left:"0",marginLeft:e,marginTop:i-m})},menuScroll:function(t,e,i){var s,o=t.dataSM("scroll"),a=t.dataSM("scroll-arrows"),n=o.up?o.upEnd:o.downEnd;if(!e&&o.momentum){if(o.momentum*=.92,s=o.momentum,.5>s)return this.menuScrollStop(t),void 0}else s=i||(e||!this.opts.scrollAccelerate?this.opts.scrollStep:Math.floor(o.step));var r=t.dataSM("level");if(this.activatedItems[r-1]&&this.activatedItems[r-1].dataSM("sub")&&this.activatedItems[r-1].dataSM("sub").is(":visible")&&this.menuHideSubMenus(r-1),o.y=o.up&&o.y>=n||!o.up&&n>=o.y?o.y:Math.abs(n-o.y)>s?o.y+(o.up?s:-s):n,t.css(this.cssTransforms3d?{"-webkit-transform":"translate3d(0, "+o.y+"px, 0)",transform:"translate3d(0, "+o.y+"px, 0)"}:{marginTop:o.y}),mouse&&(o.up&&o.y>o.downEnd||!o.up&&o.y0;t.dataSM("scroll-arrows").eq(i?0:1).is(":visible")&&(t.dataSM("scroll").up=i,this.menuScroll(t,!0))}e.preventDefault()},menuScrollOut:function(t,e){mouse&&(/^scroll-(up|down)/.test((e.relatedTarget||"").className)||(t[0]==e.relatedTarget||$.contains(t[0],e.relatedTarget))&&this.getClosestMenu(e.relatedTarget)==t[0]||t.dataSM("scroll-arrows").css("visibility","hidden"))},menuScrollOver:function(t,e){if(mouse&&!/^scroll-(up|down)/.test(e.target.className)&&this.getClosestMenu(e.target)==t[0]){this.menuScrollRefreshData(t);var i=t.dataSM("scroll"),s=$(window).scrollTop()-t.dataSM("parent-a").offset().top-i.itemH;t.dataSM("scroll-arrows").eq(0).css("margin-top",s).end().eq(1).css("margin-top",s+this.getViewportHeight()-i.arrowDownH).end().css("visibility","visible")}},menuScrollRefreshData:function(t){var e=t.dataSM("scroll"),i=$(window).scrollTop()-t.dataSM("parent-a").offset().top-e.itemH;this.cssTransforms3d&&(i=-(parseFloat(t.css("margin-top"))-i)),$.extend(e,{upEnd:i,downEnd:i+this.getViewportHeight()-e.subH})},menuScrollStop:function(t){return this.scrollTimeout?(cancelAnimationFrame(this.scrollTimeout),this.scrollTimeout=0,t.dataSM("scroll").step=1,!0):void 0},menuScrollTouch:function(t,e){if(e=e.originalEvent,isTouchEvent(e)){var i=this.getTouchPoint(e);if(this.getClosestMenu(i.target)==t[0]){var s=t.dataSM("scroll");if(/(start|down)$/i.test(e.type))this.menuScrollStop(t)?(e.preventDefault(),this.$touchScrollingSub=t):this.$touchScrollingSub=null,this.menuScrollRefreshData(t),$.extend(s,{touchStartY:i.pageY,touchStartTime:e.timeStamp});else if(/move$/i.test(e.type)){var o=void 0!==s.touchY?s.touchY:s.touchStartY;if(void 0!==o&&o!=i.pageY){this.$touchScrollingSub=t;var a=i.pageY>o;void 0!==s.up&&s.up!=a&&$.extend(s,{touchStartY:i.pageY,touchStartTime:e.timeStamp}),$.extend(s,{up:a,touchY:i.pageY}),this.menuScroll(t,!0,Math.abs(i.pageY-o))}e.preventDefault()}else void 0!==s.touchY&&((s.momentum=15*Math.pow(Math.abs(i.pageY-s.touchStartY)/(e.timeStamp-s.touchStartTime),2))&&(this.menuScrollStop(t),this.menuScroll(t),e.preventDefault()),delete s.touchY)}}},menuShow:function(t){if((t.dataSM("beforefirstshowfired")||(t.dataSM("beforefirstshowfired",!0),this.$root.triggerHandler("beforefirstshow.smapi",t[0])!==!1))&&this.$root.triggerHandler("beforeshow.smapi",t[0])!==!1&&(t.dataSM("shown-before",!0),canAnimate&&t.stop(!0,!0),!t.is(":visible"))){var e=t.dataSM("parent-a"),i=this.isCollapsible();if((this.opts.keepHighlighted||i)&&e.addClass("highlighted"),i)t.removeClass("sm-nowrap").css({zIndex:"",width:"auto",minWidth:"",maxWidth:"",top:"",left:"",marginLeft:"",marginTop:""});else{if(t.css("z-index",this.zIndexInc=(this.zIndexInc||this.getStartZIndex())+1),(this.opts.subMenusMinWidth||this.opts.subMenusMaxWidth)&&(t.css({width:"auto",minWidth:"",maxWidth:""}).addClass("sm-nowrap"),this.opts.subMenusMinWidth&&t.css("min-width",this.opts.subMenusMinWidth),this.opts.subMenusMaxWidth)){var s=this.getWidth(t);t.css("max-width",this.opts.subMenusMaxWidth),s>this.getWidth(t)&&t.removeClass("sm-nowrap").css("width",this.opts.subMenusMaxWidth)}this.menuPosition(t)}var o=function(){t.css("overflow","")};i?canAnimate&&this.opts.collapsibleShowFunction?this.opts.collapsibleShowFunction.call(this,t,o):t.show(this.opts.collapsibleShowDuration,o):canAnimate&&this.opts.showFunction?this.opts.showFunction.call(this,t,o):t.show(this.opts.showDuration,o),e.attr("aria-expanded","true"),t.attr({"aria-expanded":"true","aria-hidden":"false"}),this.visibleSubMenus.push(t),this.$root.triggerHandler("show.smapi",t[0])}},popupHide:function(t){this.hideTimeout&&(clearTimeout(this.hideTimeout),this.hideTimeout=0);var e=this;this.hideTimeout=setTimeout(function(){e.menuHideAll()},t?1:this.opts.hideTimeout)},popupShow:function(t,e){if(!this.opts.isPopup)return alert('SmartMenus jQuery Error:\n\nIf you want to show this menu via the "popupShow" method, set the isPopup:true option.'),void 0;if(this.hideTimeout&&(clearTimeout(this.hideTimeout),this.hideTimeout=0),this.$root.dataSM("shown-before",!0),canAnimate&&this.$root.stop(!0,!0),!this.$root.is(":visible")){this.$root.css({left:t,top:e});var i=this,s=function(){i.$root.css("overflow","")};canAnimate&&this.opts.showFunction?this.opts.showFunction.call(this,this.$root,s):this.$root.show(this.opts.showDuration,s),this.visibleSubMenus[0]=this.$root}},refresh:function(){this.destroy(!0),this.init(!0)},rootKeyDown:function(t){if(this.handleEvents())switch(t.keyCode){case 27:var e=this.activatedItems[0];if(e){this.menuHideAll(),e[0].focus();var i=e.dataSM("sub");i&&this.menuHide(i)}break;case 32:var s=$(t.target);if(s.is("a")&&this.handleItemEvents(s)){var i=s.dataSM("sub");i&&!i.is(":visible")&&(this.itemClick({currentTarget:t.target}),t.preventDefault())}}},rootOut:function(t){if(this.handleEvents()&&!this.isTouchMode()&&t.target!=this.$root[0]&&(this.hideTimeout&&(clearTimeout(this.hideTimeout),this.hideTimeout=0),!this.opts.showOnClick||!this.opts.hideOnClick)){var e=this;this.hideTimeout=setTimeout(function(){e.menuHideAll()},this.opts.hideTimeout)}},rootOver:function(t){this.handleEvents()&&!this.isTouchMode()&&t.target!=this.$root[0]&&this.hideTimeout&&(clearTimeout(this.hideTimeout),this.hideTimeout=0)},winResize:function(t){if(this.handleEvents()){if(!("onorientationchange"in window)||"orientationchange"==t.type){var e=this.isCollapsible();this.wasCollapsible&&e||(this.activatedItems.length&&this.activatedItems[this.activatedItems.length-1][0].blur(),this.menuHideAll()),this.wasCollapsible=e}}else if(this.$disableOverlay){var i=this.$root.offset();this.$disableOverlay.css({top:i.top,left:i.left,width:this.$root.outerWidth(),height:this.$root.outerHeight()})}}}}),$.fn.dataSM=function(t,e){return e?this.data(t+"_smartmenus",e):this.data(t+"_smartmenus")},$.fn.removeDataSM=function(t){return this.removeData(t+"_smartmenus")},$.fn.smartmenus=function(options){if("string"==typeof options){var args=arguments,method=options;return Array.prototype.shift.call(args),this.each(function(){var t=$(this).data("smartmenus");t&&t[method]&&t[method].apply(t,args)})}return this.each(function(){var dataOpts=$(this).data("sm-options")||null;if(dataOpts)try{dataOpts=eval("("+dataOpts+")")}catch(e){dataOpts=null,alert('ERROR\n\nSmartMenus jQuery init:\nInvalid "data-sm-options" attribute value syntax.')}new $.SmartMenus(this,$.extend({},$.fn.smartmenus.defaults,options,dataOpts))})},$.fn.smartmenus.defaults={isPopup:!1,mainMenuSubOffsetX:0,mainMenuSubOffsetY:0,subMenusSubOffsetX:0,subMenusSubOffsetY:0,subMenusMinWidth:"10em",subMenusMaxWidth:"20em",subIndicators:!0,subIndicatorsPos:"append",subIndicatorsText:"",scrollStep:30,scrollAccelerate:!0,showTimeout:250,hideTimeout:500,showDuration:0,showFunction:null,hideDuration:0,hideFunction:function(t,e){t.fadeOut(200,e)},collapsibleShowDuration:0,collapsibleShowFunction:function(t,e){t.slideDown(200,e)},collapsibleHideDuration:0,collapsibleHideFunction:function(t,e){t.slideUp(200,e)},showOnClick:!1,hideOnClick:!0,noMouseOver:!1,keepInViewport:!0,keepHighlighted:!0,markCurrentItem:!1,markCurrentTree:!0,rightToLeftSubMenus:!1,bottomToTopSubMenus:!1,collapsibleBehavior:"default"},$}); \ No newline at end of file + * Copyright Vasil Dinkov, Vadikom Web Ltd. http://vadikom.com; Licensed MIT */(function(t){"function"==typeof define&&define.amd?define(["jquery"],t):"object"==typeof module&&"object"==typeof module.exports?module.exports=t(require("jquery")):t(jQuery)})(function($){function initMouseDetection(t){var e=".smartmenus_mouse";if(mouseDetectionEnabled||t)mouseDetectionEnabled&&t&&($(document).off(e),mouseDetectionEnabled=!1);else{var i=!0,s=null,o={mousemove:function(t){var e={x:t.pageX,y:t.pageY,timeStamp:(new Date).getTime()};if(s){var o=Math.abs(s.x-e.x),a=Math.abs(s.y-e.y);if((o>0||a>0)&&2>=o&&2>=a&&300>=e.timeStamp-s.timeStamp&&(mouse=!0,i)){var n=$(t.target).closest("a");n.is("a")&&$.each(menuTrees,function(){return $.contains(this.$root[0],n[0])?(this.itemEnter({currentTarget:n[0]}),!1):void 0}),i=!1}}s=e}};o[touchEvents?"touchstart":"pointerover pointermove pointerout MSPointerOver MSPointerMove MSPointerOut"]=function(t){isTouchEvent(t.originalEvent)&&(mouse=!1)},$(document).on(getEventsNS(o,e)), +mouseDetectionEnabled=!0}}function isTouchEvent(t){return!/^(4|mouse)$/.test(t.pointerType)}function getEventsNS(t,e){e||(e="");var i={};for(var s in t)i[s.split(" ").join(e+" ")+e]=t[s];return i}var menuTrees=[],mouse=!1,touchEvents="ontouchstart"in window,mouseDetectionEnabled=!1,requestAnimationFrame=window.requestAnimationFrame||function(t){return setTimeout(t,1e3/60)},cancelAnimationFrame=window.cancelAnimationFrame||function(t){clearTimeout(t)},canAnimate=!!$.fn.animate;return $.SmartMenus=function(t,e){this.$root=$(t),this.opts=e,this.rootId="",this.accessIdPrefix="",this.$subArrow=null,this.activatedItems=[],this.visibleSubMenus=[],this.showTimeout=0,this.hideTimeout=0,this.scrollTimeout=0,this.clickActivated=!1,this.focusActivated=!1,this.zIndexInc=0,this.idInc=0,this.$firstLink=null,this.$firstSub=null,this.disabled=!1,this.$disableOverlay=null,this.$touchScrollingSub=null,this.cssTransforms3d="perspective"in t.style||"webkitPerspective"in t.style,this.wasCollapsible=!1,this.init()},$.extend( +$.SmartMenus,{hideAll:function(){$.each(menuTrees,function(){this.menuHideAll()})},destroy:function(){for(;menuTrees.length;)menuTrees[0].destroy();initMouseDetection(!0)},prototype:{init:function(t){var e=this;if(!t){menuTrees.push(this),this.rootId=((new Date).getTime()+Math.random()+"").replace(/\D/g,""),this.accessIdPrefix="sm-"+this.rootId+"-",this.$root.hasClass("sm-rtl")&&(this.opts.rightToLeftSubMenus=!0);var i=".smartmenus";this.$root.data("smartmenus",this).attr("data-smartmenus-id",this.rootId).dataSM("level",1).on(getEventsNS({"mouseover focusin":$.proxy(this.rootOver,this),"mouseout focusout":$.proxy(this.rootOut,this),keydown:$.proxy(this.rootKeyDown,this)},i)).on(getEventsNS({mouseenter:$.proxy(this.itemEnter,this),mouseleave:$.proxy(this.itemLeave,this),mousedown:$.proxy(this.itemDown,this),focus:$.proxy(this.itemFocus,this),blur:$.proxy(this.itemBlur,this),click:$.proxy(this.itemClick,this)},i),"a"),i+=this.rootId,this.opts.hideOnClick&&$(document).on(getEventsNS({touchstart:$.proxy( +this.docTouchStart,this),touchmove:$.proxy(this.docTouchMove,this),touchend:$.proxy(this.docTouchEnd,this),click:$.proxy(this.docClick,this)},i)),$(window).on(getEventsNS({"resize orientationchange":$.proxy(this.winResize,this)},i)),this.opts.subIndicators&&(this.$subArrow=$("").addClass("sub-arrow"),this.opts.subIndicatorsText&&this.$subArrow.html(this.opts.subIndicatorsText)),initMouseDetection()}if(this.$firstSub=this.$root.find("ul").each(function(){e.menuInit($(this))}).eq(0),this.$firstLink=this.$root.find("a").eq(0),this.opts.markCurrentItem){var s=/(index|default)\.[^#\?\/]*/i,o=/#.*/,a=window.location.href.replace(s,""),n=a.replace(o,"");this.$root.find("a").each(function(){var t=this.href.replace(s,""),i=$(this);(t==a||t==n)&&(i.addClass("current"),e.opts.markCurrentTree&&i.parentsUntil("[data-smartmenus-id]","ul").each(function(){$(this).dataSM("parent-a").addClass("current")}))})}this.wasCollapsible=this.isCollapsible()},destroy:function(t){if(!t){var e=".smartmenus";this.$root.removeData( +"smartmenus").removeAttr("data-smartmenus-id").removeDataSM("level").off(e),e+=this.rootId,$(document).off(e),$(window).off(e),this.opts.subIndicators&&(this.$subArrow=null)}this.menuHideAll();var i=this;this.$root.find("ul").each(function(){var t=$(this);t.dataSM("scroll-arrows")&&t.dataSM("scroll-arrows").remove(),t.dataSM("shown-before")&&((i.opts.subMenusMinWidth||i.opts.subMenusMaxWidth)&&t.css({width:"",minWidth:"",maxWidth:""}).removeClass("sm-nowrap"),t.dataSM("scroll-arrows")&&t.dataSM("scroll-arrows").remove(),t.css({zIndex:"",top:"",left:"",marginLeft:"",marginTop:"",display:""})),0==(t.attr("id")||"").indexOf(i.accessIdPrefix)&&t.removeAttr("id")}).removeDataSM("in-mega").removeDataSM("shown-before").removeDataSM("scroll-arrows").removeDataSM("parent-a").removeDataSM("level").removeDataSM("beforefirstshowfired").removeAttr("role").removeAttr("aria-hidden").removeAttr("aria-labelledby").removeAttr("aria-expanded"),this.$root.find("a.has-submenu").each(function(){var t=$(this);0==t.attr("id" +).indexOf(i.accessIdPrefix)&&t.removeAttr("id")}).removeClass("has-submenu").removeDataSM("sub").removeAttr("aria-haspopup").removeAttr("aria-controls").removeAttr("aria-expanded").closest("li").removeDataSM("sub"),this.opts.subIndicators&&this.$root.find("span.sub-arrow").remove(),this.opts.markCurrentItem&&this.$root.find("a.current").removeClass("current"),t||(this.$root=null,this.$firstLink=null,this.$firstSub=null,this.$disableOverlay&&(this.$disableOverlay.remove(),this.$disableOverlay=null),menuTrees.splice($.inArray(this,menuTrees),1))},disable:function(t){if(!this.disabled){if(this.menuHideAll(),!t&&!this.opts.isPopup&&this.$root.is(":visible")){var e=this.$root.offset();this.$disableOverlay=$('
    ').css({position:"absolute",top:e.top,left:e.left,width:this.$root.outerWidth(),height:this.$root.outerHeight(),zIndex:this.getStartZIndex(!0),opacity:0}).appendTo(document.body)}this.disabled=!0}},docClick:function(t){return this.$touchScrollingSub?( +this.$touchScrollingSub=null,void 0):((this.visibleSubMenus.length&&!$.contains(this.$root[0],t.target)||$(t.target).closest("a").length)&&this.menuHideAll(),void 0)},docTouchEnd:function(){if(this.lastTouch){if(!(!this.visibleSubMenus.length||void 0!==this.lastTouch.x2&&this.lastTouch.x1!=this.lastTouch.x2||void 0!==this.lastTouch.y2&&this.lastTouch.y1!=this.lastTouch.y2||this.lastTouch.target&&$.contains(this.$root[0],this.lastTouch.target))){this.hideTimeout&&(clearTimeout(this.hideTimeout),this.hideTimeout=0);var t=this;this.hideTimeout=setTimeout(function(){t.menuHideAll()},350)}this.lastTouch=null}},docTouchMove:function(t){if(this.lastTouch){var e=t.originalEvent.touches[0];this.lastTouch.x2=e.pageX,this.lastTouch.y2=e.pageY}},docTouchStart:function(t){var e=t.originalEvent.touches[0];this.lastTouch={x1:e.pageX,y1:e.pageY,target:e.target}},enable:function(){this.disabled&&(this.$disableOverlay&&(this.$disableOverlay.remove(),this.$disableOverlay=null),this.disabled=!1)},getClosestMenu:function(t){for( +var e=$(t).closest("ul");e.dataSM("in-mega");)e=e.parent().closest("ul");return e[0]||null},getHeight:function(t){return this.getOffset(t,!0)},getOffset:function(t,e){var i;"none"==t.css("display")&&(i={position:t[0].style.position,visibility:t[0].style.visibility},t.css({position:"absolute",visibility:"hidden"}).show());var s=t[0].getBoundingClientRect&&t[0].getBoundingClientRect(),o=s&&(e?s.height||s.bottom-s.top:s.width||s.right-s.left);return o||0===o||(o=e?t[0].offsetHeight:t[0].offsetWidth),i&&t.hide().css(i),o},getStartZIndex:function(t){var e=parseInt(this[t?"$root":"$firstSub"].css("z-index"));return!t&&isNaN(e)&&(e=parseInt(this.$root.css("z-index"))),isNaN(e)?1:e},getTouchPoint:function(t){return t.touches&&t.touches[0]||t.changedTouches&&t.changedTouches[0]||t},getViewport:function(t){var e=t?"Height":"Width",i=document.documentElement["client"+e],s=window["inner"+e];return s&&(i=Math.min(i,s)),i},getViewportHeight:function(){return this.getViewport(!0)},getViewportWidth:function(){ +return this.getViewport()},getWidth:function(t){return this.getOffset(t)},handleEvents:function(){return!this.disabled&&this.isCSSOn()},handleItemEvents:function(t){return this.handleEvents()&&!this.isLinkInMegaMenu(t)},isCollapsible:function(){return"static"==this.$firstSub.css("position")},isCSSOn:function(){return"inline"!=this.$firstLink.css("display")},isFixed:function(){var t="fixed"==this.$root.css("position");return t||this.$root.parentsUntil("body").each(function(){return"fixed"==$(this).css("position")?(t=!0,!1):void 0}),t},isLinkInMegaMenu:function(t){return $(this.getClosestMenu(t[0])).hasClass("mega-menu")},isTouchMode:function(){return!mouse||this.opts.noMouseOver||this.isCollapsible()},itemActivate:function(t,e){var i=t.closest("ul"),s=i.dataSM("level");if(s>1&&(!this.activatedItems[s-2]||this.activatedItems[s-2][0]!=i.dataSM("parent-a")[0])){var o=this;$(i.parentsUntil("[data-smartmenus-id]","ul").get().reverse()).add(i).each(function(){o.itemActivate($(this).dataSM("parent-a"))})}if(( +!this.isCollapsible()||e)&&this.menuHideSubMenus(this.activatedItems[s-1]&&this.activatedItems[s-1][0]==t[0]?s:s-1),this.activatedItems[s-1]=t,this.$root.triggerHandler("activate.smapi",t[0])!==!1){var a=t.dataSM("sub");a&&(this.isTouchMode()||!this.opts.showOnClick||this.clickActivated)&&this.menuShow(a)}},itemBlur:function(t){var e=$(t.currentTarget);this.handleItemEvents(e)&&this.$root.triggerHandler("blur.smapi",e[0])},itemClick:function(t){var e=$(t.currentTarget);if(this.handleItemEvents(e)){if(this.$touchScrollingSub&&this.$touchScrollingSub[0]==e.closest("ul")[0])return this.$touchScrollingSub=null,t.stopPropagation(),!1;if(this.$root.triggerHandler("click.smapi",e[0])===!1)return!1;var i=$(t.target).is(".sub-arrow"),s=e.dataSM("sub"),o=s?2==s.dataSM("level"):!1,a=this.isCollapsible(),n=/toggle$/.test(this.opts.collapsibleBehavior),r=/link$/.test(this.opts.collapsibleBehavior),h=/^accordion/.test(this.opts.collapsibleBehavior);if(s&&!s.is(":visible")){if((!r||!a||i)&&(this.opts.showOnClick&&o&&( +this.clickActivated=!0),this.itemActivate(e,h),s.is(":visible")))return this.focusActivated=!0,!1}else if(a&&(n||i))return this.itemActivate(e,h),this.menuHide(s),n&&(this.focusActivated=!1),!1;return this.opts.showOnClick&&o||e.hasClass("disabled")||this.$root.triggerHandler("select.smapi",e[0])===!1?!1:void 0}},itemDown:function(t){var e=$(t.currentTarget);this.handleItemEvents(e)&&e.dataSM("mousedown",!0)},itemEnter:function(t){var e=$(t.currentTarget);if(this.handleItemEvents(e)){if(!this.isTouchMode()){this.showTimeout&&(clearTimeout(this.showTimeout),this.showTimeout=0);var i=this;this.showTimeout=setTimeout(function(){i.itemActivate(e)},this.opts.showOnClick&&1==e.closest("ul").dataSM("level")?1:this.opts.showTimeout)}this.$root.triggerHandler("mouseenter.smapi",e[0])}},itemFocus:function(t){var e=$(t.currentTarget);this.handleItemEvents(e)&&(!this.focusActivated||this.isTouchMode()&&e.dataSM("mousedown")||this.activatedItems.length&&this.activatedItems[this.activatedItems.length-1][0]==e[0 +]||this.itemActivate(e,!0),this.$root.triggerHandler("focus.smapi",e[0]))},itemLeave:function(t){var e=$(t.currentTarget);this.handleItemEvents(e)&&(this.isTouchMode()||(e[0].blur(),this.showTimeout&&(clearTimeout(this.showTimeout),this.showTimeout=0)),e.removeDataSM("mousedown"),this.$root.triggerHandler("mouseleave.smapi",e[0]))},menuHide:function(t){if(this.$root.triggerHandler("beforehide.smapi",t[0])!==!1&&(canAnimate&&t.stop(!0,!0),"none"!=t.css("display"))){var e=function(){t.css("z-index","")};this.isCollapsible()?canAnimate&&this.opts.collapsibleHideFunction?this.opts.collapsibleHideFunction.call(this,t,e):t.hide(this.opts.collapsibleHideDuration,e):canAnimate&&this.opts.hideFunction?this.opts.hideFunction.call(this,t,e):t.hide(this.opts.hideDuration,e),t.dataSM("scroll")&&(this.menuScrollStop(t),t.css({"touch-action":"","-ms-touch-action":"","-webkit-transform":"",transform:""}).off(".smartmenus_scroll").removeDataSM("scroll").dataSM("scroll-arrows").hide()),t.dataSM("parent-a").removeClass( +"highlighted").attr("aria-expanded","false"),t.attr({"aria-expanded":"false","aria-hidden":"true"});var i=t.dataSM("level");this.activatedItems.splice(i-1,1),this.visibleSubMenus.splice($.inArray(t,this.visibleSubMenus),1),this.$root.triggerHandler("hide.smapi",t[0])}},menuHideAll:function(){this.showTimeout&&(clearTimeout(this.showTimeout),this.showTimeout=0);for(var t=this.opts.isPopup?1:0,e=this.visibleSubMenus.length-1;e>=t;e--)this.menuHide(this.visibleSubMenus[e]);this.opts.isPopup&&(canAnimate&&this.$root.stop(!0,!0),this.$root.is(":visible")&&(canAnimate&&this.opts.hideFunction?this.opts.hideFunction.call(this,this.$root):this.$root.hide(this.opts.hideDuration))),this.activatedItems=[],this.visibleSubMenus=[],this.clickActivated=!1,this.focusActivated=!1,this.zIndexInc=0,this.$root.triggerHandler("hideAll.smapi")},menuHideSubMenus:function(t){for(var e=this.activatedItems.length-1;e>=t;e--){var i=this.activatedItems[e].dataSM("sub");i&&this.menuHide(i)}},menuInit:function(t){if(!t.dataSM("in-mega")){ +t.hasClass("mega-menu")&&t.find("ul").dataSM("in-mega",!0);for(var e=2,i=t[0];(i=i.parentNode.parentNode)!=this.$root[0];)e++;var s=t.prevAll("a").eq(-1);s.length||(s=t.prevAll().find("a").eq(-1)),s.addClass("has-submenu").dataSM("sub",t),t.dataSM("parent-a",s).dataSM("level",e).parent().dataSM("sub",t);var o=s.attr("id")||this.accessIdPrefix+ ++this.idInc,a=t.attr("id")||this.accessIdPrefix+ ++this.idInc;s.attr({id:o,"aria-haspopup":"true","aria-controls":a,"aria-expanded":"false"}),t.attr({id:a,role:"group","aria-hidden":"true","aria-labelledby":o,"aria-expanded":"false"}),this.opts.subIndicators&&s[this.opts.subIndicatorsPos](this.$subArrow.clone())}},menuPosition:function(t){var e,i,s=t.dataSM("parent-a"),o=s.closest("li"),a=o.parent(),n=t.dataSM("level"),r=this.getWidth(t),h=this.getHeight(t),u=s.offset(),l=u.left,c=u.top,d=this.getWidth(s),m=this.getHeight(s),p=$(window),f=p.scrollLeft(),v=p.scrollTop(),b=this.getViewportWidth(),S=this.getViewportHeight(),g=a.parent().is("[data-sm-horizontal-sub]" +)||2==n&&!a.hasClass("sm-vertical"),M=this.opts.rightToLeftSubMenus&&!o.is("[data-sm-reverse]")||!this.opts.rightToLeftSubMenus&&o.is("[data-sm-reverse]"),w=2==n?this.opts.mainMenuSubOffsetX:this.opts.subMenusSubOffsetX,T=2==n?this.opts.mainMenuSubOffsetY:this.opts.subMenusSubOffsetY;if(g?(e=M?d-r-w:w,i=this.opts.bottomToTopSubMenus?-h-T:m+T):(e=M?w-r:d-w,i=this.opts.bottomToTopSubMenus?m-T-h:T),this.opts.keepInViewport){var y=l+e,I=c+i;if(M&&f>y?e=g?f-y+e:d-w:!M&&y+r>f+b&&(e=g?f+b-r-y+e:w-r),g||(S>h&&I+h>v+S?i+=v+S-h-I:(h>=S||v>I)&&(i+=v-I)),g&&(I+h>v+S+.49||v>I)||!g&&h>S+.49){var x=this;t.dataSM("scroll-arrows")||t.dataSM("scroll-arrows",$([$('')[0],$('')[0]]).on({mouseenter:function(){t.dataSM("scroll").up=$(this).hasClass("scroll-up"),x.menuScroll(t)},mouseleave:function(e){x.menuScrollStop(t),x.menuScrollOut(t,e)},"mousewheel DOMMouseScroll":function(t){ +t.preventDefault()}}).insertAfter(t));var A=".smartmenus_scroll";if(t.dataSM("scroll",{y:this.cssTransforms3d?0:i-m,step:1,itemH:m,subH:h,arrowDownH:this.getHeight(t.dataSM("scroll-arrows").eq(1))}).on(getEventsNS({mouseover:function(e){x.menuScrollOver(t,e)},mouseout:function(e){x.menuScrollOut(t,e)},"mousewheel DOMMouseScroll":function(e){x.menuScrollMousewheel(t,e)}},A)).dataSM("scroll-arrows").css({top:"auto",left:"0",marginLeft:e+(parseInt(t.css("border-left-width"))||0),width:r-(parseInt(t.css("border-left-width"))||0)-(parseInt(t.css("border-right-width"))||0),zIndex:t.css("z-index")}).eq(g&&this.opts.bottomToTopSubMenus?0:1).show(),this.isFixed()){var C={};C[touchEvents?"touchstart touchmove touchend":"pointerdown pointermove pointerup MSPointerDown MSPointerMove MSPointerUp"]=function(e){x.menuScrollTouch(t,e)},t.css({"touch-action":"none","-ms-touch-action":"none"}).on(getEventsNS(C,A))}}}t.css({top:"auto",left:"0",marginLeft:e,marginTop:i-m})},menuScroll:function(t,e,i){var s,o=t.dataSM("scroll"), +a=t.dataSM("scroll-arrows"),n=o.up?o.upEnd:o.downEnd;if(!e&&o.momentum){if(o.momentum*=.92,s=o.momentum,.5>s)return this.menuScrollStop(t),void 0}else s=i||(e||!this.opts.scrollAccelerate?this.opts.scrollStep:Math.floor(o.step));var r=t.dataSM("level");if(this.activatedItems[r-1]&&this.activatedItems[r-1].dataSM("sub")&&this.activatedItems[r-1].dataSM("sub").is(":visible")&&this.menuHideSubMenus(r-1),o.y=o.up&&o.y>=n||!o.up&&n>=o.y?o.y:Math.abs(n-o.y)>s?o.y+(o.up?s:-s):n,t.css(this.cssTransforms3d?{"-webkit-transform":"translate3d(0, "+o.y+"px, 0)",transform:"translate3d(0, "+o.y+"px, 0)"}:{marginTop:o.y}),mouse&&(o.up&&o.y>o.downEnd||!o.up&&o.y0;t.dataSM("scroll-arrows").eq(i?0:1).is(":visible")&&(t.dataSM("scroll").up=i,this.menuScroll(t,!0))}e.preventDefault()},menuScrollOut:function(t,e){mouse&&(/^scroll-(up|down)/.test((e.relatedTarget||"").className)||(t[0]==e.relatedTarget||$.contains(t[0],e.relatedTarget))&&this.getClosestMenu(e.relatedTarget)==t[0]||t.dataSM("scroll-arrows").css("visibility","hidden"))},menuScrollOver:function(t,e){if(mouse&&!/^scroll-(up|down)/.test(e.target.className)&&this.getClosestMenu(e.target)==t[0]){this.menuScrollRefreshData(t);var i=t.dataSM("scroll"),s=$(window).scrollTop()-t.dataSM("parent-a").offset().top-i.itemH;t.dataSM("scroll-arrows").eq(0).css("margin-top",s).end().eq(1).css("margin-top",s+this.getViewportHeight()-i.arrowDownH).end().css("visibility","visible")}},menuScrollRefreshData:function(t){var e=t.dataSM("scroll"),i=$(window).scrollTop()-t.dataSM("parent-a").offset().top-e.itemH;this.cssTransforms3d&&(i=-(parseFloat(t.css("margin-top"))-i)),$.extend(e,{upEnd:i, +downEnd:i+this.getViewportHeight()-e.subH})},menuScrollStop:function(t){return this.scrollTimeout?(cancelAnimationFrame(this.scrollTimeout),this.scrollTimeout=0,t.dataSM("scroll").step=1,!0):void 0},menuScrollTouch:function(t,e){if(e=e.originalEvent,isTouchEvent(e)){var i=this.getTouchPoint(e);if(this.getClosestMenu(i.target)==t[0]){var s=t.dataSM("scroll");if(/(start|down)$/i.test(e.type))this.menuScrollStop(t)?(e.preventDefault(),this.$touchScrollingSub=t):this.$touchScrollingSub=null,this.menuScrollRefreshData(t),$.extend(s,{touchStartY:i.pageY,touchStartTime:e.timeStamp});else if(/move$/i.test(e.type)){var o=void 0!==s.touchY?s.touchY:s.touchStartY;if(void 0!==o&&o!=i.pageY){this.$touchScrollingSub=t;var a=i.pageY>o;void 0!==s.up&&s.up!=a&&$.extend(s,{touchStartY:i.pageY,touchStartTime:e.timeStamp}),$.extend(s,{up:a,touchY:i.pageY}),this.menuScroll(t,!0,Math.abs(i.pageY-o))}e.preventDefault()}else void 0!==s.touchY&&((s.momentum=15*Math.pow(Math.abs(i.pageY-s.touchStartY)/(e.timeStamp-s.touchStartTime),2) +)&&(this.menuScrollStop(t),this.menuScroll(t),e.preventDefault()),delete s.touchY)}}},menuShow:function(t){if((t.dataSM("beforefirstshowfired")||(t.dataSM("beforefirstshowfired",!0),this.$root.triggerHandler("beforefirstshow.smapi",t[0])!==!1))&&this.$root.triggerHandler("beforeshow.smapi",t[0])!==!1&&(t.dataSM("shown-before",!0),canAnimate&&t.stop(!0,!0),!t.is(":visible"))){var e=t.dataSM("parent-a"),i=this.isCollapsible();if((this.opts.keepHighlighted||i)&&e.addClass("highlighted"),i)t.removeClass("sm-nowrap").css({zIndex:"",width:"auto",minWidth:"",maxWidth:"",top:"",left:"",marginLeft:"",marginTop:""});else{if(t.css("z-index",this.zIndexInc=(this.zIndexInc||this.getStartZIndex())+1),(this.opts.subMenusMinWidth||this.opts.subMenusMaxWidth)&&(t.css({width:"auto",minWidth:"",maxWidth:""}).addClass("sm-nowrap"),this.opts.subMenusMinWidth&&t.css("min-width",this.opts.subMenusMinWidth),this.opts.subMenusMaxWidth)){var s=this.getWidth(t);t.css("max-width",this.opts.subMenusMaxWidth),s>this.getWidth(t +)&&t.removeClass("sm-nowrap").css("width",this.opts.subMenusMaxWidth)}this.menuPosition(t)}var o=function(){t.css("overflow","")};i?canAnimate&&this.opts.collapsibleShowFunction?this.opts.collapsibleShowFunction.call(this,t,o):t.show(this.opts.collapsibleShowDuration,o):canAnimate&&this.opts.showFunction?this.opts.showFunction.call(this,t,o):t.show(this.opts.showDuration,o),e.attr("aria-expanded","true"),t.attr({"aria-expanded":"true","aria-hidden":"false"}),this.visibleSubMenus.push(t),this.$root.triggerHandler("show.smapi",t[0])}},popupHide:function(t){this.hideTimeout&&(clearTimeout(this.hideTimeout),this.hideTimeout=0);var e=this;this.hideTimeout=setTimeout(function(){e.menuHideAll()},t?1:this.opts.hideTimeout)},popupShow:function(t,e){if(!this.opts.isPopup)return alert('SmartMenus jQuery Error:\n\nIf you want to show this menu via the "popupShow" method, set the isPopup:true option.'),void 0;if(this.hideTimeout&&(clearTimeout(this.hideTimeout),this.hideTimeout=0),this.$root.dataSM("shown-before",!0), +canAnimate&&this.$root.stop(!0,!0),!this.$root.is(":visible")){this.$root.css({left:t,top:e});var i=this,s=function(){i.$root.css("overflow","")};canAnimate&&this.opts.showFunction?this.opts.showFunction.call(this,this.$root,s):this.$root.show(this.opts.showDuration,s),this.visibleSubMenus[0]=this.$root}},refresh:function(){this.destroy(!0),this.init(!0)},rootKeyDown:function(t){if(this.handleEvents())switch(t.keyCode){case 27:var e=this.activatedItems[0];if(e){this.menuHideAll(),e[0].focus();var i=e.dataSM("sub");i&&this.menuHide(i)}break;case 32:var s=$(t.target);if(s.is("a")&&this.handleItemEvents(s)){var i=s.dataSM("sub");i&&!i.is(":visible")&&(this.itemClick({currentTarget:t.target}),t.preventDefault())}}},rootOut:function(t){if(this.handleEvents()&&!this.isTouchMode()&&t.target!=this.$root[0]&&(this.hideTimeout&&(clearTimeout(this.hideTimeout),this.hideTimeout=0),!this.opts.showOnClick||!this.opts.hideOnClick)){var e=this;this.hideTimeout=setTimeout(function(){e.menuHideAll()},this.opts.hideTimeout)}}, +rootOver:function(t){this.handleEvents()&&!this.isTouchMode()&&t.target!=this.$root[0]&&this.hideTimeout&&(clearTimeout(this.hideTimeout),this.hideTimeout=0)},winResize:function(t){if(this.handleEvents()){if(!("onorientationchange"in window)||"orientationchange"==t.type){var e=this.isCollapsible();this.wasCollapsible&&e||(this.activatedItems.length&&this.activatedItems[this.activatedItems.length-1][0].blur(),this.menuHideAll()),this.wasCollapsible=e}}else if(this.$disableOverlay){var i=this.$root.offset();this.$disableOverlay.css({top:i.top,left:i.left,width:this.$root.outerWidth(),height:this.$root.outerHeight()})}}}}),$.fn.dataSM=function(t,e){return e?this.data(t+"_smartmenus",e):this.data(t+"_smartmenus")},$.fn.removeDataSM=function(t){return this.removeData(t+"_smartmenus")},$.fn.smartmenus=function(options){if("string"==typeof options){var args=arguments,method=options;return Array.prototype.shift.call(args),this.each(function(){var t=$(this).data("smartmenus");t&&t[method]&&t[method].apply(t,args)})} +return this.each(function(){var dataOpts=$(this).data("sm-options")||null;if(dataOpts)try{dataOpts=eval("("+dataOpts+")")}catch(e){dataOpts=null,alert('ERROR\n\nSmartMenus jQuery init:\nInvalid "data-sm-options" attribute value syntax.')}new $.SmartMenus(this,$.extend({},$.fn.smartmenus.defaults,options,dataOpts))})},$.fn.smartmenus.defaults={isPopup:!1,mainMenuSubOffsetX:0,mainMenuSubOffsetY:0,subMenusSubOffsetX:0,subMenusSubOffsetY:0,subMenusMinWidth:"10em",subMenusMaxWidth:"20em",subIndicators:!0,subIndicatorsPos:"append",subIndicatorsText:"",scrollStep:30,scrollAccelerate:!0,showTimeout:250,hideTimeout:500,showDuration:0,showFunction:null,hideDuration:0,hideFunction:function(t,e){t.fadeOut(200,e)},collapsibleShowDuration:0,collapsibleShowFunction:function(t,e){t.slideDown(200,e)},collapsibleHideDuration:0,collapsibleHideFunction:function(t,e){t.slideUp(200,e)},showOnClick:!1,hideOnClick:!0,noMouseOver:!1,keepInViewport:!0,keepHighlighted:!0,markCurrentItem:!1,markCurrentTree:!0,rightToLeftSubMenus:!1, +bottomToTopSubMenus:!1,collapsibleBehavior:"default"},$}); diff --git a/src/dashbls/depends/mimalloc/docs/mimalloc-doc_8h_source.html b/src/dashbls/depends/mimalloc/docs/mimalloc-doc_8h_source.html index 8935de8a8890..3c1ad4fbaed1 100644 --- a/src/dashbls/depends/mimalloc/docs/mimalloc-doc_8h_source.html +++ b/src/dashbls/depends/mimalloc/docs/mimalloc-doc_8h_source.html @@ -1,24 +1,26 @@ - + - - + + mi-malloc: mimalloc-doc.h Source File + - + + @@ -29,20 +31,16 @@
    - + - -
    -
    mi-malloc -  1.7/2.0 +
    +
    mi-malloc 1.8/2.1
    +
    - -   + @@ -56,10 +54,15 @@
    - + +
    @@ -74,8 +77,8 @@
    @@ -88,473 +91,584 @@
    - +
    +
    +
    +
    +
    Loading...
    +
    Searching...
    +
    No Matches
    +
    +
    +
    -
    -
    mimalloc-doc.h
    +
    mimalloc-doc.h
    -
    1 /* ----------------------------------------------------------------------------
    -
    2 Copyright (c) 2018-2021, Microsoft Research, Daan Leijen
    -
    3 This is free software; you can redistribute it and/or modify it under the
    -
    4 terms of the MIT license. A copy of the license can be found in the file
    -
    5 "LICENSE" at the root of this distribution.
    -
    6 -----------------------------------------------------------------------------*/
    -
    7 
    -
    8 #error "documentation file only!"
    -
    9 
    -
    10 
    -
    94 
    -
    95 
    -
    99 void mi_free(void* p);
    -
    100 
    -
    105 void* mi_malloc(size_t size);
    -
    106 
    -
    111 void* mi_zalloc(size_t size);
    -
    112 
    -
    122 void* mi_calloc(size_t count, size_t size);
    -
    123 
    -
    136 void* mi_realloc(void* p, size_t newsize);
    -
    137 
    -
    148 void* mi_recalloc(void* p, size_t count, size_t size);
    -
    149 
    -
    163 void* mi_expand(void* p, size_t newsize);
    -
    164 
    -
    174 void* mi_mallocn(size_t count, size_t size);
    -
    175 
    -
    185 void* mi_reallocn(void* p, size_t count, size_t size);
    -
    186 
    -
    203 void* mi_reallocf(void* p, size_t newsize);
    -
    204 
    -
    205 
    -
    214 char* mi_strdup(const char* s);
    -
    215 
    -
    225 char* mi_strndup(const char* s, size_t n);
    -
    226 
    -
    239 char* mi_realpath(const char* fname, char* resolved_name);
    -
    240 
    -
    242 
    -
    243 // ------------------------------------------------------
    -
    244 // Extended functionality
    -
    245 // ------------------------------------------------------
    -
    246 
    -
    250 
    -
    253 #define MI_SMALL_SIZE_MAX (128*sizeof(void*))
    -
    254 
    -
    262 void* mi_malloc_small(size_t size);
    -
    263 
    -
    271 void* mi_zalloc_small(size_t size);
    -
    272 
    -
    287 size_t mi_usable_size(void* p);
    -
    288 
    -
    298 size_t mi_good_size(size_t size);
    -
    299 
    -
    307 void mi_collect(bool force);
    -
    308 
    -
    313 void mi_stats_print(void* out);
    -
    314 
    -
    320 void mi_stats_print_out(mi_output_fun* out, void* arg);
    -
    321 
    -
    323 void mi_stats_reset(void);
    -
    324 
    -
    326 void mi_stats_merge(void);
    -
    327 
    -
    331 void mi_thread_init(void);
    -
    332 
    -
    337 void mi_thread_done(void);
    -
    338 
    - -
    345 
    -
    352 typedef void (mi_deferred_free_fun)(bool force, unsigned long long heartbeat, void* arg);
    -
    353 
    -
    369 void mi_register_deferred_free(mi_deferred_free_fun* deferred_free, void* arg);
    -
    370 
    -
    376 typedef void (mi_output_fun)(const char* msg, void* arg);
    -
    377 
    -
    384 void mi_register_output(mi_output_fun* out, void* arg);
    -
    385 
    -
    391 typedef void (mi_error_fun)(int err, void* arg);
    -
    392 
    -
    408 void mi_register_error(mi_error_fun* errfun, void* arg);
    -
    409 
    -
    414 bool mi_is_in_heap_region(const void* p);
    -
    415 
    -
    424 int mi_reserve_os_memory(size_t size, bool commit, bool allow_large);
    -
    425 
    -
    437 bool mi_manage_os_memory(void* start, size_t size, bool is_committed, bool is_large, bool is_zero, int numa_node);
    -
    438 
    -
    451 int mi_reserve_huge_os_pages_interleave(size_t pages, size_t numa_nodes, size_t timeout_msecs);
    -
    452 
    -
    465 int mi_reserve_huge_os_pages_at(size_t pages, int numa_node, size_t timeout_msecs);
    -
    466 
    -
    467 
    - -
    473 
    -
    487 void mi_process_info(size_t* elapsed_msecs, size_t* user_msecs, size_t* system_msecs, size_t* current_rss, size_t* peak_rss, size_t* current_commit, size_t* peak_commit, size_t* page_faults);
    -
    488 
    -
    490 
    -
    491 // ------------------------------------------------------
    -
    492 // Aligned allocation
    -
    493 // ------------------------------------------------------
    -
    494 
    -
    500 
    -
    502 #define MI_ALIGNMENT_MAX (1024*1024UL)
    -
    503 
    -
    516 void* mi_malloc_aligned(size_t size, size_t alignment);
    -
    517 void* mi_zalloc_aligned(size_t size, size_t alignment);
    -
    518 void* mi_calloc_aligned(size_t count, size_t size, size_t alignment);
    -
    519 void* mi_realloc_aligned(void* p, size_t newsize, size_t alignment);
    -
    520 
    -
    531 void* mi_malloc_aligned_at(size_t size, size_t alignment, size_t offset);
    -
    532 void* mi_zalloc_aligned_at(size_t size, size_t alignment, size_t offset);
    -
    533 void* mi_calloc_aligned_at(size_t count, size_t size, size_t alignment, size_t offset);
    -
    534 void* mi_realloc_aligned_at(void* p, size_t newsize, size_t alignment, size_t offset);
    -
    535 
    -
    537 
    -
    543 
    -
    548 struct mi_heap_s;
    -
    549 
    -
    554 typedef struct mi_heap_s mi_heap_t;
    -
    555 
    - -
    558 
    - -
    567 
    - -
    576 
    - -
    581 
    - -
    585 
    - -
    592 
    -
    594 void mi_heap_collect(mi_heap_t* heap, bool force);
    -
    595 
    -
    598 void* mi_heap_malloc(mi_heap_t* heap, size_t size);
    -
    599 
    -
    603 void* mi_heap_malloc_small(mi_heap_t* heap, size_t size);
    -
    604 
    -
    607 void* mi_heap_zalloc(mi_heap_t* heap, size_t size);
    -
    608 
    -
    611 void* mi_heap_calloc(mi_heap_t* heap, size_t count, size_t size);
    -
    612 
    -
    615 void* mi_heap_mallocn(mi_heap_t* heap, size_t count, size_t size);
    -
    616 
    -
    619 char* mi_heap_strdup(mi_heap_t* heap, const char* s);
    -
    620 
    -
    623 char* mi_heap_strndup(mi_heap_t* heap, const char* s, size_t n);
    -
    624 
    -
    627 char* mi_heap_realpath(mi_heap_t* heap, const char* fname, char* resolved_name);
    -
    628 
    -
    629 void* mi_heap_realloc(mi_heap_t* heap, void* p, size_t newsize);
    -
    630 void* mi_heap_reallocn(mi_heap_t* heap, void* p, size_t count, size_t size);
    -
    631 void* mi_heap_reallocf(mi_heap_t* heap, void* p, size_t newsize);
    -
    632 
    -
    633 void* mi_heap_malloc_aligned(mi_heap_t* heap, size_t size, size_t alignment);
    -
    634 void* mi_heap_malloc_aligned_at(mi_heap_t* heap, size_t size, size_t alignment, size_t offset);
    -
    635 void* mi_heap_zalloc_aligned(mi_heap_t* heap, size_t size, size_t alignment);
    -
    636 void* mi_heap_zalloc_aligned_at(mi_heap_t* heap, size_t size, size_t alignment, size_t offset);
    -
    637 void* mi_heap_calloc_aligned(mi_heap_t* heap, size_t count, size_t size, size_t alignment);
    -
    638 void* mi_heap_calloc_aligned_at(mi_heap_t* heap, size_t count, size_t size, size_t alignment, size_t offset);
    -
    639 void* mi_heap_realloc_aligned(mi_heap_t* heap, void* p, size_t newsize, size_t alignment);
    -
    640 void* mi_heap_realloc_aligned_at(mi_heap_t* heap, void* p, size_t newsize, size_t alignment, size_t offset);
    -
    641 
    -
    643 
    -
    644 
    -
    653 
    -
    654 void* mi_rezalloc(void* p, size_t newsize);
    -
    655 void* mi_recalloc(void* p, size_t newcount, size_t size) ;
    -
    656 
    -
    657 void* mi_rezalloc_aligned(void* p, size_t newsize, size_t alignment);
    -
    658 void* mi_rezalloc_aligned_at(void* p, size_t newsize, size_t alignment, size_t offset);
    -
    659 void* mi_recalloc_aligned(void* p, size_t newcount, size_t size, size_t alignment);
    -
    660 void* mi_recalloc_aligned_at(void* p, size_t newcount, size_t size, size_t alignment, size_t offset);
    -
    661 
    -
    662 void* mi_heap_rezalloc(mi_heap_t* heap, void* p, size_t newsize);
    -
    663 void* mi_heap_recalloc(mi_heap_t* heap, void* p, size_t newcount, size_t size);
    -
    664 
    -
    665 void* mi_heap_rezalloc_aligned(mi_heap_t* heap, void* p, size_t newsize, size_t alignment);
    -
    666 void* mi_heap_rezalloc_aligned_at(mi_heap_t* heap, void* p, size_t newsize, size_t alignment, size_t offset);
    -
    667 void* mi_heap_recalloc_aligned(mi_heap_t* heap, void* p, size_t newcount, size_t size, size_t alignment);
    -
    668 void* mi_heap_recalloc_aligned_at(mi_heap_t* heap, void* p, size_t newcount, size_t size, size_t alignment, size_t offset);
    -
    669 
    -
    671 
    -
    680 
    -
    692 #define mi_malloc_tp(tp) ((tp*)mi_malloc(sizeof(tp)))
    -
    693 
    -
    695 #define mi_zalloc_tp(tp) ((tp*)mi_zalloc(sizeof(tp)))
    -
    696 
    -
    698 #define mi_calloc_tp(tp,count) ((tp*)mi_calloc(count,sizeof(tp)))
    -
    699 
    -
    701 #define mi_mallocn_tp(tp,count) ((tp*)mi_mallocn(count,sizeof(tp)))
    -
    702 
    -
    704 #define mi_reallocn_tp(p,tp,count) ((tp*)mi_reallocn(p,count,sizeof(tp)))
    -
    705 
    -
    707 #define mi_heap_malloc_tp(hp,tp) ((tp*)mi_heap_malloc(hp,sizeof(tp)))
    -
    708 
    -
    710 #define mi_heap_zalloc_tp(hp,tp) ((tp*)mi_heap_zalloc(hp,sizeof(tp)))
    -
    711 
    -
    713 #define mi_heap_calloc_tp(hp,tp,count) ((tp*)mi_heap_calloc(hp,count,sizeof(tp)))
    -
    714 
    -
    716 #define mi_heap_mallocn_tp(hp,tp,count) ((tp*)mi_heap_mallocn(hp,count,sizeof(tp)))
    -
    717 
    -
    719 #define mi_heap_reallocn_tp(hp,p,tp,count) ((tp*)mi_heap_reallocn(p,count,sizeof(tp)))
    -
    720 
    -
    722 #define mi_heap_recalloc_tp(hp,p,tp,count) ((tp*)mi_heap_recalloc(p,count,sizeof(tp)))
    -
    723 
    -
    725 
    -
    731 
    -
    738 bool mi_heap_contains_block(mi_heap_t* heap, const void* p);
    -
    739 
    -
    748 bool mi_heap_check_owned(mi_heap_t* heap, const void* p);
    -
    749 
    -
    757 bool mi_check_owned(const void* p);
    -
    758 
    -
    761 typedef struct mi_heap_area_s {
    -
    762  void* blocks;
    -
    763  size_t reserved;
    -
    764  size_t committed;
    -
    765  size_t used;
    -
    766  size_t block_size;
    - -
    768 
    -
    776 typedef bool (mi_block_visit_fun)(const mi_heap_t* heap, const mi_heap_area_t* area, void* block, size_t block_size, void* arg);
    -
    777 
    -
    789 bool mi_heap_visit_blocks(const mi_heap_t* heap, bool visit_all_blocks, mi_block_visit_fun* visitor, void* arg);
    -
    790 
    -
    792 
    -
    798 
    -
    800 typedef enum mi_option_e {
    -
    801  // stable options
    - - - -
    805  // the following options are experimental
    - - - - - - - - - - - - - - - -
    821 
    -
    822 
    - - - -
    826 void mi_option_set_enabled(mi_option_t option, bool enable);
    -
    827 void mi_option_set_enabled_default(mi_option_t option, bool enable);
    -
    828 
    - -
    830 void mi_option_set(mi_option_t option, long value);
    -
    831 void mi_option_set_default(mi_option_t option, long value);
    -
    832 
    -
    833 
    -
    835 
    -
    842 
    -
    843 void* mi_recalloc(void* p, size_t count, size_t size);
    -
    844 size_t mi_malloc_size(const void* p);
    -
    845 size_t mi_malloc_usable_size(const void *p);
    -
    846 
    -
    848 void mi_cfree(void* p);
    -
    849 
    -
    850 int mi_posix_memalign(void** p, size_t alignment, size_t size);
    -
    851 int mi__posix_memalign(void** p, size_t alignment, size_t size);
    -
    852 void* mi_memalign(size_t alignment, size_t size);
    -
    853 void* mi_valloc(size_t size);
    -
    854 
    -
    855 void* mi_pvalloc(size_t size);
    -
    856 void* mi_aligned_alloc(size_t alignment, size_t size);
    -
    857 
    -
    860 void* mi_reallocarray(void* p, size_t count, size_t size);
    -
    861 
    -
    863 int mi_reallocarr(void* p, size_t count, size_t size);
    -
    864 
    -
    865 void mi_free_size(void* p, size_t size);
    -
    866 void mi_free_size_aligned(void* p, size_t size, size_t alignment);
    -
    867 void mi_free_aligned(void* p, size_t alignment);
    -
    868 
    -
    870 
    -
    883 
    -
    885 void* mi_new(std::size_t n) noexcept(false);
    -
    886 
    -
    888 void* mi_new_n(size_t count, size_t size) noexcept(false);
    -
    889 
    -
    891 void* mi_new_aligned(std::size_t n, std::align_val_t alignment) noexcept(false);
    -
    892 
    -
    894 void* mi_new_nothrow(size_t n);
    -
    895 
    -
    897 void* mi_new_aligned_nothrow(size_t n, size_t alignment);
    -
    898 
    -
    900 void* mi_new_realloc(void* p, size_t newsize);
    -
    901 
    -
    903 void* mi_new_reallocn(void* p, size_t newcount, size_t size);
    -
    904 
    -
    912 template<class T> struct mi_stl_allocator { }
    -
    913 
    -
    915 
    -
    void * mi_calloc_aligned_at(size_t count, size_t size, size_t alignment, size_t offset)
    -
    void * mi_zalloc_aligned(size_t size, size_t alignment)
    -
    void * mi_realloc_aligned(void *p, size_t newsize, size_t alignment)
    -
    void * mi_calloc_aligned(size_t count, size_t size, size_t alignment)
    -
    void * mi_malloc_aligned_at(size_t size, size_t alignment, size_t offset)
    Allocate size bytes aligned by alignment at a specified offset.
    -
    void * mi_zalloc_aligned_at(size_t size, size_t alignment, size_t offset)
    -
    void * mi_malloc_aligned(size_t size, size_t alignment)
    Allocate size bytes aligned by alignment.
    -
    void * mi_realloc_aligned_at(void *p, size_t newsize, size_t alignment, size_t offset)
    -
    size_t block_size
    size in bytes of one block
    Definition: mimalloc-doc.h:766
    -
    size_t committed
    current committed bytes of this area
    Definition: mimalloc-doc.h:764
    -
    size_t used
    bytes in use by allocated blocks
    Definition: mimalloc-doc.h:765
    -
    void * blocks
    start of the area containing heap blocks
    Definition: mimalloc-doc.h:762
    -
    size_t reserved
    bytes reserved for this area
    Definition: mimalloc-doc.h:763
    +
    1/* ----------------------------------------------------------------------------
    +
    2Copyright (c) 2018-2025, Microsoft Research, Daan Leijen
    +
    3This is free software; you can redistribute it and/or modify it under the
    +
    4terms of the MIT license. A copy of the license can be found in the file
    +
    5"LICENSE" at the root of this distribution.
    +
    6-----------------------------------------------------------------------------*/
    +
    7
    +
    8#error "documentation file only!"
    +
    9
    +
    10
    +
    92
    +
    93
    +
    97
    +
    98
    +
    102void mi_free(void* p);
    +
    103
    +
    108void* mi_malloc(size_t size);
    +
    109
    +
    114void* mi_zalloc(size_t size);
    +
    115
    +
    125void* mi_calloc(size_t count, size_t size);
    +
    126
    +
    139void* mi_realloc(void* p, size_t newsize);
    +
    140
    +
    151void* mi_recalloc(void* p, size_t count, size_t size);
    +
    152
    +
    166void* mi_expand(void* p, size_t newsize);
    +
    167
    +
    177void* mi_mallocn(size_t count, size_t size);
    +
    178
    +
    188void* mi_reallocn(void* p, size_t count, size_t size);
    +
    189
    +
    206void* mi_reallocf(void* p, size_t newsize);
    +
    207
    +
    208
    +
    217char* mi_strdup(const char* s);
    +
    218
    +
    228char* mi_strndup(const char* s, size_t n);
    +
    229
    +
    242char* mi_realpath(const char* fname, char* resolved_name);
    +
    243
    +
    245
    +
    246// ------------------------------------------------------
    +
    247// Extended functionality
    +
    248// ------------------------------------------------------
    +
    249
    +
    253
    +
    256#define MI_SMALL_SIZE_MAX (128*sizeof(void*))
    +
    257
    +
    265void* mi_malloc_small(size_t size);
    +
    266
    +
    274void* mi_zalloc_small(size_t size);
    +
    275
    +
    289size_t mi_usable_size(void* p);
    +
    290
    +
    300size_t mi_good_size(size_t size);
    +
    301
    +
    309void mi_collect(bool force);
    +
    310
    +
    315void mi_stats_print(void* out);
    +
    316
    +
    322void mi_stats_print_out(mi_output_fun* out, void* arg);
    +
    323
    +
    325void mi_stats_reset(void);
    +
    326
    +
    328void mi_stats_merge(void);
    +
    329
    +
    333void mi_thread_init(void);
    +
    334
    +
    339void mi_thread_done(void);
    +
    340
    + +
    347
    +
    354typedef void (mi_deferred_free_fun)(bool force, unsigned long long heartbeat, void* arg);
    +
    355
    +
    371void mi_register_deferred_free(mi_deferred_free_fun* deferred_free, void* arg);
    +
    372
    +
    378typedef void (mi_output_fun)(const char* msg, void* arg);
    +
    379
    +
    386void mi_register_output(mi_output_fun* out, void* arg);
    +
    387
    +
    393typedef void (mi_error_fun)(int err, void* arg);
    +
    394
    +
    410void mi_register_error(mi_error_fun* errfun, void* arg);
    +
    411
    +
    416bool mi_is_in_heap_region(const void* p);
    +
    417
    +
    426int mi_reserve_os_memory(size_t size, bool commit, bool allow_large);
    +
    427
    +
    439bool mi_manage_os_memory(void* start, size_t size, bool is_committed, bool is_large, bool is_zero, int numa_node);
    +
    440
    +
    453int mi_reserve_huge_os_pages_interleave(size_t pages, size_t numa_nodes, size_t timeout_msecs);
    +
    454
    +
    467int mi_reserve_huge_os_pages_at(size_t pages, int numa_node, size_t timeout_msecs);
    +
    468
    +
    469
    + +
    475
    +
    489void mi_process_info(size_t* elapsed_msecs, size_t* user_msecs, size_t* system_msecs, size_t* current_rss, size_t* peak_rss, size_t* current_commit, size_t* peak_commit, size_t* page_faults);
    +
    490
    +
    495void mi_debug_show_arenas(bool show_inuse, bool show_abandoned, bool show_purge);
    +
    496
    +
    499typedef int mi_arena_id_t;
    +
    500
    +
    505void* mi_arena_area(mi_arena_id_t arena_id, size_t* size);
    +
    506
    +
    514int mi_reserve_huge_os_pages_at_ex(size_t pages, int numa_node, size_t timeout_msecs, bool exclusive, mi_arena_id_t* arena_id);
    +
    515
    +
    523int mi_reserve_os_memory_ex(size_t size, bool commit, bool allow_large, bool exclusive, mi_arena_id_t* arena_id);
    +
    524
    +
    535bool mi_manage_os_memory_ex(void* start, size_t size, bool is_committed, bool is_large, bool is_zero, int numa_node, bool exclusive, mi_arena_id_t* arena_id);
    +
    536
    + +
    541
    +
    552mi_heap_t* mi_heap_new_ex(int heap_tag, bool allow_destroy, mi_arena_id_t arena_id);
    +
    553
    +
    557typedef void* mi_subproc_id_t;
    +
    558
    + +
    561
    + +
    565
    + +
    570
    + +
    574
    +
    575
    +
    577
    +
    578// ------------------------------------------------------
    +
    579// Aligned allocation
    +
    580// ------------------------------------------------------
    +
    581
    +
    589
    +
    607void* mi_malloc_aligned(size_t size, size_t alignment);
    +
    608void* mi_zalloc_aligned(size_t size, size_t alignment);
    +
    609void* mi_calloc_aligned(size_t count, size_t size, size_t alignment);
    +
    610void* mi_realloc_aligned(void* p, size_t newsize, size_t alignment);
    +
    611
    +
    623void* mi_malloc_aligned_at(size_t size, size_t alignment, size_t offset);
    +
    624void* mi_zalloc_aligned_at(size_t size, size_t alignment, size_t offset);
    +
    625void* mi_calloc_aligned_at(size_t count, size_t size, size_t alignment, size_t offset);
    +
    626void* mi_realloc_aligned_at(void* p, size_t newsize, size_t alignment, size_t offset);
    +
    627
    +
    629
    +
    635
    +
    640struct mi_heap_s;
    +
    641
    +
    646typedef struct mi_heap_s mi_heap_t;
    +
    647
    + +
    650
    + +
    659
    + +
    668
    + +
    673
    + +
    677
    + +
    684
    +
    686void mi_heap_collect(mi_heap_t* heap, bool force);
    +
    687
    +
    690void* mi_heap_malloc(mi_heap_t* heap, size_t size);
    +
    691
    +
    695void* mi_heap_malloc_small(mi_heap_t* heap, size_t size);
    +
    696
    +
    699void* mi_heap_zalloc(mi_heap_t* heap, size_t size);
    +
    700
    +
    703void* mi_heap_calloc(mi_heap_t* heap, size_t count, size_t size);
    +
    704
    +
    707void* mi_heap_mallocn(mi_heap_t* heap, size_t count, size_t size);
    +
    708
    +
    711char* mi_heap_strdup(mi_heap_t* heap, const char* s);
    +
    712
    +
    715char* mi_heap_strndup(mi_heap_t* heap, const char* s, size_t n);
    +
    716
    +
    719char* mi_heap_realpath(mi_heap_t* heap, const char* fname, char* resolved_name);
    +
    720
    +
    721void* mi_heap_realloc(mi_heap_t* heap, void* p, size_t newsize);
    +
    722void* mi_heap_reallocn(mi_heap_t* heap, void* p, size_t count, size_t size);
    +
    723void* mi_heap_reallocf(mi_heap_t* heap, void* p, size_t newsize);
    +
    724
    +
    725void* mi_heap_malloc_aligned(mi_heap_t* heap, size_t size, size_t alignment);
    +
    726void* mi_heap_malloc_aligned_at(mi_heap_t* heap, size_t size, size_t alignment, size_t offset);
    +
    727void* mi_heap_zalloc_aligned(mi_heap_t* heap, size_t size, size_t alignment);
    +
    728void* mi_heap_zalloc_aligned_at(mi_heap_t* heap, size_t size, size_t alignment, size_t offset);
    +
    729void* mi_heap_calloc_aligned(mi_heap_t* heap, size_t count, size_t size, size_t alignment);
    +
    730void* mi_heap_calloc_aligned_at(mi_heap_t* heap, size_t count, size_t size, size_t alignment, size_t offset);
    +
    731void* mi_heap_realloc_aligned(mi_heap_t* heap, void* p, size_t newsize, size_t alignment);
    +
    732void* mi_heap_realloc_aligned_at(mi_heap_t* heap, void* p, size_t newsize, size_t alignment, size_t offset);
    +
    733
    +
    735
    +
    736
    +
    745
    +
    746void* mi_rezalloc(void* p, size_t newsize);
    +
    747void* mi_recalloc(void* p, size_t newcount, size_t size) ;
    +
    748
    +
    749void* mi_rezalloc_aligned(void* p, size_t newsize, size_t alignment);
    +
    750void* mi_rezalloc_aligned_at(void* p, size_t newsize, size_t alignment, size_t offset);
    +
    751void* mi_recalloc_aligned(void* p, size_t newcount, size_t size, size_t alignment);
    +
    752void* mi_recalloc_aligned_at(void* p, size_t newcount, size_t size, size_t alignment, size_t offset);
    +
    753
    +
    754void* mi_heap_rezalloc(mi_heap_t* heap, void* p, size_t newsize);
    +
    755void* mi_heap_recalloc(mi_heap_t* heap, void* p, size_t newcount, size_t size);
    +
    756
    +
    757void* mi_heap_rezalloc_aligned(mi_heap_t* heap, void* p, size_t newsize, size_t alignment);
    +
    758void* mi_heap_rezalloc_aligned_at(mi_heap_t* heap, void* p, size_t newsize, size_t alignment, size_t offset);
    +
    759void* mi_heap_recalloc_aligned(mi_heap_t* heap, void* p, size_t newcount, size_t size, size_t alignment);
    +
    760void* mi_heap_recalloc_aligned_at(mi_heap_t* heap, void* p, size_t newcount, size_t size, size_t alignment, size_t offset);
    +
    761
    +
    763
    +
    772
    +
    784#define mi_malloc_tp(tp) ((tp*)mi_malloc(sizeof(tp)))
    +
    785
    +
    787#define mi_zalloc_tp(tp) ((tp*)mi_zalloc(sizeof(tp)))
    +
    788
    +
    790#define mi_calloc_tp(tp,count) ((tp*)mi_calloc(count,sizeof(tp)))
    +
    791
    +
    793#define mi_mallocn_tp(tp,count) ((tp*)mi_mallocn(count,sizeof(tp)))
    +
    794
    +
    796#define mi_reallocn_tp(p,tp,count) ((tp*)mi_reallocn(p,count,sizeof(tp)))
    +
    797
    +
    799#define mi_heap_malloc_tp(hp,tp) ((tp*)mi_heap_malloc(hp,sizeof(tp)))
    +
    800
    +
    802#define mi_heap_zalloc_tp(hp,tp) ((tp*)mi_heap_zalloc(hp,sizeof(tp)))
    +
    803
    +
    805#define mi_heap_calloc_tp(hp,tp,count) ((tp*)mi_heap_calloc(hp,count,sizeof(tp)))
    +
    806
    +
    808#define mi_heap_mallocn_tp(hp,tp,count) ((tp*)mi_heap_mallocn(hp,count,sizeof(tp)))
    +
    809
    +
    811#define mi_heap_reallocn_tp(hp,p,tp,count) ((tp*)mi_heap_reallocn(p,count,sizeof(tp)))
    +
    812
    +
    814#define mi_heap_recalloc_tp(hp,p,tp,count) ((tp*)mi_heap_recalloc(p,count,sizeof(tp)))
    +
    815
    +
    817
    +
    823
    +
    830bool mi_heap_contains_block(mi_heap_t* heap, const void* p);
    +
    831
    +
    840bool mi_heap_check_owned(mi_heap_t* heap, const void* p);
    +
    841
    +
    849bool mi_check_owned(const void* p);
    +
    850
    +
    +
    853typedef struct mi_heap_area_s {
    +
    854 void* blocks;
    +
    855 size_t reserved;
    +
    856 size_t committed;
    +
    857 size_t used;
    +
    858 size_t block_size;
    + + + +
    +
    862
    +
    870typedef bool (mi_block_visit_fun)(const mi_heap_t* heap, const mi_heap_area_t* area, void* block, size_t block_size, void* arg);
    +
    871
    +
    883bool mi_heap_visit_blocks(const mi_heap_t* heap, bool visit_all_blocks, mi_block_visit_fun* visitor, void* arg);
    +
    884
    +
    900bool mi_abandoned_visit_blocks(mi_subproc_id_t subproc_id, int heap_tag, bool visit_blocks, mi_block_visit_fun* visitor, void* arg);
    +
    901
    +
    903
    +
    909
    + +
    948
    +
    949
    + + + +
    953void mi_option_set_enabled(mi_option_t option, bool enable);
    + +
    955
    + +
    957long mi_option_get_clamp(mi_option_t option, long min, long max);
    + +
    959
    +
    960void mi_option_set(mi_option_t option, long value);
    +
    961void mi_option_set_default(mi_option_t option, long value);
    +
    962
    +
    963
    +
    965
    +
    972
    +
    974void mi_cfree(void* p);
    +
    975void* mi__expand(void* p, size_t newsize);
    +
    976
    +
    977void* mi_recalloc(void* p, size_t count, size_t size);
    +
    978size_t mi_malloc_size(const void* p);
    +
    979size_t mi_malloc_good_size(size_t size);
    +
    980size_t mi_malloc_usable_size(const void *p);
    +
    981
    +
    982int mi_posix_memalign(void** p, size_t alignment, size_t size);
    +
    983int mi__posix_memalign(void** p, size_t alignment, size_t size);
    +
    984void* mi_memalign(size_t alignment, size_t size);
    +
    985void* mi_valloc(size_t size);
    +
    986void* mi_pvalloc(size_t size);
    +
    987void* mi_aligned_alloc(size_t alignment, size_t size);
    +
    988
    +
    989unsigned short* mi_wcsdup(const unsigned short* s);
    +
    990unsigned char* mi_mbsdup(const unsigned char* s);
    +
    991int mi_dupenv_s(char** buf, size_t* size, const char* name);
    +
    992int mi_wdupenv_s(unsigned short** buf, size_t* size, const unsigned short* name);
    +
    993
    +
    996void* mi_reallocarray(void* p, size_t count, size_t size);
    +
    997
    +
    999int mi_reallocarr(void* p, size_t count, size_t size);
    +
    1000
    +
    1001void* mi_aligned_recalloc(void* p, size_t newcount, size_t size, size_t alignment);
    +
    1002void* mi_aligned_offset_recalloc(void* p, size_t newcount, size_t size, size_t alignment, size_t offset);
    +
    1003
    +
    1004void mi_free_size(void* p, size_t size);
    +
    1005void mi_free_size_aligned(void* p, size_t size, size_t alignment);
    +
    1006void mi_free_aligned(void* p, size_t alignment);
    +
    1007
    +
    1009
    +
    1022
    +
    1024void* mi_new(std::size_t n) noexcept(false);
    +
    1025
    +
    1027void* mi_new_n(size_t count, size_t size) noexcept(false);
    +
    1028
    +
    1030void* mi_new_aligned(std::size_t n, std::align_val_t alignment) noexcept(false);
    +
    1031
    +
    1033void* mi_new_nothrow(size_t n);
    +
    1034
    +
    1036void* mi_new_aligned_nothrow(size_t n, size_t alignment);
    +
    1037
    +
    1039void* mi_new_realloc(void* p, size_t newsize);
    +
    1040
    +
    1042void* mi_new_reallocn(void* p, size_t newcount, size_t size);
    +
    1043
    +
    1051template<class T> struct mi_stl_allocator { }
    +
    1052
    +
    1054
    +
    1113
    +
    1198
    +
    1263
    +
    1433
    +
    void * mi_malloc_aligned_at(size_t size, size_t alignment, size_t offset)
    Allocate size bytes aligned by alignment at a specified offset.
    +
    void * mi_calloc_aligned(size_t count, size_t size, size_t alignment)
    +
    void * mi_realloc_aligned(void *p, size_t newsize, size_t alignment)
    +
    void * mi_malloc_aligned(size_t size, size_t alignment)
    Allocate size bytes aligned by alignment.
    +
    void * mi_zalloc_aligned_at(size_t size, size_t alignment, size_t offset)
    +
    void * mi_calloc_aligned_at(size_t count, size_t size, size_t alignment, size_t offset)
    +
    void * mi_zalloc_aligned(size_t size, size_t alignment)
    +
    void * mi_realloc_aligned_at(void *p, size_t newsize, size_t alignment, size_t offset)
    +
    int heap_tag
    heap tag associated with this area (see mi_heap_new_ex)
    Definition mimalloc-doc.h:860
    +
    size_t block_size
    size in bytes of one block
    Definition mimalloc-doc.h:858
    +
    size_t committed
    current committed bytes of this area
    Definition mimalloc-doc.h:856
    +
    size_t full_block_size
    size in bytes of a full block including padding and metadata.
    Definition mimalloc-doc.h:859
    +
    size_t used
    bytes in use by allocated blocks
    Definition mimalloc-doc.h:857
    +
    void * blocks
    start of the area containing heap blocks
    Definition mimalloc-doc.h:854
    +
    size_t reserved
    bytes reserved for this area
    Definition mimalloc-doc.h:855
    bool mi_heap_check_owned(mi_heap_t *heap, const void *p)
    Check safely if any pointer is part of a heap.
    bool mi_check_owned(const void *p)
    Check safely if any pointer is part of the default heap of this thread.
    +
    bool mi_abandoned_visit_blocks(mi_subproc_id_t subproc_id, int heap_tag, bool visit_blocks, mi_block_visit_fun *visitor, void *arg)
    Visit all areas and blocks in abandoned heaps.
    bool mi_heap_visit_blocks(const mi_heap_t *heap, bool visit_all_blocks, mi_block_visit_fun *visitor, void *arg)
    Visit all areas and blocks in a heap.
    +
    bool mi_block_visit_fun(const mi_heap_t *heap, const mi_heap_area_t *area, void *block, size_t block_size, void *arg)
    Visitor function passed to mi_heap_visit_blocks()
    Definition mimalloc-doc.h:870
    bool mi_heap_contains_block(mi_heap_t *heap, const void *p)
    Does a heap contain a pointer to a previously allocated block?
    -
    bool() mi_block_visit_fun(const mi_heap_t *heap, const mi_heap_area_t *area, void *block, size_t block_size, void *arg)
    Visitor function passed to mi_heap_visit_blocks()
    Definition: mimalloc-doc.h:776
    -
    An area of heap space contains blocks of a single size.
    Definition: mimalloc-doc.h:761
    -
    void * mi_new_reallocn(void *p, size_t newcount, size_t size)
    like mi_reallocn(), but when out of memory, use std::get_new_handler and raise std::bad_alloc excepti...
    -
    void * mi_new_realloc(void *p, size_t newsize)
    like mi_realloc(), but when out of memory, use std::get_new_handler and raise std::bad_alloc exceptio...
    -
    void * mi_new(std::size_t n) noexcept(false)
    like mi_malloc(), but when out of memory, use std::get_new_handler and raise std::bad_alloc exception...
    -
    void * mi_new_aligned_nothrow(size_t n, size_t alignment)
    like mi_malloc_aligned, but when out of memory, use std::get_new_handler but return NULL on failure.
    -
    void * mi_new_n(size_t count, size_t size) noexcept(false)
    like mi_mallocn(), but when out of memory, use std::get_new_handler and raise std::bad_alloc exceptio...
    -
    void * mi_new_nothrow(size_t n)
    like mi_malloc, but when out of memory, use std::get_new_handler but return NULL on failure.
    -
    void * mi_new_aligned(std::size_t n, std::align_val_t alignment) noexcept(false)
    like mi_malloc_aligned(), but when out of memory, use std::get_new_handler and raise std::bad_alloc e...
    -
    std::allocator implementation for mimalloc for use in STL containers.
    Definition: mimalloc-doc.h:912
    +
    An area of heap space contains blocks of a single size.
    Definition mimalloc-doc.h:853
    +
    void * mi_new_nothrow(size_t n)
    like mi_malloc, but when out of memory, use std::get_new_handler but return NULL on failure.
    +
    void * mi_new(std::size_t n) noexcept(false)
    like mi_malloc(), but when out of memory, use std::get_new_handler and raise std::bad_alloc exception...
    +
    void * mi_new_realloc(void *p, size_t newsize)
    like mi_realloc(), but when out of memory, use std::get_new_handler and raise std::bad_alloc exceptio...
    +
    void * mi_new_aligned(std::size_t n, std::align_val_t alignment) noexcept(false)
    like mi_malloc_aligned(), but when out of memory, use std::get_new_handler and raise std::bad_alloc e...
    +
    void * mi_new_aligned_nothrow(size_t n, size_t alignment)
    like mi_malloc_aligned, but when out of memory, use std::get_new_handler but return NULL on failure.
    +
    void * mi_new_reallocn(void *p, size_t newcount, size_t size)
    like mi_reallocn(), but when out of memory, use std::get_new_handler and raise std::bad_alloc excepti...
    +
    void * mi_new_n(size_t count, size_t size) noexcept(false)
    like mi_mallocn(), but when out of memory, use std::get_new_handler and raise std::bad_alloc exceptio...
    +
    std::allocator implementation for mimalloc for use in STL containers.
    Definition mimalloc-doc.h:1051
    int mi_reserve_os_memory(size_t size, bool commit, bool allow_large)
    Reserve OS memory for use by mimalloc.
    size_t mi_usable_size(void *p)
    Return the available bytes in a memory block.
    void mi_thread_done(void)
    Uninitialize mimalloc on a thread.
    -
    void * mi_zalloc_small(size_t size)
    Allocate a zero initialized small object.
    -
    void() mi_error_fun(int err, void *arg)
    Type of error callback functions.
    Definition: mimalloc-doc.h:391
    -
    void() mi_deferred_free_fun(bool force, unsigned long long heartbeat, void *arg)
    Type of deferred free functions.
    Definition: mimalloc-doc.h:352
    +
    void mi_deferred_free_fun(bool force, unsigned long long heartbeat, void *arg)
    Type of deferred free functions.
    Definition mimalloc-doc.h:354
    void mi_stats_print(void *out)
    Deprecated.
    +
    mi_subproc_id_t mi_subproc_main(void)
    Get the main sub-process identifier.
    int mi_reserve_huge_os_pages_interleave(size_t pages, size_t numa_nodes, size_t timeout_msecs)
    Reserve pages of huge OS pages (1GiB) evenly divided over numa_nodes nodes, but stops after at most t...
    +
    int mi_reserve_os_memory_ex(size_t size, bool commit, bool allow_large, bool exclusive, mi_arena_id_t *arena_id)
    Reserve OS memory to be managed in an arena.
    void mi_register_deferred_free(mi_deferred_free_fun *deferred_free, void *arg)
    Register a deferred free function.
    +
    mi_heap_t * mi_heap_new_ex(int heap_tag, bool allow_destroy, mi_arena_id_t arena_id)
    Create a new heap.
    void mi_stats_reset(void)
    Reset statistics.
    +
    bool mi_manage_os_memory_ex(void *start, size_t size, bool is_committed, bool is_large, bool is_zero, int numa_node, bool exclusive, mi_arena_id_t *arena_id)
    Manage externally allocated memory as a mimalloc arena.
    void mi_collect(bool force)
    Eagerly free memory.
    bool mi_manage_os_memory(void *start, size_t size, bool is_committed, bool is_large, bool is_zero, int numa_node)
    Manage a particular memory area for use by mimalloc.
    +
    void * mi_zalloc_small(size_t size)
    Allocate a zero initialized small object.
    void mi_stats_print_out(mi_output_fun *out, void *arg)
    Print the main statistics.
    +
    int mi_reserve_huge_os_pages_at_ex(size_t pages, int numa_node, size_t timeout_msecs, bool exclusive, mi_arena_id_t *arena_id)
    Reserve huge OS pages (1GiB) into a single arena.
    bool mi_is_in_heap_region(const void *p)
    Is a pointer part of our heap?
    -
    void * mi_malloc_small(size_t size)
    Allocate a small object.
    int mi_reserve_huge_os_pages_at(size_t pages, int numa_node, size_t timeout_msecs)
    Reserve pages of huge OS pages (1GiB) at a specific numa_node, but stops after at most timeout_msecs ...
    void mi_process_info(size_t *elapsed_msecs, size_t *user_msecs, size_t *system_msecs, size_t *current_rss, size_t *peak_rss, size_t *current_commit, size_t *peak_commit, size_t *page_faults)
    Return process information (time and memory usage).
    +
    void * mi_malloc_small(size_t size)
    Allocate a small object.
    +
    mi_subproc_id_t mi_subproc_new(void)
    Create a fresh sub-process (with no associated threads yet).
    +
    void mi_error_fun(int err, void *arg)
    Type of error callback functions.
    Definition mimalloc-doc.h:393
    void mi_stats_merge(void)
    Merge thread local statistics with the main statistics and reset.
    +
    void * mi_subproc_id_t
    A process can associate threads with sub-processes.
    Definition mimalloc-doc.h:557
    +
    int mi_arena_id_t
    Mimalloc uses large (virtual) memory areas, called "arena"s, from the OS to manage its memory.
    Definition mimalloc-doc.h:499
    +
    void * mi_arena_area(mi_arena_id_t arena_id, size_t *size)
    Return the size of an arena.
    void mi_register_error(mi_error_fun *errfun, void *arg)
    Register an error callback function.
    +
    void mi_subproc_delete(mi_subproc_id_t subproc)
    Delete a previously created sub-process.
    bool mi_is_redirected()
    Is the C runtime malloc API redirected?
    +
    mi_heap_t * mi_heap_new_in_arena(mi_arena_id_t arena_id)
    Create a new heap that only allocates in the specified arena.
    void mi_thread_stats_print_out(mi_output_fun *out, void *arg)
    Print out heap statistics for this thread.
    size_t mi_good_size(size_t size)
    Return the used allocation size.
    -
    void() mi_output_fun(const char *msg, void *arg)
    Type of output functions.
    Definition: mimalloc-doc.h:376
    +
    void mi_debug_show_arenas(bool show_inuse, bool show_abandoned, bool show_purge)
    Show all current arena's.
    +
    void mi_subproc_add_current_thread(mi_subproc_id_t subproc)
    Add the current thread to the given sub-process.
    +
    void mi_output_fun(const char *msg, void *arg)
    Type of output functions.
    Definition mimalloc-doc.h:378
    void mi_register_output(mi_output_fun *out, void *arg)
    Register an output function.
    void mi_thread_init(void)
    Initialize mimalloc on a thread.
    -
    char * mi_heap_realpath(mi_heap_t *heap, const char *fname, char *resolved_name)
    Resolve a file path name using a specific heap to allocate the result.
    -
    void * mi_heap_calloc_aligned_at(mi_heap_t *heap, size_t count, size_t size, size_t alignment, size_t offset)
    -
    char * mi_heap_strdup(mi_heap_t *heap, const char *s)
    Duplicate a string in a specific heap.
    -
    void * mi_heap_malloc_aligned_at(mi_heap_t *heap, size_t size, size_t alignment, size_t offset)
    +
    void * mi_heap_malloc_small(mi_heap_t *heap, size_t size)
    Allocate a small object in a specific heap.
    +
    mi_heap_t * mi_heap_get_default()
    Get the default heap that is used for mi_malloc() et al.
    void mi_heap_delete(mi_heap_t *heap)
    Delete a previously allocated heap.
    -
    struct mi_heap_s mi_heap_t
    Type of first-class heaps.
    Definition: mimalloc-doc.h:554
    -
    void * mi_heap_zalloc_aligned_at(mi_heap_t *heap, size_t size, size_t alignment, size_t offset)
    -
    void * mi_heap_reallocf(mi_heap_t *heap, void *p, size_t newsize)
    -
    void * mi_heap_calloc_aligned(mi_heap_t *heap, size_t count, size_t size, size_t alignment)
    -
    mi_heap_t * mi_heap_get_backing()
    Get the backing heap.
    -
    mi_heap_t * mi_heap_new()
    Create a new heap that can be used for allocation.
    +
    void * mi_heap_malloc_aligned(mi_heap_t *heap, size_t size, size_t alignment)
    +
    mi_heap_t * mi_heap_set_default(mi_heap_t *heap)
    Set the default heap to use in the current thread for mi_malloc() et al.
    +
    struct mi_heap_s mi_heap_t
    Type of first-class heaps.
    Definition mimalloc-doc.h:646
    +
    void * mi_heap_zalloc_aligned_at(mi_heap_t *heap, size_t size, size_t alignment, size_t offset)
    +
    char * mi_heap_realpath(mi_heap_t *heap, const char *fname, char *resolved_name)
    Resolve a file path name using a specific heap to allocate the result.
    +
    char * mi_heap_strdup(mi_heap_t *heap, const char *s)
    Duplicate a string in a specific heap.
    +
    void * mi_heap_zalloc_aligned(mi_heap_t *heap, size_t size, size_t alignment)
    +
    void * mi_heap_realloc_aligned_at(mi_heap_t *heap, void *p, size_t newsize, size_t alignment, size_t offset)
    void mi_heap_collect(mi_heap_t *heap, bool force)
    Release outstanding resources in a specific heap.
    -
    void * mi_heap_mallocn(mi_heap_t *heap, size_t count, size_t size)
    Allocate count elements in a specific heap.
    -
    mi_heap_t * mi_heap_get_default()
    Get the default heap that is used for mi_malloc() et al.
    -
    char * mi_heap_strndup(mi_heap_t *heap, const char *s, size_t n)
    Duplicate a string of at most length n in a specific heap.
    -
    void * mi_heap_zalloc(mi_heap_t *heap, size_t size)
    Allocate zero-initialized in a specific heap.
    -
    void * mi_heap_malloc(mi_heap_t *heap, size_t size)
    Allocate in a specific heap.
    void mi_heap_destroy(mi_heap_t *heap)
    Destroy a heap, freeing all its still allocated blocks.
    -
    void * mi_heap_malloc_small(mi_heap_t *heap, size_t size)
    Allocate a small object in a specific heap.
    -
    void * mi_heap_zalloc_aligned(mi_heap_t *heap, size_t size, size_t alignment)
    -
    void * mi_heap_calloc(mi_heap_t *heap, size_t count, size_t size)
    Allocate count zero-initialized elements in a specific heap.
    -
    void * mi_heap_realloc(mi_heap_t *heap, void *p, size_t newsize)
    -
    void * mi_heap_malloc_aligned(mi_heap_t *heap, size_t size, size_t alignment)
    -
    mi_heap_t * mi_heap_set_default(mi_heap_t *heap)
    Set the default heap to use for mi_malloc() et al.
    -
    void * mi_heap_reallocn(mi_heap_t *heap, void *p, size_t count, size_t size)
    -
    void * mi_heap_realloc_aligned_at(mi_heap_t *heap, void *p, size_t newsize, size_t alignment, size_t offset)
    -
    void * mi_heap_realloc_aligned(mi_heap_t *heap, void *p, size_t newsize, size_t alignment)
    -
    char * mi_realpath(const char *fname, char *resolved_name)
    Resolve a file path name.
    -
    void * mi_mallocn(size_t count, size_t size)
    Allocate count elements of size bytes.
    +
    void * mi_heap_calloc_aligned_at(mi_heap_t *heap, size_t count, size_t size, size_t alignment, size_t offset)
    +
    mi_heap_t * mi_heap_new()
    Create a new heap that can be used for allocation.
    +
    void * mi_heap_mallocn(mi_heap_t *heap, size_t count, size_t size)
    Allocate count elements in a specific heap.
    +
    void * mi_heap_malloc(mi_heap_t *heap, size_t size)
    Allocate in a specific heap.
    +
    void * mi_heap_zalloc(mi_heap_t *heap, size_t size)
    Allocate zero-initialized in a specific heap.
    +
    void * mi_heap_calloc(mi_heap_t *heap, size_t count, size_t size)
    Allocate count zero-initialized elements in a specific heap.
    +
    void * mi_heap_realloc(mi_heap_t *heap, void *p, size_t newsize)
    +
    mi_heap_t * mi_heap_get_backing()
    Get the backing heap.
    +
    void * mi_heap_calloc_aligned(mi_heap_t *heap, size_t count, size_t size, size_t alignment)
    +
    void * mi_heap_reallocn(mi_heap_t *heap, void *p, size_t count, size_t size)
    +
    void * mi_heap_realloc_aligned(mi_heap_t *heap, void *p, size_t newsize, size_t alignment)
    +
    char * mi_heap_strndup(mi_heap_t *heap, const char *s, size_t n)
    Duplicate a string of at most length n in a specific heap.
    +
    void * mi_heap_reallocf(mi_heap_t *heap, void *p, size_t newsize)
    +
    void * mi_heap_malloc_aligned_at(mi_heap_t *heap, size_t size, size_t alignment, size_t offset)
    +
    void * mi_realloc(void *p, size_t newsize)
    Re-allocate memory to newsize bytes.
    +
    void * mi_expand(void *p, size_t newsize)
    Try to re-allocate memory to newsize bytes in place.
    void * mi_recalloc(void *p, size_t count, size_t size)
    Re-allocate memory to count elements of size bytes, with extra memory initialized to zero.
    -
    void * mi_malloc(size_t size)
    Allocate size bytes.
    -
    void * mi_reallocn(void *p, size_t count, size_t size)
    Re-allocate memory to count elements of size bytes.
    -
    void * mi_calloc(size_t count, size_t size)
    Allocate zero-initialized count elements of size bytes.
    -
    char * mi_strndup(const char *s, size_t n)
    Allocate and duplicate a string up to n bytes.
    -
    void * mi_expand(void *p, size_t newsize)
    Try to re-allocate memory to newsize bytes in place.
    -
    char * mi_strdup(const char *s)
    Allocate and duplicate a string.
    -
    void * mi_realloc(void *p, size_t newsize)
    Re-allocate memory to newsize bytes.
    +
    char * mi_strdup(const char *s)
    Allocate and duplicate a string.
    +
    char * mi_strndup(const char *s, size_t n)
    Allocate and duplicate a string up to n bytes.
    +
    void * mi_reallocf(void *p, size_t newsize)
    Re-allocate memory to newsize bytes,.
    +
    void * mi_mallocn(size_t count, size_t size)
    Allocate count elements of size bytes.
    +
    void * mi_calloc(size_t count, size_t size)
    Allocate zero-initialized count elements of size bytes.
    +
    void * mi_reallocn(void *p, size_t count, size_t size)
    Re-allocate memory to count elements of size bytes.
    +
    char * mi_realpath(const char *fname, char *resolved_name)
    Resolve a file path name.
    +
    void * mi_malloc(size_t size)
    Allocate size bytes.
    +
    void * mi_zalloc(size_t size)
    Allocate zero-initialized size bytes.
    void mi_free(void *p)
    Free previously allocated memory.
    -
    void * mi_zalloc(size_t size)
    Allocate zero-initialized size bytes.
    -
    void * mi_reallocf(void *p, size_t newsize)
    Re-allocate memory to newsize bytes,.
    void mi_option_enable(mi_option_t option)
    +
    size_t mi_option_get_size(mi_option_t option)
    bool mi_option_is_enabled(mi_option_t option)
    void mi_option_set_enabled_default(mi_option_t option, bool enable)
    long mi_option_get(mi_option_t option)
    void mi_option_set_default(mi_option_t option, long value)
    +
    long mi_option_get_clamp(mi_option_t option, long min, long max)
    void mi_option_set_enabled(mi_option_t option, bool enable)
    void mi_option_disable(mi_option_t option)
    void mi_option_set(mi_option_t option, long value)
    -
    mi_option_t
    Runtime options.
    Definition: mimalloc-doc.h:800
    -
    @ mi_option_show_stats
    Print statistics to stderr when the program is done.
    Definition: mimalloc-doc.h:803
    -
    @ mi_option_use_numa_nodes
    Pretend there are at most N NUMA nodes.
    Definition: mimalloc-doc.h:815
    -
    @ mi_option_reset_delay
    Delay in milli-seconds before resetting a page (100ms by default)
    Definition: mimalloc-doc.h:814
    -
    @ mi_option_eager_commit_delay
    Experimental.
    Definition: mimalloc-doc.h:817
    -
    @ mi_option_eager_commit
    Eagerly commit segments (4MiB) (enabled by default).
    Definition: mimalloc-doc.h:806
    -
    @ mi_option_segment_cache
    The number of segments per thread to keep cached.
    Definition: mimalloc-doc.h:811
    -
    @ mi_option_eager_region_commit
    Eagerly commit large (256MiB) memory regions (enabled by default, except on Windows)
    Definition: mimalloc-doc.h:807
    -
    @ mi_option_large_os_pages
    Use large OS pages (2MiB in size) if possible.
    Definition: mimalloc-doc.h:808
    -
    @ mi_option_os_tag
    OS tag to assign to mimalloc'd memory.
    Definition: mimalloc-doc.h:818
    -
    @ _mi_option_last
    Definition: mimalloc-doc.h:819
    -
    @ mi_option_verbose
    Print verbose messages to stderr.
    Definition: mimalloc-doc.h:804
    -
    @ mi_option_reserve_huge_os_pages_at
    Reserve huge OS pages at node N.
    Definition: mimalloc-doc.h:810
    -
    @ mi_option_reset_decommits
    Experimental.
    Definition: mimalloc-doc.h:816
    -
    @ mi_option_reserve_huge_os_pages
    The number of huge OS pages (1GiB in size) to reserve at the start of the program.
    Definition: mimalloc-doc.h:809
    -
    @ mi_option_page_reset
    Reset page memory after mi_option_reset_delay milliseconds when it becomes free.
    Definition: mimalloc-doc.h:812
    -
    @ mi_option_segment_reset
    Experimental.
    Definition: mimalloc-doc.h:813
    -
    @ mi_option_show_errors
    Print error messages to stderr.
    Definition: mimalloc-doc.h:802
    +
    mi_option_t
    Runtime options.
    Definition mimalloc-doc.h:911
    +
    @ mi_option_abandoned_reclaim_on_free
    allow to reclaim an abandoned segment on a free (=1)
    Definition mimalloc-doc.h:941
    +
    @ mi_option_purge_extend_delay
    extend purge delay on each subsequent delay (=1)
    Definition mimalloc-doc.h:942
    +
    @ mi_option_show_stats
    Print statistics on termination.
    Definition mimalloc-doc.h:914
    +
    @ mi_option_use_numa_nodes
    0 = use all available numa nodes, otherwise use at most N nodes.
    Definition mimalloc-doc.h:935
    +
    @ mi_option_abandoned_page_purge
    immediately purge delayed purges on thread termination
    Definition mimalloc-doc.h:933
    +
    @ mi_option_eager_commit_delay
    the first N segments per thread are not eagerly committed (but per page in the segment on demand)
    Definition mimalloc-doc.h:931
    +
    @ mi_option_eager_commit
    eager commit segments? (after eager_commit_delay segments) (enabled by default).
    Definition mimalloc-doc.h:930
    +
    @ mi_option_visit_abandoned
    allow visiting heap blocks from abandoned threads (=0)
    Definition mimalloc-doc.h:944
    +
    @ mi_option_os_tag
    tag used for OS logging (macOS only for now) (=100)
    Definition mimalloc-doc.h:926
    +
    @ _mi_option_last
    Definition mimalloc-doc.h:946
    +
    @ mi_option_destroy_on_exit
    if set, release all memory on exit; sometimes used for dynamic unloading but can be unsafe
    Definition mimalloc-doc.h:939
    +
    @ mi_option_verbose
    Print verbose messages.
    Definition mimalloc-doc.h:915
    +
    @ mi_option_allow_large_os_pages
    allow large (2 or 4 MiB) OS pages, implies eager commit. If false, also disables THP for the process.
    Definition mimalloc-doc.h:923
    +
    @ mi_option_arena_purge_mult
    multiplier for purge_delay for the purging delay for arenas (=10)
    Definition mimalloc-doc.h:940
    +
    @ mi_option_retry_on_oom
    retry on out-of-memory for N milli seconds (=400), set to 0 to disable retries. (only on windows)
    Definition mimalloc-doc.h:927
    +
    @ mi_option_purge_decommits
    should a memory purge decommit? (=1). Set to 0 to use memory reset on a purge (instead of decommit)
    Definition mimalloc-doc.h:924
    +
    @ mi_option_limit_os_alloc
    If set to 1, do not use OS memory for allocation (but only pre-reserved arenas)
    Definition mimalloc-doc.h:937
    +
    @ mi_option_reserve_huge_os_pages_at
    Reserve N huge OS pages at a specific NUMA node N.
    Definition mimalloc-doc.h:921
    +
    @ mi_option_max_segment_reclaim
    max. percentage of the abandoned segments can be reclaimed per try (=10%)
    Definition mimalloc-doc.h:938
    +
    @ mi_option_arena_reserve
    initial memory size for arena reservation (= 1 GiB on 64-bit) (internally, this value is in KiB; use ...
    Definition mimalloc-doc.h:925
    +
    @ mi_option_reserve_huge_os_pages
    reserve N huge OS pages (1GiB pages) at startup
    Definition mimalloc-doc.h:920
    +
    @ mi_option_disallow_os_alloc
    1 = do not use OS memory for allocation (but only programmatically reserved arenas)
    Definition mimalloc-doc.h:936
    +
    @ mi_option_purge_delay
    memory purging is delayed by N milli seconds; use 0 for immediate purging or -1 for no purging at all...
    Definition mimalloc-doc.h:934
    +
    @ mi_option_disallow_arena_alloc
    1 = do not use arena's for allocation (except if using specific arena id's)
    Definition mimalloc-doc.h:943
    +
    @ mi_option_max_errors
    issue at most N error messages
    Definition mimalloc-doc.h:916
    +
    @ mi_option_max_warnings
    issue at most N warning messages
    Definition mimalloc-doc.h:917
    +
    @ mi_option_show_errors
    Print error messages.
    Definition mimalloc-doc.h:913
    +
    @ mi_option_reserve_os_memory
    reserve specified amount of OS memory in an arena at startup (internally, this value is in KiB; use m...
    Definition mimalloc-doc.h:922
    +
    @ mi_option_arena_eager_commit
    eager commit arenas? Use 2 to enable just on overcommit systems (=2)
    Definition mimalloc-doc.h:932
    size_t mi_malloc_usable_size(const void *p)
    void mi_free_aligned(void *p, size_t alignment)
    -
    void * mi_aligned_alloc(size_t alignment, size_t size)
    +
    void * mi_aligned_offset_recalloc(void *p, size_t newcount, size_t size, size_t alignment, size_t offset)
    +
    void * mi_aligned_alloc(size_t alignment, size_t size)
    size_t mi_malloc_size(const void *p)
    -
    void * mi_reallocarray(void *p, size_t count, size_t size)
    Correspond s to reallocarray in FreeBSD.
    +
    void * mi_valloc(size_t size)
    +
    void * mi_pvalloc(size_t size)
    +
    void * mi__expand(void *p, size_t newsize)
    +
    int mi_wdupenv_s(unsigned short **buf, size_t *size, const unsigned short *name)
    void mi_cfree(void *p)
    Just as free but also checks if the pointer p belongs to our heap.
    +
    void * mi_memalign(size_t alignment, size_t size)
    void mi_free_size_aligned(void *p, size_t size, size_t alignment)
    -
    void * mi_valloc(size_t size)
    +
    unsigned char * mi_mbsdup(const unsigned char *s)
    int mi_reallocarr(void *p, size_t count, size_t size)
    Corresponds to reallocarr in NetBSD.
    -
    void * mi_memalign(size_t alignment, size_t size)
    +
    size_t mi_malloc_good_size(size_t size)
    +
    unsigned short * mi_wcsdup(const unsigned short *s)
    +
    int mi_dupenv_s(char **buf, size_t *size, const char *name)
    int mi_posix_memalign(void **p, size_t alignment, size_t size)
    int mi__posix_memalign(void **p, size_t alignment, size_t size)
    +
    void * mi_reallocarray(void *p, size_t count, size_t size)
    Correspond s to reallocarray in FreeBSD.
    void mi_free_size(void *p, size_t size)
    -
    void * mi_pvalloc(size_t size)
    -
    void * mi_heap_rezalloc_aligned(mi_heap_t *heap, void *p, size_t newsize, size_t alignment)
    -
    void * mi_recalloc_aligned(void *p, size_t newcount, size_t size, size_t alignment)
    -
    void * mi_heap_recalloc_aligned_at(mi_heap_t *heap, void *p, size_t newcount, size_t size, size_t alignment, size_t offset)
    -
    void * mi_recalloc_aligned_at(void *p, size_t newcount, size_t size, size_t alignment, size_t offset)
    -
    void * mi_heap_recalloc(mi_heap_t *heap, void *p, size_t newcount, size_t size)
    -
    void * mi_rezalloc(void *p, size_t newsize)
    -
    void * mi_heap_recalloc_aligned(mi_heap_t *heap, void *p, size_t newcount, size_t size, size_t alignment)
    -
    void * mi_heap_rezalloc_aligned_at(mi_heap_t *heap, void *p, size_t newsize, size_t alignment, size_t offset)
    -
    void * mi_rezalloc_aligned(void *p, size_t newsize, size_t alignment)
    -
    void * mi_heap_rezalloc(mi_heap_t *heap, void *p, size_t newsize)
    -
    void * mi_rezalloc_aligned_at(void *p, size_t newsize, size_t alignment, size_t offset)
    +
    void * mi_aligned_recalloc(void *p, size_t newcount, size_t size, size_t alignment)
    +
    void * mi_heap_recalloc_aligned_at(mi_heap_t *heap, void *p, size_t newcount, size_t size, size_t alignment, size_t offset)
    +
    void * mi_heap_rezalloc_aligned_at(mi_heap_t *heap, void *p, size_t newsize, size_t alignment, size_t offset)
    +
    void * mi_recalloc_aligned(void *p, size_t newcount, size_t size, size_t alignment)
    +
    void * mi_rezalloc_aligned(void *p, size_t newsize, size_t alignment)
    +
    void * mi_heap_rezalloc_aligned(mi_heap_t *heap, void *p, size_t newsize, size_t alignment)
    +
    void * mi_rezalloc_aligned_at(void *p, size_t newsize, size_t alignment, size_t offset)
    +
    void * mi_heap_recalloc_aligned(mi_heap_t *heap, void *p, size_t newcount, size_t size, size_t alignment)
    +
    void * mi_heap_rezalloc(mi_heap_t *heap, void *p, size_t newsize)
    +
    void * mi_recalloc_aligned_at(void *p, size_t newcount, size_t size, size_t alignment, size_t offset)
    +
    void * mi_heap_recalloc(mi_heap_t *heap, void *p, size_t newcount, size_t size)
    +
    void * mi_rezalloc(void *p, size_t newsize)
    diff --git a/src/dashbls/depends/mimalloc/docs/mimalloc-doxygen.css b/src/dashbls/depends/mimalloc/docs/mimalloc-doxygen.css index b24f5643268f..c889a8d2c326 100644 --- a/src/dashbls/depends/mimalloc/docs/mimalloc-doxygen.css +++ b/src/dashbls/depends/mimalloc/docs/mimalloc-doxygen.css @@ -47,3 +47,14 @@ div.fragment { #nav-sync img { display: none; } +h1,h2,h3,h4,h5,h6 { + transition:none; +} +.memtitle { + background-image: none; + background-color: #EEE; +} +table.memproto, .memproto { + text-shadow: none; + font-size: 110%; +} diff --git a/src/dashbls/depends/mimalloc/docs/modules.html b/src/dashbls/depends/mimalloc/docs/modules.html index 7457cb9fd23f..0129057cd1a7 100644 --- a/src/dashbls/depends/mimalloc/docs/modules.html +++ b/src/dashbls/depends/mimalloc/docs/modules.html @@ -43,8 +43,8 @@ onmouseout="return searchBox.OnSearchSelectHide()" alt=""/> @@ -69,7 +69,7 @@

    -
    @@ -88,7 +88,7 @@
    -
    diff --git a/src/dashbls/depends/mimalloc/docs/navtree.css b/src/dashbls/depends/mimalloc/docs/navtree.css index 046366ca230a..5ec66982ce29 100644 --- a/src/dashbls/depends/mimalloc/docs/navtree.css +++ b/src/dashbls/depends/mimalloc/docs/navtree.css @@ -22,10 +22,15 @@ #nav-tree .selected { background-image: url('tab_a.png'); background-repeat:repeat-x; - color: #fff; + color: white; text-shadow: 0px 1px 1px rgba(0, 0, 0, 1.0); } +#nav-tree .selected .arrow { + color: #5B6364; + text-shadow: none; +} + #nav-tree img { margin:0px; padding:0px; @@ -37,7 +42,6 @@ text-decoration:none; padding:0px; margin:0px; - outline:none; } #nav-tree .label { @@ -52,7 +56,7 @@ #nav-tree .selected a { text-decoration:none; - color:#fff; + color:white; } #nav-tree .children_ul { @@ -67,7 +71,6 @@ #nav-tree { padding: 0px 0px; - background-color: #FAFAFF; font-size:14px; overflow:auto; } @@ -86,7 +89,8 @@ display:block; position: absolute; left: 0px; - width: 180px; + width: $width; + overflow : hidden; } .ui-resizable .ui-resizable-handle { @@ -94,7 +98,7 @@ } .ui-resizable-e { - background-image:url("splitbar.png"); + background-image:url('splitbar.png'); background-size:100%; background-repeat:repeat-y; background-attachment: scroll; @@ -117,7 +121,6 @@ } #nav-tree { - background-image:url('nav_h.png'); background-repeat:repeat-x; background-color: #F2F3F3; -webkit-overflow-scrolling : touch; /* iOS 5+ */ diff --git a/src/dashbls/depends/mimalloc/docs/navtree.js b/src/dashbls/depends/mimalloc/docs/navtree.js index 1e272d31d4aa..2d4fa84a55d2 100644 --- a/src/dashbls/depends/mimalloc/docs/navtree.js +++ b/src/dashbls/depends/mimalloc/docs/navtree.js @@ -22,525 +22,462 @@ @licend The above is the entire license notice for the JavaScript code in this file */ -var navTreeSubIndices = new Array(); -var arrowDown = '▼'; -var arrowRight = '►'; - -function getData(varName) -{ - var i = varName.lastIndexOf('/'); - var n = i>=0 ? varName.substring(i+1) : varName; - return eval(n.replace(/\-/g,'_')); -} -function stripPath(uri) -{ - return uri.substring(uri.lastIndexOf('/')+1); -} +function initNavTree(toroot,relpath) { + let navTreeSubIndices = []; + const ARROW_DOWN = '▼'; + const ARROW_RIGHT = '►'; + const NAVPATH_COOKIE_NAME = ''+'navpath'; -function stripPath2(uri) -{ - var i = uri.lastIndexOf('/'); - var s = uri.substring(i+1); - var m = uri.substring(0,i+1).match(/\/d\w\/d\w\w\/$/); - return m ? uri.substring(i-6) : s; -} + const getData = function(varName) { + const i = varName.lastIndexOf('/'); + const n = i>=0 ? varName.substring(i+1) : varName; + return eval(n.replace(/-/g,'_')); + } -function hashValue() -{ - return $(location).attr('hash').substring(1).replace(/[^\w\-]/g,''); -} + const stripPath = function(uri) { + return uri.substring(uri.lastIndexOf('/')+1); + } -function hashUrl() -{ - return '#'+hashValue(); -} + const stripPath2 = function(uri) { + const i = uri.lastIndexOf('/'); + const s = uri.substring(i+1); + const m = uri.substring(0,i+1).match(/\/d\w\/d\w\w\/$/); + return m ? uri.substring(i-6) : s; + } -function pathName() -{ - return $(location).attr('pathname').replace(/[^-A-Za-z0-9+&@#/%?=~_|!:,.;\(\)]/g, ''); -} + const hashValue = function() { + return $(location).attr('hash').substring(1).replace(/[^\w-]/g,''); + } -function localStorageSupported() -{ - try { - return 'localStorage' in window && window['localStorage'] !== null && window.localStorage.getItem; + const hashUrl = function() { + return '#'+hashValue(); } - catch(e) { - return false; + + const pathName = function() { + return $(location).attr('pathname').replace(/[^-A-Za-z0-9+&@#/%?=~_|!:,.;()]/g, ''); } -} -function storeLink(link) -{ - if (!$("#nav-sync").hasClass('sync') && localStorageSupported()) { - window.localStorage.setItem('navpath',link); + const storeLink = function(link) { + if (!$("#nav-sync").hasClass('sync')) { + Cookie.writeSetting(NAVPATH_COOKIE_NAME,link,0); + } } -} -function deleteLink() -{ - if (localStorageSupported()) { - window.localStorage.setItem('navpath',''); + const deleteLink = function() { + Cookie.eraseSetting(NAVPATH_COOKIE_NAME); } -} -function cachedLink() -{ - if (localStorageSupported()) { - return window.localStorage.getItem('navpath'); - } else { - return ''; + const cachedLink = function() { + return Cookie.readSetting(NAVPATH_COOKIE_NAME,''); } -} -function getScript(scriptName,func,show) -{ - var head = document.getElementsByTagName("head")[0]; - var script = document.createElement('script'); - script.id = scriptName; - script.type = 'text/javascript'; - script.onload = func; - script.src = scriptName+'.js'; - head.appendChild(script); -} + const getScript = function(scriptName,func) { + const head = document.getElementsByTagName("head")[0]; + const script = document.createElement('script'); + script.id = scriptName; + script.type = 'text/javascript'; + script.onload = func; + script.src = scriptName+'.js'; + head.appendChild(script); + } -function createIndent(o,domNode,node,level) -{ - var level=-1; - var n = node; - while (n.parentNode) { level++; n=n.parentNode; } - if (node.childrenData) { - var imgNode = document.createElement("span"); - imgNode.className = 'arrow'; - imgNode.style.paddingLeft=(16*level).toString()+'px'; - imgNode.innerHTML=arrowRight; - node.plus_img = imgNode; - node.expandToggle = document.createElement("a"); - node.expandToggle.href = "javascript:void(0)"; - node.expandToggle.onclick = function() { - if (node.expanded) { - $(node.getChildrenUL()).slideUp("fast"); - node.plus_img.innerHTML=arrowRight; - node.expanded = false; - } else { - expandNode(o, node, false, false); + const createIndent = function(o,domNode,node) { + let level=-1; + let n = node; + while (n.parentNode) { level++; n=n.parentNode; } + if (node.childrenData) { + const imgNode = document.createElement("span"); + imgNode.className = 'arrow'; + imgNode.style.paddingLeft=(16*level).toString()+'px'; + imgNode.innerHTML=ARROW_RIGHT; + node.plus_img = imgNode; + node.expandToggle = document.createElement("a"); + node.expandToggle.href = "javascript:void(0)"; + node.expandToggle.onclick = function() { + if (node.expanded) { + $(node.getChildrenUL()).slideUp("fast"); + node.plus_img.innerHTML=ARROW_RIGHT; + node.expanded = false; + } else { + expandNode(o, node, false, true); + } } + node.expandToggle.appendChild(imgNode); + domNode.appendChild(node.expandToggle); + } else { + let span = document.createElement("span"); + span.className = 'arrow'; + span.style.width = 16*(level+1)+'px'; + span.innerHTML = ' '; + domNode.appendChild(span); } - node.expandToggle.appendChild(imgNode); - domNode.appendChild(node.expandToggle); - } else { - var span = document.createElement("span"); - span.className = 'arrow'; - span.style.width = 16*(level+1)+'px'; - span.innerHTML = ' '; - domNode.appendChild(span); } -} -var animationInProgress = false; - -function gotoAnchor(anchor,aname,updateLocation) -{ - var pos, docContent = $('#doc-content'); - var ancParent = $(anchor.parent()); - if (ancParent.hasClass('memItemLeft') || - ancParent.hasClass('memtitle') || - ancParent.hasClass('fieldname') || - ancParent.hasClass('fieldtype') || - ancParent.is(':header')) - { - pos = ancParent.position().top; - } else if (anchor.position()) { - pos = anchor.position().top; - } - if (pos) { - var dist = Math.abs(Math.min( - pos-docContent.offset().top, - docContent[0].scrollHeight- - docContent.height()-docContent.scrollTop())); - animationInProgress=true; - docContent.animate({ - scrollTop: pos + docContent.scrollTop() - docContent.offset().top - },Math.max(50,Math.min(500,dist)),function(){ - if (updateLocation) window.location.href=aname; - animationInProgress=false; - }); - } -} - -function newNode(o, po, text, link, childrenData, lastNode) -{ - var node = new Object(); - node.children = Array(); - node.childrenData = childrenData; - node.depth = po.depth + 1; - node.relpath = po.relpath; - node.isLast = lastNode; - - node.li = document.createElement("li"); - po.getChildrenUL().appendChild(node.li); - node.parentNode = po; - - node.itemDiv = document.createElement("div"); - node.itemDiv.className = "item"; - - node.labelSpan = document.createElement("span"); - node.labelSpan.className = "label"; - - createIndent(o,node.itemDiv,node,0); - node.itemDiv.appendChild(node.labelSpan); - node.li.appendChild(node.itemDiv); - - var a = document.createElement("a"); - node.labelSpan.appendChild(a); - node.label = document.createTextNode(text); - node.expanded = false; - a.appendChild(node.label); - if (link) { - var url; - if (link.substring(0,1)=='^') { - url = link.substring(1); - link = url; - } else { - url = node.relpath+link; + let animationInProgress = false; + + const gotoAnchor = function(anchor,aname) { + let pos, docContent = $('#doc-content'); + let ancParent = $(anchor.parent()); + if (ancParent.hasClass('memItemLeft') || ancParent.hasClass('memtitle') || + ancParent.hasClass('fieldname') || ancParent.hasClass('fieldtype') || + ancParent.is(':header')) { + pos = ancParent.offset().top; + } else if (anchor.position()) { + pos = anchor.offset().top; } - a.className = stripPath(link.replace('#',':')); - if (link.indexOf('#')!=-1) { - var aname = '#'+link.split('#')[1]; - var srcPage = stripPath(pathName()); - var targetPage = stripPath(link.split('#')[0]); - a.href = srcPage!=targetPage ? url : "javascript:void(0)"; - a.onclick = function(){ - storeLink(link); - if (!$(a).parent().parent().hasClass('selected')) - { - $('.item').removeClass('selected'); - $('.item').removeAttr('id'); - $(a).parent().parent().addClass('selected'); - $(a).parent().parent().attr('id','selected'); + if (pos) { + const dcOffset = docContent.offset().top; + const dcHeight = docContent.height(); + const dcScrHeight = docContent[0].scrollHeight + const dcScrTop = docContent.scrollTop(); + let dist = Math.abs(Math.min(pos-dcOffset,dcScrHeight-dcHeight-dcScrTop)); + animationInProgress = true; + docContent.animate({ + scrollTop: pos + dcScrTop - dcOffset + },Math.max(50,Math.min(500,dist)),function() { + animationInProgress=false; + if (anchor.parent().attr('class')=='memItemLeft') { + let rows = $('.memberdecls tr[class$="'+hashValue()+'"]'); + glowEffect(rows.children(),300); // member without details + } else if (anchor.parent().attr('class')=='fieldname') { + glowEffect(anchor.parent().parent(),1000); // enum value + } else if (anchor.parent().attr('class')=='fieldtype') { + glowEffect(anchor.parent().parent(),1000); // struct field + } else if (anchor.parent().is(":header")) { + glowEffect(anchor.parent(),1000); // section header + } else { + glowEffect(anchor.next(),1000); // normal member } - var anchor = $(aname); - gotoAnchor(anchor,aname,true); - }; - } else { - a.href = url; - a.onclick = function() { storeLink(link); } + }); } - } else { - if (childrenData != null) - { + } + + const newNode = function(o, po, text, link, childrenData, lastNode) { + const node = { + children : [], + childrenData : childrenData, + depth : po.depth + 1, + relpath : po.relpath, + isLast : lastNode, + li : document.createElement("li"), + parentNode : po, + itemDiv : document.createElement("div"), + labelSpan : document.createElement("span"), + label : document.createTextNode(text), + expanded : false, + childrenUL : null, + getChildrenUL : function() { + if (!this.childrenUL) { + this.childrenUL = document.createElement("ul"); + this.childrenUL.className = "children_ul"; + this.childrenUL.style.display = "none"; + this.li.appendChild(node.childrenUL); + } + return node.childrenUL; + }, + }; + + node.itemDiv.className = "item"; + node.labelSpan.className = "label"; + createIndent(o,node.itemDiv,node); + node.itemDiv.appendChild(node.labelSpan); + node.li.appendChild(node.itemDiv); + + const a = document.createElement("a"); + node.labelSpan.appendChild(a); + po.getChildrenUL().appendChild(node.li); + a.appendChild(node.label); + if (link) { + let url; + if (link.substring(0,1)=='^') { + url = link.substring(1); + link = url; + } else { + url = node.relpath+link; + } + a.className = stripPath(link.replace('#',':')); + if (link.indexOf('#')!=-1) { + const aname = '#'+link.split('#')[1]; + const srcPage = stripPath(pathName()); + const targetPage = stripPath(link.split('#')[0]); + a.href = srcPage!=targetPage ? url : aname; + a.onclick = function() { + storeLink(link); + aPPar = $(a).parent().parent(); + if (!aPPar.hasClass('selected')) { + $('.item').removeClass('selected'); + $('.item').removeAttr('id'); + aPPar.addClass('selected'); + aPPar.attr('id','selected'); + } + const anchor = $(aname); + gotoAnchor(anchor,aname); + }; + } else { + a.href = url; + a.onclick = () => storeLink(link); + } + } else if (childrenData != null) { a.className = "nolink"; a.href = "javascript:void(0)"; a.onclick = node.expandToggle.onclick; } + return node; } - node.childrenUL = null; - node.getChildrenUL = function() { - if (!node.childrenUL) { - node.childrenUL = document.createElement("ul"); - node.childrenUL.className = "children_ul"; - node.childrenUL.style.display = "none"; - node.li.appendChild(node.childrenUL); - } - return node.childrenUL; - }; - - return node; -} - -function showRoot() -{ - var headerHeight = $("#top").height(); - var footerHeight = $("#nav-path").height(); - var windowHeight = $(window).height() - headerHeight - footerHeight; - (function (){ // retry until we can scroll to the selected item - try { - var navtree=$('#nav-tree'); - navtree.scrollTo('#selected',100,{offset:-windowHeight/2}); - } catch (err) { - setTimeout(arguments.callee, 0); - } - })(); -} + const showRoot = function() { + const headerHeight = $("#top").height(); + const footerHeight = $("#nav-path").height(); + const windowHeight = $(window).height() - headerHeight - footerHeight; + (function() { // retry until we can scroll to the selected item + try { + const navtree=$('#nav-tree'); + navtree.scrollTo('#selected',100,{offset:-windowHeight/2}); + } catch (err) { + setTimeout(arguments.callee, 0); + } + })(); + } -function expandNode(o, node, imm, showRoot) -{ - if (node.childrenData && !node.expanded) { - if (typeof(node.childrenData)==='string') { - var varName = node.childrenData; - getScript(node.relpath+varName,function(){ - node.childrenData = getData(varName); - expandNode(o, node, imm, showRoot); - }, showRoot); - } else { - if (!node.childrenVisited) { - getNode(o, node); + const expandNode = function(o, node, imm, setFocus) { + if (node.childrenData && !node.expanded) { + if (typeof(node.childrenData)==='string') { + const varName = node.childrenData; + getScript(node.relpath+varName,function() { + node.childrenData = getData(varName); + expandNode(o, node, imm, setFocus); + }); + } else { + if (!node.childrenVisited) { + getNode(o, node); + } + $(node.getChildrenUL()).slideDown("fast"); + node.plus_img.innerHTML = ARROW_DOWN; + node.expanded = true; + if (setFocus) { + $(node.expandToggle).focus(); + } } - $(node.getChildrenUL()).slideDown("fast"); - node.plus_img.innerHTML = arrowDown; - node.expanded = true; } } -} -function glowEffect(n,duration) -{ - n.addClass('glow').delay(duration).queue(function(next){ - $(this).removeClass('glow');next(); - }); -} - -function highlightAnchor() -{ - var aname = hashUrl(); - var anchor = $(aname); - if (anchor.parent().attr('class')=='memItemLeft'){ - var rows = $('.memberdecls tr[class$="'+hashValue()+'"]'); - glowEffect(rows.children(),300); // member without details - } else if (anchor.parent().attr('class')=='fieldname'){ - glowEffect(anchor.parent().parent(),1000); // enum value - } else if (anchor.parent().attr('class')=='fieldtype'){ - glowEffect(anchor.parent().parent(),1000); // struct field - } else if (anchor.parent().is(":header")) { - glowEffect(anchor.parent(),1000); // section header - } else { - glowEffect(anchor.next(),1000); // normal member + const glowEffect = function(n,duration) { + n.addClass('glow').delay(duration).queue(function(next) { + $(this).removeClass('glow');next(); + }); } -} -function selectAndHighlight(hash,n) -{ - var a; - if (hash) { - var link=stripPath(pathName())+':'+hash.substring(1); - a=$('.item a[class$="'+link+'"]'); + const highlightAnchor = function() { + const aname = hashUrl(); + const anchor = $(aname); + gotoAnchor(anchor,aname); } - if (a && a.length) { - a.parent().parent().addClass('selected'); - a.parent().parent().attr('id','selected'); - highlightAnchor(); - } else if (n) { - $(n.itemDiv).addClass('selected'); - $(n.itemDiv).attr('id','selected'); - } - if ($('#nav-tree-contents .item:first').hasClass('selected')) { - $('#nav-sync').css('top','30px'); - } else { - $('#nav-sync').css('top','5px'); + + const selectAndHighlight = function(hash,n) { + let a; + if (hash) { + const link=stripPath(pathName())+':'+hash.substring(1); + a=$('.item a[class$="'+link+'"]'); + } + if (a && a.length) { + a.parent().parent().addClass('selected'); + a.parent().parent().attr('id','selected'); + highlightAnchor(); + } else if (n) { + $(n.itemDiv).addClass('selected'); + $(n.itemDiv).attr('id','selected'); + } + let topOffset=5; + if ($('#nav-tree-contents .item:first').hasClass('selected')) { + topOffset+=25; + } + $('#nav-sync').css('top',topOffset+'px'); + showRoot(); } - showRoot(); -} -function showNode(o, node, index, hash) -{ - if (node && node.childrenData) { - if (typeof(node.childrenData)==='string') { - var varName = node.childrenData; - getScript(node.relpath+varName,function(){ - node.childrenData = getData(varName); - showNode(o,node,index,hash); - },true); - } else { - if (!node.childrenVisited) { - getNode(o, node); - } - $(node.getChildrenUL()).css({'display':'block'}); - node.plus_img.innerHTML = arrowDown; - node.expanded = true; - var n = node.children[o.breadcrumbs[index]]; - if (index+11) hash = '#'+parts[1].replace(/[^\w\-]/g,''); - else hash=''; + const getNode = function(o, po) { + const insertFunction = removeToInsertLater(po.li); + po.childrenVisited = true; + const l = po.childrenData.length-1; + for (let i in po.childrenData) { + const nodeData = po.childrenData[i]; + po.children[i] = newNode(o, po, nodeData[0], nodeData[1], nodeData[2], i==l); + } + insertFunction(); } - if (hash.match(/^#l\d+$/)) { - var anchor=$('a[name='+hash.substring(1)+']'); - glowEffect(anchor.parent(),1000); // line number - hash=''; // strip line number anchors + + const gotoNode = function(o,subIndex,root,hash,relpath) { + const nti = navTreeSubIndices[subIndex][root+hash]; + o.breadcrumbs = $.extend(true, [], nti ? nti : navTreeSubIndices[subIndex][root]); + if (!o.breadcrumbs && root!=NAVTREE[0][1]) { // fallback: show index + navTo(o,NAVTREE[0][1],"",relpath); + $('.item').removeClass('selected'); + $('.item').removeAttr('id'); + } + if (o.breadcrumbs) { + o.breadcrumbs.unshift(0); // add 0 for root node + showNode(o, o.node, 0, hash); + } } - var url=root+hash; - var i=-1; - while (NAVTREEINDEX[i+1]<=url) i++; - if (i==-1) { i=0; root=NAVTREE[0][1]; } // fallback: show index - if (navTreeSubIndices[i]) { - gotoNode(o,i,root,hash,relpath) - } else { - getScript(relpath+'navtreeindex'+i,function(){ - navTreeSubIndices[i] = eval('NAVTREEINDEX'+i); - if (navTreeSubIndices[i]) { - gotoNode(o,i,root,hash,relpath); - } - },true); + + const navTo = function(o,root,hash,relpath) { + const link = cachedLink(); + if (link) { + const parts = link.split('#'); + root = parts[0]; + hash = parts.length>1 ? '#'+parts[1].replace(/[^\w-]/g,'') : ''; + } + if (hash.match(/^#l\d+$/)) { + const anchor=$('a[name='+hash.substring(1)+']'); + glowEffect(anchor.parent(),1000); // line number + hash=''; // strip line number anchors + } + const url=root+hash; + let i=-1; + while (NAVTREEINDEX[i+1]<=url) i++; + if (i==-1) { i=0; root=NAVTREE[0][1]; } // fallback: show index + if (navTreeSubIndices[i]) { + gotoNode(o,i,root,hash,relpath) + } else { + getScript(relpath+'navtreeindex'+i,function() { + navTreeSubIndices[i] = eval('NAVTREEINDEX'+i); + if (navTreeSubIndices[i]) { + gotoNode(o,i,root,hash,relpath); + } + }); + } } -} -function showSyncOff(n,relpath) -{ + const showSyncOff = function(n,relpath) { n.html(''); -} + } -function showSyncOn(n,relpath) -{ + const showSyncOn = function(n,relpath) { n.html(''); -} + } -function toggleSyncButton(relpath) -{ - var navSync = $('#nav-sync'); - if (navSync.hasClass('sync')) { - navSync.removeClass('sync'); + const o = { + toroot : toroot, + node : { + childrenData : NAVTREE, + children : [], + childrenUL : document.createElement("ul"), + getChildrenUL : function() { return this.childrenUL }, + li : document.getElementById("nav-tree-contents"), + depth : 0, + relpath : relpath, + expanded : false, + isLast : true, + plus_img : document.createElement("span"), + }, + }; + o.node.li.appendChild(o.node.childrenUL); + o.node.plus_img.className = 'arrow'; + o.node.plus_img.innerHTML = ARROW_RIGHT; + + const navSync = $('#nav-sync'); + if (cachedLink()) { showSyncOff(navSync,relpath); - storeLink(stripPath2(pathName())+hashUrl()); + navSync.removeClass('sync'); } else { - navSync.addClass('sync'); showSyncOn(navSync,relpath); - deleteLink(); - } -} - -var loadTriggered = false; -var readyTriggered = false; -var loadObject,loadToRoot,loadUrl,loadRelPath; - -$(window).on('load',function(){ - if (readyTriggered) { // ready first - navTo(loadObject,loadToRoot,loadUrl,loadRelPath); - showRoot(); } - loadTriggered=true; -}); - -function initNavTree(toroot,relpath) -{ - var o = new Object(); - o.toroot = toroot; - o.node = new Object(); - o.node.li = document.getElementById("nav-tree-contents"); - o.node.childrenData = NAVTREE; - o.node.children = new Array(); - o.node.childrenUL = document.createElement("ul"); - o.node.getChildrenUL = function() { return o.node.childrenUL; }; - o.node.li.appendChild(o.node.childrenUL); - o.node.depth = 0; - o.node.relpath = relpath; - o.node.expanded = false; - o.node.isLast = true; - o.node.plus_img = document.createElement("span"); - o.node.plus_img.className = 'arrow'; - o.node.plus_img.innerHTML = arrowRight; - if (localStorageSupported()) { - var navSync = $('#nav-sync'); - if (cachedLink()) { - showSyncOff(navSync,relpath); + navSync.click(() => { + const navSync = $('#nav-sync'); + if (navSync.hasClass('sync')) { navSync.removeClass('sync'); + showSyncOff(navSync,relpath); + storeLink(stripPath2(pathName())+hashUrl()); } else { + navSync.addClass('sync'); showSyncOn(navSync,relpath); + deleteLink(); } - navSync.click(function(){ toggleSyncButton(relpath); }); - } + }); - if (loadTriggered) { // load before ready - navTo(o,toroot,hashUrl(),relpath); - showRoot(); - } else { // ready before load - loadObject = o; - loadToRoot = toroot; - loadUrl = hashUrl(); - loadRelPath = relpath; - readyTriggered=true; - } + navTo(o,toroot,hashUrl(),relpath); + showRoot(); - $(window).bind('hashchange', function(){ - if (window.location.hash && window.location.hash.length>1){ - var a; - if ($(location).attr('hash')){ - var clslink=stripPath(pathName())+':'+hashValue(); - a=$('.item a[class$="'+clslink.replace(/ { + if (!animationInProgress) { + if (window.location.hash && window.location.hash.length>1) { + let a; + if ($(location).attr('hash')) { + const clslink=stripPath(pathName())+':'+hashValue(); + a=$('.item a[class$="'+clslink.replace(/ - + - - + + mi-malloc: Overriding Malloc + - + + @@ -29,20 +31,16 @@
    - + - -
    -
    mi-malloc -  1.7/2.0 +
    +
    mi-malloc 1.8/2.1
    +
    - -   + @@ -56,10 +54,15 @@
    - + +

    @@ -74,8 +77,8 @@

    @@ -88,43 +91,47 @@
    - +
    +
    +
    +
    +
    Loading...
    +
    Searching...
    +
    No Matches
    +
    +
    +
    -
    -
    -
    Overriding Malloc
    +
    +
    Overriding Malloc
    -

    Overriding the standard malloc can be done either dynamically or statically.

    +

    Overriding the standard malloc (and new) can be done either dynamically or statically.

    Dynamic override

    This is the recommended way to override the standard malloc interface.

    -

    Linux, BSD

    -

    On these systems we preload the mimalloc shared library so all calls to the standard malloc interface are resolved to the mimalloc library.

    -
      -
    • env LD_PRELOAD=/usr/lib/libmimalloc.so myprogram
    • -
    -

    You can set extra environment variables to check that mimalloc is running, like:

    env MIMALLOC_VERBOSE=1 LD_PRELOAD=/usr/lib/libmimalloc.so myprogram
    -

    or run with the debug version to get detailed statistics:

    env MIMALLOC_SHOW_STATS=1 LD_PRELOAD=/usr/lib/libmimalloc-debug.so myprogram
    -

    MacOS

    -

    On macOS we can also preload the mimalloc shared library so all calls to the standard malloc interface are resolved to the mimalloc library.

    -
      -
    • env DYLD_FORCE_FLAT_NAMESPACE=1 DYLD_INSERT_LIBRARIES=/usr/lib/libmimalloc.dylib myprogram
    • -
    -

    Note that certain security restrictions may apply when doing this from the shell.

    -

    (Note: macOS support for dynamic overriding is recent, please report any issues.)

    -

    Windows

    -

    Overriding on Windows is robust and has the particular advantage to be able to redirect all malloc/free calls that go through the (dynamic) C runtime allocator, including those from other DLL's or libraries.

    -

    The overriding on Windows requires that you link your program explicitly with the mimalloc DLL and use the C-runtime library as a DLL (using the /MD or /MDd switch). Also, the mimalloc-redirect.dll (or mimalloc-redirect32.dll) must be available in the same folder as the main mimalloc-override.dll at runtime (as it is a dependency). The redirection DLL ensures that all calls to the C runtime malloc API get redirected to mimalloc (in mimalloc-override.dll).

    -

    To ensure the mimalloc DLL is loaded at run-time it is easiest to insert some call to the mimalloc API in the main function, like mi_version() (or use the /INCLUDE:mi_version switch on the linker). See the mimalloc-override-test project for an example on how to use this. For best performance on Windows with C++, it is also recommended to also override the new/delete operations (by including mimalloc-new-delete.h a single(!) source file in your project without linking to the mimalloc library).

    +

    Dynamic Override on Linux, BSD

    +

    On these ELF-based systems we preload the mimalloc shared library so all calls to the standard malloc interface are resolved to the mimalloc library.

    > env LD_PRELOAD=/usr/lib/libmimalloc.so myprogram
    +

    You can set extra environment variables to check that mimalloc is running, like:

    > env MIMALLOC_VERBOSE=1 LD_PRELOAD=/usr/lib/libmimalloc.so myprogram
    +

    or run with the debug version to get detailed statistics:

    > env MIMALLOC_SHOW_STATS=1 LD_PRELOAD=/usr/lib/libmimalloc-debug.so myprogram
    +

    Dynamic Override on MacOS

    +

    On macOS we can also preload the mimalloc shared library so all calls to the standard malloc interface are resolved to the mimalloc library.

    > env DYLD_INSERT_LIBRARIES=/usr/lib/libmimalloc.dylib myprogram
    +

    Note that certain security restrictions may apply when doing this from the shell.

    +

    Dynamic Override on Windows

    +

    Dynamically overriding on mimalloc on Windows is robust and has the particular advantage to be able to redirect all malloc/free calls that go through the (dynamic) C runtime allocator, including those from other DLL's or libraries. As it intercepts all allocation calls on a low level, it can be used reliably on large programs that include other 3rd party components. There are four requirements to make the overriding work well:

    +
      +
    1. Use the C-runtime library as a DLL (using the /MD or /MDd switch).
    2. +
    3. Link your program explicitly with the mimalloc.lib export library for the mimalloc.dll. (which must be compiled with -DMI_OVERRIDE=ON, which is the default though). To ensure the mimalloc.dll is actually loaded at run-time it is easiest to insert some call to the mimalloc API in the main function, like mi_version() (or use the /include:mi_version switch on the linker command, or similarly, #pragma comment(linker, "/include:mi_version") in some source file). See the mimalloc-test-override project for an example on how to use this.
    4. +
    5. The mimalloc-redirect.dll must be put in the same directory as the main mimalloc.dll at runtime (as it is a dependency of that DLL). The redirection DLL ensures that all calls to the C runtime malloc API get redirected to mimalloc functions (which reside in mimalloc.dll).
    6. +
    7. Ensure the mimalloc.dll comes as early as possible in the import list of the final executable (so it can intercept all potential allocations). You can use minject -l <exe> to check this if needed.
    8. +
    +

    For best performance on Windows with C++, it is also recommended to also override the new/delete operations (by including mimalloc-new-delete.h a single(!) source file in your project).

    The environment variable MIMALLOC_DISABLE_REDIRECT=1 can be used to disable dynamic overriding at run-time. Use MIMALLOC_VERBOSE=1 to check if mimalloc was successfully redirected.

    -

    (Note: in principle, it is possible to even patch existing executables without any recompilation if they are linked with the dynamic C runtime (ucrtbase.dll) – just put the mimalloc-override.dll into the import table (and put mimalloc-redirect.dll in the same folder) Such patching can be done for example with CFF Explorer).

    +

    For different platforms than x64, you may need a specific [redirection dll](bin). Furthermore, we cannot always re-link an executable or ensure mimalloc.dll comes first in the import table. In such cases the [minject](bin) tool can be used to patch the executable's import tables.

    Static override

    -

    On Unix systems, you can also statically link with mimalloc to override the standard malloc interface. The recommended way is to link the final program with the mimalloc single object file (mimalloc-override.o). We use an object file instead of a library file as linkers give preference to that over archives to resolve symbols. To ensure that the standard malloc interface resolves to the mimalloc library, link it as the first object file. For example:

    -
    gcc -o myprogram mimalloc-override.o myfile1.c ...
    -

    List of Overrides:

    +

    On Unix-like systems, you can also statically link with mimalloc to override the standard malloc interface. The recommended way is to link the final program with the mimalloc single object file (mimalloc.o). We use an object file instead of a library file as linkers give preference to that over archives to resolve symbols. To ensure that the standard malloc interface resolves to the mimalloc library, link it as the first object file. For example:

    > gcc -o myprogram mimalloc.o myfile1.c ...
    +

    Another way to override statically that works on all platforms, is to link statically to mimalloc (as shown in the introduction) and include a header file in each source file that re-defines malloc etc. to mi_malloc. This is provided by mimalloc-override.h. This only works reliably though if all sources are under your control or otherwise mixing of pointers from different heaps may occur!

    +

    List of Overrides:

    The specific functions that get redirected to the mimalloc library are:

    // C
    void* malloc(size_t size);
    @@ -142,10 +149,10 @@

    Static override

    void operator delete(void* p);
    void operator delete[](void* p);
    -
    void* operator new(std::size_t n) noexcept(false);
    -
    void* operator new[](std::size_t n) noexcept(false);
    -
    void* operator new( std::size_t n, std::align_val_t align) noexcept(false);
    -
    void* operator new[]( std::size_t n, std::align_val_t align) noexcept(false);
    +
    void* operator new(std::size_t n) noexcept(false);
    +
    void* operator new[](std::size_t n) noexcept(false);
    +
    void* operator new( std::size_t n, std::align_val_t align) noexcept(false);
    +
    void* operator new[]( std::size_t n, std::align_val_t align) noexcept(false);
    void* operator new ( std::size_t count, const std::nothrow_t& tag);
    void* operator new[]( std::size_t count, const std::nothrow_t& tag);
    @@ -191,7 +198,7 @@

    Static override

    diff --git a/src/dashbls/depends/mimalloc/docs/pages.html b/src/dashbls/depends/mimalloc/docs/pages.html index 6999a810d037..b03b05f74c51 100644 --- a/src/dashbls/depends/mimalloc/docs/pages.html +++ b/src/dashbls/depends/mimalloc/docs/pages.html @@ -1,24 +1,26 @@ - + - - + + mi-malloc: Related Pages + - + + @@ -29,20 +31,16 @@
    - + - -
    -
    mi-malloc -  1.7/2.0 +
    +
    mi-malloc 1.8/2.1
    +
    - -   + @@ -56,10 +54,15 @@
    - + +
    @@ -74,8 +77,8 @@
    @@ -88,22 +91,28 @@
    - +
    +
    +
    +
    +
    Loading...
    +
    Searching...
    +
    No Matches
    +
    +
    +
    -
    -
    Related Pages
    +
    Related Pages
    Here is a list of all related documentation pages:
    @@ -112,7 +121,7 @@ diff --git a/src/dashbls/depends/mimalloc/docs/resize.js b/src/dashbls/depends/mimalloc/docs/resize.js index e1ad0fe3ba04..a571744065a0 100644 --- a/src/dashbls/depends/mimalloc/docs/resize.js +++ b/src/dashbls/depends/mimalloc/docs/resize.js @@ -22,119 +22,126 @@ @licend The above is the entire license notice for the JavaScript code in this file */ -function initResizable() -{ - var cookie_namespace = 'doxygen'; - var sidenav,navtree,content,header,collapsed,collapsedWidth=0,barWidth=6,desktop_vp=768,titleHeight; - function readCookie(cookie) - { - var myCookie = cookie_namespace+"_"+cookie+"="; - if (document.cookie) { - var index = document.cookie.indexOf(myCookie); - if (index != -1) { - var valStart = index + myCookie.length; - var valEnd = document.cookie.indexOf(";", valStart); - if (valEnd == -1) { - valEnd = document.cookie.length; - } - var val = document.cookie.substring(valStart, valEnd); - return val; - } - } - return 0; - } - - function writeCookie(cookie, val, expiration) - { - if (val==undefined) return; - if (expiration == null) { - var date = new Date(); - date.setTime(date.getTime()+(10*365*24*60*60*1000)); // default expiration is one week - expiration = date.toGMTString(); - } - document.cookie = cookie_namespace + "_" + cookie + "=" + val + "; expires=" + expiration+"; path=/"; - } +function initResizable(treeview) { + let sidenav,navtree,content,header,footer,barWidth=6; + const RESIZE_COOKIE_NAME = ''+'width'; - function resizeWidth() - { - var windowWidth = $(window).width() + "px"; - var sidenavWidth = $(sidenav).outerWidth(); + function resizeWidth() { + const sidenavWidth = $(sidenav).outerWidth(); content.css({marginLeft:parseInt(sidenavWidth)+"px"}); - writeCookie('width',sidenavWidth-barWidth, null); + if (typeof page_layout!=='undefined' && page_layout==1) { + footer.css({marginLeft:parseInt(sidenavWidth)+"px"}); + } + Cookie.writeSetting(RESIZE_COOKIE_NAME,sidenavWidth-barWidth); } - function restoreWidth(navWidth) - { - var windowWidth = $(window).width() + "px"; + function restoreWidth(navWidth) { content.css({marginLeft:parseInt(navWidth)+barWidth+"px"}); + if (typeof page_layout!=='undefined' && page_layout==1) { + footer.css({marginLeft:parseInt(navWidth)+barWidth+"px"}); + } sidenav.css({width:navWidth + "px"}); } - function resizeHeight() - { - var headerHeight = header.outerHeight(); - var footerHeight = footer.outerHeight(); - var windowHeight = $(window).height() - headerHeight - footerHeight; - content.css({height:windowHeight + "px"}); - navtree.css({height:windowHeight + "px"}); - sidenav.css({height:windowHeight + "px"}); - var width=$(window).width(); - if (width!=collapsedWidth) { - if (width=desktop_vp) { - if (!collapsed) { - collapseExpand(); - } - } else if (width>desktop_vp && collapsedWidth0) { - restoreWidth(0); - collapsed=true; - } - else { - var width = readCookie('width'); - if (width>200 && width<$(window).width()) { restoreWidth(width); } else { restoreWidth(200); } - collapsed=false; + newWidth=0; + } else { + const width = Cookie.readSetting(RESIZE_COOKIE_NAME,180); + newWidth = (width>180 && width<$(window).width()) ? width : 180; } + restoreWidth(newWidth); + const sidenavWidth = $(sidenav).outerWidth(); + Cookie.writeSetting(RESIZE_COOKIE_NAME,sidenavWidth-barWidth); } header = $("#top"); - sidenav = $("#side-nav"); content = $("#doc-content"); - navtree = $("#nav-tree"); footer = $("#nav-path"); - $(".side-nav-resizable").resizable({resize: function(e, ui) { resizeWidth(); } }); - $(sidenav).resizable({ minWidth: 0 }); - $(window).resize(function() { resizeHeight(); }); - var device = navigator.userAgent.toLowerCase(); - var touch_device = device.match(/(iphone|ipod|ipad|android)/); - if (touch_device) { /* wider split bar for touch only devices */ - $(sidenav).css({ paddingRight:'20px' }); - $('.ui-resizable-e').css({ width:'20px' }); - $('#nav-sync').css({ right:'34px' }); - barWidth=20; + sidenav = $("#side-nav"); + if (!treeview) { +// title = $("#titlearea"); +// titleH = $(title).height(); +// let animating = false; +// content.on("scroll", function() { +// slideOpts = { duration: 200, +// step: function() { +// contentHeight = $(window).height() - header.outerHeight(); +// content.css({ height : contentHeight + "px" }); +// }, +// done: function() { animating=false; } +// }; +// if (content.scrollTop()>titleH && title.css('display')!='none' && !animating) { +// title.slideUp(slideOpts); +// animating=true; +// } else if (content.scrollTop()<=titleH && title.css('display')=='none' && !animating) { +// title.slideDown(slideOpts); +// animating=true; +// } +// }); + } else { + navtree = $("#nav-tree"); + $(".side-nav-resizable").resizable({resize: function(e, ui) { resizeWidth(); } }); + $(sidenav).resizable({ minWidth: 0 }); } - var width = readCookie('width'); - if (width) { restoreWidth(width); } else { resizeWidth(); } - resizeHeight(); - var url = location.href; - var i=url.indexOf("#"); + $(window).resize(function() { resizeHeight(treeview); }); + if (treeview) + { + const device = navigator.userAgent.toLowerCase(); + const touch_device = device.match(/(iphone|ipod|ipad|android)/); + if (touch_device) { /* wider split bar for touch only devices */ + $(sidenav).css({ paddingRight:'20px' }); + $('.ui-resizable-e').css({ width:'20px' }); + $('#nav-sync').css({ right:'34px' }); + barWidth=20; + } + const width = Cookie.readSetting(RESIZE_COOKIE_NAME,180); + if (width) { restoreWidth(width); } else { resizeWidth(); } + } + resizeHeight(treeview); + const url = location.href; + const i=url.indexOf("#"); if (i>=0) window.location.hash=url.substr(i); - var _preventDefault = function(evt) { evt.preventDefault(); }; - $("#splitbar").bind("dragstart", _preventDefault).bind("selectstart", _preventDefault); - $(".ui-resizable-handle").dblclick(collapseExpand); - $(window).on('load',resizeHeight); + const _preventDefault = function(evt) { evt.preventDefault(); }; + if (treeview) + { + $("#splitbar").bind("dragstart", _preventDefault).bind("selectstart", _preventDefault); + $(".ui-resizable-handle").dblclick(collapseExpand); + // workaround for firefox + $("body").css({overflow: "hidden"}); + } + $(window).on('load',function() { resizeHeight(treeview); }); } /* @license-end */ diff --git a/src/dashbls/depends/mimalloc/docs/search/all_1.js b/src/dashbls/depends/mimalloc/docs/search/all_1.js index 7f1097c09520..d371a39915e0 100644 --- a/src/dashbls/depends/mimalloc/docs/search/all_1.js +++ b/src/dashbls/depends/mimalloc/docs/search/all_1.js @@ -1,4 +1,6 @@ var searchData= [ - ['aligned_20allocation_1',['Aligned Allocation',['../group__aligned.html',1,'']]] + ['aligned_20allocation_0',['Aligned Allocation',['../group__aligned.html',1,'']]], + ['allocation_1',['Allocation',['../group__aligned.html',1,'Aligned Allocation'],['../group__malloc.html',1,'Basic Allocation'],['../group__heap.html',1,'Heap Allocation']]], + ['allocation_2',['Zero initialized re-allocation',['../group__zeroinit.html',1,'']]] ]; diff --git a/src/dashbls/depends/mimalloc/docs/search/all_10.js b/src/dashbls/depends/mimalloc/docs/search/all_10.js new file mode 100644 index 000000000000..1437d04ac002 --- /dev/null +++ b/src/dashbls/depends/mimalloc/docs/search/all_10.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['zero_20initialized_20re_20allocation_0',['Zero initialized re-allocation',['../group__zeroinit.html',1,'']]] +]; diff --git a/src/dashbls/depends/mimalloc/docs/search/all_2.js b/src/dashbls/depends/mimalloc/docs/search/all_2.js index 00576d78a20d..6a297a47bfaf 100644 --- a/src/dashbls/depends/mimalloc/docs/search/all_2.js +++ b/src/dashbls/depends/mimalloc/docs/search/all_2.js @@ -1,7 +1,7 @@ var searchData= [ - ['basic_20allocation_2',['Basic Allocation',['../group__malloc.html',1,'']]], - ['block_5fsize_3',['block_size',['../group__analysis.html#a332a6c14d736a99699d5453a1cb04b41',1,'mi_heap_area_t']]], - ['blocks_4',['blocks',['../group__analysis.html#ae0085e6e1cf059a4eb7767e30e9991b8',1,'mi_heap_area_t']]], - ['building_5',['Building',['../build.html',1,'']]] + ['basic_20allocation_0',['Basic Allocation',['../group__malloc.html',1,'']]], + ['block_5fsize_1',['block_size',['../group__analysis.html#a332a6c14d736a99699d5453a1cb04b41',1,'mi_heap_area_t']]], + ['blocks_2',['blocks',['../group__analysis.html#ae0085e6e1cf059a4eb7767e30e9991b8',1,'mi_heap_area_t']]], + ['building_3',['Building',['../build.html',1,'']]] ]; diff --git a/src/dashbls/depends/mimalloc/docs/search/all_3.js b/src/dashbls/depends/mimalloc/docs/search/all_3.js index 9a029ee0b764..76374a610538 100644 --- a/src/dashbls/depends/mimalloc/docs/search/all_3.js +++ b/src/dashbls/depends/mimalloc/docs/search/all_3.js @@ -1,5 +1,5 @@ var searchData= [ - ['c_2b_2b_20wrappers_6',['C++ wrappers',['../group__cpp.html',1,'']]], - ['committed_7',['committed',['../group__analysis.html#ab47526df656d8837ec3e97f11b83f835',1,'mi_heap_area_t']]] + ['c_20wrappers_0',['C++ wrappers',['../group__cpp.html',1,'']]], + ['committed_1',['committed',['../group__analysis.html#ab47526df656d8837ec3e97f11b83f835',1,'mi_heap_area_t']]] ]; diff --git a/src/dashbls/depends/mimalloc/docs/search/all_4.js b/src/dashbls/depends/mimalloc/docs/search/all_4.js index 5dc5128610b7..a2c108b7efbf 100644 --- a/src/dashbls/depends/mimalloc/docs/search/all_4.js +++ b/src/dashbls/depends/mimalloc/docs/search/all_4.js @@ -1,5 +1,5 @@ var searchData= [ - ['environment_20options_8',['Environment Options',['../environment.html',1,'']]], - ['extended_20functions_9',['Extended Functions',['../group__extended.html',1,'']]] + ['environment_20options_0',['Environment Options',['../environment.html',1,'']]], + ['extended_20functions_1',['Extended Functions',['../group__extended.html',1,'']]] ]; diff --git a/src/dashbls/depends/mimalloc/docs/search/all_5.js b/src/dashbls/depends/mimalloc/docs/search/all_5.js index 7441d85349c2..6f8d30e9f2b4 100644 --- a/src/dashbls/depends/mimalloc/docs/search/all_5.js +++ b/src/dashbls/depends/mimalloc/docs/search/all_5.js @@ -1,5 +1,5 @@ var searchData= [ - ['heap_20allocation_10',['Heap Allocation',['../group__heap.html',1,'']]], - ['heap_20introspection_11',['Heap Introspection',['../group__analysis.html',1,'']]] + ['full_5fblock_5fsize_0',['full_block_size',['../group__analysis.html#ab53664e31d7fe2564f8d42041ef75cb3',1,'mi_heap_area_t']]], + ['functions_1',['Extended Functions',['../group__extended.html',1,'']]] ]; diff --git a/src/dashbls/depends/mimalloc/docs/search/all_6.js b/src/dashbls/depends/mimalloc/docs/search/all_6.js index 6d32b7b1dba9..5a38d8485110 100644 --- a/src/dashbls/depends/mimalloc/docs/search/all_6.js +++ b/src/dashbls/depends/mimalloc/docs/search/all_6.js @@ -1,153 +1,6 @@ var searchData= [ - ['mi_5f_5fposix_5fmemalign_12',['mi__posix_memalign',['../group__posix.html#gad5a69c8fea96aa2b7a7c818c2130090a',1,'mimalloc-doc.h']]], - ['mi_5faligned_5falloc_13',['mi_aligned_alloc',['../group__posix.html#ga1326d2e4388630b5f81ca7206318b8e5',1,'mimalloc-doc.h']]], - ['mi_5falignment_5fmax_14',['MI_ALIGNMENT_MAX',['../group__aligned.html#ga83c03016066b438f51a8095e9140be06',1,'mimalloc-doc.h']]], - ['mi_5fblock_5fvisit_5ffun_15',['mi_block_visit_fun',['../group__analysis.html#gadfa01e2900f0e5d515ad5506b26f6d65',1,'mimalloc-doc.h']]], - ['mi_5fcalloc_16',['mi_calloc',['../group__malloc.html#ga97fedb4f7107c592fd7f0f0a8949a57d',1,'mimalloc-doc.h']]], - ['mi_5fcalloc_5faligned_17',['mi_calloc_aligned',['../group__aligned.html#ga53dddb4724042a90315b94bc268fb4c9',1,'mimalloc-doc.h']]], - ['mi_5fcalloc_5faligned_5fat_18',['mi_calloc_aligned_at',['../group__aligned.html#ga08647c4593f3b2eef24a919a73eba3a3',1,'mimalloc-doc.h']]], - ['mi_5fcalloc_5ftp_19',['mi_calloc_tp',['../group__typed.html#gae80c47c9d4cab10961fff1a8ac98fc07',1,'mimalloc-doc.h']]], - ['mi_5fcfree_20',['mi_cfree',['../group__posix.html#ga705dc7a64bffacfeeb0141501a5c35d7',1,'mimalloc-doc.h']]], - ['mi_5fcheck_5fowned_21',['mi_check_owned',['../group__analysis.html#ga628c237489c2679af84a4d0d143b3dd5',1,'mimalloc-doc.h']]], - ['mi_5fcollect_22',['mi_collect',['../group__extended.html#ga421430e2226d7d468529cec457396756',1,'mimalloc-doc.h']]], - ['mi_5fdeferred_5ffree_5ffun_23',['mi_deferred_free_fun',['../group__extended.html#ga299dae78d25ce112e384a98b7309c5be',1,'mimalloc-doc.h']]], - ['mi_5ferror_5ffun_24',['mi_error_fun',['../group__extended.html#ga251d369cda3f1c2a955c555486ed90e5',1,'mimalloc-doc.h']]], - ['mi_5fexpand_25',['mi_expand',['../group__malloc.html#gaaee66a1d483c3e28f585525fb96707e4',1,'mimalloc-doc.h']]], - ['mi_5ffree_26',['mi_free',['../group__malloc.html#gaf2c7b89c327d1f60f59e68b9ea644d95',1,'mimalloc-doc.h']]], - ['mi_5ffree_5faligned_27',['mi_free_aligned',['../group__posix.html#ga0d28d5cf61e6bfbb18c63092939fe5c9',1,'mimalloc-doc.h']]], - ['mi_5ffree_5fsize_28',['mi_free_size',['../group__posix.html#gae01389eedab8d67341ff52e2aad80ebb',1,'mimalloc-doc.h']]], - ['mi_5ffree_5fsize_5faligned_29',['mi_free_size_aligned',['../group__posix.html#ga72e9d7ffb5fe94d69bc722c8506e27bc',1,'mimalloc-doc.h']]], - ['mi_5fgood_5fsize_30',['mi_good_size',['../group__extended.html#gac057927cd06c854b45fe7847e921bd47',1,'mimalloc-doc.h']]], - ['mi_5fheap_5farea_5ft_31',['mi_heap_area_t',['../group__analysis.html#structmi__heap__area__t',1,'']]], - ['mi_5fheap_5fcalloc_32',['mi_heap_calloc',['../group__heap.html#gaa6702b3c48e9e53e50e81b36f5011d55',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fcalloc_5faligned_33',['mi_heap_calloc_aligned',['../group__heap.html#ga4af03a6e2b93fae77424d93f889705c3',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fcalloc_5faligned_5fat_34',['mi_heap_calloc_aligned_at',['../group__heap.html#ga08ca6419a5c057a4d965868998eef487',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fcalloc_5ftp_35',['mi_heap_calloc_tp',['../group__typed.html#ga4e5d1f1707c90e5f55e023ac5f45fe74',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fcheck_5fowned_36',['mi_heap_check_owned',['../group__analysis.html#ga0d67c1789faaa15ff366c024fcaf6377',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fcollect_37',['mi_heap_collect',['../group__heap.html#ga7922f7495cde30b1984d0e6072419298',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fcontains_5fblock_38',['mi_heap_contains_block',['../group__analysis.html#gaa862aa8ed8d57d84cae41fc1022d71af',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fdelete_39',['mi_heap_delete',['../group__heap.html#ga2ab1af8d438819b55319c7ef51d1e409',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fdestroy_40',['mi_heap_destroy',['../group__heap.html#ga9f9c0844edb9717f4feacd79116b8e0d',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fget_5fbacking_41',['mi_heap_get_backing',['../group__heap.html#ga5d03fbe062ffcf38f0f417fd968357fc',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fget_5fdefault_42',['mi_heap_get_default',['../group__heap.html#ga8db4cbb87314a989a9a187464d6b5e05',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fmalloc_43',['mi_heap_malloc',['../group__heap.html#ga9cbed01e42c0647907295de92c3fa296',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fmalloc_5faligned_44',['mi_heap_malloc_aligned',['../group__heap.html#gab5b87e1805306f70df38789fcfcf6653',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fmalloc_5faligned_5fat_45',['mi_heap_malloc_aligned_at',['../group__heap.html#ga23acd7680fb0976dde3783254c6c874b',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fmalloc_5fsmall_46',['mi_heap_malloc_small',['../group__heap.html#gaa1a1c7a1f4da6826b5a25b70ef878368',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fmalloc_5ftp_47',['mi_heap_malloc_tp',['../group__typed.html#ga653bcb24ac495bc19940ecd6898f9cd7',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fmallocn_48',['mi_heap_mallocn',['../group__heap.html#ga851da6c43fe0b71c1376cee8aef90db0',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fmallocn_5ftp_49',['mi_heap_mallocn_tp',['../group__typed.html#ga6b75cb9c4b9c647661d0924552dc6e83',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fnew_50',['mi_heap_new',['../group__heap.html#ga766f672ba56f2fbfeb9d9dbb0b7f6b11',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frealloc_51',['mi_heap_realloc',['../group__heap.html#gaaef3395f66be48f37bdc8322509c5d81',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frealloc_5faligned_52',['mi_heap_realloc_aligned',['../group__heap.html#gafc603b696bd14cae6da28658f950d98c',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frealloc_5faligned_5fat_53',['mi_heap_realloc_aligned_at',['../group__heap.html#gaf96c788a1bf553fe2d371de9365e047c',1,'mimalloc-doc.h']]], - ['mi_5fheap_5freallocf_54',['mi_heap_reallocf',['../group__heap.html#ga4a21070eb4e7cce018133c8d5f4b0527',1,'mimalloc-doc.h']]], - ['mi_5fheap_5freallocn_55',['mi_heap_reallocn',['../group__heap.html#gac74e94ad9b0c9b57c1c4d88b8825b7a8',1,'mimalloc-doc.h']]], - ['mi_5fheap_5freallocn_5ftp_56',['mi_heap_reallocn_tp',['../group__typed.html#gaf213d5422ec35e7f6caad827c79bc948',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frealpath_57',['mi_heap_realpath',['../group__heap.html#ga00e95ba1e01acac3cfd95bb7a357a6f0',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frecalloc_58',['mi_heap_recalloc',['../group__zeroinit.html#ga8648c5fbb22a80f0262859099f06dfbd',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frecalloc_5faligned_59',['mi_heap_recalloc_aligned',['../group__zeroinit.html#ga9f3f999396c8f77ca5e80e7b40ac29e3',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frecalloc_5faligned_5fat_60',['mi_heap_recalloc_aligned_at',['../group__zeroinit.html#ga496452c96f1de8c500be9fddf52edaf7',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frecalloc_5ftp_61',['mi_heap_recalloc_tp',['../group__typed.html#ga3e50a1600958fcaf1a7f3560c9174f9e',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frezalloc_62',['mi_heap_rezalloc',['../group__zeroinit.html#gacfad83f14eb5d6a42a497a898e19fc76',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frezalloc_5faligned_63',['mi_heap_rezalloc_aligned',['../group__zeroinit.html#ga375fa8a611c51905e592d5d467c49664',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frezalloc_5faligned_5fat_64',['mi_heap_rezalloc_aligned_at',['../group__zeroinit.html#gac90da54fa7e5d10bdc97ce0b51dce2eb',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fset_5fdefault_65',['mi_heap_set_default',['../group__heap.html#gab8631ec88c8d26641b68b5d25dcd4422',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fstrdup_66',['mi_heap_strdup',['../group__heap.html#ga139d6b09dbf50c3c2523d0f4d1cfdeb5',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fstrndup_67',['mi_heap_strndup',['../group__heap.html#ga8e3dbd46650dd26573cf307a2c8f1f5a',1,'mimalloc-doc.h']]], - ['mi_5fheap_5ft_68',['mi_heap_t',['../group__heap.html#ga34a47cde5a5b38c29f1aa3c5e76943c2',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fvisit_5fblocks_69',['mi_heap_visit_blocks',['../group__analysis.html#ga70c46687dc6e9dc98b232b02646f8bed',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fzalloc_70',['mi_heap_zalloc',['../group__heap.html#ga903104592c8ed53417a3762da6241133',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fzalloc_5faligned_71',['mi_heap_zalloc_aligned',['../group__heap.html#gaa450a59c6c7ae5fdbd1c2b80a8329ef0',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fzalloc_5faligned_5fat_72',['mi_heap_zalloc_aligned_at',['../group__heap.html#ga45fb43a62776fbebbdf1edd99b527954',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fzalloc_5ftp_73',['mi_heap_zalloc_tp',['../group__typed.html#gad6e87e86e994aa14416ae9b5d4c188fe',1,'mimalloc-doc.h']]], - ['mi_5fis_5fin_5fheap_5fregion_74',['mi_is_in_heap_region',['../group__extended.html#ga5f071b10d4df1c3658e04e7fd67a94e6',1,'mimalloc-doc.h']]], - ['mi_5fis_5fredirected_75',['mi_is_redirected',['../group__extended.html#gaad25050b19f30cd79397b227e0157a3f',1,'mimalloc-doc.h']]], - ['mi_5fmalloc_76',['mi_malloc',['../group__malloc.html#ga3406e8b168bc74c8637b11571a6da83a',1,'mimalloc-doc.h']]], - ['mi_5fmalloc_5faligned_77',['mi_malloc_aligned',['../group__aligned.html#ga68930196751fa2cca9e1fd0d71bade56',1,'mimalloc-doc.h']]], - ['mi_5fmalloc_5faligned_5fat_78',['mi_malloc_aligned_at',['../group__aligned.html#ga5850da130c936bd77db039dcfbc8295d',1,'mimalloc-doc.h']]], - ['mi_5fmalloc_5fsize_79',['mi_malloc_size',['../group__posix.html#ga4531c9e775bb3ae12db57c1ba8a5d7de',1,'mimalloc-doc.h']]], - ['mi_5fmalloc_5fsmall_80',['mi_malloc_small',['../group__extended.html#ga7136c2e55cb22c98ecf95d08d6debb99',1,'mimalloc-doc.h']]], - ['mi_5fmalloc_5ftp_81',['mi_malloc_tp',['../group__typed.html#ga0619a62c5fd886f1016030abe91f0557',1,'mimalloc-doc.h']]], - ['mi_5fmalloc_5fusable_5fsize_82',['mi_malloc_usable_size',['../group__posix.html#ga06d07cf357bbac5c73ba5d0c0c421e17',1,'mimalloc-doc.h']]], - ['mi_5fmallocn_83',['mi_mallocn',['../group__malloc.html#ga0b05e2bf0f73e7401ae08597ff782ac6',1,'mimalloc-doc.h']]], - ['mi_5fmallocn_5ftp_84',['mi_mallocn_tp',['../group__typed.html#gae5cb6e0fafc9f23169c5622e077afe8b',1,'mimalloc-doc.h']]], - ['mi_5fmanage_5fos_5fmemory_85',['mi_manage_os_memory',['../group__extended.html#ga4c6486a1fdcd7a423b5f25fe4be8e0cf',1,'mimalloc-doc.h']]], - ['mi_5fmemalign_86',['mi_memalign',['../group__posix.html#gaab7fa71ea93b96873f5d9883db57d40e',1,'mimalloc-doc.h']]], - ['mi_5fnew_87',['mi_new',['../group__cpp.html#gaad048a9fce3d02c5909cd05c6ec24545',1,'mimalloc-doc.h']]], - ['mi_5fnew_5faligned_88',['mi_new_aligned',['../group__cpp.html#gaef2c2bdb4f70857902d3c8903ac095f3',1,'mimalloc-doc.h']]], - ['mi_5fnew_5faligned_5fnothrow_89',['mi_new_aligned_nothrow',['../group__cpp.html#gab5e29558926d934c3f1cae8c815f942c',1,'mimalloc-doc.h']]], - ['mi_5fnew_5fn_90',['mi_new_n',['../group__cpp.html#gae7bc4f56cd57ed3359060ff4f38bda81',1,'mimalloc-doc.h']]], - ['mi_5fnew_5fnothrow_91',['mi_new_nothrow',['../group__cpp.html#gaeaded64eda71ed6b1d569d3e723abc4a',1,'mimalloc-doc.h']]], - ['mi_5fnew_5frealloc_92',['mi_new_realloc',['../group__cpp.html#gaab78a32f55149e9fbf432d5288e38e1e',1,'mimalloc-doc.h']]], - ['mi_5fnew_5freallocn_93',['mi_new_reallocn',['../group__cpp.html#ga756f4b2bc6a7ecd0a90baea8e90c7907',1,'mimalloc-doc.h']]], - ['mi_5foption_5fdisable_94',['mi_option_disable',['../group__options.html#gaebf6ff707a2e688ebb1a2296ca564054',1,'mimalloc-doc.h']]], - ['mi_5foption_5feager_5fcommit_95',['mi_option_eager_commit',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca1e8de72c93da7ff22d91e1e27b52ac2b',1,'mimalloc-doc.h']]], - ['mi_5foption_5feager_5fcommit_5fdelay_96',['mi_option_eager_commit_delay',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca17a190c25be381142d87e0468c4c068c',1,'mimalloc-doc.h']]], - ['mi_5foption_5feager_5fregion_5fcommit_97',['mi_option_eager_region_commit',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca32ce97ece29f69e82579679cf8a307ad',1,'mimalloc-doc.h']]], - ['mi_5foption_5fenable_98',['mi_option_enable',['../group__options.html#ga04180ae41b0d601421dd62ced40ca050',1,'mimalloc-doc.h']]], - ['mi_5foption_5fget_99',['mi_option_get',['../group__options.html#ga7e8af195cc81d3fa64ccf2662caa565a',1,'mimalloc-doc.h']]], - ['mi_5foption_5fis_5fenabled_100',['mi_option_is_enabled',['../group__options.html#ga459ad98f18b3fc9275474807fe0ca188',1,'mimalloc-doc.h']]], - ['mi_5foption_5flarge_5fos_5fpages_101',['mi_option_large_os_pages',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca4192d491200d0055df0554d4cf65054e',1,'mimalloc-doc.h']]], - ['mi_5foption_5fos_5ftag_102',['mi_option_os_tag',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca4b74ae2a69e445de6c2361b73c1d14bf',1,'mimalloc-doc.h']]], - ['mi_5foption_5fpage_5freset_103',['mi_option_page_reset',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cada854dd272c66342f18a93ee254a2968',1,'mimalloc-doc.h']]], - ['mi_5foption_5freserve_5fhuge_5fos_5fpages_104',['mi_option_reserve_huge_os_pages',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caca7ed041be3b0b9d0b82432c7bf41af2',1,'mimalloc-doc.h']]], - ['mi_5foption_5freserve_5fhuge_5fos_5fpages_5fat_105',['mi_option_reserve_huge_os_pages_at',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caa13e7926d4339d2aa6fbf61d4473fd5c',1,'mimalloc-doc.h']]], - ['mi_5foption_5freset_5fdecommits_106',['mi_option_reset_decommits',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cac81ee965b130fa81238913a3c239d536',1,'mimalloc-doc.h']]], - ['mi_5foption_5freset_5fdelay_107',['mi_option_reset_delay',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca154fe170131d5212cff57e22b99523c5',1,'mimalloc-doc.h']]], - ['mi_5foption_5fsegment_5fcache_108',['mi_option_segment_cache',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca2ecbe7ef32f5c84de3739aa4f0b805a1',1,'mimalloc-doc.h']]], - ['mi_5foption_5fsegment_5freset_109',['mi_option_segment_reset',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cafb121d30d87591850d5410ccc3a95c6d',1,'mimalloc-doc.h']]], - ['mi_5foption_5fset_110',['mi_option_set',['../group__options.html#gaf84921c32375e25754dc2ee6a911fa60',1,'mimalloc-doc.h']]], - ['mi_5foption_5fset_5fdefault_111',['mi_option_set_default',['../group__options.html#ga7ef623e440e6e5545cb08c94e71e4b90',1,'mimalloc-doc.h']]], - ['mi_5foption_5fset_5fenabled_112',['mi_option_set_enabled',['../group__options.html#ga9a13d05fcb77489cb06d4d017ebd8bed',1,'mimalloc-doc.h']]], - ['mi_5foption_5fset_5fenabled_5fdefault_113',['mi_option_set_enabled_default',['../group__options.html#ga65518b69ec5d32336b50e07f74b3f629',1,'mimalloc-doc.h']]], - ['mi_5foption_5fshow_5ferrors_114',['mi_option_show_errors',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cafbf4822e5c00732c5984b32a032837f0',1,'mimalloc-doc.h']]], - ['mi_5foption_5fshow_5fstats_115',['mi_option_show_stats',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca0957ef73b2550764b4840edf48422fda',1,'mimalloc-doc.h']]], - ['mi_5foption_5ft_116',['mi_option_t',['../group__options.html#gafebf7ed116adb38ae5218bc3ce06884c',1,'mimalloc-doc.h']]], - ['mi_5foption_5fuse_5fnuma_5fnodes_117',['mi_option_use_numa_nodes',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca0ac33a18f6b659fcfaf44efb0bab1b74',1,'mimalloc-doc.h']]], - ['mi_5foption_5fverbose_118',['mi_option_verbose',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca7c8b7bf5281c581bad64f5daa6442777',1,'mimalloc-doc.h']]], - ['mi_5foutput_5ffun_119',['mi_output_fun',['../group__extended.html#gad823d23444a4b77a40f66bf075a98a0c',1,'mimalloc-doc.h']]], - ['mi_5fposix_5fmemalign_120',['mi_posix_memalign',['../group__posix.html#gacff84f226ba9feb2031b8992e5579447',1,'mimalloc-doc.h']]], - ['mi_5fprocess_5finfo_121',['mi_process_info',['../group__extended.html#ga7d862c2affd5790381da14eb102a364d',1,'mimalloc-doc.h']]], - ['mi_5fpvalloc_122',['mi_pvalloc',['../group__posix.html#gaeb325c39b887d3b90d85d1eb1712fb1e',1,'mimalloc-doc.h']]], - ['mi_5frealloc_123',['mi_realloc',['../group__malloc.html#gaf11eb497da57bdfb2de65eb191c69db6',1,'mimalloc-doc.h']]], - ['mi_5frealloc_5faligned_124',['mi_realloc_aligned',['../group__aligned.html#ga4028d1cf4aa4c87c880747044a8322ae',1,'mimalloc-doc.h']]], - ['mi_5frealloc_5faligned_5fat_125',['mi_realloc_aligned_at',['../group__aligned.html#gaf66a9ae6c6f08bd6be6fb6ea771faffb',1,'mimalloc-doc.h']]], - ['mi_5freallocarr_126',['mi_reallocarr',['../group__posix.html#ga7e1934d60a3e697950eeb48e042bfad5',1,'mimalloc-doc.h']]], - ['mi_5freallocarray_127',['mi_reallocarray',['../group__posix.html#ga48fad8648a2f1dab9c87ea9448a52088',1,'mimalloc-doc.h']]], - ['mi_5freallocf_128',['mi_reallocf',['../group__malloc.html#gafe68ac7c5e24a65cd55c9d6b152211a0',1,'mimalloc-doc.h']]], - ['mi_5freallocn_129',['mi_reallocn',['../group__malloc.html#ga61d57b4144ba24fba5c1e9b956d13853',1,'mimalloc-doc.h']]], - ['mi_5freallocn_5ftp_130',['mi_reallocn_tp',['../group__typed.html#ga1158b49a55dfa81f58a4426a7578f523',1,'mimalloc-doc.h']]], - ['mi_5frealpath_131',['mi_realpath',['../group__malloc.html#ga08cec32dd5bbe7da91c78d19f1b5bebe',1,'mimalloc-doc.h']]], - ['mi_5frecalloc_132',['mi_recalloc',['../group__malloc.html#ga23a0fbb452b5dce8e31fab1a1958cacc',1,'mimalloc-doc.h']]], - ['mi_5frecalloc_5faligned_133',['mi_recalloc_aligned',['../group__zeroinit.html#ga3e7e5c291acf1c7fd7ffd9914a9f945f',1,'mimalloc-doc.h']]], - ['mi_5frecalloc_5faligned_5fat_134',['mi_recalloc_aligned_at',['../group__zeroinit.html#ga4ff5e92ad73585418a072c9d059e5cf9',1,'mimalloc-doc.h']]], - ['mi_5fregister_5fdeferred_5ffree_135',['mi_register_deferred_free',['../group__extended.html#ga3460a6ca91af97be4058f523d3cb8ece',1,'mimalloc-doc.h']]], - ['mi_5fregister_5ferror_136',['mi_register_error',['../group__extended.html#gaa1d55e0e894be240827e5d87ec3a1f45',1,'mimalloc-doc.h']]], - ['mi_5fregister_5foutput_137',['mi_register_output',['../group__extended.html#gae5b17ff027cd2150b43a33040250cf3f',1,'mimalloc-doc.h']]], - ['mi_5freserve_5fhuge_5fos_5fpages_5fat_138',['mi_reserve_huge_os_pages_at',['../group__extended.html#ga7795a13d20087447281858d2c771cca1',1,'mimalloc-doc.h']]], - ['mi_5freserve_5fhuge_5fos_5fpages_5finterleave_139',['mi_reserve_huge_os_pages_interleave',['../group__extended.html#ga3132f521fb756fc0e8ec0b74fb58df50',1,'mimalloc-doc.h']]], - ['mi_5freserve_5fos_5fmemory_140',['mi_reserve_os_memory',['../group__extended.html#ga00ec3324b6b2591c7fe3677baa30a767',1,'mimalloc-doc.h']]], - ['mi_5frezalloc_141',['mi_rezalloc',['../group__zeroinit.html#ga8c292e142110229a2980b37ab036dbc6',1,'mimalloc-doc.h']]], - ['mi_5frezalloc_5faligned_142',['mi_rezalloc_aligned',['../group__zeroinit.html#gacd71a7bce96aab38ae6de17af2eb2cf0',1,'mimalloc-doc.h']]], - ['mi_5frezalloc_5faligned_5fat_143',['mi_rezalloc_aligned_at',['../group__zeroinit.html#gae8b358c417e61d5307da002702b0a8e1',1,'mimalloc-doc.h']]], - ['mi_5fsmall_5fsize_5fmax_144',['MI_SMALL_SIZE_MAX',['../group__extended.html#ga1ea64283508718d9d645c38efc2f4305',1,'mimalloc-doc.h']]], - ['mi_5fstats_5fmerge_145',['mi_stats_merge',['../group__extended.html#ga854b1de8cb067c7316286c28b2fcd3d1',1,'mimalloc-doc.h']]], - ['mi_5fstats_5fprint_146',['mi_stats_print',['../group__extended.html#ga2d126e5c62d3badc35445e5d84166df2',1,'mimalloc-doc.h']]], - ['mi_5fstats_5fprint_5fout_147',['mi_stats_print_out',['../group__extended.html#ga537f13b299ddf801e49a5a94fde02c79',1,'mimalloc-doc.h']]], - ['mi_5fstats_5freset_148',['mi_stats_reset',['../group__extended.html#ga3bb8468b8cfcc6e2a61d98aee85c5f99',1,'mimalloc-doc.h']]], - ['mi_5fstl_5fallocator_149',['mi_stl_allocator',['../group__cpp.html#structmi__stl__allocator',1,'']]], - ['mi_5fstrdup_150',['mi_strdup',['../group__malloc.html#gac7cffe13f1f458ed16789488bf92b9b2',1,'mimalloc-doc.h']]], - ['mi_5fstrndup_151',['mi_strndup',['../group__malloc.html#gaaabf971c2571891433477e2d21a35266',1,'mimalloc-doc.h']]], - ['mi_5fthread_5fdone_152',['mi_thread_done',['../group__extended.html#ga0ae4581e85453456a0d658b2b98bf7bf',1,'mimalloc-doc.h']]], - ['mi_5fthread_5finit_153',['mi_thread_init',['../group__extended.html#gaf8e73efc2cbca9ebfdfb166983a04c17',1,'mimalloc-doc.h']]], - ['mi_5fthread_5fstats_5fprint_5fout_154',['mi_thread_stats_print_out',['../group__extended.html#gab1dac8476c46cb9eecab767eb40c1525',1,'mimalloc-doc.h']]], - ['mi_5fusable_5fsize_155',['mi_usable_size',['../group__extended.html#ga089c859d9eddc5f9b4bd946cd53cebee',1,'mimalloc-doc.h']]], - ['mi_5fvalloc_156',['mi_valloc',['../group__posix.html#ga73baaf5951f5165ba0763d0c06b6a93b',1,'mimalloc-doc.h']]], - ['mi_5fzalloc_157',['mi_zalloc',['../group__malloc.html#gafdd9d8bb2986e668ba9884f28af38000',1,'mimalloc-doc.h']]], - ['mi_5fzalloc_5faligned_158',['mi_zalloc_aligned',['../group__aligned.html#ga0cadbcf5b89a7b6fb171bc8df8734819',1,'mimalloc-doc.h']]], - ['mi_5fzalloc_5faligned_5fat_159',['mi_zalloc_aligned_at',['../group__aligned.html#ga5f8c2353766db522565e642fafd8a3f8',1,'mimalloc-doc.h']]], - ['mi_5fzalloc_5fsmall_160',['mi_zalloc_small',['../group__extended.html#ga220f29f40a44404b0061c15bc1c31152',1,'mimalloc-doc.h']]], - ['mi_5fzalloc_5ftp_161',['mi_zalloc_tp',['../group__typed.html#gac77a61bdaf680a803785fe307820b48c',1,'mimalloc-doc.h']]] + ['heap_20allocation_0',['Heap Allocation',['../group__heap.html',1,'']]], + ['heap_20introspection_1',['Heap Introspection',['../group__analysis.html',1,'']]], + ['heap_5ftag_2',['heap_tag',['../group__analysis.html#a2b7a0c92ece8daf46b558efc990ebdc1',1,'mi_heap_area_t']]] ]; diff --git a/src/dashbls/depends/mimalloc/docs/search/all_7.js b/src/dashbls/depends/mimalloc/docs/search/all_7.js index 8f296aa53e1b..6d20843280ff 100644 --- a/src/dashbls/depends/mimalloc/docs/search/all_7.js +++ b/src/dashbls/depends/mimalloc/docs/search/all_7.js @@ -1,4 +1,5 @@ var searchData= [ - ['overriding_20malloc_162',['Overriding Malloc',['../overrides.html',1,'']]] + ['initialized_20re_20allocation_0',['Zero initialized re-allocation',['../group__zeroinit.html',1,'']]], + ['introspection_1',['Heap Introspection',['../group__analysis.html',1,'']]] ]; diff --git a/src/dashbls/depends/mimalloc/docs/search/all_8.js b/src/dashbls/depends/mimalloc/docs/search/all_8.js index a9caa77c7bfd..5071ed69e8a2 100644 --- a/src/dashbls/depends/mimalloc/docs/search/all_8.js +++ b/src/dashbls/depends/mimalloc/docs/search/all_8.js @@ -1,5 +1,4 @@ var searchData= [ - ['performance_163',['Performance',['../bench.html',1,'']]], - ['posix_164',['Posix',['../group__posix.html',1,'']]] + ['library_0',['Using the library',['../using.html',1,'']]] ]; diff --git a/src/dashbls/depends/mimalloc/docs/search/all_9.js b/src/dashbls/depends/mimalloc/docs/search/all_9.js index f6b4ba352ef6..400cd0239def 100644 --- a/src/dashbls/depends/mimalloc/docs/search/all_9.js +++ b/src/dashbls/depends/mimalloc/docs/search/all_9.js @@ -1,5 +1,192 @@ var searchData= [ - ['reserved_165',['reserved',['../group__analysis.html#ae848a3e6840414891035423948ca0383',1,'mi_heap_area_t']]], - ['runtime_20options_166',['Runtime Options',['../group__options.html',1,'']]] + ['macros_0',['Typed Macros',['../group__typed.html',1,'']]], + ['malloc_1',['Overriding Malloc',['../overrides.html',1,'']]], + ['malloc_2',['mi-malloc',['../index.html',1,'']]], + ['mi_20malloc_3',['mi-malloc',['../index.html',1,'']]], + ['mi_5f_5fexpand_4',['mi__expand',['../group__posix.html#ga66bcfeb4faedbb42b796bc680821ef84',1,'mimalloc-doc.h']]], + ['mi_5f_5fposix_5fmemalign_5',['mi__posix_memalign',['../group__posix.html#gad5a69c8fea96aa2b7a7c818c2130090a',1,'mimalloc-doc.h']]], + ['mi_5fabandoned_5fvisit_5fblocks_6',['mi_abandoned_visit_blocks',['../group__analysis.html#ga6a4865a887b2ec5247854af61562503c',1,'mimalloc-doc.h']]], + ['mi_5faligned_5falloc_7',['mi_aligned_alloc',['../group__posix.html#ga430ed1513f0571ff83be00ec58a98ee0',1,'mimalloc-doc.h']]], + ['mi_5faligned_5foffset_5frecalloc_8',['mi_aligned_offset_recalloc',['../group__posix.html#ga16570deddd559001b44953eedbad0084',1,'mimalloc-doc.h']]], + ['mi_5faligned_5frecalloc_9',['mi_aligned_recalloc',['../group__posix.html#gaf82cbb4b4f24acf723348628451798d3',1,'mimalloc-doc.h']]], + ['mi_5farena_5farea_10',['mi_arena_area',['../group__extended.html#ga9a25a00a22151619a0be91a10af7787f',1,'mimalloc-doc.h']]], + ['mi_5farena_5fid_5ft_11',['mi_arena_id_t',['../group__extended.html#ga99fe38650d0b02e0e0f89ee024db91d3',1,'mimalloc-doc.h']]], + ['mi_5fblock_5fvisit_5ffun_12',['mi_block_visit_fun',['../group__analysis.html#ga8255dc9371e6b299d9802a610c4e34ec',1,'mimalloc-doc.h']]], + ['mi_5fcalloc_13',['mi_calloc',['../group__malloc.html#ga6686568014b54d1e6c7ac64a076e4f56',1,'mimalloc-doc.h']]], + ['mi_5fcalloc_5faligned_14',['mi_calloc_aligned',['../group__aligned.html#ga424ef386fb1f9f8e0a86ab53f16eaaf1',1,'mimalloc-doc.h']]], + ['mi_5fcalloc_5faligned_5fat_15',['mi_calloc_aligned_at',['../group__aligned.html#ga977f96bd2c5c141bcd70e6685c90d6c3',1,'mimalloc-doc.h']]], + ['mi_5fcalloc_5ftp_16',['mi_calloc_tp',['../group__typed.html#gae80c47c9d4cab10961fff1a8ac98fc07',1,'mimalloc-doc.h']]], + ['mi_5fcfree_17',['mi_cfree',['../group__posix.html#ga705dc7a64bffacfeeb0141501a5c35d7',1,'mimalloc-doc.h']]], + ['mi_5fcheck_5fowned_18',['mi_check_owned',['../group__analysis.html#ga628c237489c2679af84a4d0d143b3dd5',1,'mimalloc-doc.h']]], + ['mi_5fcollect_19',['mi_collect',['../group__extended.html#ga421430e2226d7d468529cec457396756',1,'mimalloc-doc.h']]], + ['mi_5fdebug_5fshow_5farenas_20',['mi_debug_show_arenas',['../group__extended.html#gad7439207f8f71fb6c382a9ea20b997e7',1,'mimalloc-doc.h']]], + ['mi_5fdeferred_5ffree_5ffun_21',['mi_deferred_free_fun',['../group__extended.html#ga292a45f7dbc7cd23c5352ce1f0002816',1,'mimalloc-doc.h']]], + ['mi_5fdupenv_5fs_22',['mi_dupenv_s',['../group__posix.html#gab41369c1a1da7504013a7a0b1d4dd958',1,'mimalloc-doc.h']]], + ['mi_5ferror_5ffun_23',['mi_error_fun',['../group__extended.html#ga83fc6a688b322261e1c2deab000b0591',1,'mimalloc-doc.h']]], + ['mi_5fexpand_24',['mi_expand',['../group__malloc.html#ga19299856216cfbb08e2628593654dfb0',1,'mimalloc-doc.h']]], + ['mi_5ffree_25',['mi_free',['../group__malloc.html#gaf2c7b89c327d1f60f59e68b9ea644d95',1,'mimalloc-doc.h']]], + ['mi_5ffree_5faligned_26',['mi_free_aligned',['../group__posix.html#ga0d28d5cf61e6bfbb18c63092939fe5c9',1,'mimalloc-doc.h']]], + ['mi_5ffree_5fsize_27',['mi_free_size',['../group__posix.html#gae01389eedab8d67341ff52e2aad80ebb',1,'mimalloc-doc.h']]], + ['mi_5ffree_5fsize_5faligned_28',['mi_free_size_aligned',['../group__posix.html#ga72e9d7ffb5fe94d69bc722c8506e27bc',1,'mimalloc-doc.h']]], + ['mi_5fgood_5fsize_29',['mi_good_size',['../group__extended.html#gac057927cd06c854b45fe7847e921bd47',1,'mimalloc-doc.h']]], + ['mi_5fheap_5farea_5ft_30',['mi_heap_area_t',['../group__analysis.html#structmi__heap__area__t',1,'']]], + ['mi_5fheap_5fcalloc_31',['mi_heap_calloc',['../group__heap.html#gac0098aaf231d3e9586c73136d5df95da',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fcalloc_5faligned_32',['mi_heap_calloc_aligned',['../group__heap.html#gacafcc26df827c7a7de5e850217566108',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fcalloc_5faligned_5fat_33',['mi_heap_calloc_aligned_at',['../group__heap.html#gaa42ec2079989c4374f2c331d9b35f4e4',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fcalloc_5ftp_34',['mi_heap_calloc_tp',['../group__typed.html#ga4e5d1f1707c90e5f55e023ac5f45fe74',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fcheck_5fowned_35',['mi_heap_check_owned',['../group__analysis.html#ga0d67c1789faaa15ff366c024fcaf6377',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fcollect_36',['mi_heap_collect',['../group__heap.html#ga7922f7495cde30b1984d0e6072419298',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fcontains_5fblock_37',['mi_heap_contains_block',['../group__analysis.html#gaa862aa8ed8d57d84cae41fc1022d71af',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fdelete_38',['mi_heap_delete',['../group__heap.html#ga2ab1af8d438819b55319c7ef51d1e409',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fdestroy_39',['mi_heap_destroy',['../group__heap.html#ga9f9c0844edb9717f4feacd79116b8e0d',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fget_5fbacking_40',['mi_heap_get_backing',['../group__heap.html#gac6ac9f0e7be9ab4ff70acfc8dad1235a',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fget_5fdefault_41',['mi_heap_get_default',['../group__heap.html#ga14c667a6e2c5d28762d8cb7d4e057909',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fmalloc_42',['mi_heap_malloc',['../group__heap.html#gab374e206c7034e0d899fb934e4f4a863',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fmalloc_5faligned_43',['mi_heap_malloc_aligned',['../group__heap.html#ga33f4f05b7fea7af2113c62a4bf882cc5',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fmalloc_5faligned_5fat_44',['mi_heap_malloc_aligned_at',['../group__heap.html#gae7ffc045c3996497a7f3a5f6fe7b8aaa',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fmalloc_5fsmall_45',['mi_heap_malloc_small',['../group__heap.html#ga012c5c8abe22b10043de39ff95909541',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fmalloc_5ftp_46',['mi_heap_malloc_tp',['../group__typed.html#ga653bcb24ac495bc19940ecd6898f9cd7',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fmallocn_47',['mi_heap_mallocn',['../group__heap.html#gab0f755c0b21c387fe8e9024200faa372',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fmallocn_5ftp_48',['mi_heap_mallocn_tp',['../group__typed.html#ga6b75cb9c4b9c647661d0924552dc6e83',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fnew_49',['mi_heap_new',['../group__heap.html#gaa718bb226ec0546ba6d1b6cb32179f3a',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fnew_5fex_50',['mi_heap_new_ex',['../group__extended.html#ga3ae360583f4351aa5267ee7e43008faf',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fnew_5fin_5farena_51',['mi_heap_new_in_arena',['../group__extended.html#gaaf2d9976576d5efd5544be12848af949',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frealloc_52',['mi_heap_realloc',['../group__heap.html#gac5252d6a2e510bd349e4fcb452e6a93a',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frealloc_5faligned_53',['mi_heap_realloc_aligned',['../group__heap.html#gaccf8c249872f30bf1c2493a09197d734',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frealloc_5faligned_5fat_54',['mi_heap_realloc_aligned_at',['../group__heap.html#ga6df988a7219d5707f010d5f3eb0dc3f5',1,'mimalloc-doc.h']]], + ['mi_5fheap_5freallocf_55',['mi_heap_reallocf',['../group__heap.html#gae7cd171425bee04c683c65a3701f0b4a',1,'mimalloc-doc.h']]], + ['mi_5fheap_5freallocn_56',['mi_heap_reallocn',['../group__heap.html#gaccf7bfe10ce510a000d3547d9cf7fa29',1,'mimalloc-doc.h']]], + ['mi_5fheap_5freallocn_5ftp_57',['mi_heap_reallocn_tp',['../group__typed.html#gaf213d5422ec35e7f6caad827c79bc948',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frealpath_58',['mi_heap_realpath',['../group__heap.html#ga55545a3ec6da29c5b4f62e540ecac1e2',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frecalloc_59',['mi_heap_recalloc',['../group__zeroinit.html#gad1a0d325d930eeb80f25e3fea37aacde',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frecalloc_5faligned_60',['mi_heap_recalloc_aligned',['../group__zeroinit.html#ga87ddd674bf1c67237d780d0b9e0f0f32',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frecalloc_5faligned_5fat_61',['mi_heap_recalloc_aligned_at',['../group__zeroinit.html#ga07b5bcbaf00d0d2e598c232982588496',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frecalloc_5ftp_62',['mi_heap_recalloc_tp',['../group__typed.html#ga3e50a1600958fcaf1a7f3560c9174f9e',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frezalloc_63',['mi_heap_rezalloc',['../group__zeroinit.html#ga8d8b7ebb24b513cd84d1a696048da60d',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frezalloc_5faligned_64',['mi_heap_rezalloc_aligned',['../group__zeroinit.html#ga5129f6dc46ee1613d918820a8a0533a7',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frezalloc_5faligned_5fat_65',['mi_heap_rezalloc_aligned_at',['../group__zeroinit.html#ga2bafa79c3f98ea74882349d44cffa5d9',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fset_5fdefault_66',['mi_heap_set_default',['../group__heap.html#ga349b677dec7da5eacdbc7a385bd62a4a',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fstrdup_67',['mi_heap_strdup',['../group__heap.html#ga5754e09ccc51dd6bc73885bb6ea21b7a',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fstrndup_68',['mi_heap_strndup',['../group__heap.html#gad224df78f1fbee942df8adf023e12cf3',1,'mimalloc-doc.h']]], + ['mi_5fheap_5ft_69',['mi_heap_t',['../group__heap.html#ga34a47cde5a5b38c29f1aa3c5e76943c2',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fvisit_5fblocks_70',['mi_heap_visit_blocks',['../group__analysis.html#ga70c46687dc6e9dc98b232b02646f8bed',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fzalloc_71',['mi_heap_zalloc',['../group__heap.html#gabebc796399619d964d8db77aa835e8c1',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fzalloc_5faligned_72',['mi_heap_zalloc_aligned',['../group__heap.html#ga6466bde8b5712aa34e081a8317f9f471',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fzalloc_5faligned_5fat_73',['mi_heap_zalloc_aligned_at',['../group__heap.html#ga484e3d01cd174f78c7e53370e5a7c819',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fzalloc_5ftp_74',['mi_heap_zalloc_tp',['../group__typed.html#gad6e87e86e994aa14416ae9b5d4c188fe',1,'mimalloc-doc.h']]], + ['mi_5fis_5fin_5fheap_5fregion_75',['mi_is_in_heap_region',['../group__extended.html#ga5f071b10d4df1c3658e04e7fd67a94e6',1,'mimalloc-doc.h']]], + ['mi_5fis_5fredirected_76',['mi_is_redirected',['../group__extended.html#gaad25050b19f30cd79397b227e0157a3f',1,'mimalloc-doc.h']]], + ['mi_5fmalloc_77',['mi_malloc',['../group__malloc.html#gae1dd97b542420c87ae085e822b1229e8',1,'mimalloc-doc.h']]], + ['mi_5fmalloc_5faligned_78',['mi_malloc_aligned',['../group__aligned.html#ga69578ff1a98ca16e1dcd02c0995cd65c',1,'mimalloc-doc.h']]], + ['mi_5fmalloc_5faligned_5fat_79',['mi_malloc_aligned_at',['../group__aligned.html#ga2022f71b95a7cd6cce1b6e07752ae8ca',1,'mimalloc-doc.h']]], + ['mi_5fmalloc_5fgood_5fsize_80',['mi_malloc_good_size',['../group__posix.html#ga9d23ac7885fed7413c11d8e0ffa31071',1,'mimalloc-doc.h']]], + ['mi_5fmalloc_5fsize_81',['mi_malloc_size',['../group__posix.html#ga4531c9e775bb3ae12db57c1ba8a5d7de',1,'mimalloc-doc.h']]], + ['mi_5fmalloc_5fsmall_82',['mi_malloc_small',['../group__extended.html#ga7f050bc6b897da82692174f5fce59cde',1,'mimalloc-doc.h']]], + ['mi_5fmalloc_5ftp_83',['mi_malloc_tp',['../group__typed.html#ga0619a62c5fd886f1016030abe91f0557',1,'mimalloc-doc.h']]], + ['mi_5fmalloc_5fusable_5fsize_84',['mi_malloc_usable_size',['../group__posix.html#ga06d07cf357bbac5c73ba5d0c0c421e17',1,'mimalloc-doc.h']]], + ['mi_5fmallocn_85',['mi_mallocn',['../group__malloc.html#ga61f46bade3db76ca24aaafedc40de7b6',1,'mimalloc-doc.h']]], + ['mi_5fmallocn_5ftp_86',['mi_mallocn_tp',['../group__typed.html#gae5cb6e0fafc9f23169c5622e077afe8b',1,'mimalloc-doc.h']]], + ['mi_5fmanage_5fos_5fmemory_87',['mi_manage_os_memory',['../group__extended.html#ga4c6486a1fdcd7a423b5f25fe4be8e0cf',1,'mimalloc-doc.h']]], + ['mi_5fmanage_5fos_5fmemory_5fex_88',['mi_manage_os_memory_ex',['../group__extended.html#ga41ce8525d77bbb60f618fa1029994f6e',1,'mimalloc-doc.h']]], + ['mi_5fmbsdup_89',['mi_mbsdup',['../group__posix.html#ga7b82a44094fdec4d2084eb4288a979b0',1,'mimalloc-doc.h']]], + ['mi_5fmemalign_90',['mi_memalign',['../group__posix.html#ga726867f13fd29ca36064954c0285b1d8',1,'mimalloc-doc.h']]], + ['mi_5fnew_91',['mi_new',['../group__cpp.html#ga633d96e3bc7011f960df9f3b2731fc6a',1,'mimalloc-doc.h']]], + ['mi_5fnew_5faligned_92',['mi_new_aligned',['../group__cpp.html#ga79c54da0b4b4ce9fcc11d2f6ef6675f8',1,'mimalloc-doc.h']]], + ['mi_5fnew_5faligned_5fnothrow_93',['mi_new_aligned_nothrow',['../group__cpp.html#ga92ae00b6dd64406c7e64557711ec04b7',1,'mimalloc-doc.h']]], + ['mi_5fnew_5fn_94',['mi_new_n',['../group__cpp.html#gadd11b85c15d21d308386844b5233856c',1,'mimalloc-doc.h']]], + ['mi_5fnew_5fnothrow_95',['mi_new_nothrow',['../group__cpp.html#ga5cb4f120d1f7296074256215aa9a9e54',1,'mimalloc-doc.h']]], + ['mi_5fnew_5frealloc_96',['mi_new_realloc',['../group__cpp.html#ga6867d89baf992728e0cc20a1f47db4d0',1,'mimalloc-doc.h']]], + ['mi_5fnew_5freallocn_97',['mi_new_reallocn',['../group__cpp.html#gaace912ce086682d56f3ce9f7638d9d67',1,'mimalloc-doc.h']]], + ['mi_5foption_5fabandoned_5fpage_5fpurge_98',['mi_option_abandoned_page_purge',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca11e62ed69200a489a5be955582078c0c',1,'mimalloc-doc.h']]], + ['mi_5foption_5fabandoned_5freclaim_5fon_5ffree_99',['mi_option_abandoned_reclaim_on_free',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca009e4b5684922ce664d73d2a8e1698d9',1,'mimalloc-doc.h']]], + ['mi_5foption_5fallow_5flarge_5fos_5fpages_100',['mi_option_allow_large_os_pages',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca7cc4804ced69004fa42a9a136a9ba556',1,'mimalloc-doc.h']]], + ['mi_5foption_5farena_5feager_5fcommit_101',['mi_option_arena_eager_commit',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cafd0c5ddbc4b59fd8b5216871728167a5',1,'mimalloc-doc.h']]], + ['mi_5foption_5farena_5fpurge_5fmult_102',['mi_option_arena_purge_mult',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca8236501f1ab45d26e6fd885d191a2b5e',1,'mimalloc-doc.h']]], + ['mi_5foption_5farena_5freserve_103',['mi_option_arena_reserve',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cab1c88e23ae290bbeec824038a97959de',1,'mimalloc-doc.h']]], + ['mi_5foption_5fdestroy_5fon_5fexit_104',['mi_option_destroy_on_exit',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca6364331e305e7d3c0218b058ff3afc88',1,'mimalloc-doc.h']]], + ['mi_5foption_5fdisable_105',['mi_option_disable',['../group__options.html#gaebf6ff707a2e688ebb1a2296ca564054',1,'mimalloc-doc.h']]], + ['mi_5foption_5fdisallow_5farena_5falloc_106',['mi_option_disallow_arena_alloc',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caeae1696100e4057ffc4182730cc04e40',1,'mimalloc-doc.h']]], + ['mi_5foption_5fdisallow_5fos_5falloc_107',['mi_option_disallow_os_alloc',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cadcfb5a09580361b1be65901d2d812de6',1,'mimalloc-doc.h']]], + ['mi_5foption_5feager_5fcommit_108',['mi_option_eager_commit',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca1e8de72c93da7ff22d91e1e27b52ac2b',1,'mimalloc-doc.h']]], + ['mi_5foption_5feager_5fcommit_5fdelay_109',['mi_option_eager_commit_delay',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca17a190c25be381142d87e0468c4c068c',1,'mimalloc-doc.h']]], + ['mi_5foption_5fenable_110',['mi_option_enable',['../group__options.html#ga04180ae41b0d601421dd62ced40ca050',1,'mimalloc-doc.h']]], + ['mi_5foption_5fget_111',['mi_option_get',['../group__options.html#ga7e8af195cc81d3fa64ccf2662caa565a',1,'mimalloc-doc.h']]], + ['mi_5foption_5fget_5fclamp_112',['mi_option_get_clamp',['../group__options.html#ga96ad9c406338bd314cfe878cfc9bf723',1,'mimalloc-doc.h']]], + ['mi_5foption_5fget_5fsize_113',['mi_option_get_size',['../group__options.html#ga274db5a6ac87cc24ef0b23e7006ed02c',1,'mimalloc-doc.h']]], + ['mi_5foption_5fis_5fenabled_114',['mi_option_is_enabled',['../group__options.html#ga459ad98f18b3fc9275474807fe0ca188',1,'mimalloc-doc.h']]], + ['mi_5foption_5flimit_5fos_5falloc_115',['mi_option_limit_os_alloc',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca9fa61bd9668479f8452d2195759444cc',1,'mimalloc-doc.h']]], + ['mi_5foption_5fmax_5ferrors_116',['mi_option_max_errors',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caec6ecbe29d46a48205ed8823a8a52a6a',1,'mimalloc-doc.h']]], + ['mi_5foption_5fmax_5fsegment_5freclaim_117',['mi_option_max_segment_reclaim',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caa9ad9005d7017c8c30ad2d6ba31db909',1,'mimalloc-doc.h']]], + ['mi_5foption_5fmax_5fwarnings_118',['mi_option_max_warnings',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caf9595921087e942602ee079158762665',1,'mimalloc-doc.h']]], + ['mi_5foption_5fos_5ftag_119',['mi_option_os_tag',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca4b74ae2a69e445de6c2361b73c1d14bf',1,'mimalloc-doc.h']]], + ['mi_5foption_5fpurge_5fdecommits_120',['mi_option_purge_decommits',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca9d15c5e3d2115eef681c17e4dd5ab9a4',1,'mimalloc-doc.h']]], + ['mi_5foption_5fpurge_5fdelay_121',['mi_option_purge_delay',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cadd351e615acd8563529c20a347be7290',1,'mimalloc-doc.h']]], + ['mi_5foption_5fpurge_5fextend_5fdelay_122',['mi_option_purge_extend_delay',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca02005f164bdf03f5f00c5be726adf487',1,'mimalloc-doc.h']]], + ['mi_5foption_5freserve_5fhuge_5fos_5fpages_123',['mi_option_reserve_huge_os_pages',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caca7ed041be3b0b9d0b82432c7bf41af2',1,'mimalloc-doc.h']]], + ['mi_5foption_5freserve_5fhuge_5fos_5fpages_5fat_124',['mi_option_reserve_huge_os_pages_at',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caa13e7926d4339d2aa6fbf61d4473fd5c',1,'mimalloc-doc.h']]], + ['mi_5foption_5freserve_5fos_5fmemory_125',['mi_option_reserve_os_memory',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cafbf4999c828cf79a0fb2de65d23f7333',1,'mimalloc-doc.h']]], + ['mi_5foption_5fretry_5fon_5foom_126',['mi_option_retry_on_oom',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca8f51df355bf6651db899e6085b54865e',1,'mimalloc-doc.h']]], + ['mi_5foption_5fset_127',['mi_option_set',['../group__options.html#gaf84921c32375e25754dc2ee6a911fa60',1,'mimalloc-doc.h']]], + ['mi_5foption_5fset_5fdefault_128',['mi_option_set_default',['../group__options.html#ga7ef623e440e6e5545cb08c94e71e4b90',1,'mimalloc-doc.h']]], + ['mi_5foption_5fset_5fenabled_129',['mi_option_set_enabled',['../group__options.html#ga9a13d05fcb77489cb06d4d017ebd8bed',1,'mimalloc-doc.h']]], + ['mi_5foption_5fset_5fenabled_5fdefault_130',['mi_option_set_enabled_default',['../group__options.html#ga65518b69ec5d32336b50e07f74b3f629',1,'mimalloc-doc.h']]], + ['mi_5foption_5fshow_5ferrors_131',['mi_option_show_errors',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cafbf4822e5c00732c5984b32a032837f0',1,'mimalloc-doc.h']]], + ['mi_5foption_5fshow_5fstats_132',['mi_option_show_stats',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca0957ef73b2550764b4840edf48422fda',1,'mimalloc-doc.h']]], + ['mi_5foption_5ft_133',['mi_option_t',['../group__options.html#gafebf7ed116adb38ae5218bc3ce06884c',1,'mimalloc-doc.h']]], + ['mi_5foption_5fuse_5fnuma_5fnodes_134',['mi_option_use_numa_nodes',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca0ac33a18f6b659fcfaf44efb0bab1b74',1,'mimalloc-doc.h']]], + ['mi_5foption_5fverbose_135',['mi_option_verbose',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca7c8b7bf5281c581bad64f5daa6442777',1,'mimalloc-doc.h']]], + ['mi_5foption_5fvisit_5fabandoned_136',['mi_option_visit_abandoned',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca38c67733a3956a1f4eeaca89fab9e78e',1,'mimalloc-doc.h']]], + ['mi_5foutput_5ffun_137',['mi_output_fun',['../group__extended.html#gadf31cea7d0332a81c8b882cbbdbadb8d',1,'mimalloc-doc.h']]], + ['mi_5fposix_5fmemalign_138',['mi_posix_memalign',['../group__posix.html#gacff84f226ba9feb2031b8992e5579447',1,'mimalloc-doc.h']]], + ['mi_5fprocess_5finfo_139',['mi_process_info',['../group__extended.html#ga7d862c2affd5790381da14eb102a364d',1,'mimalloc-doc.h']]], + ['mi_5fpvalloc_140',['mi_pvalloc',['../group__posix.html#ga644bebccdbb2821542dd8c7e7641f476',1,'mimalloc-doc.h']]], + ['mi_5frealloc_141',['mi_realloc',['../group__malloc.html#ga0621af6a5e3aa384e6a1b548958bf583',1,'mimalloc-doc.h']]], + ['mi_5frealloc_5faligned_142',['mi_realloc_aligned',['../group__aligned.html#ga5d7a46d054b4d7abe9d8d2474add2edf',1,'mimalloc-doc.h']]], + ['mi_5frealloc_5faligned_5fat_143',['mi_realloc_aligned_at',['../group__aligned.html#gad06dcf2bb8faadb2c8ea61ee5d24bbf6',1,'mimalloc-doc.h']]], + ['mi_5freallocarr_144',['mi_reallocarr',['../group__posix.html#ga7e1934d60a3e697950eeb48e042bfad5',1,'mimalloc-doc.h']]], + ['mi_5freallocarray_145',['mi_reallocarray',['../group__posix.html#gadfeccb72748a2f6305474a37d9d57bce',1,'mimalloc-doc.h']]], + ['mi_5freallocf_146',['mi_reallocf',['../group__malloc.html#ga4dc3a4067037b151a64629fe8a332641',1,'mimalloc-doc.h']]], + ['mi_5freallocn_147',['mi_reallocn',['../group__malloc.html#ga8bddfb4a1270a0854bbcf44cb3980467',1,'mimalloc-doc.h']]], + ['mi_5freallocn_5ftp_148',['mi_reallocn_tp',['../group__typed.html#ga1158b49a55dfa81f58a4426a7578f523',1,'mimalloc-doc.h']]], + ['mi_5frealpath_149',['mi_realpath',['../group__malloc.html#ga94c3afcc086e85d75a57e9f76b9b71dd',1,'mimalloc-doc.h']]], + ['mi_5frecalloc_150',['mi_recalloc',['../group__malloc.html#ga23a0fbb452b5dce8e31fab1a1958cacc',1,'mimalloc-doc.h']]], + ['mi_5frecalloc_5faligned_151',['mi_recalloc_aligned',['../group__zeroinit.html#ga3e2169b48683aa0ab64f813fd68d839e',1,'mimalloc-doc.h']]], + ['mi_5frecalloc_5faligned_5fat_152',['mi_recalloc_aligned_at',['../group__zeroinit.html#gaae25e4ddedd4e0fb61b1a8bd5d452750',1,'mimalloc-doc.h']]], + ['mi_5fregister_5fdeferred_5ffree_153',['mi_register_deferred_free',['../group__extended.html#ga3460a6ca91af97be4058f523d3cb8ece',1,'mimalloc-doc.h']]], + ['mi_5fregister_5ferror_154',['mi_register_error',['../group__extended.html#gaa1d55e0e894be240827e5d87ec3a1f45',1,'mimalloc-doc.h']]], + ['mi_5fregister_5foutput_155',['mi_register_output',['../group__extended.html#gae5b17ff027cd2150b43a33040250cf3f',1,'mimalloc-doc.h']]], + ['mi_5freserve_5fhuge_5fos_5fpages_5fat_156',['mi_reserve_huge_os_pages_at',['../group__extended.html#ga7795a13d20087447281858d2c771cca1',1,'mimalloc-doc.h']]], + ['mi_5freserve_5fhuge_5fos_5fpages_5fat_5fex_157',['mi_reserve_huge_os_pages_at_ex',['../group__extended.html#ga591aab1c2bc2ca920e33f0f9f9cb5c52',1,'mimalloc-doc.h']]], + ['mi_5freserve_5fhuge_5fos_5fpages_5finterleave_158',['mi_reserve_huge_os_pages_interleave',['../group__extended.html#ga3132f521fb756fc0e8ec0b74fb58df50',1,'mimalloc-doc.h']]], + ['mi_5freserve_5fos_5fmemory_159',['mi_reserve_os_memory',['../group__extended.html#ga00ec3324b6b2591c7fe3677baa30a767',1,'mimalloc-doc.h']]], + ['mi_5freserve_5fos_5fmemory_5fex_160',['mi_reserve_os_memory_ex',['../group__extended.html#ga32f519797fd9a81acb4f52d36e6d751b',1,'mimalloc-doc.h']]], + ['mi_5frezalloc_161',['mi_rezalloc',['../group__zeroinit.html#gadfd34cd7b4f2bbda7ae06367a6360756',1,'mimalloc-doc.h']]], + ['mi_5frezalloc_5faligned_162',['mi_rezalloc_aligned',['../group__zeroinit.html#ga4d02404fe1e7db00beb65f185e012caa',1,'mimalloc-doc.h']]], + ['mi_5frezalloc_5faligned_5fat_163',['mi_rezalloc_aligned_at',['../group__zeroinit.html#ga6843a88285bbfcc3bdfccc60aafd1270',1,'mimalloc-doc.h']]], + ['mi_5fsmall_5fsize_5fmax_164',['MI_SMALL_SIZE_MAX',['../group__extended.html#ga1ea64283508718d9d645c38efc2f4305',1,'mimalloc-doc.h']]], + ['mi_5fstats_5fmerge_165',['mi_stats_merge',['../group__extended.html#ga854b1de8cb067c7316286c28b2fcd3d1',1,'mimalloc-doc.h']]], + ['mi_5fstats_5fprint_166',['mi_stats_print',['../group__extended.html#ga2d126e5c62d3badc35445e5d84166df2',1,'mimalloc-doc.h']]], + ['mi_5fstats_5fprint_5fout_167',['mi_stats_print_out',['../group__extended.html#ga537f13b299ddf801e49a5a94fde02c79',1,'mimalloc-doc.h']]], + ['mi_5fstats_5freset_168',['mi_stats_reset',['../group__extended.html#ga3bb8468b8cfcc6e2a61d98aee85c5f99',1,'mimalloc-doc.h']]], + ['mi_5fstl_5fallocator_169',['mi_stl_allocator',['../group__cpp.html#structmi__stl__allocator',1,'']]], + ['mi_5fstrdup_170',['mi_strdup',['../group__malloc.html#ga245ac90ebc2cfdd17de599e5fea59889',1,'mimalloc-doc.h']]], + ['mi_5fstrndup_171',['mi_strndup',['../group__malloc.html#ga486d0d26b3b3794f6d1cdb41a9aed92d',1,'mimalloc-doc.h']]], + ['mi_5fsubproc_5fadd_5fcurrent_5fthread_172',['mi_subproc_add_current_thread',['../group__extended.html#gadbc53414eb68b275588ec001ce1ddc7c',1,'mimalloc-doc.h']]], + ['mi_5fsubproc_5fdelete_173',['mi_subproc_delete',['../group__extended.html#gaa7d263e9429bac9ac8345c9d25de610e',1,'mimalloc-doc.h']]], + ['mi_5fsubproc_5fid_5ft_174',['mi_subproc_id_t',['../group__extended.html#ga8c0bcd1fee27c7641e9c3c0d991b3b7d',1,'mimalloc-doc.h']]], + ['mi_5fsubproc_5fmain_175',['mi_subproc_main',['../group__extended.html#ga2ecba0d7ebdc99e71bb985c4a1609806',1,'mimalloc-doc.h']]], + ['mi_5fsubproc_5fnew_176',['mi_subproc_new',['../group__extended.html#ga8068cac328e41fa2170faef707315243',1,'mimalloc-doc.h']]], + ['mi_5fthread_5fdone_177',['mi_thread_done',['../group__extended.html#ga0ae4581e85453456a0d658b2b98bf7bf',1,'mimalloc-doc.h']]], + ['mi_5fthread_5finit_178',['mi_thread_init',['../group__extended.html#gaf8e73efc2cbca9ebfdfb166983a04c17',1,'mimalloc-doc.h']]], + ['mi_5fthread_5fstats_5fprint_5fout_179',['mi_thread_stats_print_out',['../group__extended.html#gab1dac8476c46cb9eecab767eb40c1525',1,'mimalloc-doc.h']]], + ['mi_5fusable_5fsize_180',['mi_usable_size',['../group__extended.html#ga089c859d9eddc5f9b4bd946cd53cebee',1,'mimalloc-doc.h']]], + ['mi_5fvalloc_181',['mi_valloc',['../group__posix.html#ga50cafb9722020402f065de93799f64ca',1,'mimalloc-doc.h']]], + ['mi_5fwcsdup_182',['mi_wcsdup',['../group__posix.html#gaa9fd7f25c9ac3a20e89b33bd6e383fcf',1,'mimalloc-doc.h']]], + ['mi_5fwdupenv_5fs_183',['mi_wdupenv_s',['../group__posix.html#ga6ac6a6a8f3c96f1af24bb8d0439cbbd1',1,'mimalloc-doc.h']]], + ['mi_5fzalloc_184',['mi_zalloc',['../group__malloc.html#gae6e38c4403247a7b40d80419e093bfb8',1,'mimalloc-doc.h']]], + ['mi_5fzalloc_5faligned_185',['mi_zalloc_aligned',['../group__aligned.html#gaac7d0beb782f9b9ac31f47492b130f82',1,'mimalloc-doc.h']]], + ['mi_5fzalloc_5faligned_5fat_186',['mi_zalloc_aligned_at',['../group__aligned.html#ga7c1778805ce50ebbf02ccbd5e39d5dba',1,'mimalloc-doc.h']]], + ['mi_5fzalloc_5fsmall_187',['mi_zalloc_small',['../group__extended.html#ga51c47637e81df0e2f13a2d7a2dec123e',1,'mimalloc-doc.h']]], + ['mi_5fzalloc_5ftp_188',['mi_zalloc_tp',['../group__typed.html#gac77a61bdaf680a803785fe307820b48c',1,'mimalloc-doc.h']]] ]; diff --git a/src/dashbls/depends/mimalloc/docs/search/all_a.js b/src/dashbls/depends/mimalloc/docs/search/all_a.js index 699b5456e717..dee0ab7ccfc4 100644 --- a/src/dashbls/depends/mimalloc/docs/search/all_a.js +++ b/src/dashbls/depends/mimalloc/docs/search/all_a.js @@ -1,4 +1,5 @@ var searchData= [ - ['typed_20macros_167',['Typed Macros',['../group__typed.html',1,'']]] + ['options_0',['Options',['../environment.html',1,'Environment Options'],['../group__options.html',1,'Runtime Options']]], + ['overriding_20malloc_1',['Overriding Malloc',['../overrides.html',1,'']]] ]; diff --git a/src/dashbls/depends/mimalloc/docs/search/all_b.js b/src/dashbls/depends/mimalloc/docs/search/all_b.js index 73a2671d9261..44ef0a69f929 100644 --- a/src/dashbls/depends/mimalloc/docs/search/all_b.js +++ b/src/dashbls/depends/mimalloc/docs/search/all_b.js @@ -1,5 +1,5 @@ var searchData= [ - ['used_168',['used',['../group__analysis.html#ab820302c5cd0df133eb8e51650a008b4',1,'mi_heap_area_t']]], - ['using_20the_20library_169',['Using the library',['../using.html',1,'']]] + ['performance_0',['Performance',['../bench.html',1,'']]], + ['posix_1',['Posix',['../group__posix.html',1,'']]] ]; diff --git a/src/dashbls/depends/mimalloc/docs/search/all_c.js b/src/dashbls/depends/mimalloc/docs/search/all_c.js index 192fb1cb78b0..d0a080fe2dcf 100644 --- a/src/dashbls/depends/mimalloc/docs/search/all_c.js +++ b/src/dashbls/depends/mimalloc/docs/search/all_c.js @@ -1,4 +1,6 @@ var searchData= [ - ['zero_20initialized_20re_2dallocation_170',['Zero initialized re-allocation',['../group__zeroinit.html',1,'']]] + ['re_20allocation_0',['Zero initialized re-allocation',['../group__zeroinit.html',1,'']]], + ['reserved_1',['reserved',['../group__analysis.html#ae848a3e6840414891035423948ca0383',1,'mi_heap_area_t']]], + ['runtime_20options_2',['Runtime Options',['../group__options.html',1,'']]] ]; diff --git a/src/dashbls/depends/mimalloc/docs/search/all_d.js b/src/dashbls/depends/mimalloc/docs/search/all_d.js index 2b9b4cea09de..2cce101acf5c 100644 --- a/src/dashbls/depends/mimalloc/docs/search/all_d.js +++ b/src/dashbls/depends/mimalloc/docs/search/all_d.js @@ -1,4 +1,5 @@ var searchData= [ - ['zero_20initialized_20re_2dallocation',['Zero initialized re-allocation',['../group__zeroinit.html',1,'']]] + ['the_20library_0',['Using the library',['../using.html',1,'']]], + ['typed_20macros_1',['Typed Macros',['../group__typed.html',1,'']]] ]; diff --git a/src/dashbls/depends/mimalloc/docs/search/all_e.js b/src/dashbls/depends/mimalloc/docs/search/all_e.js new file mode 100644 index 000000000000..4c8c2e890ffe --- /dev/null +++ b/src/dashbls/depends/mimalloc/docs/search/all_e.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['used_0',['used',['../group__analysis.html#ab820302c5cd0df133eb8e51650a008b4',1,'mi_heap_area_t']]], + ['using_20the_20library_1',['Using the library',['../using.html',1,'']]] +]; diff --git a/src/dashbls/depends/mimalloc/docs/search/all_f.js b/src/dashbls/depends/mimalloc/docs/search/all_f.js new file mode 100644 index 000000000000..8f445b9fc8c2 --- /dev/null +++ b/src/dashbls/depends/mimalloc/docs/search/all_f.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['wrappers_0',['C++ wrappers',['../group__cpp.html',1,'']]] +]; diff --git a/src/dashbls/depends/mimalloc/docs/search/classes_0.js b/src/dashbls/depends/mimalloc/docs/search/classes_0.js index e3770fb49170..5ba187064f9a 100644 --- a/src/dashbls/depends/mimalloc/docs/search/classes_0.js +++ b/src/dashbls/depends/mimalloc/docs/search/classes_0.js @@ -1,5 +1,5 @@ var searchData= [ - ['mi_5fheap_5farea_5ft_171',['mi_heap_area_t',['../group__analysis.html#structmi__heap__area__t',1,'']]], - ['mi_5fstl_5fallocator_172',['mi_stl_allocator',['../group__cpp.html#structmi__stl__allocator',1,'']]] + ['mi_5fheap_5farea_5ft_0',['mi_heap_area_t',['../group__analysis.html#structmi__heap__area__t',1,'']]], + ['mi_5fstl_5fallocator_1',['mi_stl_allocator',['../group__cpp.html#structmi__stl__allocator',1,'']]] ]; diff --git a/src/dashbls/depends/mimalloc/docs/search/close.svg b/src/dashbls/depends/mimalloc/docs/search/close.svg new file mode 100644 index 000000000000..337d6cc13298 --- /dev/null +++ b/src/dashbls/depends/mimalloc/docs/search/close.svg @@ -0,0 +1,18 @@ + + + + + + diff --git a/src/dashbls/depends/mimalloc/docs/search/enums_0.js b/src/dashbls/depends/mimalloc/docs/search/enums_0.js index 6f1f38338b6c..9bc2f56b2b0c 100644 --- a/src/dashbls/depends/mimalloc/docs/search/enums_0.js +++ b/src/dashbls/depends/mimalloc/docs/search/enums_0.js @@ -1,4 +1,4 @@ var searchData= [ - ['mi_5foption_5ft_296',['mi_option_t',['../group__options.html#gafebf7ed116adb38ae5218bc3ce06884c',1,'mimalloc-doc.h']]] + ['mi_5foption_5ft_0',['mi_option_t',['../group__options.html#gafebf7ed116adb38ae5218bc3ce06884c',1,'mimalloc-doc.h']]] ]; diff --git a/src/dashbls/depends/mimalloc/docs/search/enumvalues_0.js b/src/dashbls/depends/mimalloc/docs/search/enumvalues_0.js index 1aca63bbee65..cd7bb4196726 100644 --- a/src/dashbls/depends/mimalloc/docs/search/enumvalues_0.js +++ b/src/dashbls/depends/mimalloc/docs/search/enumvalues_0.js @@ -1,4 +1,4 @@ var searchData= [ - ['_5fmi_5foption_5flast_297',['_mi_option_last',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca5b4357b74be0d87568036c32eb1a2e4a',1,'mimalloc-doc.h']]] + ['_5fmi_5foption_5flast_0',['_mi_option_last',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca5b4357b74be0d87568036c32eb1a2e4a',1,'mimalloc-doc.h']]] ]; diff --git a/src/dashbls/depends/mimalloc/docs/search/enumvalues_1.js b/src/dashbls/depends/mimalloc/docs/search/enumvalues_1.js index bd525bb854f3..d40f943b33d6 100644 --- a/src/dashbls/depends/mimalloc/docs/search/enumvalues_1.js +++ b/src/dashbls/depends/mimalloc/docs/search/enumvalues_1.js @@ -1,19 +1,31 @@ var searchData= [ - ['mi_5foption_5feager_5fcommit_298',['mi_option_eager_commit',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca1e8de72c93da7ff22d91e1e27b52ac2b',1,'mimalloc-doc.h']]], - ['mi_5foption_5feager_5fcommit_5fdelay_299',['mi_option_eager_commit_delay',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca17a190c25be381142d87e0468c4c068c',1,'mimalloc-doc.h']]], - ['mi_5foption_5feager_5fregion_5fcommit_300',['mi_option_eager_region_commit',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca32ce97ece29f69e82579679cf8a307ad',1,'mimalloc-doc.h']]], - ['mi_5foption_5flarge_5fos_5fpages_301',['mi_option_large_os_pages',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca4192d491200d0055df0554d4cf65054e',1,'mimalloc-doc.h']]], - ['mi_5foption_5fos_5ftag_302',['mi_option_os_tag',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca4b74ae2a69e445de6c2361b73c1d14bf',1,'mimalloc-doc.h']]], - ['mi_5foption_5fpage_5freset_303',['mi_option_page_reset',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cada854dd272c66342f18a93ee254a2968',1,'mimalloc-doc.h']]], - ['mi_5foption_5freserve_5fhuge_5fos_5fpages_304',['mi_option_reserve_huge_os_pages',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caca7ed041be3b0b9d0b82432c7bf41af2',1,'mimalloc-doc.h']]], - ['mi_5foption_5freserve_5fhuge_5fos_5fpages_5fat_305',['mi_option_reserve_huge_os_pages_at',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caa13e7926d4339d2aa6fbf61d4473fd5c',1,'mimalloc-doc.h']]], - ['mi_5foption_5freset_5fdecommits_306',['mi_option_reset_decommits',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cac81ee965b130fa81238913a3c239d536',1,'mimalloc-doc.h']]], - ['mi_5foption_5freset_5fdelay_307',['mi_option_reset_delay',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca154fe170131d5212cff57e22b99523c5',1,'mimalloc-doc.h']]], - ['mi_5foption_5fsegment_5fcache_308',['mi_option_segment_cache',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca2ecbe7ef32f5c84de3739aa4f0b805a1',1,'mimalloc-doc.h']]], - ['mi_5foption_5fsegment_5freset_309',['mi_option_segment_reset',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cafb121d30d87591850d5410ccc3a95c6d',1,'mimalloc-doc.h']]], - ['mi_5foption_5fshow_5ferrors_310',['mi_option_show_errors',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cafbf4822e5c00732c5984b32a032837f0',1,'mimalloc-doc.h']]], - ['mi_5foption_5fshow_5fstats_311',['mi_option_show_stats',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca0957ef73b2550764b4840edf48422fda',1,'mimalloc-doc.h']]], - ['mi_5foption_5fuse_5fnuma_5fnodes_312',['mi_option_use_numa_nodes',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca0ac33a18f6b659fcfaf44efb0bab1b74',1,'mimalloc-doc.h']]], - ['mi_5foption_5fverbose_313',['mi_option_verbose',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca7c8b7bf5281c581bad64f5daa6442777',1,'mimalloc-doc.h']]] + ['mi_5foption_5fabandoned_5fpage_5fpurge_0',['mi_option_abandoned_page_purge',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca11e62ed69200a489a5be955582078c0c',1,'mimalloc-doc.h']]], + ['mi_5foption_5fabandoned_5freclaim_5fon_5ffree_1',['mi_option_abandoned_reclaim_on_free',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca009e4b5684922ce664d73d2a8e1698d9',1,'mimalloc-doc.h']]], + ['mi_5foption_5fallow_5flarge_5fos_5fpages_2',['mi_option_allow_large_os_pages',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca7cc4804ced69004fa42a9a136a9ba556',1,'mimalloc-doc.h']]], + ['mi_5foption_5farena_5feager_5fcommit_3',['mi_option_arena_eager_commit',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cafd0c5ddbc4b59fd8b5216871728167a5',1,'mimalloc-doc.h']]], + ['mi_5foption_5farena_5fpurge_5fmult_4',['mi_option_arena_purge_mult',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca8236501f1ab45d26e6fd885d191a2b5e',1,'mimalloc-doc.h']]], + ['mi_5foption_5farena_5freserve_5',['mi_option_arena_reserve',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cab1c88e23ae290bbeec824038a97959de',1,'mimalloc-doc.h']]], + ['mi_5foption_5fdestroy_5fon_5fexit_6',['mi_option_destroy_on_exit',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca6364331e305e7d3c0218b058ff3afc88',1,'mimalloc-doc.h']]], + ['mi_5foption_5fdisallow_5farena_5falloc_7',['mi_option_disallow_arena_alloc',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caeae1696100e4057ffc4182730cc04e40',1,'mimalloc-doc.h']]], + ['mi_5foption_5fdisallow_5fos_5falloc_8',['mi_option_disallow_os_alloc',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cadcfb5a09580361b1be65901d2d812de6',1,'mimalloc-doc.h']]], + ['mi_5foption_5feager_5fcommit_9',['mi_option_eager_commit',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca1e8de72c93da7ff22d91e1e27b52ac2b',1,'mimalloc-doc.h']]], + ['mi_5foption_5feager_5fcommit_5fdelay_10',['mi_option_eager_commit_delay',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca17a190c25be381142d87e0468c4c068c',1,'mimalloc-doc.h']]], + ['mi_5foption_5flimit_5fos_5falloc_11',['mi_option_limit_os_alloc',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca9fa61bd9668479f8452d2195759444cc',1,'mimalloc-doc.h']]], + ['mi_5foption_5fmax_5ferrors_12',['mi_option_max_errors',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caec6ecbe29d46a48205ed8823a8a52a6a',1,'mimalloc-doc.h']]], + ['mi_5foption_5fmax_5fsegment_5freclaim_13',['mi_option_max_segment_reclaim',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caa9ad9005d7017c8c30ad2d6ba31db909',1,'mimalloc-doc.h']]], + ['mi_5foption_5fmax_5fwarnings_14',['mi_option_max_warnings',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caf9595921087e942602ee079158762665',1,'mimalloc-doc.h']]], + ['mi_5foption_5fos_5ftag_15',['mi_option_os_tag',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca4b74ae2a69e445de6c2361b73c1d14bf',1,'mimalloc-doc.h']]], + ['mi_5foption_5fpurge_5fdecommits_16',['mi_option_purge_decommits',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca9d15c5e3d2115eef681c17e4dd5ab9a4',1,'mimalloc-doc.h']]], + ['mi_5foption_5fpurge_5fdelay_17',['mi_option_purge_delay',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cadd351e615acd8563529c20a347be7290',1,'mimalloc-doc.h']]], + ['mi_5foption_5fpurge_5fextend_5fdelay_18',['mi_option_purge_extend_delay',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca02005f164bdf03f5f00c5be726adf487',1,'mimalloc-doc.h']]], + ['mi_5foption_5freserve_5fhuge_5fos_5fpages_19',['mi_option_reserve_huge_os_pages',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caca7ed041be3b0b9d0b82432c7bf41af2',1,'mimalloc-doc.h']]], + ['mi_5foption_5freserve_5fhuge_5fos_5fpages_5fat_20',['mi_option_reserve_huge_os_pages_at',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caa13e7926d4339d2aa6fbf61d4473fd5c',1,'mimalloc-doc.h']]], + ['mi_5foption_5freserve_5fos_5fmemory_21',['mi_option_reserve_os_memory',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cafbf4999c828cf79a0fb2de65d23f7333',1,'mimalloc-doc.h']]], + ['mi_5foption_5fretry_5fon_5foom_22',['mi_option_retry_on_oom',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca8f51df355bf6651db899e6085b54865e',1,'mimalloc-doc.h']]], + ['mi_5foption_5fshow_5ferrors_23',['mi_option_show_errors',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cafbf4822e5c00732c5984b32a032837f0',1,'mimalloc-doc.h']]], + ['mi_5foption_5fshow_5fstats_24',['mi_option_show_stats',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca0957ef73b2550764b4840edf48422fda',1,'mimalloc-doc.h']]], + ['mi_5foption_5fuse_5fnuma_5fnodes_25',['mi_option_use_numa_nodes',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca0ac33a18f6b659fcfaf44efb0bab1b74',1,'mimalloc-doc.h']]], + ['mi_5foption_5fverbose_26',['mi_option_verbose',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca7c8b7bf5281c581bad64f5daa6442777',1,'mimalloc-doc.h']]], + ['mi_5foption_5fvisit_5fabandoned_27',['mi_option_visit_abandoned',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca38c67733a3956a1f4eeaca89fab9e78e',1,'mimalloc-doc.h']]] ]; diff --git a/src/dashbls/depends/mimalloc/docs/search/functions_0.js b/src/dashbls/depends/mimalloc/docs/search/functions_0.js index b44917a5be23..8899d6e4ba47 100644 --- a/src/dashbls/depends/mimalloc/docs/search/functions_0.js +++ b/src/dashbls/depends/mimalloc/docs/search/functions_0.js @@ -1,116 +1,138 @@ var searchData= [ - ['mi_5f_5fposix_5fmemalign_173',['mi__posix_memalign',['../group__posix.html#gad5a69c8fea96aa2b7a7c818c2130090a',1,'mimalloc-doc.h']]], - ['mi_5faligned_5falloc_174',['mi_aligned_alloc',['../group__posix.html#ga1326d2e4388630b5f81ca7206318b8e5',1,'mimalloc-doc.h']]], - ['mi_5fcalloc_175',['mi_calloc',['../group__malloc.html#ga97fedb4f7107c592fd7f0f0a8949a57d',1,'mimalloc-doc.h']]], - ['mi_5fcalloc_5faligned_176',['mi_calloc_aligned',['../group__aligned.html#ga53dddb4724042a90315b94bc268fb4c9',1,'mimalloc-doc.h']]], - ['mi_5fcalloc_5faligned_5fat_177',['mi_calloc_aligned_at',['../group__aligned.html#ga08647c4593f3b2eef24a919a73eba3a3',1,'mimalloc-doc.h']]], - ['mi_5fcfree_178',['mi_cfree',['../group__posix.html#ga705dc7a64bffacfeeb0141501a5c35d7',1,'mimalloc-doc.h']]], - ['mi_5fcheck_5fowned_179',['mi_check_owned',['../group__analysis.html#ga628c237489c2679af84a4d0d143b3dd5',1,'mimalloc-doc.h']]], - ['mi_5fcollect_180',['mi_collect',['../group__extended.html#ga421430e2226d7d468529cec457396756',1,'mimalloc-doc.h']]], - ['mi_5fexpand_181',['mi_expand',['../group__malloc.html#gaaee66a1d483c3e28f585525fb96707e4',1,'mimalloc-doc.h']]], - ['mi_5ffree_182',['mi_free',['../group__malloc.html#gaf2c7b89c327d1f60f59e68b9ea644d95',1,'mimalloc-doc.h']]], - ['mi_5ffree_5faligned_183',['mi_free_aligned',['../group__posix.html#ga0d28d5cf61e6bfbb18c63092939fe5c9',1,'mimalloc-doc.h']]], - ['mi_5ffree_5fsize_184',['mi_free_size',['../group__posix.html#gae01389eedab8d67341ff52e2aad80ebb',1,'mimalloc-doc.h']]], - ['mi_5ffree_5fsize_5faligned_185',['mi_free_size_aligned',['../group__posix.html#ga72e9d7ffb5fe94d69bc722c8506e27bc',1,'mimalloc-doc.h']]], - ['mi_5fgood_5fsize_186',['mi_good_size',['../group__extended.html#gac057927cd06c854b45fe7847e921bd47',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fcalloc_187',['mi_heap_calloc',['../group__heap.html#gaa6702b3c48e9e53e50e81b36f5011d55',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fcalloc_5faligned_188',['mi_heap_calloc_aligned',['../group__heap.html#ga4af03a6e2b93fae77424d93f889705c3',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fcalloc_5faligned_5fat_189',['mi_heap_calloc_aligned_at',['../group__heap.html#ga08ca6419a5c057a4d965868998eef487',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fcheck_5fowned_190',['mi_heap_check_owned',['../group__analysis.html#ga0d67c1789faaa15ff366c024fcaf6377',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fcollect_191',['mi_heap_collect',['../group__heap.html#ga7922f7495cde30b1984d0e6072419298',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fcontains_5fblock_192',['mi_heap_contains_block',['../group__analysis.html#gaa862aa8ed8d57d84cae41fc1022d71af',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fdelete_193',['mi_heap_delete',['../group__heap.html#ga2ab1af8d438819b55319c7ef51d1e409',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fdestroy_194',['mi_heap_destroy',['../group__heap.html#ga9f9c0844edb9717f4feacd79116b8e0d',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fget_5fbacking_195',['mi_heap_get_backing',['../group__heap.html#ga5d03fbe062ffcf38f0f417fd968357fc',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fget_5fdefault_196',['mi_heap_get_default',['../group__heap.html#ga8db4cbb87314a989a9a187464d6b5e05',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fmalloc_197',['mi_heap_malloc',['../group__heap.html#ga9cbed01e42c0647907295de92c3fa296',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fmalloc_5faligned_198',['mi_heap_malloc_aligned',['../group__heap.html#gab5b87e1805306f70df38789fcfcf6653',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fmalloc_5faligned_5fat_199',['mi_heap_malloc_aligned_at',['../group__heap.html#ga23acd7680fb0976dde3783254c6c874b',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fmalloc_5fsmall_200',['mi_heap_malloc_small',['../group__heap.html#gaa1a1c7a1f4da6826b5a25b70ef878368',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fmallocn_201',['mi_heap_mallocn',['../group__heap.html#ga851da6c43fe0b71c1376cee8aef90db0',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fnew_202',['mi_heap_new',['../group__heap.html#ga766f672ba56f2fbfeb9d9dbb0b7f6b11',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frealloc_203',['mi_heap_realloc',['../group__heap.html#gaaef3395f66be48f37bdc8322509c5d81',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frealloc_5faligned_204',['mi_heap_realloc_aligned',['../group__heap.html#gafc603b696bd14cae6da28658f950d98c',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frealloc_5faligned_5fat_205',['mi_heap_realloc_aligned_at',['../group__heap.html#gaf96c788a1bf553fe2d371de9365e047c',1,'mimalloc-doc.h']]], - ['mi_5fheap_5freallocf_206',['mi_heap_reallocf',['../group__heap.html#ga4a21070eb4e7cce018133c8d5f4b0527',1,'mimalloc-doc.h']]], - ['mi_5fheap_5freallocn_207',['mi_heap_reallocn',['../group__heap.html#gac74e94ad9b0c9b57c1c4d88b8825b7a8',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frealpath_208',['mi_heap_realpath',['../group__heap.html#ga00e95ba1e01acac3cfd95bb7a357a6f0',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frecalloc_209',['mi_heap_recalloc',['../group__zeroinit.html#ga8648c5fbb22a80f0262859099f06dfbd',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frecalloc_5faligned_210',['mi_heap_recalloc_aligned',['../group__zeroinit.html#ga9f3f999396c8f77ca5e80e7b40ac29e3',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frecalloc_5faligned_5fat_211',['mi_heap_recalloc_aligned_at',['../group__zeroinit.html#ga496452c96f1de8c500be9fddf52edaf7',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frezalloc_212',['mi_heap_rezalloc',['../group__zeroinit.html#gacfad83f14eb5d6a42a497a898e19fc76',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frezalloc_5faligned_213',['mi_heap_rezalloc_aligned',['../group__zeroinit.html#ga375fa8a611c51905e592d5d467c49664',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frezalloc_5faligned_5fat_214',['mi_heap_rezalloc_aligned_at',['../group__zeroinit.html#gac90da54fa7e5d10bdc97ce0b51dce2eb',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fset_5fdefault_215',['mi_heap_set_default',['../group__heap.html#gab8631ec88c8d26641b68b5d25dcd4422',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fstrdup_216',['mi_heap_strdup',['../group__heap.html#ga139d6b09dbf50c3c2523d0f4d1cfdeb5',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fstrndup_217',['mi_heap_strndup',['../group__heap.html#ga8e3dbd46650dd26573cf307a2c8f1f5a',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fvisit_5fblocks_218',['mi_heap_visit_blocks',['../group__analysis.html#ga70c46687dc6e9dc98b232b02646f8bed',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fzalloc_219',['mi_heap_zalloc',['../group__heap.html#ga903104592c8ed53417a3762da6241133',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fzalloc_5faligned_220',['mi_heap_zalloc_aligned',['../group__heap.html#gaa450a59c6c7ae5fdbd1c2b80a8329ef0',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fzalloc_5faligned_5fat_221',['mi_heap_zalloc_aligned_at',['../group__heap.html#ga45fb43a62776fbebbdf1edd99b527954',1,'mimalloc-doc.h']]], - ['mi_5fis_5fin_5fheap_5fregion_222',['mi_is_in_heap_region',['../group__extended.html#ga5f071b10d4df1c3658e04e7fd67a94e6',1,'mimalloc-doc.h']]], - ['mi_5fis_5fredirected_223',['mi_is_redirected',['../group__extended.html#gaad25050b19f30cd79397b227e0157a3f',1,'mimalloc-doc.h']]], - ['mi_5fmalloc_224',['mi_malloc',['../group__malloc.html#ga3406e8b168bc74c8637b11571a6da83a',1,'mimalloc-doc.h']]], - ['mi_5fmalloc_5faligned_225',['mi_malloc_aligned',['../group__aligned.html#ga68930196751fa2cca9e1fd0d71bade56',1,'mimalloc-doc.h']]], - ['mi_5fmalloc_5faligned_5fat_226',['mi_malloc_aligned_at',['../group__aligned.html#ga5850da130c936bd77db039dcfbc8295d',1,'mimalloc-doc.h']]], - ['mi_5fmalloc_5fsize_227',['mi_malloc_size',['../group__posix.html#ga4531c9e775bb3ae12db57c1ba8a5d7de',1,'mimalloc-doc.h']]], - ['mi_5fmalloc_5fsmall_228',['mi_malloc_small',['../group__extended.html#ga7136c2e55cb22c98ecf95d08d6debb99',1,'mimalloc-doc.h']]], - ['mi_5fmalloc_5fusable_5fsize_229',['mi_malloc_usable_size',['../group__posix.html#ga06d07cf357bbac5c73ba5d0c0c421e17',1,'mimalloc-doc.h']]], - ['mi_5fmallocn_230',['mi_mallocn',['../group__malloc.html#ga0b05e2bf0f73e7401ae08597ff782ac6',1,'mimalloc-doc.h']]], - ['mi_5fmanage_5fos_5fmemory_231',['mi_manage_os_memory',['../group__extended.html#ga4c6486a1fdcd7a423b5f25fe4be8e0cf',1,'mimalloc-doc.h']]], - ['mi_5fmemalign_232',['mi_memalign',['../group__posix.html#gaab7fa71ea93b96873f5d9883db57d40e',1,'mimalloc-doc.h']]], - ['mi_5fnew_233',['mi_new',['../group__cpp.html#gaad048a9fce3d02c5909cd05c6ec24545',1,'mimalloc-doc.h']]], - ['mi_5fnew_5faligned_234',['mi_new_aligned',['../group__cpp.html#gaef2c2bdb4f70857902d3c8903ac095f3',1,'mimalloc-doc.h']]], - ['mi_5fnew_5faligned_5fnothrow_235',['mi_new_aligned_nothrow',['../group__cpp.html#gab5e29558926d934c3f1cae8c815f942c',1,'mimalloc-doc.h']]], - ['mi_5fnew_5fn_236',['mi_new_n',['../group__cpp.html#gae7bc4f56cd57ed3359060ff4f38bda81',1,'mimalloc-doc.h']]], - ['mi_5fnew_5fnothrow_237',['mi_new_nothrow',['../group__cpp.html#gaeaded64eda71ed6b1d569d3e723abc4a',1,'mimalloc-doc.h']]], - ['mi_5fnew_5frealloc_238',['mi_new_realloc',['../group__cpp.html#gaab78a32f55149e9fbf432d5288e38e1e',1,'mimalloc-doc.h']]], - ['mi_5fnew_5freallocn_239',['mi_new_reallocn',['../group__cpp.html#ga756f4b2bc6a7ecd0a90baea8e90c7907',1,'mimalloc-doc.h']]], - ['mi_5foption_5fdisable_240',['mi_option_disable',['../group__options.html#gaebf6ff707a2e688ebb1a2296ca564054',1,'mimalloc-doc.h']]], - ['mi_5foption_5fenable_241',['mi_option_enable',['../group__options.html#ga04180ae41b0d601421dd62ced40ca050',1,'mimalloc-doc.h']]], - ['mi_5foption_5fget_242',['mi_option_get',['../group__options.html#ga7e8af195cc81d3fa64ccf2662caa565a',1,'mimalloc-doc.h']]], - ['mi_5foption_5fis_5fenabled_243',['mi_option_is_enabled',['../group__options.html#ga459ad98f18b3fc9275474807fe0ca188',1,'mimalloc-doc.h']]], - ['mi_5foption_5fset_244',['mi_option_set',['../group__options.html#gaf84921c32375e25754dc2ee6a911fa60',1,'mimalloc-doc.h']]], - ['mi_5foption_5fset_5fdefault_245',['mi_option_set_default',['../group__options.html#ga7ef623e440e6e5545cb08c94e71e4b90',1,'mimalloc-doc.h']]], - ['mi_5foption_5fset_5fenabled_246',['mi_option_set_enabled',['../group__options.html#ga9a13d05fcb77489cb06d4d017ebd8bed',1,'mimalloc-doc.h']]], - ['mi_5foption_5fset_5fenabled_5fdefault_247',['mi_option_set_enabled_default',['../group__options.html#ga65518b69ec5d32336b50e07f74b3f629',1,'mimalloc-doc.h']]], - ['mi_5fposix_5fmemalign_248',['mi_posix_memalign',['../group__posix.html#gacff84f226ba9feb2031b8992e5579447',1,'mimalloc-doc.h']]], - ['mi_5fprocess_5finfo_249',['mi_process_info',['../group__extended.html#ga7d862c2affd5790381da14eb102a364d',1,'mimalloc-doc.h']]], - ['mi_5fpvalloc_250',['mi_pvalloc',['../group__posix.html#gaeb325c39b887d3b90d85d1eb1712fb1e',1,'mimalloc-doc.h']]], - ['mi_5frealloc_251',['mi_realloc',['../group__malloc.html#gaf11eb497da57bdfb2de65eb191c69db6',1,'mimalloc-doc.h']]], - ['mi_5frealloc_5faligned_252',['mi_realloc_aligned',['../group__aligned.html#ga4028d1cf4aa4c87c880747044a8322ae',1,'mimalloc-doc.h']]], - ['mi_5frealloc_5faligned_5fat_253',['mi_realloc_aligned_at',['../group__aligned.html#gaf66a9ae6c6f08bd6be6fb6ea771faffb',1,'mimalloc-doc.h']]], - ['mi_5freallocarr_254',['mi_reallocarr',['../group__posix.html#ga7e1934d60a3e697950eeb48e042bfad5',1,'mimalloc-doc.h']]], - ['mi_5freallocarray_255',['mi_reallocarray',['../group__posix.html#ga48fad8648a2f1dab9c87ea9448a52088',1,'mimalloc-doc.h']]], - ['mi_5freallocf_256',['mi_reallocf',['../group__malloc.html#gafe68ac7c5e24a65cd55c9d6b152211a0',1,'mimalloc-doc.h']]], - ['mi_5freallocn_257',['mi_reallocn',['../group__malloc.html#ga61d57b4144ba24fba5c1e9b956d13853',1,'mimalloc-doc.h']]], - ['mi_5frealpath_258',['mi_realpath',['../group__malloc.html#ga08cec32dd5bbe7da91c78d19f1b5bebe',1,'mimalloc-doc.h']]], - ['mi_5frecalloc_259',['mi_recalloc',['../group__malloc.html#ga23a0fbb452b5dce8e31fab1a1958cacc',1,'mimalloc-doc.h']]], - ['mi_5frecalloc_5faligned_260',['mi_recalloc_aligned',['../group__zeroinit.html#ga3e7e5c291acf1c7fd7ffd9914a9f945f',1,'mimalloc-doc.h']]], - ['mi_5frecalloc_5faligned_5fat_261',['mi_recalloc_aligned_at',['../group__zeroinit.html#ga4ff5e92ad73585418a072c9d059e5cf9',1,'mimalloc-doc.h']]], - ['mi_5fregister_5fdeferred_5ffree_262',['mi_register_deferred_free',['../group__extended.html#ga3460a6ca91af97be4058f523d3cb8ece',1,'mimalloc-doc.h']]], - ['mi_5fregister_5ferror_263',['mi_register_error',['../group__extended.html#gaa1d55e0e894be240827e5d87ec3a1f45',1,'mimalloc-doc.h']]], - ['mi_5fregister_5foutput_264',['mi_register_output',['../group__extended.html#gae5b17ff027cd2150b43a33040250cf3f',1,'mimalloc-doc.h']]], - ['mi_5freserve_5fhuge_5fos_5fpages_5fat_265',['mi_reserve_huge_os_pages_at',['../group__extended.html#ga7795a13d20087447281858d2c771cca1',1,'mimalloc-doc.h']]], - ['mi_5freserve_5fhuge_5fos_5fpages_5finterleave_266',['mi_reserve_huge_os_pages_interleave',['../group__extended.html#ga3132f521fb756fc0e8ec0b74fb58df50',1,'mimalloc-doc.h']]], - ['mi_5freserve_5fos_5fmemory_267',['mi_reserve_os_memory',['../group__extended.html#ga00ec3324b6b2591c7fe3677baa30a767',1,'mimalloc-doc.h']]], - ['mi_5frezalloc_268',['mi_rezalloc',['../group__zeroinit.html#ga8c292e142110229a2980b37ab036dbc6',1,'mimalloc-doc.h']]], - ['mi_5frezalloc_5faligned_269',['mi_rezalloc_aligned',['../group__zeroinit.html#gacd71a7bce96aab38ae6de17af2eb2cf0',1,'mimalloc-doc.h']]], - ['mi_5frezalloc_5faligned_5fat_270',['mi_rezalloc_aligned_at',['../group__zeroinit.html#gae8b358c417e61d5307da002702b0a8e1',1,'mimalloc-doc.h']]], - ['mi_5fstats_5fmerge_271',['mi_stats_merge',['../group__extended.html#ga854b1de8cb067c7316286c28b2fcd3d1',1,'mimalloc-doc.h']]], - ['mi_5fstats_5fprint_272',['mi_stats_print',['../group__extended.html#ga2d126e5c62d3badc35445e5d84166df2',1,'mimalloc-doc.h']]], - ['mi_5fstats_5fprint_5fout_273',['mi_stats_print_out',['../group__extended.html#ga537f13b299ddf801e49a5a94fde02c79',1,'mimalloc-doc.h']]], - ['mi_5fstats_5freset_274',['mi_stats_reset',['../group__extended.html#ga3bb8468b8cfcc6e2a61d98aee85c5f99',1,'mimalloc-doc.h']]], - ['mi_5fstrdup_275',['mi_strdup',['../group__malloc.html#gac7cffe13f1f458ed16789488bf92b9b2',1,'mimalloc-doc.h']]], - ['mi_5fstrndup_276',['mi_strndup',['../group__malloc.html#gaaabf971c2571891433477e2d21a35266',1,'mimalloc-doc.h']]], - ['mi_5fthread_5fdone_277',['mi_thread_done',['../group__extended.html#ga0ae4581e85453456a0d658b2b98bf7bf',1,'mimalloc-doc.h']]], - ['mi_5fthread_5finit_278',['mi_thread_init',['../group__extended.html#gaf8e73efc2cbca9ebfdfb166983a04c17',1,'mimalloc-doc.h']]], - ['mi_5fthread_5fstats_5fprint_5fout_279',['mi_thread_stats_print_out',['../group__extended.html#gab1dac8476c46cb9eecab767eb40c1525',1,'mimalloc-doc.h']]], - ['mi_5fusable_5fsize_280',['mi_usable_size',['../group__extended.html#ga089c859d9eddc5f9b4bd946cd53cebee',1,'mimalloc-doc.h']]], - ['mi_5fvalloc_281',['mi_valloc',['../group__posix.html#ga73baaf5951f5165ba0763d0c06b6a93b',1,'mimalloc-doc.h']]], - ['mi_5fzalloc_282',['mi_zalloc',['../group__malloc.html#gafdd9d8bb2986e668ba9884f28af38000',1,'mimalloc-doc.h']]], - ['mi_5fzalloc_5faligned_283',['mi_zalloc_aligned',['../group__aligned.html#ga0cadbcf5b89a7b6fb171bc8df8734819',1,'mimalloc-doc.h']]], - ['mi_5fzalloc_5faligned_5fat_284',['mi_zalloc_aligned_at',['../group__aligned.html#ga5f8c2353766db522565e642fafd8a3f8',1,'mimalloc-doc.h']]], - ['mi_5fzalloc_5fsmall_285',['mi_zalloc_small',['../group__extended.html#ga220f29f40a44404b0061c15bc1c31152',1,'mimalloc-doc.h']]] + ['mi_5f_5fexpand_0',['mi__expand',['../group__posix.html#ga66bcfeb4faedbb42b796bc680821ef84',1,'mimalloc-doc.h']]], + ['mi_5f_5fposix_5fmemalign_1',['mi__posix_memalign',['../group__posix.html#gad5a69c8fea96aa2b7a7c818c2130090a',1,'mimalloc-doc.h']]], + ['mi_5fabandoned_5fvisit_5fblocks_2',['mi_abandoned_visit_blocks',['../group__analysis.html#ga6a4865a887b2ec5247854af61562503c',1,'mimalloc-doc.h']]], + ['mi_5faligned_5falloc_3',['mi_aligned_alloc',['../group__posix.html#ga430ed1513f0571ff83be00ec58a98ee0',1,'mimalloc-doc.h']]], + ['mi_5faligned_5foffset_5frecalloc_4',['mi_aligned_offset_recalloc',['../group__posix.html#ga16570deddd559001b44953eedbad0084',1,'mimalloc-doc.h']]], + ['mi_5faligned_5frecalloc_5',['mi_aligned_recalloc',['../group__posix.html#gaf82cbb4b4f24acf723348628451798d3',1,'mimalloc-doc.h']]], + ['mi_5farena_5farea_6',['mi_arena_area',['../group__extended.html#ga9a25a00a22151619a0be91a10af7787f',1,'mimalloc-doc.h']]], + ['mi_5fcalloc_7',['mi_calloc',['../group__malloc.html#ga6686568014b54d1e6c7ac64a076e4f56',1,'mimalloc-doc.h']]], + ['mi_5fcalloc_5faligned_8',['mi_calloc_aligned',['../group__aligned.html#ga424ef386fb1f9f8e0a86ab53f16eaaf1',1,'mimalloc-doc.h']]], + ['mi_5fcalloc_5faligned_5fat_9',['mi_calloc_aligned_at',['../group__aligned.html#ga977f96bd2c5c141bcd70e6685c90d6c3',1,'mimalloc-doc.h']]], + ['mi_5fcfree_10',['mi_cfree',['../group__posix.html#ga705dc7a64bffacfeeb0141501a5c35d7',1,'mimalloc-doc.h']]], + ['mi_5fcheck_5fowned_11',['mi_check_owned',['../group__analysis.html#ga628c237489c2679af84a4d0d143b3dd5',1,'mimalloc-doc.h']]], + ['mi_5fcollect_12',['mi_collect',['../group__extended.html#ga421430e2226d7d468529cec457396756',1,'mimalloc-doc.h']]], + ['mi_5fdebug_5fshow_5farenas_13',['mi_debug_show_arenas',['../group__extended.html#gad7439207f8f71fb6c382a9ea20b997e7',1,'mimalloc-doc.h']]], + ['mi_5fdupenv_5fs_14',['mi_dupenv_s',['../group__posix.html#gab41369c1a1da7504013a7a0b1d4dd958',1,'mimalloc-doc.h']]], + ['mi_5fexpand_15',['mi_expand',['../group__malloc.html#ga19299856216cfbb08e2628593654dfb0',1,'mimalloc-doc.h']]], + ['mi_5ffree_16',['mi_free',['../group__malloc.html#gaf2c7b89c327d1f60f59e68b9ea644d95',1,'mimalloc-doc.h']]], + ['mi_5ffree_5faligned_17',['mi_free_aligned',['../group__posix.html#ga0d28d5cf61e6bfbb18c63092939fe5c9',1,'mimalloc-doc.h']]], + ['mi_5ffree_5fsize_18',['mi_free_size',['../group__posix.html#gae01389eedab8d67341ff52e2aad80ebb',1,'mimalloc-doc.h']]], + ['mi_5ffree_5fsize_5faligned_19',['mi_free_size_aligned',['../group__posix.html#ga72e9d7ffb5fe94d69bc722c8506e27bc',1,'mimalloc-doc.h']]], + ['mi_5fgood_5fsize_20',['mi_good_size',['../group__extended.html#gac057927cd06c854b45fe7847e921bd47',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fcalloc_21',['mi_heap_calloc',['../group__heap.html#gac0098aaf231d3e9586c73136d5df95da',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fcalloc_5faligned_22',['mi_heap_calloc_aligned',['../group__heap.html#gacafcc26df827c7a7de5e850217566108',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fcalloc_5faligned_5fat_23',['mi_heap_calloc_aligned_at',['../group__heap.html#gaa42ec2079989c4374f2c331d9b35f4e4',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fcheck_5fowned_24',['mi_heap_check_owned',['../group__analysis.html#ga0d67c1789faaa15ff366c024fcaf6377',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fcollect_25',['mi_heap_collect',['../group__heap.html#ga7922f7495cde30b1984d0e6072419298',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fcontains_5fblock_26',['mi_heap_contains_block',['../group__analysis.html#gaa862aa8ed8d57d84cae41fc1022d71af',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fdelete_27',['mi_heap_delete',['../group__heap.html#ga2ab1af8d438819b55319c7ef51d1e409',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fdestroy_28',['mi_heap_destroy',['../group__heap.html#ga9f9c0844edb9717f4feacd79116b8e0d',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fget_5fbacking_29',['mi_heap_get_backing',['../group__heap.html#gac6ac9f0e7be9ab4ff70acfc8dad1235a',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fget_5fdefault_30',['mi_heap_get_default',['../group__heap.html#ga14c667a6e2c5d28762d8cb7d4e057909',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fmalloc_31',['mi_heap_malloc',['../group__heap.html#gab374e206c7034e0d899fb934e4f4a863',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fmalloc_5faligned_32',['mi_heap_malloc_aligned',['../group__heap.html#ga33f4f05b7fea7af2113c62a4bf882cc5',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fmalloc_5faligned_5fat_33',['mi_heap_malloc_aligned_at',['../group__heap.html#gae7ffc045c3996497a7f3a5f6fe7b8aaa',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fmalloc_5fsmall_34',['mi_heap_malloc_small',['../group__heap.html#ga012c5c8abe22b10043de39ff95909541',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fmallocn_35',['mi_heap_mallocn',['../group__heap.html#gab0f755c0b21c387fe8e9024200faa372',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fnew_36',['mi_heap_new',['../group__heap.html#gaa718bb226ec0546ba6d1b6cb32179f3a',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fnew_5fex_37',['mi_heap_new_ex',['../group__extended.html#ga3ae360583f4351aa5267ee7e43008faf',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fnew_5fin_5farena_38',['mi_heap_new_in_arena',['../group__extended.html#gaaf2d9976576d5efd5544be12848af949',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frealloc_39',['mi_heap_realloc',['../group__heap.html#gac5252d6a2e510bd349e4fcb452e6a93a',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frealloc_5faligned_40',['mi_heap_realloc_aligned',['../group__heap.html#gaccf8c249872f30bf1c2493a09197d734',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frealloc_5faligned_5fat_41',['mi_heap_realloc_aligned_at',['../group__heap.html#ga6df988a7219d5707f010d5f3eb0dc3f5',1,'mimalloc-doc.h']]], + ['mi_5fheap_5freallocf_42',['mi_heap_reallocf',['../group__heap.html#gae7cd171425bee04c683c65a3701f0b4a',1,'mimalloc-doc.h']]], + ['mi_5fheap_5freallocn_43',['mi_heap_reallocn',['../group__heap.html#gaccf7bfe10ce510a000d3547d9cf7fa29',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frealpath_44',['mi_heap_realpath',['../group__heap.html#ga55545a3ec6da29c5b4f62e540ecac1e2',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frecalloc_45',['mi_heap_recalloc',['../group__zeroinit.html#gad1a0d325d930eeb80f25e3fea37aacde',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frecalloc_5faligned_46',['mi_heap_recalloc_aligned',['../group__zeroinit.html#ga87ddd674bf1c67237d780d0b9e0f0f32',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frecalloc_5faligned_5fat_47',['mi_heap_recalloc_aligned_at',['../group__zeroinit.html#ga07b5bcbaf00d0d2e598c232982588496',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frezalloc_48',['mi_heap_rezalloc',['../group__zeroinit.html#ga8d8b7ebb24b513cd84d1a696048da60d',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frezalloc_5faligned_49',['mi_heap_rezalloc_aligned',['../group__zeroinit.html#ga5129f6dc46ee1613d918820a8a0533a7',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frezalloc_5faligned_5fat_50',['mi_heap_rezalloc_aligned_at',['../group__zeroinit.html#ga2bafa79c3f98ea74882349d44cffa5d9',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fset_5fdefault_51',['mi_heap_set_default',['../group__heap.html#ga349b677dec7da5eacdbc7a385bd62a4a',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fstrdup_52',['mi_heap_strdup',['../group__heap.html#ga5754e09ccc51dd6bc73885bb6ea21b7a',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fstrndup_53',['mi_heap_strndup',['../group__heap.html#gad224df78f1fbee942df8adf023e12cf3',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fvisit_5fblocks_54',['mi_heap_visit_blocks',['../group__analysis.html#ga70c46687dc6e9dc98b232b02646f8bed',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fzalloc_55',['mi_heap_zalloc',['../group__heap.html#gabebc796399619d964d8db77aa835e8c1',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fzalloc_5faligned_56',['mi_heap_zalloc_aligned',['../group__heap.html#ga6466bde8b5712aa34e081a8317f9f471',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fzalloc_5faligned_5fat_57',['mi_heap_zalloc_aligned_at',['../group__heap.html#ga484e3d01cd174f78c7e53370e5a7c819',1,'mimalloc-doc.h']]], + ['mi_5fis_5fin_5fheap_5fregion_58',['mi_is_in_heap_region',['../group__extended.html#ga5f071b10d4df1c3658e04e7fd67a94e6',1,'mimalloc-doc.h']]], + ['mi_5fis_5fredirected_59',['mi_is_redirected',['../group__extended.html#gaad25050b19f30cd79397b227e0157a3f',1,'mimalloc-doc.h']]], + ['mi_5fmalloc_60',['mi_malloc',['../group__malloc.html#gae1dd97b542420c87ae085e822b1229e8',1,'mimalloc-doc.h']]], + ['mi_5fmalloc_5faligned_61',['mi_malloc_aligned',['../group__aligned.html#ga69578ff1a98ca16e1dcd02c0995cd65c',1,'mimalloc-doc.h']]], + ['mi_5fmalloc_5faligned_5fat_62',['mi_malloc_aligned_at',['../group__aligned.html#ga2022f71b95a7cd6cce1b6e07752ae8ca',1,'mimalloc-doc.h']]], + ['mi_5fmalloc_5fgood_5fsize_63',['mi_malloc_good_size',['../group__posix.html#ga9d23ac7885fed7413c11d8e0ffa31071',1,'mimalloc-doc.h']]], + ['mi_5fmalloc_5fsize_64',['mi_malloc_size',['../group__posix.html#ga4531c9e775bb3ae12db57c1ba8a5d7de',1,'mimalloc-doc.h']]], + ['mi_5fmalloc_5fsmall_65',['mi_malloc_small',['../group__extended.html#ga7f050bc6b897da82692174f5fce59cde',1,'mimalloc-doc.h']]], + ['mi_5fmalloc_5fusable_5fsize_66',['mi_malloc_usable_size',['../group__posix.html#ga06d07cf357bbac5c73ba5d0c0c421e17',1,'mimalloc-doc.h']]], + ['mi_5fmallocn_67',['mi_mallocn',['../group__malloc.html#ga61f46bade3db76ca24aaafedc40de7b6',1,'mimalloc-doc.h']]], + ['mi_5fmanage_5fos_5fmemory_68',['mi_manage_os_memory',['../group__extended.html#ga4c6486a1fdcd7a423b5f25fe4be8e0cf',1,'mimalloc-doc.h']]], + ['mi_5fmanage_5fos_5fmemory_5fex_69',['mi_manage_os_memory_ex',['../group__extended.html#ga41ce8525d77bbb60f618fa1029994f6e',1,'mimalloc-doc.h']]], + ['mi_5fmbsdup_70',['mi_mbsdup',['../group__posix.html#ga7b82a44094fdec4d2084eb4288a979b0',1,'mimalloc-doc.h']]], + ['mi_5fmemalign_71',['mi_memalign',['../group__posix.html#ga726867f13fd29ca36064954c0285b1d8',1,'mimalloc-doc.h']]], + ['mi_5fnew_72',['mi_new',['../group__cpp.html#ga633d96e3bc7011f960df9f3b2731fc6a',1,'mimalloc-doc.h']]], + ['mi_5fnew_5faligned_73',['mi_new_aligned',['../group__cpp.html#ga79c54da0b4b4ce9fcc11d2f6ef6675f8',1,'mimalloc-doc.h']]], + ['mi_5fnew_5faligned_5fnothrow_74',['mi_new_aligned_nothrow',['../group__cpp.html#ga92ae00b6dd64406c7e64557711ec04b7',1,'mimalloc-doc.h']]], + ['mi_5fnew_5fn_75',['mi_new_n',['../group__cpp.html#gadd11b85c15d21d308386844b5233856c',1,'mimalloc-doc.h']]], + ['mi_5fnew_5fnothrow_76',['mi_new_nothrow',['../group__cpp.html#ga5cb4f120d1f7296074256215aa9a9e54',1,'mimalloc-doc.h']]], + ['mi_5fnew_5frealloc_77',['mi_new_realloc',['../group__cpp.html#ga6867d89baf992728e0cc20a1f47db4d0',1,'mimalloc-doc.h']]], + ['mi_5fnew_5freallocn_78',['mi_new_reallocn',['../group__cpp.html#gaace912ce086682d56f3ce9f7638d9d67',1,'mimalloc-doc.h']]], + ['mi_5foption_5fdisable_79',['mi_option_disable',['../group__options.html#gaebf6ff707a2e688ebb1a2296ca564054',1,'mimalloc-doc.h']]], + ['mi_5foption_5fenable_80',['mi_option_enable',['../group__options.html#ga04180ae41b0d601421dd62ced40ca050',1,'mimalloc-doc.h']]], + ['mi_5foption_5fget_81',['mi_option_get',['../group__options.html#ga7e8af195cc81d3fa64ccf2662caa565a',1,'mimalloc-doc.h']]], + ['mi_5foption_5fget_5fclamp_82',['mi_option_get_clamp',['../group__options.html#ga96ad9c406338bd314cfe878cfc9bf723',1,'mimalloc-doc.h']]], + ['mi_5foption_5fget_5fsize_83',['mi_option_get_size',['../group__options.html#ga274db5a6ac87cc24ef0b23e7006ed02c',1,'mimalloc-doc.h']]], + ['mi_5foption_5fis_5fenabled_84',['mi_option_is_enabled',['../group__options.html#ga459ad98f18b3fc9275474807fe0ca188',1,'mimalloc-doc.h']]], + ['mi_5foption_5fset_85',['mi_option_set',['../group__options.html#gaf84921c32375e25754dc2ee6a911fa60',1,'mimalloc-doc.h']]], + ['mi_5foption_5fset_5fdefault_86',['mi_option_set_default',['../group__options.html#ga7ef623e440e6e5545cb08c94e71e4b90',1,'mimalloc-doc.h']]], + ['mi_5foption_5fset_5fenabled_87',['mi_option_set_enabled',['../group__options.html#ga9a13d05fcb77489cb06d4d017ebd8bed',1,'mimalloc-doc.h']]], + ['mi_5foption_5fset_5fenabled_5fdefault_88',['mi_option_set_enabled_default',['../group__options.html#ga65518b69ec5d32336b50e07f74b3f629',1,'mimalloc-doc.h']]], + ['mi_5fposix_5fmemalign_89',['mi_posix_memalign',['../group__posix.html#gacff84f226ba9feb2031b8992e5579447',1,'mimalloc-doc.h']]], + ['mi_5fprocess_5finfo_90',['mi_process_info',['../group__extended.html#ga7d862c2affd5790381da14eb102a364d',1,'mimalloc-doc.h']]], + ['mi_5fpvalloc_91',['mi_pvalloc',['../group__posix.html#ga644bebccdbb2821542dd8c7e7641f476',1,'mimalloc-doc.h']]], + ['mi_5frealloc_92',['mi_realloc',['../group__malloc.html#ga0621af6a5e3aa384e6a1b548958bf583',1,'mimalloc-doc.h']]], + ['mi_5frealloc_5faligned_93',['mi_realloc_aligned',['../group__aligned.html#ga5d7a46d054b4d7abe9d8d2474add2edf',1,'mimalloc-doc.h']]], + ['mi_5frealloc_5faligned_5fat_94',['mi_realloc_aligned_at',['../group__aligned.html#gad06dcf2bb8faadb2c8ea61ee5d24bbf6',1,'mimalloc-doc.h']]], + ['mi_5freallocarr_95',['mi_reallocarr',['../group__posix.html#ga7e1934d60a3e697950eeb48e042bfad5',1,'mimalloc-doc.h']]], + ['mi_5freallocarray_96',['mi_reallocarray',['../group__posix.html#gadfeccb72748a2f6305474a37d9d57bce',1,'mimalloc-doc.h']]], + ['mi_5freallocf_97',['mi_reallocf',['../group__malloc.html#ga4dc3a4067037b151a64629fe8a332641',1,'mimalloc-doc.h']]], + ['mi_5freallocn_98',['mi_reallocn',['../group__malloc.html#ga8bddfb4a1270a0854bbcf44cb3980467',1,'mimalloc-doc.h']]], + ['mi_5frealpath_99',['mi_realpath',['../group__malloc.html#ga94c3afcc086e85d75a57e9f76b9b71dd',1,'mimalloc-doc.h']]], + ['mi_5frecalloc_100',['mi_recalloc',['../group__malloc.html#ga23a0fbb452b5dce8e31fab1a1958cacc',1,'mimalloc-doc.h']]], + ['mi_5frecalloc_5faligned_101',['mi_recalloc_aligned',['../group__zeroinit.html#ga3e2169b48683aa0ab64f813fd68d839e',1,'mimalloc-doc.h']]], + ['mi_5frecalloc_5faligned_5fat_102',['mi_recalloc_aligned_at',['../group__zeroinit.html#gaae25e4ddedd4e0fb61b1a8bd5d452750',1,'mimalloc-doc.h']]], + ['mi_5fregister_5fdeferred_5ffree_103',['mi_register_deferred_free',['../group__extended.html#ga3460a6ca91af97be4058f523d3cb8ece',1,'mimalloc-doc.h']]], + ['mi_5fregister_5ferror_104',['mi_register_error',['../group__extended.html#gaa1d55e0e894be240827e5d87ec3a1f45',1,'mimalloc-doc.h']]], + ['mi_5fregister_5foutput_105',['mi_register_output',['../group__extended.html#gae5b17ff027cd2150b43a33040250cf3f',1,'mimalloc-doc.h']]], + ['mi_5freserve_5fhuge_5fos_5fpages_5fat_106',['mi_reserve_huge_os_pages_at',['../group__extended.html#ga7795a13d20087447281858d2c771cca1',1,'mimalloc-doc.h']]], + ['mi_5freserve_5fhuge_5fos_5fpages_5fat_5fex_107',['mi_reserve_huge_os_pages_at_ex',['../group__extended.html#ga591aab1c2bc2ca920e33f0f9f9cb5c52',1,'mimalloc-doc.h']]], + ['mi_5freserve_5fhuge_5fos_5fpages_5finterleave_108',['mi_reserve_huge_os_pages_interleave',['../group__extended.html#ga3132f521fb756fc0e8ec0b74fb58df50',1,'mimalloc-doc.h']]], + ['mi_5freserve_5fos_5fmemory_109',['mi_reserve_os_memory',['../group__extended.html#ga00ec3324b6b2591c7fe3677baa30a767',1,'mimalloc-doc.h']]], + ['mi_5freserve_5fos_5fmemory_5fex_110',['mi_reserve_os_memory_ex',['../group__extended.html#ga32f519797fd9a81acb4f52d36e6d751b',1,'mimalloc-doc.h']]], + ['mi_5frezalloc_111',['mi_rezalloc',['../group__zeroinit.html#gadfd34cd7b4f2bbda7ae06367a6360756',1,'mimalloc-doc.h']]], + ['mi_5frezalloc_5faligned_112',['mi_rezalloc_aligned',['../group__zeroinit.html#ga4d02404fe1e7db00beb65f185e012caa',1,'mimalloc-doc.h']]], + ['mi_5frezalloc_5faligned_5fat_113',['mi_rezalloc_aligned_at',['../group__zeroinit.html#ga6843a88285bbfcc3bdfccc60aafd1270',1,'mimalloc-doc.h']]], + ['mi_5fstats_5fmerge_114',['mi_stats_merge',['../group__extended.html#ga854b1de8cb067c7316286c28b2fcd3d1',1,'mimalloc-doc.h']]], + ['mi_5fstats_5fprint_115',['mi_stats_print',['../group__extended.html#ga2d126e5c62d3badc35445e5d84166df2',1,'mimalloc-doc.h']]], + ['mi_5fstats_5fprint_5fout_116',['mi_stats_print_out',['../group__extended.html#ga537f13b299ddf801e49a5a94fde02c79',1,'mimalloc-doc.h']]], + ['mi_5fstats_5freset_117',['mi_stats_reset',['../group__extended.html#ga3bb8468b8cfcc6e2a61d98aee85c5f99',1,'mimalloc-doc.h']]], + ['mi_5fstrdup_118',['mi_strdup',['../group__malloc.html#ga245ac90ebc2cfdd17de599e5fea59889',1,'mimalloc-doc.h']]], + ['mi_5fstrndup_119',['mi_strndup',['../group__malloc.html#ga486d0d26b3b3794f6d1cdb41a9aed92d',1,'mimalloc-doc.h']]], + ['mi_5fsubproc_5fadd_5fcurrent_5fthread_120',['mi_subproc_add_current_thread',['../group__extended.html#gadbc53414eb68b275588ec001ce1ddc7c',1,'mimalloc-doc.h']]], + ['mi_5fsubproc_5fdelete_121',['mi_subproc_delete',['../group__extended.html#gaa7d263e9429bac9ac8345c9d25de610e',1,'mimalloc-doc.h']]], + ['mi_5fsubproc_5fmain_122',['mi_subproc_main',['../group__extended.html#ga2ecba0d7ebdc99e71bb985c4a1609806',1,'mimalloc-doc.h']]], + ['mi_5fsubproc_5fnew_123',['mi_subproc_new',['../group__extended.html#ga8068cac328e41fa2170faef707315243',1,'mimalloc-doc.h']]], + ['mi_5fthread_5fdone_124',['mi_thread_done',['../group__extended.html#ga0ae4581e85453456a0d658b2b98bf7bf',1,'mimalloc-doc.h']]], + ['mi_5fthread_5finit_125',['mi_thread_init',['../group__extended.html#gaf8e73efc2cbca9ebfdfb166983a04c17',1,'mimalloc-doc.h']]], + ['mi_5fthread_5fstats_5fprint_5fout_126',['mi_thread_stats_print_out',['../group__extended.html#gab1dac8476c46cb9eecab767eb40c1525',1,'mimalloc-doc.h']]], + ['mi_5fusable_5fsize_127',['mi_usable_size',['../group__extended.html#ga089c859d9eddc5f9b4bd946cd53cebee',1,'mimalloc-doc.h']]], + ['mi_5fvalloc_128',['mi_valloc',['../group__posix.html#ga50cafb9722020402f065de93799f64ca',1,'mimalloc-doc.h']]], + ['mi_5fwcsdup_129',['mi_wcsdup',['../group__posix.html#gaa9fd7f25c9ac3a20e89b33bd6e383fcf',1,'mimalloc-doc.h']]], + ['mi_5fwdupenv_5fs_130',['mi_wdupenv_s',['../group__posix.html#ga6ac6a6a8f3c96f1af24bb8d0439cbbd1',1,'mimalloc-doc.h']]], + ['mi_5fzalloc_131',['mi_zalloc',['../group__malloc.html#gae6e38c4403247a7b40d80419e093bfb8',1,'mimalloc-doc.h']]], + ['mi_5fzalloc_5faligned_132',['mi_zalloc_aligned',['../group__aligned.html#gaac7d0beb782f9b9ac31f47492b130f82',1,'mimalloc-doc.h']]], + ['mi_5fzalloc_5faligned_5fat_133',['mi_zalloc_aligned_at',['../group__aligned.html#ga7c1778805ce50ebbf02ccbd5e39d5dba',1,'mimalloc-doc.h']]], + ['mi_5fzalloc_5fsmall_134',['mi_zalloc_small',['../group__extended.html#ga51c47637e81df0e2f13a2d7a2dec123e',1,'mimalloc-doc.h']]] ]; diff --git a/src/dashbls/depends/mimalloc/docs/search/groups_0.js b/src/dashbls/depends/mimalloc/docs/search/groups_0.js index 0ed99b804cea..d371a39915e0 100644 --- a/src/dashbls/depends/mimalloc/docs/search/groups_0.js +++ b/src/dashbls/depends/mimalloc/docs/search/groups_0.js @@ -1,4 +1,6 @@ var searchData= [ - ['aligned_20allocation_314',['Aligned Allocation',['../group__aligned.html',1,'']]] + ['aligned_20allocation_0',['Aligned Allocation',['../group__aligned.html',1,'']]], + ['allocation_1',['Allocation',['../group__aligned.html',1,'Aligned Allocation'],['../group__malloc.html',1,'Basic Allocation'],['../group__heap.html',1,'Heap Allocation']]], + ['allocation_2',['Zero initialized re-allocation',['../group__zeroinit.html',1,'']]] ]; diff --git a/src/dashbls/depends/mimalloc/docs/search/groups_1.js b/src/dashbls/depends/mimalloc/docs/search/groups_1.js index f27c5847a097..8fca27170125 100644 --- a/src/dashbls/depends/mimalloc/docs/search/groups_1.js +++ b/src/dashbls/depends/mimalloc/docs/search/groups_1.js @@ -1,4 +1,4 @@ var searchData= [ - ['basic_20allocation_315',['Basic Allocation',['../group__malloc.html',1,'']]] + ['basic_20allocation_0',['Basic Allocation',['../group__malloc.html',1,'']]] ]; diff --git a/src/dashbls/depends/mimalloc/docs/search/groups_2.js b/src/dashbls/depends/mimalloc/docs/search/groups_2.js index 6da64b68be2a..d260dec8a03d 100644 --- a/src/dashbls/depends/mimalloc/docs/search/groups_2.js +++ b/src/dashbls/depends/mimalloc/docs/search/groups_2.js @@ -1,4 +1,4 @@ var searchData= [ - ['c_2b_2b_20wrappers_316',['C++ wrappers',['../group__cpp.html',1,'']]] + ['c_20wrappers_0',['C++ wrappers',['../group__cpp.html',1,'']]] ]; diff --git a/src/dashbls/depends/mimalloc/docs/search/groups_3.js b/src/dashbls/depends/mimalloc/docs/search/groups_3.js index cdfbe640a16a..7099da010d37 100644 --- a/src/dashbls/depends/mimalloc/docs/search/groups_3.js +++ b/src/dashbls/depends/mimalloc/docs/search/groups_3.js @@ -1,4 +1,4 @@ var searchData= [ - ['extended_20functions_317',['Extended Functions',['../group__extended.html',1,'']]] + ['extended_20functions_0',['Extended Functions',['../group__extended.html',1,'']]] ]; diff --git a/src/dashbls/depends/mimalloc/docs/search/groups_4.js b/src/dashbls/depends/mimalloc/docs/search/groups_4.js index 687f1ea72825..87efcce9a042 100644 --- a/src/dashbls/depends/mimalloc/docs/search/groups_4.js +++ b/src/dashbls/depends/mimalloc/docs/search/groups_4.js @@ -1,5 +1,4 @@ var searchData= [ - ['heap_20allocation_318',['Heap Allocation',['../group__heap.html',1,'']]], - ['heap_20introspection_319',['Heap Introspection',['../group__analysis.html',1,'']]] + ['functions_0',['Extended Functions',['../group__extended.html',1,'']]] ]; diff --git a/src/dashbls/depends/mimalloc/docs/search/groups_5.js b/src/dashbls/depends/mimalloc/docs/search/groups_5.js index 43c8b1fc4743..3131f4a2ec05 100644 --- a/src/dashbls/depends/mimalloc/docs/search/groups_5.js +++ b/src/dashbls/depends/mimalloc/docs/search/groups_5.js @@ -1,4 +1,5 @@ var searchData= [ - ['posix_320',['Posix',['../group__posix.html',1,'']]] + ['heap_20allocation_0',['Heap Allocation',['../group__heap.html',1,'']]], + ['heap_20introspection_1',['Heap Introspection',['../group__analysis.html',1,'']]] ]; diff --git a/src/dashbls/depends/mimalloc/docs/search/groups_6.js b/src/dashbls/depends/mimalloc/docs/search/groups_6.js index 346318794bc3..6d20843280ff 100644 --- a/src/dashbls/depends/mimalloc/docs/search/groups_6.js +++ b/src/dashbls/depends/mimalloc/docs/search/groups_6.js @@ -1,4 +1,5 @@ var searchData= [ - ['runtime_20options_321',['Runtime Options',['../group__options.html',1,'']]] + ['initialized_20re_20allocation_0',['Zero initialized re-allocation',['../group__zeroinit.html',1,'']]], + ['introspection_1',['Heap Introspection',['../group__analysis.html',1,'']]] ]; diff --git a/src/dashbls/depends/mimalloc/docs/search/groups_7.js b/src/dashbls/depends/mimalloc/docs/search/groups_7.js index aa150e973f4b..aafc4dae67f3 100644 --- a/src/dashbls/depends/mimalloc/docs/search/groups_7.js +++ b/src/dashbls/depends/mimalloc/docs/search/groups_7.js @@ -1,4 +1,4 @@ var searchData= [ - ['typed_20macros_322',['Typed Macros',['../group__typed.html',1,'']]] + ['macros_0',['Typed Macros',['../group__typed.html',1,'']]] ]; diff --git a/src/dashbls/depends/mimalloc/docs/search/groups_8.js b/src/dashbls/depends/mimalloc/docs/search/groups_8.js index f9c29fe3bc1d..30681f7b5cd7 100644 --- a/src/dashbls/depends/mimalloc/docs/search/groups_8.js +++ b/src/dashbls/depends/mimalloc/docs/search/groups_8.js @@ -1,4 +1,4 @@ var searchData= [ - ['zero_20initialized_20re_2dallocation_323',['Zero initialized re-allocation',['../group__zeroinit.html',1,'']]] + ['options_0',['Runtime Options',['../group__options.html',1,'']]] ]; diff --git a/src/dashbls/depends/mimalloc/docs/search/groups_9.js b/src/dashbls/depends/mimalloc/docs/search/groups_9.js new file mode 100644 index 000000000000..bc3429469219 --- /dev/null +++ b/src/dashbls/depends/mimalloc/docs/search/groups_9.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['posix_0',['Posix',['../group__posix.html',1,'']]] +]; diff --git a/src/dashbls/depends/mimalloc/docs/search/groups_a.js b/src/dashbls/depends/mimalloc/docs/search/groups_a.js new file mode 100644 index 000000000000..5f2947aafb6b --- /dev/null +++ b/src/dashbls/depends/mimalloc/docs/search/groups_a.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['re_20allocation_0',['Zero initialized re-allocation',['../group__zeroinit.html',1,'']]], + ['runtime_20options_1',['Runtime Options',['../group__options.html',1,'']]] +]; diff --git a/src/dashbls/depends/mimalloc/docs/search/groups_b.js b/src/dashbls/depends/mimalloc/docs/search/groups_b.js new file mode 100644 index 000000000000..56eb25eae6e9 --- /dev/null +++ b/src/dashbls/depends/mimalloc/docs/search/groups_b.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['typed_20macros_0',['Typed Macros',['../group__typed.html',1,'']]] +]; diff --git a/src/dashbls/depends/mimalloc/docs/search/groups_c.js b/src/dashbls/depends/mimalloc/docs/search/groups_c.js new file mode 100644 index 000000000000..8f445b9fc8c2 --- /dev/null +++ b/src/dashbls/depends/mimalloc/docs/search/groups_c.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['wrappers_0',['C++ wrappers',['../group__cpp.html',1,'']]] +]; diff --git a/src/dashbls/depends/mimalloc/docs/search/groups_d.js b/src/dashbls/depends/mimalloc/docs/search/groups_d.js new file mode 100644 index 000000000000..1437d04ac002 --- /dev/null +++ b/src/dashbls/depends/mimalloc/docs/search/groups_d.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['zero_20initialized_20re_20allocation_0',['Zero initialized re-allocation',['../group__zeroinit.html',1,'']]] +]; diff --git a/src/dashbls/depends/mimalloc/docs/search/pages_0.js b/src/dashbls/depends/mimalloc/docs/search/pages_0.js index 07922dae7add..9c92133c3c92 100644 --- a/src/dashbls/depends/mimalloc/docs/search/pages_0.js +++ b/src/dashbls/depends/mimalloc/docs/search/pages_0.js @@ -1,4 +1,4 @@ var searchData= [ - ['building_324',['Building',['../build.html',1,'']]] + ['building_0',['Building',['../build.html',1,'']]] ]; diff --git a/src/dashbls/depends/mimalloc/docs/search/pages_1.js b/src/dashbls/depends/mimalloc/docs/search/pages_1.js index 6433daeccef5..4e3b12eec4d1 100644 --- a/src/dashbls/depends/mimalloc/docs/search/pages_1.js +++ b/src/dashbls/depends/mimalloc/docs/search/pages_1.js @@ -1,4 +1,4 @@ var searchData= [ - ['environment_20options_325',['Environment Options',['../environment.html',1,'']]] + ['environment_20options_0',['Environment Options',['../environment.html',1,'']]] ]; diff --git a/src/dashbls/depends/mimalloc/docs/search/pages_2.js b/src/dashbls/depends/mimalloc/docs/search/pages_2.js index 7577377b9719..5071ed69e8a2 100644 --- a/src/dashbls/depends/mimalloc/docs/search/pages_2.js +++ b/src/dashbls/depends/mimalloc/docs/search/pages_2.js @@ -1,4 +1,4 @@ var searchData= [ - ['overriding_20malloc_326',['Overriding Malloc',['../overrides.html',1,'']]] + ['library_0',['Using the library',['../using.html',1,'']]] ]; diff --git a/src/dashbls/depends/mimalloc/docs/search/pages_3.js b/src/dashbls/depends/mimalloc/docs/search/pages_3.js index d62a3cfd1322..4c761a084669 100644 --- a/src/dashbls/depends/mimalloc/docs/search/pages_3.js +++ b/src/dashbls/depends/mimalloc/docs/search/pages_3.js @@ -1,4 +1,6 @@ var searchData= [ - ['performance_327',['Performance',['../bench.html',1,'']]] + ['malloc_0',['Overriding Malloc',['../overrides.html',1,'']]], + ['malloc_1',['mi-malloc',['../index.html',1,'']]], + ['mi_20malloc_2',['mi-malloc',['../index.html',1,'']]] ]; diff --git a/src/dashbls/depends/mimalloc/docs/search/pages_4.js b/src/dashbls/depends/mimalloc/docs/search/pages_4.js index 4e4e64dc489e..a0c748ac09be 100644 --- a/src/dashbls/depends/mimalloc/docs/search/pages_4.js +++ b/src/dashbls/depends/mimalloc/docs/search/pages_4.js @@ -1,4 +1,5 @@ var searchData= [ - ['using_20the_20library_328',['Using the library',['../using.html',1,'']]] + ['options_0',['Environment Options',['../environment.html',1,'']]], + ['overriding_20malloc_1',['Overriding Malloc',['../overrides.html',1,'']]] ]; diff --git a/src/dashbls/depends/mimalloc/docs/search/pages_5.js b/src/dashbls/depends/mimalloc/docs/search/pages_5.js new file mode 100644 index 000000000000..3142480928b9 --- /dev/null +++ b/src/dashbls/depends/mimalloc/docs/search/pages_5.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['performance_0',['Performance',['../bench.html',1,'']]] +]; diff --git a/src/dashbls/depends/mimalloc/docs/search/pages_6.js b/src/dashbls/depends/mimalloc/docs/search/pages_6.js new file mode 100644 index 000000000000..308a1780009f --- /dev/null +++ b/src/dashbls/depends/mimalloc/docs/search/pages_6.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['the_20library_0',['Using the library',['../using.html',1,'']]] +]; diff --git a/src/dashbls/depends/mimalloc/docs/search/pages_7.js b/src/dashbls/depends/mimalloc/docs/search/pages_7.js new file mode 100644 index 000000000000..4806a8183e75 --- /dev/null +++ b/src/dashbls/depends/mimalloc/docs/search/pages_7.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['using_20the_20library_0',['Using the library',['../using.html',1,'']]] +]; diff --git a/src/dashbls/depends/mimalloc/docs/search/search.css b/src/dashbls/depends/mimalloc/docs/search/search.css index 10bd4b55d93a..190ed7fdbb7b 100644 --- a/src/dashbls/depends/mimalloc/docs/search/search.css +++ b/src/dashbls/depends/mimalloc/docs/search/search.css @@ -1,100 +1,111 @@ /*---------------- Search Box */ -#FSearchBox { - float: left; +#MSearchBox { + position: absolute; + right: 5px; +} +/*---------------- Search box styling */ + +.SRPage * { + font-weight: normal; + line-height: normal; +} + +dark-mode-toggle { + margin-left: 5px; + display: flex; + float: right; } #MSearchBox { + display: inline-block; white-space : nowrap; - float: none; - margin-top: 0px; - right: 0px; - width: 170px; - height: 24px; + background: white; + border-radius: 0.65em; + box-shadow: inset 0.5px 0.5px 3px 0px #555; z-index: 102; - display: inline; - position: absolute; } -#MSearchBox .left -{ - display:block; - position:absolute; - left:10px; - width:20px; - height:19px; - background:url('search_l.png') no-repeat; - background-position:right; +#MSearchBox .left { + display: inline-block; + vertical-align: middle; + height: 1.4em; } #MSearchSelect { - display:block; - position:absolute; - width:20px; - height:19px; + display: inline-block; + vertical-align: middle; + width: 20px; + height: 19px; + background-image: url('mag_sel.svg'); + margin: 0 0 0 0.3em; + padding: 0; } -.left #MSearchSelect { - left:4px; +#MSearchSelectExt { + display: inline-block; + vertical-align: middle; + width: 10px; + height: 19px; + background-image: url('mag.svg'); + margin: 0 0 0 0.5em; + padding: 0; } -.right #MSearchSelect { - right:5px; -} #MSearchField { - display:block; - position:absolute; - height:19px; - background:url('search_m.png') repeat-x; + display: inline-block; + vertical-align: middle; + width: 7.5em; + height: 19px; + margin: 0 0.15em; + padding: 0; + line-height: 1em; border:none; - width:111px; - margin-left:20px; - padding-left:4px; color: #909090; outline: none; - font: 9pt Arial, Verdana, sans-serif; + font-family: Arial,Verdana,sans-serif; -webkit-border-radius: 0px; + border-radius: 0px; + background: none; } -#FSearchBox #MSearchField { - margin-left:15px; +@media(hover: none) { + /* to avoid zooming on iOS */ + #MSearchField { + font-size: 16px; + } } #MSearchBox .right { - display:block; - position:absolute; - right:10px; - top:0px; - width:20px; - height:19px; - background:url('search_r.png') no-repeat; - background-position:left; + display: inline-block; + vertical-align: middle; + width: 1.4em; + height: 1.4em; } #MSearchClose { display: none; - position: absolute; - top: 4px; + font-size: inherit; background : none; border: none; - margin: 0px 4px 0px 0px; - padding: 0px 0px; + margin: 0; + padding: 0; outline: none; -} -.left #MSearchClose { - left: 6px; } -.right #MSearchClose { - right: 2px; +#MSearchCloseImg { + padding: 0.3em; + margin: 0; } .MSearchBoxActive #MSearchField { - color: #000000; + color: black; } + + /*---------------- Search filter selection */ #MSearchSelectWindow { @@ -115,7 +126,7 @@ } .SelectItem { - font: 8pt Arial, Verdana, sans-serif; + font: 8pt Arial,Verdana,sans-serif; padding-left: 2px; padding-right: 12px; border: 0px; @@ -123,7 +134,7 @@ span.SelectionMark { margin-right: 4px; - font-family: monospace; + font-family: 'JetBrains Mono',Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace,fixed; outline-style: none; text-decoration: none; } @@ -131,7 +142,7 @@ span.SelectionMark { a.SelectItem { display: block; outline-style: none; - color: #000000; + color: black; text-decoration: none; padding-left: 6px; padding-right: 12px; @@ -139,13 +150,13 @@ a.SelectItem { a.SelectItem:focus, a.SelectItem:active { - color: #000000; + color: black; outline-style: none; text-decoration: none; } a.SelectItem:hover { - color: #FFFFFF; + color: white; background-color: #0F1010; outline-style: none; text-decoration: none; @@ -156,7 +167,7 @@ a.SelectItem:hover { /*---------------- Search results window */ iframe#MSearchResults { - width: 60ex; + /*width: 60ex;*/ height: 15em; } @@ -164,9 +175,12 @@ iframe#MSearchResults { display: none; position: absolute; left: 0; top: 0; - border: 1px solid #000; + border: 1px solid black; background-color: #DADDDE; z-index:10000; + width: 300px; + height: 400px; + overflow: auto; } /* ----------------------------------- */ @@ -174,7 +188,6 @@ iframe#MSearchResults { #SRIndex { clear:both; - padding-bottom: 15px; } .SREntry { @@ -187,8 +200,9 @@ iframe#MSearchResults { padding: 1px 5px; } -body.SRPage { +div.SRPage { margin: 5px 2px; + background-color: #DADDDE; } .SRChildren { @@ -200,17 +214,18 @@ body.SRPage { } .SRSymbol { - font-weight: bold; + font-weight: bold; color: #121414; - font-family: Arial, Verdana, sans-serif; + font-family: Arial,Verdana,sans-serif; text-decoration: none; outline: none; } a.SRScope { display: block; - color: #121414; - font-family: Arial, Verdana, sans-serif; + color: #121414; + font-family: Arial,Verdana,sans-serif; + font-size: 8pt; text-decoration: none; outline: none; } @@ -222,29 +237,27 @@ a.SRScope:focus, a.SRScope:active { span.SRScope { padding-left: 4px; + font-family: Arial,Verdana,sans-serif; } .SRPage .SRStatus { padding: 2px 5px; font-size: 8pt; font-style: italic; + font-family: Arial,Verdana,sans-serif; } .SRResult { display: none; } -DIV.searchresults { +div.searchresults { margin-left: 10px; margin-right: 10px; } /*---------------- External search page results */ -.searchresult { - background-color: #DFE1E2; -} - .pages b { color: white; padding: 5px 5px 3px 5px; diff --git a/src/dashbls/depends/mimalloc/docs/search/search.js b/src/dashbls/depends/mimalloc/docs/search/search.js index fb226f734e6d..666af01e5ea2 100644 --- a/src/dashbls/depends/mimalloc/docs/search/search.js +++ b/src/dashbls/depends/mimalloc/docs/search/search.js @@ -22,56 +22,9 @@ @licend The above is the entire license notice for the JavaScript code in this file */ -function convertToId(search) -{ - var result = ''; - for (i=0;i document.getElementById("MSearchField"); + this.DOMSearchSelect = () => document.getElementById("MSearchSelect"); + this.DOMSearchSelectWindow = () => document.getElementById("MSearchSelectWindow"); + this.DOMPopupSearchResults = () => document.getElementById("MSearchResults"); + this.DOMPopupSearchResultsWindow = () => document.getElementById("MSearchResultsWindow"); + this.DOMSearchClose = () => document.getElementById("MSearchClose"); + this.DOMSearchBox = () => document.getElementById("MSearchBox"); // ------------ Event Handlers // Called when focus is added or removed from the search field. - this.OnSearchFieldFocus = function(isActive) - { + this.OnSearchFieldFocus = function(isActive) { this.Activate(isActive); } - this.OnSearchSelectShow = function() - { - var searchSelectWindow = this.DOMSearchSelectWindow(); - var searchField = this.DOMSearchSelect(); - - if (this.insideFrame) - { - var left = getXPos(searchField); - var top = getYPos(searchField); - left += searchField.offsetWidth + 6; - top += searchField.offsetHeight; - - // show search selection popup - searchSelectWindow.style.display='block'; - left -= searchSelectWindow.offsetWidth; - searchSelectWindow.style.left = left + 'px'; - searchSelectWindow.style.top = top + 'px'; - } - else - { - var left = getXPos(searchField); - var top = getYPos(searchField); - top += searchField.offsetHeight; - - // show search selection popup - searchSelectWindow.style.display='block'; - searchSelectWindow.style.left = left + 'px'; - searchSelectWindow.style.top = top + 'px'; - } + this.OnSearchSelectShow = function() { + const searchSelectWindow = this.DOMSearchSelectWindow(); + const searchField = this.DOMSearchSelect(); + + const left = getXPos(searchField); + const top = getYPos(searchField) + searchField.offsetHeight; + + // show search selection popup + searchSelectWindow.style.display='block'; + searchSelectWindow.style.left = left + 'px'; + searchSelectWindow.style.top = top + 'px'; // stop selection hide timer - if (this.hideTimeout) - { + if (this.hideTimeout) { clearTimeout(this.hideTimeout); this.hideTimeout=0; } return false; // to avoid "image drag" default event } - this.OnSearchSelectHide = function() - { - this.hideTimeout = setTimeout(this.name +".CloseSelectionWindow()", + this.OnSearchSelectHide = function() { + this.hideTimeout = setTimeout(this.CloseSelectionWindow.bind(this), this.closeSelectionTimeout); } // Called when the content of the search field is changed. - this.OnSearchFieldChange = function(evt) - { - if (this.keyTimeout) // kill running timer - { + this.OnSearchFieldChange = function(evt) { + if (this.keyTimeout) { // kill running timer clearTimeout(this.keyTimeout); this.keyTimeout = 0; } - var e = (evt) ? evt : window.event; // for IE - if (e.keyCode==40 || e.keyCode==13) - { - if (e.shiftKey==1) - { + const e = evt ? evt : window.event; // for IE + if (e.keyCode==40 || e.keyCode==13) { + if (e.shiftKey==1) { this.OnSearchSelectShow(); - var win=this.DOMSearchSelectWindow(); - for (i=0;i do a search - { + const searchValue = this.DOMSearchField().value.replace(/ +/g, ""); + if (searchValue!="" && this.searchActive) { // something was found -> do a search this.Search(); } } - this.OnSearchSelectKey = function(evt) - { - var e = (evt) ? evt : window.event; // for IE - if (e.keyCode==40 && this.searchIndex0) // Up - { + } else if (e.keyCode==38 && this.searchIndex>0) { // Up this.searchIndex--; this.OnSelectItem(this.searchIndex); - } - else if (e.keyCode==13 || e.keyCode==27) - { + } else if (e.keyCode==13 || e.keyCode==27) { + e.stopPropagation(); this.OnSelectItem(this.searchIndex); this.CloseSelectionWindow(); this.DOMSearchField().focus(); @@ -314,111 +239,108 @@ function SearchBox(name, resultsPath, inFrame, label, extension) // --------- Actions // Closes the results window. - this.CloseResultsWindow = function() - { + this.CloseResultsWindow = function() { this.DOMPopupSearchResultsWindow().style.display = 'none'; this.DOMSearchClose().style.display = 'none'; this.Activate(false); } - this.CloseSelectionWindow = function() - { + this.CloseSelectionWindow = function() { this.DOMSearchSelectWindow().style.display = 'none'; } // Performs a search. - this.Search = function() - { + this.Search = function() { this.keyTimeout = 0; // strip leading whitespace - var searchValue = this.DOMSearchField().value.replace(/^ +/, ""); + const searchValue = this.DOMSearchField().value.replace(/^ +/, ""); - var code = searchValue.toLowerCase().charCodeAt(0); - var idxChar = searchValue.substr(0, 1).toLowerCase(); - if ( 0xD800 <= code && code <= 0xDBFF && searchValue > 1) // surrogate pair - { + const code = searchValue.toLowerCase().charCodeAt(0); + let idxChar = searchValue.substr(0, 1).toLowerCase(); + if ( 0xD800 <= code && code <= 0xDBFF && searchValue > 1) { // surrogate pair idxChar = searchValue.substr(0, 2); } - var resultsPage; - var resultsPageWithSearch; - var hasResultsPage; - - var idx = indexSectionsWithContent[this.searchIndex].indexOf(idxChar); - if (idx!=-1) - { - var hexCode=idx.toString(16); - resultsPage = this.resultsPath + '/' + indexSectionNames[this.searchIndex] + '_' + hexCode + this.extension; - resultsPageWithSearch = resultsPage+'?'+escape(searchValue); - hasResultsPage = true; + let jsFile; + let idx = indexSectionsWithContent[this.searchIndex].indexOf(idxChar); + if (idx!=-1) { + const hexCode=idx.toString(16); + jsFile = this.resultsPath + indexSectionNames[this.searchIndex] + '_' + hexCode + '.js'; + } + + const loadJS = function(url, impl, loc) { + const scriptTag = document.createElement('script'); + scriptTag.src = url; + scriptTag.onload = impl; + scriptTag.onreadystatechange = impl; + loc.appendChild(scriptTag); } - else // nothing available for this search term - { - resultsPage = this.resultsPath + '/nomatches' + this.extension; - resultsPageWithSearch = resultsPage; - hasResultsPage = false; + + const domPopupSearchResultsWindow = this.DOMPopupSearchResultsWindow(); + const domSearchBox = this.DOMSearchBox(); + const domPopupSearchResults = this.DOMPopupSearchResults(); + const domSearchClose = this.DOMSearchClose(); + const resultsPath = this.resultsPath; + + const handleResults = function() { + document.getElementById("Loading").style.display="none"; + if (typeof searchData !== 'undefined') { + createResults(resultsPath); + document.getElementById("NoMatches").style.display="none"; + } + + if (idx!=-1) { + searchResults.Search(searchValue); + } else { // no file with search results => force empty search results + searchResults.Search('===='); + } + + if (domPopupSearchResultsWindow.style.display!='block') { + domSearchClose.style.display = 'inline-block'; + let left = getXPos(domSearchBox) + 150; + let top = getYPos(domSearchBox) + 20; + domPopupSearchResultsWindow.style.display = 'block'; + left -= domPopupSearchResults.offsetWidth; + const maxWidth = document.body.clientWidth; + const maxHeight = document.body.clientHeight; + let width = 300; + if (left<10) left=10; + if (width+left+8>maxWidth) width=maxWidth-left-8; + let height = 400; + if (height+top+8>maxHeight) height=maxHeight-top-8; + domPopupSearchResultsWindow.style.top = top + 'px'; + domPopupSearchResultsWindow.style.left = left + 'px'; + domPopupSearchResultsWindow.style.width = width + 'px'; + domPopupSearchResultsWindow.style.height = height + 'px'; + } } - window.frames.MSearchResults.location = resultsPageWithSearch; - var domPopupSearchResultsWindow = this.DOMPopupSearchResultsWindow(); - - if (domPopupSearchResultsWindow.style.display!='block') - { - var domSearchBox = this.DOMSearchBox(); - this.DOMSearchClose().style.display = 'inline-block'; - if (this.insideFrame) - { - var domPopupSearchResults = this.DOMPopupSearchResults(); - domPopupSearchResultsWindow.style.position = 'relative'; - domPopupSearchResultsWindow.style.display = 'block'; - var width = document.body.clientWidth - 8; // the -8 is for IE :-( - domPopupSearchResultsWindow.style.width = width + 'px'; - domPopupSearchResults.style.width = width + 'px'; - } - else - { - var domPopupSearchResults = this.DOMPopupSearchResults(); - var left = getXPos(domSearchBox) + 150; // domSearchBox.offsetWidth; - var top = getYPos(domSearchBox) + 20; // domSearchBox.offsetHeight + 1; - domPopupSearchResultsWindow.style.display = 'block'; - left -= domPopupSearchResults.offsetWidth; - domPopupSearchResultsWindow.style.top = top + 'px'; - domPopupSearchResultsWindow.style.left = left + 'px'; - } + if (jsFile) { + loadJS(jsFile, handleResults, this.DOMPopupSearchResultsWindow()); + } else { + handleResults(); } this.lastSearchValue = searchValue; - this.lastResultsPage = resultsPage; } // -------- Activation Functions // Activates or deactivates the search panel, resetting things to // their default values if necessary. - this.Activate = function(isActive) - { + this.Activate = function(isActive) { if (isActive || // open it - this.DOMPopupSearchResultsWindow().style.display == 'block' - ) - { + this.DOMPopupSearchResultsWindow().style.display == 'block' + ) { this.DOMSearchBox().className = 'MSearchBoxActive'; - - var searchField = this.DOMSearchField(); - - if (searchField.value == this.searchLabel) // clear "Search" term upon entry - { - searchField.value = ''; - this.searchActive = true; - } - } - else if (!isActive) // directly remove the panel - { + this.searchActive = true; + } else if (!isActive) { // directly remove the panel this.DOMSearchBox().className = 'MSearchBoxInactive'; - this.DOMSearchField().value = this.searchLabel; this.searchActive = false; this.lastSearchValue = '' this.lastResultsPage = ''; + this.DOMSearchField().value = ''; } } } @@ -426,391 +348,347 @@ function SearchBox(name, resultsPath, inFrame, label, extension) // ----------------------------------------------------------------------- // The class that handles everything on the search results page. -function SearchResults(name) -{ - // The number of matches from the last run of . - this.lastMatchCount = 0; - this.lastKey = 0; - this.repeatOn = false; - - // Toggles the visibility of the passed element ID. - this.FindChildElement = function(id) - { - var parentElement = document.getElementById(id); - var element = parentElement.firstChild; - - while (element && element!=parentElement) - { - if (element.nodeName.toLowerCase() == 'div' && element.className == 'SRChildren') - { - return element; - } +function SearchResults() { + + function convertToId(search) { + let result = ''; + for (let i=0;i. + this.lastMatchCount = 0; + this.lastKey = 0; + this.repeatOn = false; - if (element && element!=parentElement) - { - element = element.nextSibling; - } - } + // Toggles the visibility of the passed element ID. + this.FindChildElement = function(id) { + const parentElement = document.getElementById(id); + let element = parentElement.firstChild; + + while (element && element!=parentElement) { + if (element.nodeName.toLowerCase() == 'div' && element.className == 'SRChildren') { + return element; } - } - this.Toggle = function(id) - { - var element = this.FindChildElement(id); - if (element) - { - if (element.style.display == 'block') - { - element.style.display = 'none'; + if (element.nodeName.toLowerCase() == 'div' && element.hasChildNodes()) { + element = element.firstChild; + } else if (element.nextSibling) { + element = element.nextSibling; + } else { + do { + element = element.parentNode; } - else - { - element.style.display = 'block'; + while (element && element!=parentElement && !element.nextSibling); + + if (element && element!=parentElement) { + element = element.nextSibling; } } } + } - // Searches for the passed string. If there is no parameter, - // it takes it from the URL query. - // - // Always returns true, since other documents may try to call it - // and that may or may not be possible. - this.Search = function(search) - { - if (!search) // get search word from URL - { - search = window.location.search; - search = search.substring(1); // Remove the leading '?' - search = unescape(search); + this.Toggle = function(id) { + const element = this.FindChildElement(id); + if (element) { + if (element.style.display == 'block') { + element.style.display = 'none'; + } else { + element.style.display = 'block'; } + } + } - search = search.replace(/^ +/, ""); // strip leading spaces - search = search.replace(/ +$/, ""); // strip trailing spaces - search = search.toLowerCase(); - search = convertToId(search); - - var resultRows = document.getElementsByTagName("div"); - var matches = 0; - - var i = 0; - while (i < resultRows.length) - { - var row = resultRows.item(i); - if (row.className == "SRResult") - { - var rowMatchName = row.id.toLowerCase(); - rowMatchName = rowMatchName.replace(/^sr\d*_/, ''); // strip 'sr123_' - - if (search.length<=rowMatchName.length && - rowMatchName.substr(0, search.length)==search) - { - row.style.display = 'block'; - matches++; - } - else - { - row.style.display = 'none'; - } + // Searches for the passed string. If there is no parameter, + // it takes it from the URL query. + // + // Always returns true, since other documents may try to call it + // and that may or may not be possible. + this.Search = function(search) { + if (!search) { // get search word from URL + search = window.location.search; + search = search.substring(1); // Remove the leading '?' + search = unescape(search); + } + + search = search.replace(/^ +/, ""); // strip leading spaces + search = search.replace(/ +$/, ""); // strip trailing spaces + search = search.toLowerCase(); + search = convertToId(search); + + const resultRows = document.getElementsByTagName("div"); + let matches = 0; + + let i = 0; + while (i < resultRows.length) { + const row = resultRows.item(i); + if (row.className == "SRResult") { + let rowMatchName = row.id.toLowerCase(); + rowMatchName = rowMatchName.replace(/^sr\d*_/, ''); // strip 'sr123_' + + if (search.length<=rowMatchName.length && + rowMatchName.substr(0, search.length)==search) { + row.style.display = 'block'; + matches++; + } else { + row.style.display = 'none'; } - i++; - } - document.getElementById("Searching").style.display='none'; - if (matches == 0) // no results - { - document.getElementById("NoMatches").style.display='block'; } - else // at least one result - { - document.getElementById("NoMatches").style.display='none'; - } - this.lastMatchCount = matches; - return true; + i++; } + document.getElementById("Searching").style.display='none'; + if (matches == 0) { // no results + document.getElementById("NoMatches").style.display='block'; + } else { // at least one result + document.getElementById("NoMatches").style.display='none'; + } + this.lastMatchCount = matches; + return true; + } - // return the first item with index index or higher that is visible - this.NavNext = function(index) - { - var focusItem; - while (1) - { - var focusName = 'Item'+index; - focusItem = document.getElementById(focusName); - if (focusItem && focusItem.parentNode.parentNode.style.display=='block') - { - break; - } - else if (!focusItem) // last element - { - break; - } - focusItem=null; - index++; + // return the first item with index index or higher that is visible + this.NavNext = function(index) { + let focusItem; + for (;;) { + const focusName = 'Item'+index; + focusItem = document.getElementById(focusName); + if (focusItem && focusItem.parentNode.parentNode.style.display=='block') { + break; + } else if (!focusItem) { // last element + break; } - return focusItem; + focusItem=null; + index++; } + return focusItem; + } - this.NavPrev = function(index) - { - var focusItem; - while (1) - { - var focusName = 'Item'+index; - focusItem = document.getElementById(focusName); - if (focusItem && focusItem.parentNode.parentNode.style.display=='block') - { - break; - } - else if (!focusItem) // last element - { - break; - } - focusItem=null; - index--; + this.NavPrev = function(index) { + let focusItem; + for (;;) { + const focusName = 'Item'+index; + focusItem = document.getElementById(focusName); + if (focusItem && focusItem.parentNode.parentNode.style.display=='block') { + break; + } else if (!focusItem) { // last element + break; } - return focusItem; + focusItem=null; + index--; } + return focusItem; + } - this.ProcessKeys = function(e) - { - if (e.type == "keydown") - { - this.repeatOn = false; - this.lastKey = e.keyCode; + this.ProcessKeys = function(e) { + if (e.type == "keydown") { + this.repeatOn = false; + this.lastKey = e.keyCode; + } else if (e.type == "keypress") { + if (!this.repeatOn) { + if (this.lastKey) this.repeatOn = true; + return false; // ignore first keypress after keydown } - else if (e.type == "keypress") - { - if (!this.repeatOn) - { - if (this.lastKey) this.repeatOn = true; - return false; // ignore first keypress after keydown - } - } - else if (e.type == "keyup") - { - this.lastKey = 0; - this.repeatOn = false; - } - return this.lastKey!=0; + } else if (e.type == "keyup") { + this.lastKey = 0; + this.repeatOn = false; } + return this.lastKey!=0; + } - this.Nav = function(evt,itemIndex) - { - var e = (evt) ? evt : window.event; // for IE - if (e.keyCode==13) return true; - if (!this.ProcessKeys(e)) return false; - - if (this.lastKey==38) // Up - { - var newIndex = itemIndex-1; - var focusItem = this.NavPrev(newIndex); - if (focusItem) - { - var child = this.FindChildElement(focusItem.parentNode.parentNode.id); - if (child && child.style.display == 'block') // children visible - { - var n=0; - var tmpElem; - while (1) // search for last child - { - tmpElem = document.getElementById('Item'+newIndex+'_c'+n); - if (tmpElem) - { - focusItem = tmpElem; - } - else // found it! - { - break; - } - n++; + this.Nav = function(evt,itemIndex) { + const e = (evt) ? evt : window.event; // for IE + if (e.keyCode==13) return true; + if (!this.ProcessKeys(e)) return false; + + if (this.lastKey==38) { // Up + const newIndex = itemIndex-1; + let focusItem = this.NavPrev(newIndex); + if (focusItem) { + let child = this.FindChildElement(focusItem.parentNode.parentNode.id); + if (child && child.style.display == 'block') { // children visible + let n=0; + let tmpElem; + for (;;) { // search for last child + tmpElem = document.getElementById('Item'+newIndex+'_c'+n); + if (tmpElem) { + focusItem = tmpElem; + } else { // found it! + break; } + n++; } } - if (focusItem) - { - focusItem.focus(); - } - else // return focus to search field - { - parent.document.getElementById("MSearchField").focus(); - } - } - else if (this.lastKey==40) // Down - { - var newIndex = itemIndex+1; - var focusItem; - var item = document.getElementById('Item'+itemIndex); - var elem = this.FindChildElement(item.parentNode.parentNode.id); - if (elem && elem.style.display == 'block') // children visible - { - focusItem = document.getElementById('Item'+itemIndex+'_c0'); - } - if (!focusItem) focusItem = this.NavNext(newIndex); - if (focusItem) focusItem.focus(); } - else if (this.lastKey==39) // Right - { - var item = document.getElementById('Item'+itemIndex); - var elem = this.FindChildElement(item.parentNode.parentNode.id); - if (elem) elem.style.display = 'block'; + if (focusItem) { + focusItem.focus(); + } else { // return focus to search field + document.getElementById("MSearchField").focus(); } - else if (this.lastKey==37) // Left - { - var item = document.getElementById('Item'+itemIndex); - var elem = this.FindChildElement(item.parentNode.parentNode.id); - if (elem) elem.style.display = 'none'; + } else if (this.lastKey==40) { // Down + const newIndex = itemIndex+1; + let focusItem; + const item = document.getElementById('Item'+itemIndex); + const elem = this.FindChildElement(item.parentNode.parentNode.id); + if (elem && elem.style.display == 'block') { // children visible + focusItem = document.getElementById('Item'+itemIndex+'_c0'); } - else if (this.lastKey==27) // Escape - { - parent.searchBox.CloseResultsWindow(); - parent.document.getElementById("MSearchField").focus(); - } - else if (this.lastKey==13) // Enter - { - return true; - } - return false; + if (!focusItem) focusItem = this.NavNext(newIndex); + if (focusItem) focusItem.focus(); + } else if (this.lastKey==39) { // Right + const item = document.getElementById('Item'+itemIndex); + const elem = this.FindChildElement(item.parentNode.parentNode.id); + if (elem) elem.style.display = 'block'; + } else if (this.lastKey==37) { // Left + const item = document.getElementById('Item'+itemIndex); + const elem = this.FindChildElement(item.parentNode.parentNode.id); + if (elem) elem.style.display = 'none'; + } else if (this.lastKey==27) { // Escape + e.stopPropagation(); + searchBox.CloseResultsWindow(); + document.getElementById("MSearchField").focus(); + } else if (this.lastKey==13) { // Enter + return true; } + return false; + } - this.NavChild = function(evt,itemIndex,childIndex) - { - var e = (evt) ? evt : window.event; // for IE - if (e.keyCode==13) return true; - if (!this.ProcessKeys(e)) return false; - - if (this.lastKey==38) // Up - { - if (childIndex>0) - { - var newIndex = childIndex-1; - document.getElementById('Item'+itemIndex+'_c'+newIndex).focus(); - } - else // already at first child, jump to parent - { - document.getElementById('Item'+itemIndex).focus(); - } - } - else if (this.lastKey==40) // Down - { - var newIndex = childIndex+1; - var elem = document.getElementById('Item'+itemIndex+'_c'+newIndex); - if (!elem) // last child, jump to parent next parent - { - elem = this.NavNext(itemIndex+1); - } - if (elem) - { - elem.focus(); - } + this.NavChild = function(evt,itemIndex,childIndex) { + const e = (evt) ? evt : window.event; // for IE + if (e.keyCode==13) return true; + if (!this.ProcessKeys(e)) return false; + + if (this.lastKey==38) { // Up + if (childIndex>0) { + const newIndex = childIndex-1; + document.getElementById('Item'+itemIndex+'_c'+newIndex).focus(); + } else { // already at first child, jump to parent + document.getElementById('Item'+itemIndex).focus(); } - else if (this.lastKey==27) // Escape - { - parent.searchBox.CloseResultsWindow(); - parent.document.getElementById("MSearchField").focus(); + } else if (this.lastKey==40) { // Down + const newIndex = childIndex+1; + let elem = document.getElementById('Item'+itemIndex+'_c'+newIndex); + if (!elem) { // last child, jump to parent next parent + elem = this.NavNext(itemIndex+1); } - else if (this.lastKey==13) // Enter - { - return true; + if (elem) { + elem.focus(); } - return false; + } else if (this.lastKey==27) { // Escape + e.stopPropagation(); + searchBox.CloseResultsWindow(); + document.getElementById("MSearchField").focus(); + } else if (this.lastKey==13) { // Enter + return true; } + return false; + } } -function setKeyActions(elem,action) -{ - elem.setAttribute('onkeydown',action); - elem.setAttribute('onkeypress',action); - elem.setAttribute('onkeyup',action); -} +function createResults(resultsPath) { -function setClassAttr(elem,attr) -{ - elem.setAttribute('class',attr); - elem.setAttribute('className',attr); -} + function setKeyActions(elem,action) { + elem.setAttribute('onkeydown',action); + elem.setAttribute('onkeypress',action); + elem.setAttribute('onkeyup',action); + } + + function setClassAttr(elem,attr) { + elem.setAttribute('class',attr); + elem.setAttribute('className',attr); + } -function createResults() -{ - var results = document.getElementById("SRResults"); - for (var e=0; e { + const id = elem[0]; + const srResult = document.createElement('div'); srResult.setAttribute('id','SR_'+id); setClassAttr(srResult,'SRResult'); - var srEntry = document.createElement('div'); + const srEntry = document.createElement('div'); setClassAttr(srEntry,'SREntry'); - var srLink = document.createElement('a'); - srLink.setAttribute('id','Item'+e); - setKeyActions(srLink,'return searchResults.Nav(event,'+e+')'); + const srLink = document.createElement('a'); + srLink.setAttribute('id','Item'+index); + setKeyActions(srLink,'return searchResults.Nav(event,'+index+')'); setClassAttr(srLink,'SRSymbol'); - srLink.innerHTML = searchData[e][1][0]; + srLink.innerHTML = elem[1][0]; srEntry.appendChild(srLink); - if (searchData[e][1].length==2) // single result - { - srLink.setAttribute('href',searchData[e][1][1][0]); - if (searchData[e][1][1][1]) - { + if (elem[1].length==2) { // single result + srLink.setAttribute('href',resultsPath+elem[1][1][0]); + srLink.setAttribute('onclick','searchBox.CloseResultsWindow()'); + if (elem[1][1][1]) { srLink.setAttribute('target','_parent'); + } else { + srLink.setAttribute('target','_blank'); } - var srScope = document.createElement('span'); + const srScope = document.createElement('span'); setClassAttr(srScope,'SRScope'); - srScope.innerHTML = searchData[e][1][1][2]; + srScope.innerHTML = elem[1][1][2]; srEntry.appendChild(srScope); - } - else // multiple results - { + } else { // multiple results srLink.setAttribute('href','javascript:searchResults.Toggle("SR_'+id+'")'); - var srChildren = document.createElement('div'); + const srChildren = document.createElement('div'); setClassAttr(srChildren,'SRChildren'); - for (var c=0; c - + - - + + mi-malloc: Using the library + - + + @@ -29,20 +31,16 @@
    - + - -
    -
    mi-malloc -  1.7/2.0 +
    +
    mi-malloc 1.8/2.1
    +
    - -   + @@ -56,10 +54,15 @@
    - + +
    @@ -74,8 +77,8 @@
    @@ -88,24 +91,30 @@
    - +
    +
    +
    +
    +
    Loading...
    +
    Searching...
    +
    No Matches
    +
    +
    +
    -
    -
    -
    Using the library
    +
    +
    Using the library

    Build

    The preferred usage is including <mimalloc.h>, linking with the shared- or static library, and using the mi_malloc API exclusively for allocation. For example,

    gcc -o myprogram -lmimalloc myfile.c
    -

    mimalloc uses only safe OS calls (mmap and VirtualAlloc) and can co-exist with other allocators linked to the same program. If you use cmake, you can simply use:

    find_package(mimalloc 1.0 REQUIRED)
    +

    mimalloc uses only safe OS calls (mmap and VirtualAlloc) and can co-exist with other allocators linked to the same program. If you use cmake, you can simply use:

    find_package(mimalloc 2.1 REQUIRED)

    in your CMakeLists.txt to find a locally installed mimalloc. Then use either:

    target_link_libraries(myapp PUBLIC mimalloc)

    to link with the shared (dynamic) library, or:

    target_link_libraries(myapp PUBLIC mimalloc-static)

    to link with the static library. See test\CMakeLists.txt for an example.

    C++

    -

    For best performance in C++ programs, it is also recommended to override the global new and delete operators. For convience, mimalloc provides mimalloc-new-delete.h which does this for you – just include it in a single(!) source file in your project without linking to the mimalloc's library.

    +

    For best performance in C++ programs, it is also recommended to override the global new and delete operators. For convenience, mimalloc provides mimalloc-new-delete.h which does this for you – just include it in a single(!) source file in your project.

    In C++, mimalloc also provides the mi_stl_allocator struct which implements the std::allocator interface. For example:

    std::vector<some_struct, mi_stl_allocator<some_struct>> vec;
    vec.push_back(some_struct());

    Statistics

    @@ -148,7 +157,7 @@

    C++

    diff --git a/src/dashbls/depends/mimalloc/ide/vs2017/mimalloc-override-test.vcxproj b/src/dashbls/depends/mimalloc/ide/vs2017/mimalloc-override-test.vcxproj deleted file mode 100644 index faaa00e35477..000000000000 --- a/src/dashbls/depends/mimalloc/ide/vs2017/mimalloc-override-test.vcxproj +++ /dev/null @@ -1,190 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - 15.0 - {FEF7868F-750E-4C21-A04D-22707CC66879} - mimalloc-override-test - 10.0.17134.0 - mimalloc-override-test - - - - Application - true - v141 - - - Application - false - v141 - true - - - Application - true - v141 - - - Application - false - v141 - true - - - - - - - - - - - - - - - - - - - - - $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - - - $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - - - $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - - - $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - - - - Level3 - Disabled - true - true - ..\..\include - MultiThreadedDebugDLL - false - Default - false - - - Console - kernel32.lib;%(AdditionalDependencies) - - - - - - - - - - Level3 - Disabled - true - true - ..\..\include - MultiThreadedDebugDLL - Sync - Default - false - - - Console - - - kernel32.lib;%(AdditionalDependencies) - - - - - - - - - - Level3 - MaxSpeed - true - true - true - true - ..\..\include - _MBCS;%(PreprocessorDefinitions);NDEBUG - MultiThreadedDLL - - - true - true - Console - kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - - - - - - - - - Level3 - MaxSpeed - true - true - true - true - ..\..\include - _MBCS;%(PreprocessorDefinitions);NDEBUG - MultiThreadedDLL - - - true - true - Console - - - kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - - - - - - - - - {abb5eae7-b3e6-432e-b636-333449892ea7} - - - - - - - - - \ No newline at end of file diff --git a/src/dashbls/depends/mimalloc/ide/vs2017/mimalloc-override-test.vcxproj.filters b/src/dashbls/depends/mimalloc/ide/vs2017/mimalloc-override-test.vcxproj.filters deleted file mode 100644 index eb5e70b7c25b..000000000000 --- a/src/dashbls/depends/mimalloc/ide/vs2017/mimalloc-override-test.vcxproj.filters +++ /dev/null @@ -1,22 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;hm;inl;inc;ipp;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Source Files - - - \ No newline at end of file diff --git a/src/dashbls/depends/mimalloc/ide/vs2017/mimalloc-override.vcxproj b/src/dashbls/depends/mimalloc/ide/vs2017/mimalloc-override.vcxproj deleted file mode 100644 index a87b69ac6887..000000000000 --- a/src/dashbls/depends/mimalloc/ide/vs2017/mimalloc-override.vcxproj +++ /dev/null @@ -1,256 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - 15.0 - {ABB5EAE7-B3E6-432E-B636-333449892EA7} - mimalloc-override - 10.0.17134.0 - mimalloc-override - - - - DynamicLibrary - true - v141 - - - DynamicLibrary - false - v141 - - - DynamicLibrary - true - v141 - - - DynamicLibrary - false - v141 - - - - - - - - - - - - - - - - - - - - - $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - .dll - mimalloc-override - - - $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - .dll - mimalloc-override - - - $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - .dll - mimalloc-override - - - $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - .dll - mimalloc-override - - - - Level3 - Disabled - true - true - ../../include - _CRT_SECURE_NO_WARNINGS;MI_SHARED_LIB;MI_SHARED_LIB_EXPORT;MI_MALLOC_OVERRIDE;%(PreprocessorDefinitions); - MultiThreadedDebugDLL - false - Default - - - $(ProjectDir)\..\..\bin\mimalloc-redirect32.lib;%(AdditionalDependencies) - - - - - Default - false - - - COPY /Y $(ProjectDir)..\..\bin\mimalloc-redirect32.dll $(OutputPath) - - - Copy mimalloc-redirect32.dll to the output directory - - - - - Level3 - Disabled - true - true - ../../include - _CRT_SECURE_NO_WARNINGS;MI_SHARED_LIB;MI_SHARED_LIB_EXPORT;MI_MALLOC_OVERRIDE;%(PreprocessorDefinitions); - MultiThreadedDebugDLL - false - Default - - - $(ProjectDir)\..\..\bin\mimalloc-redirect.lib;bcrypt.lib;%(AdditionalDependencies) - - - - - Default - false - - - COPY /Y $(ProjectDir)..\..\bin\mimalloc-redirect.dll $(OutputPath) - - - copy mimalloc-redirect.dll to the output directory - - - - - Level3 - MaxSpeed - true - true - true - ../../include - _CRT_SECURE_NO_WARNINGS;MI_SHARED_LIB;MI_SHARED_LIB_EXPORT;MI_MALLOC_OVERRIDE;%(PreprocessorDefinitions);NDEBUG - AssemblyAndSourceCode - $(IntDir) - false - MultiThreadedDLL - Default - false - - - true - true - $(ProjectDir)\..\..\bin\mimalloc-redirect32.lib;%(AdditionalDependencies) - - - Default - false - - - COPY /Y $(ProjectDir)..\..\bin\mimalloc-redirect32.dll $(OutputPath) - - - Copy mimalloc-redirect32.dll to the output directory - - - - - Level3 - MaxSpeed - true - true - true - ../../include - _CRT_SECURE_NO_WARNINGS;MI_SHARED_LIB;MI_SHARED_LIB_EXPORT;MI_MALLOC_OVERRIDE;%(PreprocessorDefinitions);NDEBUG - AssemblyAndSourceCode - $(IntDir) - false - MultiThreadedDLL - Default - false - - - true - true - $(ProjectDir)\..\..\bin\mimalloc-redirect.lib;bcrypt.lib;%(AdditionalDependencies) - - - Default - false - - - COPY /Y $(ProjectDir)..\..\bin\mimalloc-redirect.dll $(OutputPath) - - - copy mimalloc-redirect.dll to the output directory - - - - - - - - - - - - - - false - false - false - false - - - true - true - true - true - - - - - - - - - - - true - true - true - true - - - - - - - - - - - \ No newline at end of file diff --git a/src/dashbls/depends/mimalloc/ide/vs2017/mimalloc-override.vcxproj.filters b/src/dashbls/depends/mimalloc/ide/vs2017/mimalloc-override.vcxproj.filters deleted file mode 100644 index d01f9311f199..000000000000 --- a/src/dashbls/depends/mimalloc/ide/vs2017/mimalloc-override.vcxproj.filters +++ /dev/null @@ -1,86 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;hm;inl;inc;ipp;xsd - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - \ No newline at end of file diff --git a/src/dashbls/depends/mimalloc/ide/vs2017/mimalloc-test-stress.vcxproj b/src/dashbls/depends/mimalloc/ide/vs2017/mimalloc-test-stress.vcxproj deleted file mode 100644 index b8267d0b39b2..000000000000 --- a/src/dashbls/depends/mimalloc/ide/vs2017/mimalloc-test-stress.vcxproj +++ /dev/null @@ -1,159 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - 15.0 - {FEF7958F-750E-4C21-A04D-22707CC66878} - mimalloc-test-stress - 10.0.17134.0 - mimalloc-test-stress - - - - Application - true - v141 - - - Application - false - v141 - true - - - Application - true - v141 - - - Application - false - v141 - true - - - - - - - - - - - - - - - - - - - - - $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - - - $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - - - $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - - - $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - - - - Level3 - Disabled - true - true - ..\..\include - - - Console - - - - - Level3 - Disabled - true - true - ..\..\include - - - Console - - - - - Level3 - MaxSpeed - true - true - true - true - ..\..\include - %(PreprocessorDefinitions);NDEBUG - - - true - true - Console - - - - - Level3 - MaxSpeed - true - true - true - true - ..\..\include - %(PreprocessorDefinitions);NDEBUG - - - true - true - Console - - - - - false - false - false - false - - - - - {abb5eae7-b3e6-432e-b636-333449892ea6} - - - - - - \ No newline at end of file diff --git a/src/dashbls/depends/mimalloc/ide/vs2017/mimalloc-test-stress.vcxproj.filters b/src/dashbls/depends/mimalloc/ide/vs2017/mimalloc-test-stress.vcxproj.filters deleted file mode 100644 index 7c5239e8271c..000000000000 --- a/src/dashbls/depends/mimalloc/ide/vs2017/mimalloc-test-stress.vcxproj.filters +++ /dev/null @@ -1,22 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;hm;inl;inc;ipp;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Source Files - - - \ No newline at end of file diff --git a/src/dashbls/depends/mimalloc/ide/vs2017/mimalloc-test.vcxproj b/src/dashbls/depends/mimalloc/ide/vs2017/mimalloc-test.vcxproj deleted file mode 100644 index 27c7bb6ea44c..000000000000 --- a/src/dashbls/depends/mimalloc/ide/vs2017/mimalloc-test.vcxproj +++ /dev/null @@ -1,158 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - 15.0 - {FEF7858F-750E-4C21-A04D-22707CC66878} - mimalloctest - 10.0.17134.0 - mimalloc-test - - - - Application - true - v141 - - - Application - false - v141 - true - - - Application - true - v141 - - - Application - false - v141 - true - - - - - - - - - - - - - - - - - - - - - $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - - - $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - - - $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - - - $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - - - - Level3 - Disabled - true - true - ..\..\include - stdcpp17 - - - Console - - - - - Level3 - Disabled - true - true - ..\..\include - stdcpp17 - - - Console - - - - - Level3 - MaxSpeed - true - true - true - true - ..\..\include - _MBCS;%(PreprocessorDefinitions);NDEBUG - stdcpp17 - - - true - true - Console - - - - - Level3 - MaxSpeed - true - true - true - true - ..\..\include - _MBCS;%(PreprocessorDefinitions);NDEBUG - stdcpp17 - - - true - true - Console - - - - - {abb5eae7-b3e6-432e-b636-333449892ea6} - - - - - - - - - \ No newline at end of file diff --git a/src/dashbls/depends/mimalloc/ide/vs2017/mimalloc-test.vcxproj.filters b/src/dashbls/depends/mimalloc/ide/vs2017/mimalloc-test.vcxproj.filters deleted file mode 100644 index fca75e1c3023..000000000000 --- a/src/dashbls/depends/mimalloc/ide/vs2017/mimalloc-test.vcxproj.filters +++ /dev/null @@ -1,22 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;hm;inl;inc;ipp;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Source Files - - - \ No newline at end of file diff --git a/src/dashbls/depends/mimalloc/ide/vs2017/mimalloc.sln b/src/dashbls/depends/mimalloc/ide/vs2017/mimalloc.sln deleted file mode 100644 index aeab6b88fc35..000000000000 --- a/src/dashbls/depends/mimalloc/ide/vs2017/mimalloc.sln +++ /dev/null @@ -1,71 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.28010.2016 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mimalloc", "mimalloc.vcxproj", "{ABB5EAE7-B3E6-432E-B636-333449892EA6}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mimalloc-test", "mimalloc-test.vcxproj", "{FEF7858F-750E-4C21-A04D-22707CC66878}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mimalloc-override", "mimalloc-override.vcxproj", "{ABB5EAE7-B3E6-432E-B636-333449892EA7}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mimalloc-override-test", "mimalloc-override-test.vcxproj", "{FEF7868F-750E-4C21-A04D-22707CC66879}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mimalloc-test-stress", "mimalloc-test-stress.vcxproj", "{FEF7958F-750E-4C21-A04D-22707CC66878}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Release|x64 = Release|x64 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Debug|x64.ActiveCfg = Debug|x64 - {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Debug|x64.Build.0 = Debug|x64 - {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Debug|x86.ActiveCfg = Debug|Win32 - {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Debug|x86.Build.0 = Debug|Win32 - {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Release|x64.ActiveCfg = Release|x64 - {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Release|x64.Build.0 = Release|x64 - {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Release|x86.ActiveCfg = Release|Win32 - {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Release|x86.Build.0 = Release|Win32 - {FEF7858F-750E-4C21-A04D-22707CC66878}.Debug|x64.ActiveCfg = Debug|x64 - {FEF7858F-750E-4C21-A04D-22707CC66878}.Debug|x64.Build.0 = Debug|x64 - {FEF7858F-750E-4C21-A04D-22707CC66878}.Debug|x86.ActiveCfg = Debug|Win32 - {FEF7858F-750E-4C21-A04D-22707CC66878}.Debug|x86.Build.0 = Debug|Win32 - {FEF7858F-750E-4C21-A04D-22707CC66878}.Release|x64.ActiveCfg = Release|x64 - {FEF7858F-750E-4C21-A04D-22707CC66878}.Release|x64.Build.0 = Release|x64 - {FEF7858F-750E-4C21-A04D-22707CC66878}.Release|x86.ActiveCfg = Release|Win32 - {FEF7858F-750E-4C21-A04D-22707CC66878}.Release|x86.Build.0 = Release|Win32 - {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Debug|x64.ActiveCfg = Debug|x64 - {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Debug|x64.Build.0 = Debug|x64 - {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Debug|x86.ActiveCfg = Debug|Win32 - {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Debug|x86.Build.0 = Debug|Win32 - {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Release|x64.ActiveCfg = Release|x64 - {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Release|x64.Build.0 = Release|x64 - {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Release|x86.ActiveCfg = Release|Win32 - {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Release|x86.Build.0 = Release|Win32 - {FEF7868F-750E-4C21-A04D-22707CC66879}.Debug|x64.ActiveCfg = Debug|x64 - {FEF7868F-750E-4C21-A04D-22707CC66879}.Debug|x64.Build.0 = Debug|x64 - {FEF7868F-750E-4C21-A04D-22707CC66879}.Debug|x86.ActiveCfg = Debug|Win32 - {FEF7868F-750E-4C21-A04D-22707CC66879}.Debug|x86.Build.0 = Debug|Win32 - {FEF7868F-750E-4C21-A04D-22707CC66879}.Release|x64.ActiveCfg = Release|x64 - {FEF7868F-750E-4C21-A04D-22707CC66879}.Release|x64.Build.0 = Release|x64 - {FEF7868F-750E-4C21-A04D-22707CC66879}.Release|x86.ActiveCfg = Release|Win32 - {FEF7868F-750E-4C21-A04D-22707CC66879}.Release|x86.Build.0 = Release|Win32 - {FEF7958F-750E-4C21-A04D-22707CC66878}.Debug|x64.ActiveCfg = Debug|x64 - {FEF7958F-750E-4C21-A04D-22707CC66878}.Debug|x64.Build.0 = Debug|x64 - {FEF7958F-750E-4C21-A04D-22707CC66878}.Debug|x86.ActiveCfg = Debug|Win32 - {FEF7958F-750E-4C21-A04D-22707CC66878}.Debug|x86.Build.0 = Debug|Win32 - {FEF7958F-750E-4C21-A04D-22707CC66878}.Release|x64.ActiveCfg = Release|x64 - {FEF7958F-750E-4C21-A04D-22707CC66878}.Release|x64.Build.0 = Release|x64 - {FEF7958F-750E-4C21-A04D-22707CC66878}.Release|x86.ActiveCfg = Release|Win32 - {FEF7958F-750E-4C21-A04D-22707CC66878}.Release|x86.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {4297F93D-486A-4243-995F-7D32F59AE82A} - EndGlobalSection -EndGlobal diff --git a/src/dashbls/depends/mimalloc/ide/vs2017/mimalloc.vcxproj b/src/dashbls/depends/mimalloc/ide/vs2017/mimalloc.vcxproj deleted file mode 100644 index 41fb77c1bf23..000000000000 --- a/src/dashbls/depends/mimalloc/ide/vs2017/mimalloc.vcxproj +++ /dev/null @@ -1,262 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - 15.0 - {ABB5EAE7-B3E6-432E-B636-333449892EA6} - mimalloc - 10.0.17134.0 - mimalloc - - - - StaticLibrary - true - v141 - - - StaticLibrary - false - v141 - true - - - StaticLibrary - true - v141 - - - StaticLibrary - false - v141 - true - - - - - - - - - - - - - - - - - - - - - $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - .lib - mimalloc-static - - - $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - .lib - mimalloc-static - - - $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - .lib - mimalloc-static - - - $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - .lib - mimalloc-static - - - false - - - false - - - false - - - false - - - - Level3 - Disabled - true - true - ../../include - _CRT_SECURE_NO_WARNINGS;MI_DEBUG=3;%(PreprocessorDefinitions); - CompileAsC - false - stdcpp17 - - - - - - - - - - - Level4 - Disabled - true - true - ../../include - _CRT_SECURE_NO_WARNINGS;MI_DEBUG=3;%(PreprocessorDefinitions); - CompileAsC - false - stdcpp17 - - - - - - - - - - - - - - - - - - - Level3 - MaxSpeed - true - true - ../../include - _CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions);NDEBUG - AssemblyAndSourceCode - $(IntDir) - false - false - Default - CompileAsC - true - - - true - true - - - - - - - - - - - Level4 - MaxSpeed - true - true - ../../include - _CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions);NDEBUG - AssemblyAndSourceCode - $(IntDir) - false - false - Default - CompileAsC - true - - - true - true - - - - - - - - - - - - - - - - - false - false - false - false - - - true - true - true - true - - - true - true - true - true - - - - - - - - - - true - true - true - true - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/dashbls/depends/mimalloc/ide/vs2017/mimalloc.vcxproj.filters b/src/dashbls/depends/mimalloc/ide/vs2017/mimalloc.vcxproj.filters deleted file mode 100644 index 054176452686..000000000000 --- a/src/dashbls/depends/mimalloc/ide/vs2017/mimalloc.vcxproj.filters +++ /dev/null @@ -1,92 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;hm;inl;inc;ipp;xsd - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - \ No newline at end of file diff --git a/src/dashbls/depends/mimalloc/ide/vs2019/mimalloc-override-test.vcxproj b/src/dashbls/depends/mimalloc/ide/vs2019/mimalloc-override-test.vcxproj deleted file mode 100644 index 7a9202f1b1b6..000000000000 --- a/src/dashbls/depends/mimalloc/ide/vs2019/mimalloc-override-test.vcxproj +++ /dev/null @@ -1,190 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - 15.0 - {FEF7868F-750E-4C21-A04D-22707CC66879} - mimalloc-override-test - 10.0 - mimalloc-override-test - - - - Application - true - v142 - - - Application - false - v142 - true - - - Application - true - v142 - - - Application - false - v142 - true - - - - - - - - - - - - - - - - - - - - - $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - - - $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - - - $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - - - $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - - - - Level3 - Disabled - true - true - ..\..\include - MultiThreadedDebugDLL - Sync - Default - false - - - Console - kernel32.lib;%(AdditionalDependencies) - - - - - - - - - - Level3 - Disabled - true - true - ..\..\include - MultiThreadedDebugDLL - Sync - Default - false - - - Console - - - kernel32.lib;%(AdditionalDependencies) - - - - - - - - - - Level3 - MaxSpeed - true - true - true - true - ..\..\include - _MBCS;%(PreprocessorDefinitions);NDEBUG - MultiThreadedDLL - - - true - true - Console - kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - - - - - - - - - Level3 - MaxSpeed - true - true - true - true - ..\..\include - _MBCS;%(PreprocessorDefinitions);NDEBUG - MultiThreadedDLL - - - true - true - Console - - - kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - - - - - - - - - - - - {abb5eae7-b3e6-432e-b636-333449892ea7} - - - - - - \ No newline at end of file diff --git a/src/dashbls/depends/mimalloc/ide/vs2019/mimalloc-override.vcxproj b/src/dashbls/depends/mimalloc/ide/vs2019/mimalloc-override.vcxproj deleted file mode 100644 index 4136e574a83c..000000000000 --- a/src/dashbls/depends/mimalloc/ide/vs2019/mimalloc-override.vcxproj +++ /dev/null @@ -1,256 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - 15.0 - {ABB5EAE7-B3E6-432E-B636-333449892EA7} - mimalloc-override - 10.0 - mimalloc-override - - - - DynamicLibrary - true - v142 - - - DynamicLibrary - false - v142 - - - DynamicLibrary - true - v142 - - - DynamicLibrary - false - v142 - - - - - - - - - - - - - - - - - - - - - $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - .dll - mimalloc-override - - - $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - .dll - mimalloc-override - - - $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - .dll - mimalloc-override - - - $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - .dll - mimalloc-override - - - - Level3 - Disabled - true - true - ../../include - MI_SHARED_LIB;MI_SHARED_LIB_EXPORT;MI_MALLOC_OVERRIDE;%(PreprocessorDefinitions); - MultiThreadedDebugDLL - false - Default - - - $(ProjectDir)\..\..\bin\mimalloc-redirect32.lib;%(AdditionalDependencies) - - - - - Default - false - - - COPY /Y $(ProjectDir)..\..\bin\mimalloc-redirect32.dll $(OutputPath) - - - Copy mimalloc-redirect32.dll to the output directory - - - - - Level3 - Disabled - true - true - ../../include - MI_DEBUG=3;MI_SHARED_LIB;MI_SHARED_LIB_EXPORT;MI_MALLOC_OVERRIDE;%(PreprocessorDefinitions); - MultiThreadedDebugDLL - false - Default - - - $(ProjectDir)\..\..\bin\mimalloc-redirect.lib;%(AdditionalDependencies) - - - - - Default - false - - - COPY /Y $(ProjectDir)..\..\bin\mimalloc-redirect.dll $(OutputPath) - - - copy mimalloc-redirect.dll to the output directory - - - - - Level3 - MaxSpeed - true - true - true - ../../include - MI_SHARED_LIB;MI_SHARED_LIB_EXPORT;MI_MALLOC_OVERRIDE;%(PreprocessorDefinitions);NDEBUG - AssemblyAndSourceCode - $(IntDir) - false - MultiThreadedDLL - Default - false - - - true - true - $(ProjectDir)\..\..\bin\mimalloc-redirect32.lib;%(AdditionalDependencies) - - - Default - false - - - COPY /Y $(ProjectDir)..\..\bin\mimalloc-redirect32.dll $(OutputPath) - - - Copy mimalloc-redirect32.dll to the output directory - - - - - Level3 - MaxSpeed - true - true - true - ../../include - MI_SHARED_LIB;MI_SHARED_LIB_EXPORT;MI_MALLOC_OVERRIDE;%(PreprocessorDefinitions);NDEBUG - AssemblyAndSourceCode - $(IntDir) - false - MultiThreadedDLL - Default - false - - - true - true - $(ProjectDir)\..\..\bin\mimalloc-redirect.lib;%(AdditionalDependencies) - - - Default - false - - - COPY /Y $(ProjectDir)..\..\bin\mimalloc-redirect.dll $(OutputPath) - - - copy mimalloc-redirect.dll to the output directory - - - - - - - - - - - - - - false - false - false - false - - - true - true - true - true - - - - - - - - - - - true - true - true - true - - - - - - - - - - - \ No newline at end of file diff --git a/src/dashbls/depends/mimalloc/ide/vs2019/mimalloc-override.vcxproj.filters b/src/dashbls/depends/mimalloc/ide/vs2019/mimalloc-override.vcxproj.filters deleted file mode 100644 index d6b7b5a966df..000000000000 --- a/src/dashbls/depends/mimalloc/ide/vs2019/mimalloc-override.vcxproj.filters +++ /dev/null @@ -1,84 +0,0 @@ - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - {f1fccf27-17b9-42dd-ba51-6070baff85c6} - - - {39cb7e38-69d0-43fb-8406-6a0f7cefc3b4} - - - \ No newline at end of file diff --git a/src/dashbls/depends/mimalloc/ide/vs2019/mimalloc-test-api.vcxproj b/src/dashbls/depends/mimalloc/ide/vs2019/mimalloc-test-api.vcxproj deleted file mode 100644 index 812a9cb1163c..000000000000 --- a/src/dashbls/depends/mimalloc/ide/vs2019/mimalloc-test-api.vcxproj +++ /dev/null @@ -1,155 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - 15.0 - {FFF7958F-750E-4C21-A04D-22707CC66878} - mimalloc-test-api - 10.0 - mimalloc-test-api - - - - Application - true - v142 - - - Application - false - v142 - true - - - Application - true - v142 - - - Application - false - v142 - true - - - - - - - - - - - - - - - - - - - - - $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - - - $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - - - $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - - - $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - - - - Level3 - Disabled - true - true - ..\..\include - - - Console - - - - - Level3 - Disabled - true - true - ..\..\include - - - Console - - - - - Level3 - MaxSpeed - true - true - true - true - ..\..\include - %(PreprocessorDefinitions);NDEBUG - - - true - true - Console - - - - - Level3 - MaxSpeed - true - true - true - true - ..\..\include - %(PreprocessorDefinitions);NDEBUG - - - true - true - Console - - - - - - - - - {abb5eae7-b3e6-432e-b636-333449892ea6} - - - - - - diff --git a/src/dashbls/depends/mimalloc/ide/vs2019/mimalloc-test-stress.vcxproj b/src/dashbls/depends/mimalloc/ide/vs2019/mimalloc-test-stress.vcxproj deleted file mode 100644 index ef7ab3575a96..000000000000 --- a/src/dashbls/depends/mimalloc/ide/vs2019/mimalloc-test-stress.vcxproj +++ /dev/null @@ -1,159 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - 15.0 - {FEF7958F-750E-4C21-A04D-22707CC66878} - mimalloc-test-stress - 10.0 - mimalloc-test-stress - - - - Application - true - v142 - - - Application - false - v142 - true - - - Application - true - v142 - - - Application - false - v142 - true - - - - - - - - - - - - - - - - - - - - - $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - - - $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - - - $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - - - $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - - - - Level3 - Disabled - true - true - ..\..\include - - - Console - - - - - Level3 - Disabled - true - true - ..\..\include - - - Console - - - - - Level3 - MaxSpeed - true - true - true - true - ..\..\include - %(PreprocessorDefinitions);NDEBUG - - - true - true - Console - - - - - Level3 - MaxSpeed - true - true - true - true - ..\..\include - %(PreprocessorDefinitions);NDEBUG - - - true - true - Console - - - - - false - false - false - false - - - - - {abb5eae7-b3e6-432e-b636-333449892ea6} - - - - - - \ No newline at end of file diff --git a/src/dashbls/depends/mimalloc/ide/vs2019/mimalloc-test.vcxproj b/src/dashbls/depends/mimalloc/ide/vs2019/mimalloc-test.vcxproj deleted file mode 100644 index 13af6ab4953b..000000000000 --- a/src/dashbls/depends/mimalloc/ide/vs2019/mimalloc-test.vcxproj +++ /dev/null @@ -1,158 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - 15.0 - {FEF7858F-750E-4C21-A04D-22707CC66878} - mimalloctest - 10.0 - mimalloc-test - - - - Application - true - v142 - - - Application - false - v142 - true - - - Application - true - v142 - - - Application - false - v142 - true - - - - - - - - - - - - - - - - - - - - - $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - - - $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - - - $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - - - $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - - - - Level3 - Disabled - true - true - ..\..\include - stdcpp17 - - - Console - - - - - Level3 - Disabled - true - true - ..\..\include - stdcpp17 - - - Console - - - - - Level3 - MaxSpeed - true - true - true - true - ..\..\include - _MBCS;%(PreprocessorDefinitions);NDEBUG - stdcpp17 - - - true - true - Console - - - - - Level3 - MaxSpeed - true - true - true - true - ..\..\include - _MBCS;%(PreprocessorDefinitions);NDEBUG - stdcpp17 - - - true - true - Console - - - - - {abb5eae7-b3e6-432e-b636-333449892ea6} - - - - - - - - - \ No newline at end of file diff --git a/src/dashbls/depends/mimalloc/ide/vs2019/mimalloc.sln b/src/dashbls/depends/mimalloc/ide/vs2019/mimalloc.sln deleted file mode 100644 index fcb938a4fe2a..000000000000 --- a/src/dashbls/depends/mimalloc/ide/vs2019/mimalloc.sln +++ /dev/null @@ -1,81 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.29709.97 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mimalloc", "mimalloc.vcxproj", "{ABB5EAE7-B3E6-432E-B636-333449892EA6}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mimalloc-test", "mimalloc-test.vcxproj", "{FEF7858F-750E-4C21-A04D-22707CC66878}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mimalloc-override", "mimalloc-override.vcxproj", "{ABB5EAE7-B3E6-432E-B636-333449892EA7}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mimalloc-override-test", "mimalloc-override-test.vcxproj", "{FEF7868F-750E-4C21-A04D-22707CC66879}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mimalloc-test-stress", "mimalloc-test-stress.vcxproj", "{FEF7958F-750E-4C21-A04D-22707CC66878}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mimalloc-test-api", "mimalloc-test-api.vcxproj", "{FFF7958F-750E-4C21-A04D-22707CC66878}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Release|x64 = Release|x64 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Debug|x64.ActiveCfg = Debug|x64 - {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Debug|x64.Build.0 = Debug|x64 - {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Debug|x86.ActiveCfg = Debug|Win32 - {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Debug|x86.Build.0 = Debug|Win32 - {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Release|x64.ActiveCfg = Release|x64 - {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Release|x64.Build.0 = Release|x64 - {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Release|x86.ActiveCfg = Release|Win32 - {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Release|x86.Build.0 = Release|Win32 - {FEF7858F-750E-4C21-A04D-22707CC66878}.Debug|x64.ActiveCfg = Debug|x64 - {FEF7858F-750E-4C21-A04D-22707CC66878}.Debug|x64.Build.0 = Debug|x64 - {FEF7858F-750E-4C21-A04D-22707CC66878}.Debug|x86.ActiveCfg = Debug|Win32 - {FEF7858F-750E-4C21-A04D-22707CC66878}.Debug|x86.Build.0 = Debug|Win32 - {FEF7858F-750E-4C21-A04D-22707CC66878}.Release|x64.ActiveCfg = Release|x64 - {FEF7858F-750E-4C21-A04D-22707CC66878}.Release|x64.Build.0 = Release|x64 - {FEF7858F-750E-4C21-A04D-22707CC66878}.Release|x86.ActiveCfg = Release|Win32 - {FEF7858F-750E-4C21-A04D-22707CC66878}.Release|x86.Build.0 = Release|Win32 - {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Debug|x64.ActiveCfg = Debug|x64 - {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Debug|x64.Build.0 = Debug|x64 - {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Debug|x86.ActiveCfg = Debug|Win32 - {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Debug|x86.Build.0 = Debug|Win32 - {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Release|x64.ActiveCfg = Release|x64 - {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Release|x64.Build.0 = Release|x64 - {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Release|x86.ActiveCfg = Release|Win32 - {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Release|x86.Build.0 = Release|Win32 - {FEF7868F-750E-4C21-A04D-22707CC66879}.Debug|x64.ActiveCfg = Debug|x64 - {FEF7868F-750E-4C21-A04D-22707CC66879}.Debug|x64.Build.0 = Debug|x64 - {FEF7868F-750E-4C21-A04D-22707CC66879}.Debug|x86.ActiveCfg = Debug|Win32 - {FEF7868F-750E-4C21-A04D-22707CC66879}.Debug|x86.Build.0 = Debug|Win32 - {FEF7868F-750E-4C21-A04D-22707CC66879}.Release|x64.ActiveCfg = Release|x64 - {FEF7868F-750E-4C21-A04D-22707CC66879}.Release|x64.Build.0 = Release|x64 - {FEF7868F-750E-4C21-A04D-22707CC66879}.Release|x86.ActiveCfg = Release|Win32 - {FEF7868F-750E-4C21-A04D-22707CC66879}.Release|x86.Build.0 = Release|Win32 - {FEF7958F-750E-4C21-A04D-22707CC66878}.Debug|x64.ActiveCfg = Debug|x64 - {FEF7958F-750E-4C21-A04D-22707CC66878}.Debug|x64.Build.0 = Debug|x64 - {FEF7958F-750E-4C21-A04D-22707CC66878}.Debug|x86.ActiveCfg = Debug|Win32 - {FEF7958F-750E-4C21-A04D-22707CC66878}.Debug|x86.Build.0 = Debug|Win32 - {FEF7958F-750E-4C21-A04D-22707CC66878}.Release|x64.ActiveCfg = Release|x64 - {FEF7958F-750E-4C21-A04D-22707CC66878}.Release|x64.Build.0 = Release|x64 - {FEF7958F-750E-4C21-A04D-22707CC66878}.Release|x86.ActiveCfg = Release|Win32 - {FEF7958F-750E-4C21-A04D-22707CC66878}.Release|x86.Build.0 = Release|Win32 - {FFF7958F-750E-4C21-A04D-22707CC66878}.Debug|x64.ActiveCfg = Debug|x64 - {FFF7958F-750E-4C21-A04D-22707CC66878}.Debug|x64.Build.0 = Debug|x64 - {FFF7958F-750E-4C21-A04D-22707CC66878}.Debug|x86.ActiveCfg = Debug|Win32 - {FFF7958F-750E-4C21-A04D-22707CC66878}.Debug|x86.Build.0 = Debug|Win32 - {FFF7958F-750E-4C21-A04D-22707CC66878}.Release|x64.ActiveCfg = Release|x64 - {FFF7958F-750E-4C21-A04D-22707CC66878}.Release|x64.Build.0 = Release|x64 - {FFF7958F-750E-4C21-A04D-22707CC66878}.Release|x86.ActiveCfg = Release|Win32 - {FFF7958F-750E-4C21-A04D-22707CC66878}.Release|x86.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {4297F93D-486A-4243-995F-7D32F59AE82A} - EndGlobalSection -EndGlobal diff --git a/src/dashbls/depends/mimalloc/ide/vs2019/mimalloc.vcxproj b/src/dashbls/depends/mimalloc/ide/vs2019/mimalloc.vcxproj deleted file mode 100644 index 9f967d94464b..000000000000 --- a/src/dashbls/depends/mimalloc/ide/vs2019/mimalloc.vcxproj +++ /dev/null @@ -1,254 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - 15.0 - {ABB5EAE7-B3E6-432E-B636-333449892EA6} - mimalloc - 10.0 - mimalloc - - - - StaticLibrary - true - v142 - - - StaticLibrary - false - v142 - true - - - StaticLibrary - true - v142 - - - StaticLibrary - false - v142 - true - - - - - - - - - - - - - - - - - - - - - $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - .lib - mimalloc-static - - - $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - .lib - mimalloc-static - - - $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - .lib - mimalloc-static - - - $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - .lib - mimalloc-static - - - - Level4 - Disabled - true - true - ../../include - MI_DEBUG=3;%(PreprocessorDefinitions); - CompileAsCpp - false - Default - - - - - - - - - - - Level4 - Disabled - true - true - ../../include - MI_DEBUG=3;%(PreprocessorDefinitions); - CompileAsCpp - false - Default - - - - - - - - - - - - - - - - - - - Level4 - MaxSpeed - true - true - ../../include - %(PreprocessorDefinitions);NDEBUG - AssemblyAndSourceCode - $(IntDir) - false - false - Default - CompileAsCpp - true - Default - - - true - true - - - - - - - - - - - Level4 - MaxSpeed - true - true - ../../include - %(PreprocessorDefinitions);NDEBUG - AssemblyAndSourceCode - $(IntDir) - false - false - Default - CompileAsCpp - true - Default - - - true - true - - - - - - - - - - - - - - - - - false - false - false - false - - - true - true - true - true - - - true - true - true - true - - - - - - false - - - - - - true - true - true - true - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/dashbls/depends/mimalloc/ide/vs2019/mimalloc.vcxproj.filters b/src/dashbls/depends/mimalloc/ide/vs2019/mimalloc.vcxproj.filters deleted file mode 100644 index 92be7cb47e81..000000000000 --- a/src/dashbls/depends/mimalloc/ide/vs2019/mimalloc.vcxproj.filters +++ /dev/null @@ -1,87 +0,0 @@ - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Source Files - - - - - {2b556b10-f559-4b2d-896e-142652adbf0c} - - - {852a14ae-6dde-4e95-8077-ca705e97e5af} - - - \ No newline at end of file diff --git a/src/dashbls/depends/mimalloc/ide/vs2022/mimalloc-lib.vcxproj b/src/dashbls/depends/mimalloc/ide/vs2022/mimalloc-lib.vcxproj new file mode 100644 index 000000000000..b4bf013e0890 --- /dev/null +++ b/src/dashbls/depends/mimalloc/ide/vs2022/mimalloc-lib.vcxproj @@ -0,0 +1,500 @@ + + + + + Debug + ARM64 + + + Debug + ARM64EC + + + Debug + Win32 + + + Release + ARM64 + + + Release + ARM64EC + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {ABB5EAE7-B3E6-432E-B636-333449892EA6} + mimalloc-lib + 10.0 + mimalloc-lib + + + + StaticLibrary + true + v143 + + + StaticLibrary + false + v143 + true + + + StaticLibrary + true + v143 + + + StaticLibrary + true + v143 + + + StaticLibrary + true + v143 + + + StaticLibrary + false + v143 + true + + + StaticLibrary + false + v143 + true + + + StaticLibrary + false + v143 + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ + $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + .lib + mimalloc + + + $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ + $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + .lib + mimalloc + + + $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ + $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + .lib + mimalloc + + + $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ + $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + .lib + mimalloc + + + $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ + $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + .lib + mimalloc + + + $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ + $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + .lib + mimalloc + + + $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ + $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + .lib + mimalloc + + + $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ + $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + .lib + mimalloc + + + false + + + + Level4 + Disabled + true + Default + ../../include + MI_DEBUG=3;%(PreprocessorDefinitions); + CompileAsCpp + false + stdcpp20 + /Zc:__cplusplus %(AdditionalOptions) + + + + + + + + + + + Level4 + Disabled + true + Default + ../../include + MI_DEBUG=3;MI_GUARDED=0;%(PreprocessorDefinitions); + CompileAsCpp + false + stdcpp20 + /Zc:__cplusplus %(AdditionalOptions) + + + + + + + + + + + + + + + + + + + Level4 + Disabled + true + Default + ../../include + MI_DEBUG=3;MI_GUARDED=0;%(PreprocessorDefinitions); + CompileAsCpp + false + stdcpp20 + /Zc:__cplusplus %(AdditionalOptions) + + + + + + + + + + + + + + + + + + + Level4 + Disabled + true + Default + ../../include + MI_DEBUG=3;MI_GUARDED=0;%(PreprocessorDefinitions); + CompileAsCpp + false + stdcpp20 + /Zc:__cplusplus %(AdditionalOptions) + + + + + + + + + + + + + + + + + + + Level4 + MaxSpeed + true + Default + ../../include + %(PreprocessorDefinitions);NDEBUG + AssemblyAndSourceCode + $(IntDir) + false + false + Default + CompileAsCpp + true + stdcpp20 + /Zc:__cplusplus %(AdditionalOptions) + + + true + true + + + + + + + + + + + Level4 + MaxSpeed + true + Default + ../../include + %(PreprocessorDefinitions);NDEBUG + AssemblyAndSourceCode + $(IntDir) + false + false + Default + CompileAsCpp + true + stdcpp20 + AdvancedVectorExtensions2 + /Zc:__cplusplus %(AdditionalOptions) + + + true + true + + + + + + + + + + + + + + + + + Level4 + MaxSpeed + true + Default + ../../include + %(PreprocessorDefinitions);NDEBUG + AssemblyAndSourceCode + $(IntDir) + false + false + Default + CompileAsCpp + true + stdcpp20 + CPUExtensionRequirementsARMv81 + Sync + /Zc:__cplusplus %(AdditionalOptions) + + + true + true + + + + + + + + + + + + + + + + + Level4 + MaxSpeed + true + Default + ../../include + %(PreprocessorDefinitions);NDEBUG + AssemblyAndSourceCode + $(IntDir) + false + false + Default + CompileAsCpp + true + stdcpp20 + CPUExtensionRequirementsARMv81 + Sync + /Zc:__cplusplus %(AdditionalOptions) + + + true + true + + + + + + + + + + + + + + + + + false + false + false + false + false + false + false + false + + + true + true + true + true + true + true + true + true + + + + + + + false + false + false + + + true + true + true + true + true + true + true + true + + + + + + + + true + true + true + true + true + true + true + true + + + + true + true + true + true + true + true + true + true + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/dashbls/depends/mimalloc/ide/vs2022/mimalloc-lib.vcxproj.filters b/src/dashbls/depends/mimalloc/ide/vs2022/mimalloc-lib.vcxproj.filters new file mode 100644 index 000000000000..6825f113fd69 --- /dev/null +++ b/src/dashbls/depends/mimalloc/ide/vs2022/mimalloc-lib.vcxproj.filters @@ -0,0 +1,108 @@ + + + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + + + {1430490c-e711-4ace-a1b8-36f4d5105873} + + + {461c78ef-04b0-44d1-a0ca-7d488abaa592} + + + \ No newline at end of file diff --git a/src/dashbls/depends/mimalloc/ide/vs2022/mimalloc-override-dll.vcxproj b/src/dashbls/depends/mimalloc/ide/vs2022/mimalloc-override-dll.vcxproj new file mode 100644 index 000000000000..556d7926b766 --- /dev/null +++ b/src/dashbls/depends/mimalloc/ide/vs2022/mimalloc-override-dll.vcxproj @@ -0,0 +1,515 @@ + + + + + Debug + ARM64 + + + Debug + ARM64EC + + + Debug + Win32 + + + Release + ARM64 + + + Release + ARM64EC + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {ABB5EAE7-B3E6-432E-B636-333449892EA7} + mimalloc-override-dll + 10.0 + mimalloc-override-dll + + + + DynamicLibrary + true + v143 + + + DynamicLibrary + false + v143 + + + DynamicLibrary + true + v143 + + + DynamicLibrary + true + v143 + + + DynamicLibrary + true + v143 + + + DynamicLibrary + false + v143 + + + DynamicLibrary + false + v143 + + + DynamicLibrary + false + v143 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ + $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + .dll + mimalloc + + + $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ + $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + .dll + mimalloc + + + $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ + $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + .dll + mimalloc + + + $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ + $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + .dll + mimalloc + + + $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ + $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + .dll + mimalloc + + + $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ + $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + .dll + mimalloc + + + $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ + $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + .dll + mimalloc + + + $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ + $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + .dll + mimalloc + + + false + + + + Level3 + Disabled + true + true + ../../include + MI_SHARED_LIB;MI_SHARED_LIB_EXPORT;MI_MALLOC_OVERRIDE;%(PreprocessorDefinitions); + MultiThreadedDebugDLL + false + CompileAsCpp + /Zc:__cplusplus %(AdditionalOptions) + + + $(ProjectDir)\..\..\bin\mimalloc-redirect32.lib;%(AdditionalDependencies) + + + + + Default + false + $(OutDir)$(TargetName).dll.lib + $(OutDir)$(TargetName).dll.pdb + + + COPY /Y "$(ProjectDir)..\..\bin\mimalloc-redirect32.dll" "$(OutputPath)" + + + Copy mimalloc-redirect32.dll to the output directory + + + + + Level3 + Disabled + true + true + ../../include + MI_DEBUG=4;MI_SHARED_LIB;MI_SHARED_LIB_EXPORT;MI_MALLOC_OVERRIDE;%(PreprocessorDefinitions); + MultiThreadedDebugDLL + false + CompileAsCpp + /Zc:__cplusplus %(AdditionalOptions) + + + $(ProjectDir)\..\..\bin\mimalloc-redirect.lib;%(AdditionalDependencies) + + + + + Default + false + $(OutDir)$(TargetName).dll.lib + $(OutDir)$(TargetName).dll.pdb + + + COPY /Y "$(ProjectDir)..\..\bin\mimalloc-redirect.dll" "$(OutputPath)" + + + copy mimalloc-redirect.dll to the output directory + + + + + Level3 + Disabled + true + true + ../../include + MI_DEBUG=4;MI_SHARED_LIB;MI_SHARED_LIB_EXPORT;MI_MALLOC_OVERRIDE;%(PreprocessorDefinitions); + MultiThreadedDebugDLL + false + CompileAsCpp + /Zc:__cplusplus %(AdditionalOptions) + + + $(ProjectDir)\..\..\bin\mimalloc-redirect-arm64.lib;%(AdditionalDependencies) + + + + + Default + false + $(OutDir)$(TargetName).dll.lib + $(OutDir)$(TargetName).dll.pdb + + + COPY /Y "$(ProjectDir)..\..\bin\mimalloc-redirect-arm64.dll" "$(OutputPath)" + + + copy mimalloc-redirect-arm64.dll to the output directory + + + + + Level3 + Disabled + true + true + ../../include + MI_DEBUG=4;MI_SHARED_LIB;MI_SHARED_LIB_EXPORT;MI_MALLOC_OVERRIDE;%(PreprocessorDefinitions); + MultiThreadedDebugDLL + false + CompileAsCpp + /Zc:__cplusplus %(AdditionalOptions) + + + $(ProjectDir)\..\..\bin\mimalloc-redirect-arm64ec.lib;%(AdditionalDependencies) + + + + + Default + false + $(OutDir)$(TargetName).dll.lib + $(OutDir)$(TargetName).dll.pdb + + + COPY /Y "$(ProjectDir)..\..\bin\mimalloc-redirect-arm64ec.dll" "$(OutputPath)" + + + copy mimalloc-redirect-arm64ec.dll to the output directory + + + + + Level3 + MaxSpeed + true + true + true + ../../include + MI_SHARED_LIB;MI_SHARED_LIB_EXPORT;MI_MALLOC_OVERRIDE;%(PreprocessorDefinitions);NDEBUG + AssemblyAndSourceCode + $(IntDir) + false + MultiThreadedDLL + CompileAsCpp + false + /Zc:__cplusplus %(AdditionalOptions) + + + true + true + $(ProjectDir)\..\..\bin\mimalloc-redirect32.lib;%(AdditionalDependencies) + + + Default + false + $(OutDir)$(TargetName).dll.lib + $(OutDir)$(TargetName).dll.pdb + + + COPY /Y "$(ProjectDir)..\..\bin\mimalloc-redirect32.dll" "$(OutputPath)" + + + Copy mimalloc-redirect32.dll to the output directory + + + + + Level3 + MaxSpeed + true + true + true + ../../include + MI_SHARED_LIB;MI_SHARED_LIB_EXPORT;MI_MALLOC_OVERRIDE;%(PreprocessorDefinitions);NDEBUG + AssemblyAndSourceCode + $(IntDir) + false + MultiThreadedDLL + CompileAsCpp + false + /Zc:__cplusplus %(AdditionalOptions) + + + true + true + $(ProjectDir)\..\..\bin\mimalloc-redirect.lib;%(AdditionalDependencies) + + + Default + false + $(OutDir)$(TargetName).dll.lib + $(OutDir)$(TargetName).dll.pdb + + + COPY /Y "$(ProjectDir)..\..\bin\mimalloc-redirect.dll" "$(OutputPath)" + + + copy mimalloc-redirect.dll to the output directory + + + + + Level3 + MaxSpeed + true + true + true + ../../include + MI_SHARED_LIB;MI_SHARED_LIB_EXPORT;MI_MALLOC_OVERRIDE;%(PreprocessorDefinitions);NDEBUG + AssemblyAndSourceCode + $(IntDir) + false + MultiThreadedDLL + CompileAsCpp + false + CPUExtensionRequirementsARMv81 + /Zc:__cplusplus %(AdditionalOptions) + + + true + true + $(ProjectDir)\..\..\bin\mimalloc-redirect-arm64.lib;%(AdditionalDependencies) + + + Default + false + $(OutDir)$(TargetName).dll.lib + $(OutDir)$(TargetName).dll.pdb + + + COPY /Y "$(ProjectDir)..\..\bin\mimalloc-redirect-arm64.dll" "$(OutputPath)" + + + copy mimalloc-redirect-arm64.dll to the output directory + + + + + Level3 + MaxSpeed + true + true + true + ../../include + MI_SHARED_LIB;MI_SHARED_LIB_EXPORT;MI_MALLOC_OVERRIDE;%(PreprocessorDefinitions);NDEBUG + AssemblyAndSourceCode + $(IntDir) + false + MultiThreadedDLL + CompileAsCpp + false + CPUExtensionRequirementsARMv81 + /Zc:__cplusplus %(AdditionalOptions) + + + true + true + $(ProjectDir)\..\..\bin\mimalloc-redirect-arm64ec.lib;%(AdditionalDependencies) + + + Default + false + $(OutDir)$(TargetName).dll.lib + $(OutDir)$(TargetName).dll.pdb + + + COPY /Y "$(ProjectDir)..\..\bin\mimalloc-redirect-arm64ec.dll" "$(OutputPath)" + + + copy mimalloc-redirect-arm64ec.dll to the output directory + + + + + + + + + + + + + + + + + + false + false + false + false + false + false + false + false + + + true + true + true + true + true + true + true + true + + + + + + + + true + true + true + true + true + true + true + true + + + + + + + + true + true + true + true + true + true + true + true + + + + + true + true + true + true + true + true + true + true + + + + + + + + + \ No newline at end of file diff --git a/src/dashbls/depends/mimalloc/ide/vs2022/mimalloc-override-dll.vcxproj.filters b/src/dashbls/depends/mimalloc/ide/vs2022/mimalloc-override-dll.vcxproj.filters new file mode 100644 index 000000000000..ebcf545af7e2 --- /dev/null +++ b/src/dashbls/depends/mimalloc/ide/vs2022/mimalloc-override-dll.vcxproj.filters @@ -0,0 +1,108 @@ + + + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + + + {262c6c21-e270-4ba6-bd63-4ac999307e4e} + + + {94b40bdc-a741-45dd-81aa-c05fabcd2970} + + + \ No newline at end of file diff --git a/src/dashbls/depends/mimalloc/ide/vs2022/mimalloc-override-test-dep.vcxproj b/src/dashbls/depends/mimalloc/ide/vs2022/mimalloc-override-test-dep.vcxproj new file mode 100644 index 000000000000..c1b89690e448 --- /dev/null +++ b/src/dashbls/depends/mimalloc/ide/vs2022/mimalloc-override-test-dep.vcxproj @@ -0,0 +1,355 @@ + + + + + Debug + ARM64 + + + Debug + ARM64EC + + + Debug + Win32 + + + Release + ARM64 + + + Release + ARM64EC + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {FEF7869F-750E-4C21-A04D-22707CC66879} + mimalloc-test-override-dep + 10.0 + mimalloc-test-override-dep + + + + DynamicLibrary + true + v143 + + + DynamicLibrary + false + v143 + true + + + DynamicLibrary + true + v143 + + + DynamicLibrary + true + v143 + + + DynamicLibrary + true + v143 + + + DynamicLibrary + false + v143 + true + + + DynamicLibrary + false + v143 + true + + + DynamicLibrary + false + v143 + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ + $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + + + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ + $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + + + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ + $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + + + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ + $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + + + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ + $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + + + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ + $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + + + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ + $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + + + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ + $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + + + false + + + + Level3 + Disabled + true + true + ..\..\include + MultiThreadedDebugDLL + Sync + Default + false + + + Console + kernel32.lib;%(AdditionalDependencies) + + + + + + + + + + Level3 + Disabled + true + true + ..\..\include + MultiThreadedDebugDLL + Sync + Default + false + + + Console + + + kernel32.lib;%(AdditionalDependencies) + + + + + + + + + + Level3 + Disabled + true + true + ..\..\include + MultiThreadedDebugDLL + Sync + Default + false + + + Console + + + kernel32.lib;%(AdditionalDependencies) + + + + + + + + + + Level3 + Disabled + true + true + ..\..\include + MultiThreadedDebugDLL + Sync + Default + false + + + Console + + + kernel32.lib;%(AdditionalDependencies) + + + + + + + + + + Level3 + MaxSpeed + true + true + true + true + ..\..\include + _MBCS;%(PreprocessorDefinitions);NDEBUG + MultiThreadedDLL + + + true + true + Console + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + + + Level3 + MaxSpeed + true + true + true + true + ..\..\include + _MBCS;%(PreprocessorDefinitions);NDEBUG + MultiThreadedDLL + + + true + true + Console + + + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + + + Level3 + MaxSpeed + true + true + true + true + ..\..\include + _MBCS;%(PreprocessorDefinitions);NDEBUG + MultiThreadedDLL + + + true + true + Console + + + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + + + Level3 + MaxSpeed + true + true + true + true + ..\..\include + _MBCS;%(PreprocessorDefinitions);NDEBUG + MultiThreadedDLL + + + true + true + Console + + + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/dashbls/depends/mimalloc/ide/vs2022/mimalloc-override-test.vcxproj b/src/dashbls/depends/mimalloc/ide/vs2022/mimalloc-override-test.vcxproj index a3c56f7badce..1dc2cee71b60 100644 --- a/src/dashbls/depends/mimalloc/ide/vs2022/mimalloc-override-test.vcxproj +++ b/src/dashbls/depends/mimalloc/ide/vs2022/mimalloc-override-test.vcxproj @@ -1,10 +1,26 @@ + + Debug + ARM64 + + + Debug + ARM64EC + Debug Win32 + + Release + ARM64 + + + Release + ARM64EC + Release Win32 @@ -23,7 +39,7 @@ {FEF7868F-750E-4C21-A04D-22707CC66879} mimalloc-override-test 10.0 - mimalloc-override-test + mimalloc-test-override @@ -42,12 +58,34 @@ true v143 + + Application + true + v143 + + + Application + true + v143 + Application false v143 true + + Application + false + v143 + true + + + Application + false + v143 + true + @@ -62,9 +100,21 @@ + + + + + + + + + + + + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ @@ -78,10 +128,29 @@ $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ + $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + + + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ + $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ + $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + + + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ + $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + + + false + Level3 @@ -128,6 +197,54 @@ + + + Level3 + Disabled + true + true + ..\..\include + MultiThreadedDebugDLL + Sync + Default + false + + + Console + + + kernel32.lib;%(AdditionalDependencies) + + + + + + + + + + Level3 + Disabled + true + true + ..\..\include + MultiThreadedDebugDLL + Sync + Default + false + + + Console + + + kernel32.lib;%(AdditionalDependencies) + + + + + + + Level3 @@ -176,13 +293,66 @@ + + + Level3 + MaxSpeed + true + true + true + true + ..\..\include + _MBCS;%(PreprocessorDefinitions);NDEBUG + MultiThreadedDLL + + + true + true + Console + + + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + + + Level3 + MaxSpeed + true + true + true + true + ..\..\include + _MBCS;%(PreprocessorDefinitions);NDEBUG + MultiThreadedDLL + + + true + true + Console + + + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + - + {abb5eae7-b3e6-432e-b636-333449892ea7} + + {fef7869f-750e-4c21-a04d-22707cc66879} + diff --git a/src/dashbls/depends/mimalloc/ide/vs2022/mimalloc-override.vcxproj b/src/dashbls/depends/mimalloc/ide/vs2022/mimalloc-override.vcxproj deleted file mode 100644 index f22d54a4edf4..000000000000 --- a/src/dashbls/depends/mimalloc/ide/vs2022/mimalloc-override.vcxproj +++ /dev/null @@ -1,257 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - 15.0 - {ABB5EAE7-B3E6-432E-B636-333449892EA7} - mimalloc-override - 10.0 - mimalloc-override - - - - DynamicLibrary - true - v143 - - - DynamicLibrary - false - v143 - - - DynamicLibrary - true - v143 - - - DynamicLibrary - false - v143 - - - - - - - - - - - - - - - - - - - - - $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - .dll - mimalloc-override - - - $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - .dll - mimalloc-override - - - $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - .dll - mimalloc-override - - - $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - .dll - mimalloc-override - - - - Level3 - Disabled - true - true - ../../include - MI_SHARED_LIB;MI_SHARED_LIB_EXPORT;MI_MALLOC_OVERRIDE;%(PreprocessorDefinitions); - MultiThreadedDebugDLL - false - Default - - - $(ProjectDir)\..\..\bin\mimalloc-redirect32.lib;%(AdditionalDependencies) - - - - - Default - false - - - COPY /Y $(ProjectDir)..\..\bin\mimalloc-redirect32.dll $(OutputPath) - - - Copy mimalloc-redirect32.dll to the output directory - - - - - Level3 - Disabled - true - true - ../../include - MI_DEBUG=3;MI_SHARED_LIB;MI_SHARED_LIB_EXPORT;MI_MALLOC_OVERRIDE;%(PreprocessorDefinitions); - MultiThreadedDebugDLL - false - Default - - - $(ProjectDir)\..\..\bin\mimalloc-redirect.lib;%(AdditionalDependencies) - - - - - Default - false - - - COPY /Y $(ProjectDir)..\..\bin\mimalloc-redirect.dll $(OutputPath) - - - copy mimalloc-redirect.dll to the output directory - - - - - Level3 - MaxSpeed - true - true - true - ../../include - MI_SHARED_LIB;MI_SHARED_LIB_EXPORT;MI_MALLOC_OVERRIDE;%(PreprocessorDefinitions);NDEBUG - AssemblyAndSourceCode - $(IntDir) - false - MultiThreadedDLL - Default - false - - - true - true - $(ProjectDir)\..\..\bin\mimalloc-redirect32.lib;%(AdditionalDependencies) - - - Default - false - - - COPY /Y $(ProjectDir)..\..\bin\mimalloc-redirect32.dll $(OutputPath) - - - Copy mimalloc-redirect32.dll to the output directory - - - - - Level3 - MaxSpeed - true - true - true - ../../include - MI_SHARED_LIB;MI_SHARED_LIB_EXPORT;MI_MALLOC_OVERRIDE;%(PreprocessorDefinitions);NDEBUG - AssemblyAndSourceCode - $(IntDir) - false - MultiThreadedDLL - Default - false - - - true - true - $(ProjectDir)\..\..\bin\mimalloc-redirect.lib;%(AdditionalDependencies) - - - Default - false - - - COPY /Y $(ProjectDir)..\..\bin\mimalloc-redirect.dll $(OutputPath) - - - copy mimalloc-redirect.dll to the output directory - - - - - - - - - - - - - - - false - false - false - false - - - true - true - true - true - - - - - - - - - - - true - true - true - true - - - - - - - - - - - \ No newline at end of file diff --git a/src/dashbls/depends/mimalloc/ide/vs2022/mimalloc-test-api.vcxproj b/src/dashbls/depends/mimalloc/ide/vs2022/mimalloc-test-api.vcxproj index 6023c251fbe2..440693a2162e 100644 --- a/src/dashbls/depends/mimalloc/ide/vs2022/mimalloc-test-api.vcxproj +++ b/src/dashbls/depends/mimalloc/ide/vs2022/mimalloc-test-api.vcxproj @@ -1,10 +1,26 @@ + + Debug + ARM64 + + + Debug + ARM64EC + Debug Win32 + + Release + ARM64 + + + Release + ARM64EC + Release Win32 @@ -42,12 +58,34 @@ true v143 + + Application + true + v143 + + + Application + true + v143 + Application false v143 true + + Application + false + v143 + true + + + Application + false + v143 + true + @@ -62,9 +100,21 @@ + + + + + + + + + + + + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ @@ -78,10 +128,29 @@ $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ + $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + + + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ + $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ + $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + + + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ + $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + + + false + Level3 @@ -106,6 +175,30 @@ Console + + + Level3 + Disabled + true + true + ..\..\include + + + Console + + + + + Level3 + Disabled + true + true + ..\..\include + + + Console + + Level3 @@ -140,12 +233,59 @@ Console + + + Level3 + MaxSpeed + true + true + true + true + ..\..\include + %(PreprocessorDefinitions);NDEBUG + + + true + true + Console + + + + + Level3 + MaxSpeed + true + true + true + true + ..\..\include + %(PreprocessorDefinitions);NDEBUG + + + true + true + Console + + + + true + true + true + true + true + true + true + true + + false + false + false - + {abb5eae7-b3e6-432e-b636-333449892ea6} diff --git a/src/dashbls/depends/mimalloc/ide/vs2022/mimalloc-test-stress.vcxproj b/src/dashbls/depends/mimalloc/ide/vs2022/mimalloc-test-stress.vcxproj index c7e820dfecf2..128a4ff6cf69 100644 --- a/src/dashbls/depends/mimalloc/ide/vs2022/mimalloc-test-stress.vcxproj +++ b/src/dashbls/depends/mimalloc/ide/vs2022/mimalloc-test-stress.vcxproj @@ -1,10 +1,26 @@ + + Debug + ARM64 + + + Debug + ARM64EC + Debug Win32 + + Release + ARM64 + + + Release + ARM64EC + Release Win32 @@ -42,12 +58,34 @@ true v143 + + Application + true + v143 + + + Application + true + v143 + Application false v143 true + + Application + false + v143 + true + + + Application + false + v143 + true + @@ -62,9 +100,21 @@ + + + + + + + + + + + + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ @@ -78,10 +128,29 @@ $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ + $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + + + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ + $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ + $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + + + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ + $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + + + false + Level3 @@ -106,6 +175,30 @@ Console + + + Level3 + Disabled + true + true + ..\..\include + + + Console + + + + + Level3 + Disabled + true + true + ..\..\include + + + Console + + Level3 @@ -140,17 +233,57 @@ Console + + + Level3 + MaxSpeed + true + true + true + true + ..\..\include + %(PreprocessorDefinitions);NDEBUG + CPUExtensionRequirementsARMv81 + + + true + true + Console + + + + + Level3 + MaxSpeed + true + true + true + true + ..\..\include + %(PreprocessorDefinitions);NDEBUG + CPUExtensionRequirementsARMv81 + + + true + true + Console + + false false + false + false false false + false + false - - {abb5eae7-b3e6-432e-b636-333449892ea6} + + {abb5eae7-b3e6-432e-b636-333449892ea7} diff --git a/src/dashbls/depends/mimalloc/ide/vs2022/mimalloc-test.vcxproj b/src/dashbls/depends/mimalloc/ide/vs2022/mimalloc-test.vcxproj index 506dd7d457e8..1e41fca115cc 100644 --- a/src/dashbls/depends/mimalloc/ide/vs2022/mimalloc-test.vcxproj +++ b/src/dashbls/depends/mimalloc/ide/vs2022/mimalloc-test.vcxproj @@ -1,10 +1,26 @@ + + Debug + ARM64 + + + Debug + ARM64EC + Debug Win32 + + Release + ARM64 + + + Release + ARM64EC + Release Win32 @@ -23,7 +39,7 @@ {FEF7858F-750E-4C21-A04D-22707CC66878} mimalloctest 10.0 - mimalloc-test + mimalloc-test-static @@ -42,12 +58,34 @@ true v143 + + Application + true + v143 + + + Application + true + v143 + Application false v143 true + + Application + false + v143 + true + + + Application + false + v143 + true + @@ -62,9 +100,21 @@ + + + + + + + + + + + + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ @@ -78,10 +128,29 @@ $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ + $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + + + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ + $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ + $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + + + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ + $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + + + false + Level3 @@ -108,6 +177,32 @@ Console + + + Level3 + Disabled + true + true + ..\..\include + stdcpp17 + + + Console + + + + + Level3 + Disabled + true + true + ..\..\include + stdcpp17 + + + Console + + Level3 @@ -144,13 +239,49 @@ Console + + + Level3 + MaxSpeed + true + true + true + true + ..\..\include + _MBCS;%(PreprocessorDefinitions);NDEBUG + stdcpp17 + + + true + true + Console + + + + + Level3 + MaxSpeed + true + true + true + true + ..\..\include + _MBCS;%(PreprocessorDefinitions);NDEBUG + stdcpp17 + + + true + true + Console + + - - {abb5eae7-b3e6-432e-b636-333449892ea6} - + - + + {abb5eae7-b3e6-432e-b636-333449892ea6} + diff --git a/src/dashbls/depends/mimalloc/ide/vs2022/mimalloc.sln b/src/dashbls/depends/mimalloc/ide/vs2022/mimalloc.sln index fcb938a4fe2a..212b75155517 100644 --- a/src/dashbls/depends/mimalloc/ide/vs2022/mimalloc.sln +++ b/src/dashbls/depends/mimalloc/ide/vs2022/mimalloc.sln @@ -1,15 +1,17 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.29709.97 +# Visual Studio Version 17 +VisualStudioVersion = 17.12.35527.113 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mimalloc", "mimalloc.vcxproj", "{ABB5EAE7-B3E6-432E-B636-333449892EA6}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mimalloc-lib", "mimalloc-lib.vcxproj", "{ABB5EAE7-B3E6-432E-B636-333449892EA6}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mimalloc-test", "mimalloc-test.vcxproj", "{FEF7858F-750E-4C21-A04D-22707CC66878}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mimalloc-test-static", "mimalloc-test.vcxproj", "{FEF7858F-750E-4C21-A04D-22707CC66878}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mimalloc-override", "mimalloc-override.vcxproj", "{ABB5EAE7-B3E6-432E-B636-333449892EA7}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mimalloc-override-dll", "mimalloc-override-dll.vcxproj", "{ABB5EAE7-B3E6-432E-B636-333449892EA7}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mimalloc-override-test", "mimalloc-override-test.vcxproj", "{FEF7868F-750E-4C21-A04D-22707CC66879}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mimalloc-test-override-dep", "mimalloc-override-test-dep.vcxproj", "{FEF7869F-750E-4C21-A04D-22707CC66879}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mimalloc-test-override", "mimalloc-override-test.vcxproj", "{FEF7868F-750E-4C21-A04D-22707CC66879}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mimalloc-test-stress", "mimalloc-test-stress.vcxproj", "{FEF7958F-750E-4C21-A04D-22707CC66878}" EndProject @@ -17,56 +19,124 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mimalloc-test-api", "mimall EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|ARM64 = Debug|ARM64 + Debug|ARM64EC = Debug|ARM64EC Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 + Release|ARM64 = Release|ARM64 + Release|ARM64EC = Release|ARM64EC Release|x64 = Release|x64 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution + {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Debug|ARM64.Build.0 = Debug|ARM64 + {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Debug|ARM64EC.ActiveCfg = Debug|ARM64EC + {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Debug|ARM64EC.Build.0 = Debug|ARM64EC {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Debug|x64.ActiveCfg = Debug|x64 {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Debug|x64.Build.0 = Debug|x64 {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Debug|x86.ActiveCfg = Debug|Win32 {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Debug|x86.Build.0 = Debug|Win32 + {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Release|ARM64.ActiveCfg = Release|ARM64 + {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Release|ARM64.Build.0 = Release|ARM64 + {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Release|ARM64EC.ActiveCfg = Release|ARM64EC + {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Release|ARM64EC.Build.0 = Release|ARM64EC {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Release|x64.ActiveCfg = Release|x64 {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Release|x64.Build.0 = Release|x64 {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Release|x86.ActiveCfg = Release|Win32 {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Release|x86.Build.0 = Release|Win32 + {FEF7858F-750E-4C21-A04D-22707CC66878}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {FEF7858F-750E-4C21-A04D-22707CC66878}.Debug|ARM64.Build.0 = Debug|ARM64 + {FEF7858F-750E-4C21-A04D-22707CC66878}.Debug|ARM64EC.ActiveCfg = Debug|ARM64EC + {FEF7858F-750E-4C21-A04D-22707CC66878}.Debug|ARM64EC.Build.0 = Debug|ARM64EC {FEF7858F-750E-4C21-A04D-22707CC66878}.Debug|x64.ActiveCfg = Debug|x64 {FEF7858F-750E-4C21-A04D-22707CC66878}.Debug|x64.Build.0 = Debug|x64 {FEF7858F-750E-4C21-A04D-22707CC66878}.Debug|x86.ActiveCfg = Debug|Win32 {FEF7858F-750E-4C21-A04D-22707CC66878}.Debug|x86.Build.0 = Debug|Win32 + {FEF7858F-750E-4C21-A04D-22707CC66878}.Release|ARM64.ActiveCfg = Release|ARM64 + {FEF7858F-750E-4C21-A04D-22707CC66878}.Release|ARM64.Build.0 = Release|ARM64 + {FEF7858F-750E-4C21-A04D-22707CC66878}.Release|ARM64EC.ActiveCfg = Release|ARM64EC + {FEF7858F-750E-4C21-A04D-22707CC66878}.Release|ARM64EC.Build.0 = Release|ARM64EC {FEF7858F-750E-4C21-A04D-22707CC66878}.Release|x64.ActiveCfg = Release|x64 {FEF7858F-750E-4C21-A04D-22707CC66878}.Release|x64.Build.0 = Release|x64 {FEF7858F-750E-4C21-A04D-22707CC66878}.Release|x86.ActiveCfg = Release|Win32 {FEF7858F-750E-4C21-A04D-22707CC66878}.Release|x86.Build.0 = Release|Win32 + {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Debug|ARM64.Build.0 = Debug|ARM64 + {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Debug|ARM64EC.ActiveCfg = Debug|ARM64EC + {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Debug|ARM64EC.Build.0 = Debug|ARM64EC {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Debug|x64.ActiveCfg = Debug|x64 {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Debug|x64.Build.0 = Debug|x64 {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Debug|x86.ActiveCfg = Debug|Win32 {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Debug|x86.Build.0 = Debug|Win32 + {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Release|ARM64.ActiveCfg = Release|ARM64 + {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Release|ARM64.Build.0 = Release|ARM64 + {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Release|ARM64EC.ActiveCfg = Release|ARM64EC + {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Release|ARM64EC.Build.0 = Release|ARM64EC {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Release|x64.ActiveCfg = Release|x64 {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Release|x64.Build.0 = Release|x64 {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Release|x86.ActiveCfg = Release|Win32 {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Release|x86.Build.0 = Release|Win32 + {FEF7869F-750E-4C21-A04D-22707CC66879}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {FEF7869F-750E-4C21-A04D-22707CC66879}.Debug|ARM64.Build.0 = Debug|ARM64 + {FEF7869F-750E-4C21-A04D-22707CC66879}.Debug|ARM64EC.ActiveCfg = Debug|ARM64EC + {FEF7869F-750E-4C21-A04D-22707CC66879}.Debug|ARM64EC.Build.0 = Debug|ARM64EC + {FEF7869F-750E-4C21-A04D-22707CC66879}.Debug|x64.ActiveCfg = Debug|x64 + {FEF7869F-750E-4C21-A04D-22707CC66879}.Debug|x64.Build.0 = Debug|x64 + {FEF7869F-750E-4C21-A04D-22707CC66879}.Debug|x86.ActiveCfg = Debug|Win32 + {FEF7869F-750E-4C21-A04D-22707CC66879}.Debug|x86.Build.0 = Debug|Win32 + {FEF7869F-750E-4C21-A04D-22707CC66879}.Release|ARM64.ActiveCfg = Release|ARM64 + {FEF7869F-750E-4C21-A04D-22707CC66879}.Release|ARM64.Build.0 = Release|ARM64 + {FEF7869F-750E-4C21-A04D-22707CC66879}.Release|ARM64EC.ActiveCfg = Release|ARM64EC + {FEF7869F-750E-4C21-A04D-22707CC66879}.Release|ARM64EC.Build.0 = Release|ARM64EC + {FEF7869F-750E-4C21-A04D-22707CC66879}.Release|x64.ActiveCfg = Release|x64 + {FEF7869F-750E-4C21-A04D-22707CC66879}.Release|x64.Build.0 = Release|x64 + {FEF7869F-750E-4C21-A04D-22707CC66879}.Release|x86.ActiveCfg = Release|Win32 + {FEF7869F-750E-4C21-A04D-22707CC66879}.Release|x86.Build.0 = Release|Win32 + {FEF7868F-750E-4C21-A04D-22707CC66879}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {FEF7868F-750E-4C21-A04D-22707CC66879}.Debug|ARM64.Build.0 = Debug|ARM64 + {FEF7868F-750E-4C21-A04D-22707CC66879}.Debug|ARM64EC.ActiveCfg = Debug|ARM64EC + {FEF7868F-750E-4C21-A04D-22707CC66879}.Debug|ARM64EC.Build.0 = Debug|ARM64EC {FEF7868F-750E-4C21-A04D-22707CC66879}.Debug|x64.ActiveCfg = Debug|x64 {FEF7868F-750E-4C21-A04D-22707CC66879}.Debug|x64.Build.0 = Debug|x64 {FEF7868F-750E-4C21-A04D-22707CC66879}.Debug|x86.ActiveCfg = Debug|Win32 {FEF7868F-750E-4C21-A04D-22707CC66879}.Debug|x86.Build.0 = Debug|Win32 + {FEF7868F-750E-4C21-A04D-22707CC66879}.Release|ARM64.ActiveCfg = Release|ARM64 + {FEF7868F-750E-4C21-A04D-22707CC66879}.Release|ARM64.Build.0 = Release|ARM64 + {FEF7868F-750E-4C21-A04D-22707CC66879}.Release|ARM64EC.ActiveCfg = Release|ARM64EC + {FEF7868F-750E-4C21-A04D-22707CC66879}.Release|ARM64EC.Build.0 = Release|ARM64EC {FEF7868F-750E-4C21-A04D-22707CC66879}.Release|x64.ActiveCfg = Release|x64 {FEF7868F-750E-4C21-A04D-22707CC66879}.Release|x64.Build.0 = Release|x64 {FEF7868F-750E-4C21-A04D-22707CC66879}.Release|x86.ActiveCfg = Release|Win32 {FEF7868F-750E-4C21-A04D-22707CC66879}.Release|x86.Build.0 = Release|Win32 + {FEF7958F-750E-4C21-A04D-22707CC66878}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {FEF7958F-750E-4C21-A04D-22707CC66878}.Debug|ARM64.Build.0 = Debug|ARM64 + {FEF7958F-750E-4C21-A04D-22707CC66878}.Debug|ARM64EC.ActiveCfg = Debug|ARM64EC + {FEF7958F-750E-4C21-A04D-22707CC66878}.Debug|ARM64EC.Build.0 = Debug|ARM64EC {FEF7958F-750E-4C21-A04D-22707CC66878}.Debug|x64.ActiveCfg = Debug|x64 {FEF7958F-750E-4C21-A04D-22707CC66878}.Debug|x64.Build.0 = Debug|x64 {FEF7958F-750E-4C21-A04D-22707CC66878}.Debug|x86.ActiveCfg = Debug|Win32 {FEF7958F-750E-4C21-A04D-22707CC66878}.Debug|x86.Build.0 = Debug|Win32 + {FEF7958F-750E-4C21-A04D-22707CC66878}.Release|ARM64.ActiveCfg = Release|ARM64 + {FEF7958F-750E-4C21-A04D-22707CC66878}.Release|ARM64.Build.0 = Release|ARM64 + {FEF7958F-750E-4C21-A04D-22707CC66878}.Release|ARM64EC.ActiveCfg = Release|ARM64EC + {FEF7958F-750E-4C21-A04D-22707CC66878}.Release|ARM64EC.Build.0 = Release|ARM64EC {FEF7958F-750E-4C21-A04D-22707CC66878}.Release|x64.ActiveCfg = Release|x64 {FEF7958F-750E-4C21-A04D-22707CC66878}.Release|x64.Build.0 = Release|x64 {FEF7958F-750E-4C21-A04D-22707CC66878}.Release|x86.ActiveCfg = Release|Win32 {FEF7958F-750E-4C21-A04D-22707CC66878}.Release|x86.Build.0 = Release|Win32 + {FFF7958F-750E-4C21-A04D-22707CC66878}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {FFF7958F-750E-4C21-A04D-22707CC66878}.Debug|ARM64.Build.0 = Debug|ARM64 + {FFF7958F-750E-4C21-A04D-22707CC66878}.Debug|ARM64EC.ActiveCfg = Debug|ARM64EC + {FFF7958F-750E-4C21-A04D-22707CC66878}.Debug|ARM64EC.Build.0 = Debug|ARM64EC {FFF7958F-750E-4C21-A04D-22707CC66878}.Debug|x64.ActiveCfg = Debug|x64 {FFF7958F-750E-4C21-A04D-22707CC66878}.Debug|x64.Build.0 = Debug|x64 {FFF7958F-750E-4C21-A04D-22707CC66878}.Debug|x86.ActiveCfg = Debug|Win32 {FFF7958F-750E-4C21-A04D-22707CC66878}.Debug|x86.Build.0 = Debug|Win32 + {FFF7958F-750E-4C21-A04D-22707CC66878}.Release|ARM64.ActiveCfg = Release|ARM64 + {FFF7958F-750E-4C21-A04D-22707CC66878}.Release|ARM64.Build.0 = Release|ARM64 + {FFF7958F-750E-4C21-A04D-22707CC66878}.Release|ARM64EC.ActiveCfg = Release|ARM64EC + {FFF7958F-750E-4C21-A04D-22707CC66878}.Release|ARM64EC.Build.0 = Release|ARM64EC {FFF7958F-750E-4C21-A04D-22707CC66878}.Release|x64.ActiveCfg = Release|x64 {FFF7958F-750E-4C21-A04D-22707CC66878}.Release|x64.Build.0 = Release|x64 {FFF7958F-750E-4C21-A04D-22707CC66878}.Release|x86.ActiveCfg = Release|Win32 diff --git a/src/dashbls/depends/mimalloc/ide/vs2022/mimalloc.vcxproj b/src/dashbls/depends/mimalloc/ide/vs2022/mimalloc.vcxproj deleted file mode 100644 index 00aaaffabb29..000000000000 --- a/src/dashbls/depends/mimalloc/ide/vs2022/mimalloc.vcxproj +++ /dev/null @@ -1,255 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - 15.0 - {ABB5EAE7-B3E6-432E-B636-333449892EA6} - mimalloc - 10.0 - mimalloc - - - - StaticLibrary - true - v143 - - - StaticLibrary - false - v143 - true - - - StaticLibrary - true - v143 - - - StaticLibrary - false - v143 - true - - - - - - - - - - - - - - - - - - - - - $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - .lib - mimalloc-static - - - $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - .lib - mimalloc-static - - - $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - .lib - mimalloc-static - - - $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - .lib - mimalloc-static - - - - Level4 - Disabled - true - true - ../../include - MI_DEBUG=3;%(PreprocessorDefinitions); - CompileAsCpp - false - Default - - - - - - - - - - - Level4 - Disabled - true - true - ../../include - MI_DEBUG=3;%(PreprocessorDefinitions); - CompileAsCpp - false - stdcpp20 - - - - - - - - - - - - - - - - - - - Level4 - MaxSpeed - true - true - ../../include - %(PreprocessorDefinitions);NDEBUG - AssemblyAndSourceCode - $(IntDir) - false - false - Default - CompileAsCpp - true - Default - - - true - true - - - - - - - - - - - Level4 - MaxSpeed - true - true - ../../include - %(PreprocessorDefinitions);NDEBUG - AssemblyAndSourceCode - $(IntDir) - false - false - Default - CompileAsCpp - true - stdcpp20 - - - true - true - - - - - - - - - - - - - - - - - false - false - false - false - - - true - true - true - true - - - true - true - true - true - - - - - - false - - - - - - true - true - true - true - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/dashbls/depends/mimalloc/include/mimalloc-internal.h b/src/dashbls/depends/mimalloc/include/mimalloc-internal.h deleted file mode 100644 index 550b654338ad..000000000000 --- a/src/dashbls/depends/mimalloc/include/mimalloc-internal.h +++ /dev/null @@ -1,1093 +0,0 @@ -/* ---------------------------------------------------------------------------- -Copyright (c) 2018-2022, Microsoft Research, Daan Leijen -This is free software; you can redistribute it and/or modify it under the -terms of the MIT license. A copy of the license can be found in the file -"LICENSE" at the root of this distribution. ------------------------------------------------------------------------------*/ -#pragma once -#ifndef MIMALLOC_INTERNAL_H -#define MIMALLOC_INTERNAL_H - -#include "mimalloc-types.h" -#include "mimalloc-track.h" - -#if (MI_DEBUG>0) -#define mi_trace_message(...) _mi_trace_message(__VA_ARGS__) -#else -#define mi_trace_message(...) -#endif - -#define MI_CACHE_LINE 64 -#if defined(_MSC_VER) -#pragma warning(disable:4127) // suppress constant conditional warning (due to MI_SECURE paths) -#pragma warning(disable:26812) // unscoped enum warning -#define mi_decl_noinline __declspec(noinline) -#define mi_decl_thread __declspec(thread) -#define mi_decl_cache_align __declspec(align(MI_CACHE_LINE)) -#elif (defined(__GNUC__) && (__GNUC__ >= 3)) || defined(__clang__) // includes clang and icc -#define mi_decl_noinline __attribute__((noinline)) -#define mi_decl_thread __thread -#define mi_decl_cache_align __attribute__((aligned(MI_CACHE_LINE))) -#else -#define mi_decl_noinline -#define mi_decl_thread __thread // hope for the best :-) -#define mi_decl_cache_align -#endif - -#if defined(__EMSCRIPTEN__) && !defined(__wasi__) -#define __wasi__ -#endif - -#if defined(__cplusplus) -#define mi_decl_externc extern "C" -#else -#define mi_decl_externc -#endif - -#if !defined(_WIN32) && !defined(__wasi__) -#define MI_USE_PTHREADS -#include -#endif - -// "options.c" -void _mi_fputs(mi_output_fun* out, void* arg, const char* prefix, const char* message); -void _mi_fprintf(mi_output_fun* out, void* arg, const char* fmt, ...); -void _mi_warning_message(const char* fmt, ...); -void _mi_verbose_message(const char* fmt, ...); -void _mi_trace_message(const char* fmt, ...); -void _mi_options_init(void); -void _mi_error_message(int err, const char* fmt, ...); - -// random.c -void _mi_random_init(mi_random_ctx_t* ctx); -void _mi_random_split(mi_random_ctx_t* ctx, mi_random_ctx_t* new_ctx); -uintptr_t _mi_random_next(mi_random_ctx_t* ctx); -uintptr_t _mi_heap_random_next(mi_heap_t* heap); -uintptr_t _mi_os_random_weak(uintptr_t extra_seed); -static inline uintptr_t _mi_random_shuffle(uintptr_t x); - -// init.c -extern mi_decl_cache_align mi_stats_t _mi_stats_main; -extern mi_decl_cache_align const mi_page_t _mi_page_empty; -bool _mi_is_main_thread(void); -size_t _mi_current_thread_count(void); -bool _mi_preloading(void); // true while the C runtime is not ready - -// os.c -size_t _mi_os_page_size(void); -void _mi_os_init(void); // called from process init -void* _mi_os_alloc(size_t size, mi_stats_t* stats); // to allocate thread local data -void _mi_os_free(void* p, size_t size, mi_stats_t* stats); // to free thread local data - -bool _mi_os_protect(void* addr, size_t size); -bool _mi_os_unprotect(void* addr, size_t size); -bool _mi_os_commit(void* addr, size_t size, bool* is_zero, mi_stats_t* stats); -bool _mi_os_decommit(void* p, size_t size, mi_stats_t* stats); -bool _mi_os_reset(void* p, size_t size, mi_stats_t* stats); -// bool _mi_os_unreset(void* p, size_t size, bool* is_zero, mi_stats_t* stats); -size_t _mi_os_good_alloc_size(size_t size); -bool _mi_os_has_overcommit(void); - -// arena.c -void* _mi_arena_alloc_aligned(size_t size, size_t alignment, bool* commit, bool* large, bool* is_pinned, bool* is_zero, mi_arena_id_t req_arena_id, size_t* memid, mi_os_tld_t* tld); -void* _mi_arena_alloc(size_t size, bool* commit, bool* large, bool* is_pinned, bool* is_zero, mi_arena_id_t req_arena_id, size_t* memid, mi_os_tld_t* tld); -void _mi_arena_free(void* p, size_t size, size_t memid, bool is_committed, mi_os_tld_t* tld); -mi_arena_id_t _mi_arena_id_none(void); -bool _mi_arena_memid_is_suitable(size_t memid, mi_arena_id_t req_arena_id); - -// "segment-cache.c" -void* _mi_segment_cache_pop(size_t size, mi_commit_mask_t* commit_mask, mi_commit_mask_t* decommit_mask, bool* large, bool* is_pinned, bool* is_zero, mi_arena_id_t req_arena_id, size_t* memid, mi_os_tld_t* tld); -bool _mi_segment_cache_push(void* start, size_t size, size_t memid, const mi_commit_mask_t* commit_mask, const mi_commit_mask_t* decommit_mask, bool is_large, bool is_pinned, mi_os_tld_t* tld); -void _mi_segment_cache_collect(bool force, mi_os_tld_t* tld); -void _mi_segment_map_allocated_at(const mi_segment_t* segment); -void _mi_segment_map_freed_at(const mi_segment_t* segment); - -// "segment.c" -mi_page_t* _mi_segment_page_alloc(mi_heap_t* heap, size_t block_wsize, mi_segments_tld_t* tld, mi_os_tld_t* os_tld); -void _mi_segment_page_free(mi_page_t* page, bool force, mi_segments_tld_t* tld); -void _mi_segment_page_abandon(mi_page_t* page, mi_segments_tld_t* tld); -bool _mi_segment_try_reclaim_abandoned( mi_heap_t* heap, bool try_all, mi_segments_tld_t* tld); -void _mi_segment_thread_collect(mi_segments_tld_t* tld); -void _mi_segment_huge_page_free(mi_segment_t* segment, mi_page_t* page, mi_block_t* block); - -uint8_t* _mi_segment_page_start(const mi_segment_t* segment, const mi_page_t* page, size_t* page_size); // page start for any page -void _mi_abandoned_reclaim_all(mi_heap_t* heap, mi_segments_tld_t* tld); -void _mi_abandoned_await_readers(void); -void _mi_abandoned_collect(mi_heap_t* heap, bool force, mi_segments_tld_t* tld); - - - -// "page.c" -void* _mi_malloc_generic(mi_heap_t* heap, size_t size, bool zero) mi_attr_noexcept mi_attr_malloc; - -void _mi_page_retire(mi_page_t* page) mi_attr_noexcept; // free the page if there are no other pages with many free blocks -void _mi_page_unfull(mi_page_t* page); -void _mi_page_free(mi_page_t* page, mi_page_queue_t* pq, bool force); // free the page -void _mi_page_abandon(mi_page_t* page, mi_page_queue_t* pq); // abandon the page, to be picked up by another thread... -void _mi_heap_delayed_free_all(mi_heap_t* heap); -bool _mi_heap_delayed_free_partial(mi_heap_t* heap); -void _mi_heap_collect_retired(mi_heap_t* heap, bool force); - -void _mi_page_use_delayed_free(mi_page_t* page, mi_delayed_t delay, bool override_never); -bool _mi_page_try_use_delayed_free(mi_page_t* page, mi_delayed_t delay, bool override_never); -size_t _mi_page_queue_append(mi_heap_t* heap, mi_page_queue_t* pq, mi_page_queue_t* append); -void _mi_deferred_free(mi_heap_t* heap, bool force); - -void _mi_page_free_collect(mi_page_t* page,bool force); -void _mi_page_reclaim(mi_heap_t* heap, mi_page_t* page); // callback from segments - -size_t _mi_bin_size(uint8_t bin); // for stats -uint8_t _mi_bin(size_t size); // for stats - -// "heap.c" -void _mi_heap_destroy_pages(mi_heap_t* heap); -void _mi_heap_collect_abandon(mi_heap_t* heap); -void _mi_heap_set_default_direct(mi_heap_t* heap); -bool _mi_heap_memid_is_suitable(mi_heap_t* heap, size_t memid); - -// "stats.c" -void _mi_stats_done(mi_stats_t* stats); - -mi_msecs_t _mi_clock_now(void); -mi_msecs_t _mi_clock_end(mi_msecs_t start); -mi_msecs_t _mi_clock_start(void); - -// "alloc.c" -void* _mi_page_malloc(mi_heap_t* heap, mi_page_t* page, size_t size, bool zero) mi_attr_noexcept; // called from `_mi_malloc_generic` -void* _mi_heap_malloc_zero(mi_heap_t* heap, size_t size, bool zero) mi_attr_noexcept; -void* _mi_heap_realloc_zero(mi_heap_t* heap, void* p, size_t newsize, bool zero) mi_attr_noexcept; -mi_block_t* _mi_page_ptr_unalign(const mi_segment_t* segment, const mi_page_t* page, const void* p); -bool _mi_free_delayed_block(mi_block_t* block); - -#if MI_DEBUG>1 -bool _mi_page_is_valid(mi_page_t* page); -#endif - - -// ------------------------------------------------------ -// Branches -// ------------------------------------------------------ - -#if defined(__GNUC__) || defined(__clang__) -#define mi_unlikely(x) (__builtin_expect(!!(x),false)) -#define mi_likely(x) (__builtin_expect(!!(x),true)) -#elif (defined(__cplusplus) && (__cplusplus >= 202002L)) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L) -#define mi_unlikely(x) (x) [[unlikely]] -#define mi_likely(x) (x) [[likely]] -#else -#define mi_unlikely(x) (x) -#define mi_likely(x) (x) -#endif - -#ifndef __has_builtin -#define __has_builtin(x) 0 -#endif - - -/* ----------------------------------------------------------- - Error codes passed to `_mi_fatal_error` - All are recoverable but EFAULT is a serious error and aborts by default in secure mode. - For portability define undefined error codes using common Unix codes: - ------------------------------------------------------------ */ -#include -#ifndef EAGAIN // double free -#define EAGAIN (11) -#endif -#ifndef ENOMEM // out of memory -#define ENOMEM (12) -#endif -#ifndef EFAULT // corrupted free-list or meta-data -#define EFAULT (14) -#endif -#ifndef EINVAL // trying to free an invalid pointer -#define EINVAL (22) -#endif -#ifndef EOVERFLOW // count*size overflow -#define EOVERFLOW (75) -#endif - - -/* ----------------------------------------------------------- - Inlined definitions ------------------------------------------------------------ */ -#define MI_UNUSED(x) (void)(x) -#if (MI_DEBUG>0) -#define MI_UNUSED_RELEASE(x) -#else -#define MI_UNUSED_RELEASE(x) MI_UNUSED(x) -#endif - -#define MI_INIT4(x) x(),x(),x(),x() -#define MI_INIT8(x) MI_INIT4(x),MI_INIT4(x) -#define MI_INIT16(x) MI_INIT8(x),MI_INIT8(x) -#define MI_INIT32(x) MI_INIT16(x),MI_INIT16(x) -#define MI_INIT64(x) MI_INIT32(x),MI_INIT32(x) -#define MI_INIT128(x) MI_INIT64(x),MI_INIT64(x) -#define MI_INIT256(x) MI_INIT128(x),MI_INIT128(x) - - -// Is `x` a power of two? (0 is considered a power of two) -static inline bool _mi_is_power_of_two(uintptr_t x) { - return ((x & (x - 1)) == 0); -} - -// Is a pointer aligned? -static inline bool _mi_is_aligned(void* p, size_t alignment) { - mi_assert_internal(alignment != 0); - return (((uintptr_t)p % alignment) == 0); -} - -// Align upwards -static inline uintptr_t _mi_align_up(uintptr_t sz, size_t alignment) { - mi_assert_internal(alignment != 0); - uintptr_t mask = alignment - 1; - if ((alignment & mask) == 0) { // power of two? - return ((sz + mask) & ~mask); - } - else { - return (((sz + mask)/alignment)*alignment); - } -} - -// Align downwards -static inline uintptr_t _mi_align_down(uintptr_t sz, size_t alignment) { - mi_assert_internal(alignment != 0); - uintptr_t mask = alignment - 1; - if ((alignment & mask) == 0) { // power of two? - return (sz & ~mask); - } - else { - return ((sz / alignment) * alignment); - } -} - -// Divide upwards: `s <= _mi_divide_up(s,d)*d < s+d`. -static inline uintptr_t _mi_divide_up(uintptr_t size, size_t divider) { - mi_assert_internal(divider != 0); - return (divider == 0 ? size : ((size + divider - 1) / divider)); -} - -// Is memory zero initialized? -static inline bool mi_mem_is_zero(void* p, size_t size) { - for (size_t i = 0; i < size; i++) { - if (((uint8_t*)p)[i] != 0) return false; - } - return true; -} - - -// Align a byte size to a size in _machine words_, -// i.e. byte size == `wsize*sizeof(void*)`. -static inline size_t _mi_wsize_from_size(size_t size) { - mi_assert_internal(size <= SIZE_MAX - sizeof(uintptr_t)); - return (size + sizeof(uintptr_t) - 1) / sizeof(uintptr_t); -} - -// Overflow detecting multiply -#if __has_builtin(__builtin_umul_overflow) || (defined(__GNUC__) && (__GNUC__ >= 5)) -#include // UINT_MAX, ULONG_MAX -#if defined(_CLOCK_T) // for Illumos -#undef _CLOCK_T -#endif -static inline bool mi_mul_overflow(size_t count, size_t size, size_t* total) { - #if (SIZE_MAX == ULONG_MAX) - return __builtin_umull_overflow(count, size, (unsigned long *)total); - #elif (SIZE_MAX == UINT_MAX) - return __builtin_umul_overflow(count, size, (unsigned int *)total); - #else - return __builtin_umulll_overflow(count, size, (unsigned long long *)total); - #endif -} -#else /* __builtin_umul_overflow is unavailable */ -static inline bool mi_mul_overflow(size_t count, size_t size, size_t* total) { - #define MI_MUL_NO_OVERFLOW ((size_t)1 << (4*sizeof(size_t))) // sqrt(SIZE_MAX) - *total = count * size; - // note: gcc/clang optimize this to directly check the overflow flag - return ((size >= MI_MUL_NO_OVERFLOW || count >= MI_MUL_NO_OVERFLOW) && size > 0 && (SIZE_MAX / size) < count); -} -#endif - -// Safe multiply `count*size` into `total`; return `true` on overflow. -static inline bool mi_count_size_overflow(size_t count, size_t size, size_t* total) { - if (count==1) { // quick check for the case where count is one (common for C++ allocators) - *total = size; - return false; - } - else if mi_unlikely(mi_mul_overflow(count, size, total)) { - #if MI_DEBUG > 0 - _mi_error_message(EOVERFLOW, "allocation request is too large (%zu * %zu bytes)\n", count, size); - #endif - *total = SIZE_MAX; - return true; - } - else return false; -} - - -/* ---------------------------------------------------------------------------------------- -The thread local default heap: `_mi_get_default_heap` returns the thread local heap. -On most platforms (Windows, Linux, FreeBSD, NetBSD, etc), this just returns a -__thread local variable (`_mi_heap_default`). With the initial-exec TLS model this ensures -that the storage will always be available (allocated on the thread stacks). -On some platforms though we cannot use that when overriding `malloc` since the underlying -TLS implementation (or the loader) will call itself `malloc` on a first access and recurse. -We try to circumvent this in an efficient way: -- macOSX : we use an unused TLS slot from the OS allocated slots (MI_TLS_SLOT). On OSX, the - loader itself calls `malloc` even before the modules are initialized. -- OpenBSD: we use an unused slot from the pthread block (MI_TLS_PTHREAD_SLOT_OFS). -- DragonFly: defaults are working but seem slow compared to freeBSD (see PR #323) -------------------------------------------------------------------------------------------- */ - -extern const mi_heap_t _mi_heap_empty; // read-only empty heap, initial value of the thread local default heap -extern bool _mi_process_is_initialized; -mi_heap_t* _mi_heap_main_get(void); // statically allocated main backing heap - -#if defined(MI_MALLOC_OVERRIDE) -#if defined(__APPLE__) // macOS -#define MI_TLS_SLOT 89 // seems unused? -// #define MI_TLS_RECURSE_GUARD 1 -// other possible unused ones are 9, 29, __PTK_FRAMEWORK_JAVASCRIPTCORE_KEY4 (94), __PTK_FRAMEWORK_GC_KEY9 (112) and __PTK_FRAMEWORK_OLDGC_KEY9 (89) -// see -#elif defined(__OpenBSD__) -// use end bytes of a name; goes wrong if anyone uses names > 23 characters (ptrhread specifies 16) -// see -#define MI_TLS_PTHREAD_SLOT_OFS (6*sizeof(int) + 4*sizeof(void*) + 24) -// #elif defined(__DragonFly__) -// #warning "mimalloc is not working correctly on DragonFly yet." -// #define MI_TLS_PTHREAD_SLOT_OFS (4 + 1*sizeof(void*)) // offset `uniqueid` (also used by gdb?) -#elif defined(__ANDROID__) -// See issue #381 -#define MI_TLS_PTHREAD -#endif -#endif - -#if defined(MI_TLS_SLOT) -static inline void* mi_tls_slot(size_t slot) mi_attr_noexcept; // forward declaration -#elif defined(MI_TLS_PTHREAD_SLOT_OFS) -static inline mi_heap_t** mi_tls_pthread_heap_slot(void) { - pthread_t self = pthread_self(); - #if defined(__DragonFly__) - if (self==NULL) { - mi_heap_t* pheap_main = _mi_heap_main_get(); - return &pheap_main; - } - #endif - return (mi_heap_t**)((uint8_t*)self + MI_TLS_PTHREAD_SLOT_OFS); -} -#elif defined(MI_TLS_PTHREAD) -extern pthread_key_t _mi_heap_default_key; -#endif - -// Default heap to allocate from (if not using TLS- or pthread slots). -// Do not use this directly but use through `mi_heap_get_default()` (or the unchecked `mi_get_default_heap`). -// This thread local variable is only used when neither MI_TLS_SLOT, MI_TLS_PTHREAD, or MI_TLS_PTHREAD_SLOT_OFS are defined. -// However, on the Apple M1 we do use the address of this variable as the unique thread-id (issue #356). -extern mi_decl_thread mi_heap_t* _mi_heap_default; // default heap to allocate from - -static inline mi_heap_t* mi_get_default_heap(void) { -#if defined(MI_TLS_SLOT) - mi_heap_t* heap = (mi_heap_t*)mi_tls_slot(MI_TLS_SLOT); - if mi_unlikely(heap == NULL) { - #ifdef __GNUC__ - __asm(""); // prevent conditional load of the address of _mi_heap_empty - #endif - heap = (mi_heap_t*)&_mi_heap_empty; - } - return heap; -#elif defined(MI_TLS_PTHREAD_SLOT_OFS) - mi_heap_t* heap = *mi_tls_pthread_heap_slot(); - return (mi_unlikely(heap == NULL) ? (mi_heap_t*)&_mi_heap_empty : heap); -#elif defined(MI_TLS_PTHREAD) - mi_heap_t* heap = (mi_unlikely(_mi_heap_default_key == (pthread_key_t)(-1)) ? _mi_heap_main_get() : (mi_heap_t*)pthread_getspecific(_mi_heap_default_key)); - return (mi_unlikely(heap == NULL) ? (mi_heap_t*)&_mi_heap_empty : heap); -#else - #if defined(MI_TLS_RECURSE_GUARD) - if (mi_unlikely(!_mi_process_is_initialized)) return _mi_heap_main_get(); - #endif - return _mi_heap_default; -#endif -} - -static inline bool mi_heap_is_default(const mi_heap_t* heap) { - return (heap == mi_get_default_heap()); -} - -static inline bool mi_heap_is_backing(const mi_heap_t* heap) { - return (heap->tld->heap_backing == heap); -} - -static inline bool mi_heap_is_initialized(mi_heap_t* heap) { - mi_assert_internal(heap != NULL); - return (heap != &_mi_heap_empty); -} - -static inline uintptr_t _mi_ptr_cookie(const void* p) { - extern mi_heap_t _mi_heap_main; - mi_assert_internal(_mi_heap_main.cookie != 0); - return ((uintptr_t)p ^ _mi_heap_main.cookie); -} - -/* ----------------------------------------------------------- - Pages ------------------------------------------------------------ */ - -static inline mi_page_t* _mi_heap_get_free_small_page(mi_heap_t* heap, size_t size) { - mi_assert_internal(size <= (MI_SMALL_SIZE_MAX + MI_PADDING_SIZE)); - const size_t idx = _mi_wsize_from_size(size); - mi_assert_internal(idx < MI_PAGES_DIRECT); - return heap->pages_free_direct[idx]; -} - -// Get the page belonging to a certain size class -static inline mi_page_t* _mi_get_free_small_page(size_t size) { - return _mi_heap_get_free_small_page(mi_get_default_heap(), size); -} - -// Segment that contains the pointer -static inline mi_segment_t* _mi_ptr_segment(const void* p) { - // mi_assert_internal(p != NULL); - return (mi_segment_t*)((uintptr_t)p & ~MI_SEGMENT_MASK); -} - -static inline mi_page_t* mi_slice_to_page(mi_slice_t* s) { - mi_assert_internal(s->slice_offset== 0 && s->slice_count > 0); - return (mi_page_t*)(s); -} - -static inline mi_slice_t* mi_page_to_slice(mi_page_t* p) { - mi_assert_internal(p->slice_offset== 0 && p->slice_count > 0); - return (mi_slice_t*)(p); -} - -// Segment belonging to a page -static inline mi_segment_t* _mi_page_segment(const mi_page_t* page) { - mi_segment_t* segment = _mi_ptr_segment(page); - mi_assert_internal(segment == NULL || ((mi_slice_t*)page >= segment->slices && (mi_slice_t*)page < segment->slices + segment->slice_entries)); - return segment; -} - -static inline mi_slice_t* mi_slice_first(const mi_slice_t* slice) { - mi_slice_t* start = (mi_slice_t*)((uint8_t*)slice - slice->slice_offset); - mi_assert_internal(start >= _mi_ptr_segment(slice)->slices); - mi_assert_internal(start->slice_offset == 0); - mi_assert_internal(start + start->slice_count > slice); - return start; -} - -// Get the page containing the pointer -static inline mi_page_t* _mi_segment_page_of(const mi_segment_t* segment, const void* p) { - ptrdiff_t diff = (uint8_t*)p - (uint8_t*)segment; - mi_assert_internal(diff >= 0 && diff < (ptrdiff_t)MI_SEGMENT_SIZE); - size_t idx = (size_t)diff >> MI_SEGMENT_SLICE_SHIFT; - mi_assert_internal(idx < segment->slice_entries); - mi_slice_t* slice0 = (mi_slice_t*)&segment->slices[idx]; - mi_slice_t* slice = mi_slice_first(slice0); // adjust to the block that holds the page data - mi_assert_internal(slice->slice_offset == 0); - mi_assert_internal(slice >= segment->slices && slice < segment->slices + segment->slice_entries); - return mi_slice_to_page(slice); -} - -// Quick page start for initialized pages -static inline uint8_t* _mi_page_start(const mi_segment_t* segment, const mi_page_t* page, size_t* page_size) { - return _mi_segment_page_start(segment, page, page_size); -} - -// Get the page containing the pointer -static inline mi_page_t* _mi_ptr_page(void* p) { - return _mi_segment_page_of(_mi_ptr_segment(p), p); -} - -// Get the block size of a page (special case for huge objects) -static inline size_t mi_page_block_size(const mi_page_t* page) { - const size_t bsize = page->xblock_size; - mi_assert_internal(bsize > 0); - if mi_likely(bsize < MI_HUGE_BLOCK_SIZE) { - return bsize; - } - else { - size_t psize; - _mi_segment_page_start(_mi_page_segment(page), page, &psize); - return psize; - } -} - -// Get the usable block size of a page without fixed padding. -// This may still include internal padding due to alignment and rounding up size classes. -static inline size_t mi_page_usable_block_size(const mi_page_t* page) { - return mi_page_block_size(page) - MI_PADDING_SIZE; -} - -// size of a segment -static inline size_t mi_segment_size(mi_segment_t* segment) { - return segment->segment_slices * MI_SEGMENT_SLICE_SIZE; -} - -static inline uint8_t* mi_segment_end(mi_segment_t* segment) { - return (uint8_t*)segment + mi_segment_size(segment); -} - -// Thread free access -static inline mi_block_t* mi_page_thread_free(const mi_page_t* page) { - return (mi_block_t*)(mi_atomic_load_relaxed(&((mi_page_t*)page)->xthread_free) & ~3); -} - -static inline mi_delayed_t mi_page_thread_free_flag(const mi_page_t* page) { - return (mi_delayed_t)(mi_atomic_load_relaxed(&((mi_page_t*)page)->xthread_free) & 3); -} - -// Heap access -static inline mi_heap_t* mi_page_heap(const mi_page_t* page) { - return (mi_heap_t*)(mi_atomic_load_relaxed(&((mi_page_t*)page)->xheap)); -} - -static inline void mi_page_set_heap(mi_page_t* page, mi_heap_t* heap) { - mi_assert_internal(mi_page_thread_free_flag(page) != MI_DELAYED_FREEING); - mi_atomic_store_release(&page->xheap,(uintptr_t)heap); -} - -// Thread free flag helpers -static inline mi_block_t* mi_tf_block(mi_thread_free_t tf) { - return (mi_block_t*)(tf & ~0x03); -} -static inline mi_delayed_t mi_tf_delayed(mi_thread_free_t tf) { - return (mi_delayed_t)(tf & 0x03); -} -static inline mi_thread_free_t mi_tf_make(mi_block_t* block, mi_delayed_t delayed) { - return (mi_thread_free_t)((uintptr_t)block | (uintptr_t)delayed); -} -static inline mi_thread_free_t mi_tf_set_delayed(mi_thread_free_t tf, mi_delayed_t delayed) { - return mi_tf_make(mi_tf_block(tf),delayed); -} -static inline mi_thread_free_t mi_tf_set_block(mi_thread_free_t tf, mi_block_t* block) { - return mi_tf_make(block, mi_tf_delayed(tf)); -} - -// are all blocks in a page freed? -// note: needs up-to-date used count, (as the `xthread_free` list may not be empty). see `_mi_page_collect_free`. -static inline bool mi_page_all_free(const mi_page_t* page) { - mi_assert_internal(page != NULL); - return (page->used == 0); -} - -// are there any available blocks? -static inline bool mi_page_has_any_available(const mi_page_t* page) { - mi_assert_internal(page != NULL && page->reserved > 0); - return (page->used < page->reserved || (mi_page_thread_free(page) != NULL)); -} - -// are there immediately available blocks, i.e. blocks available on the free list. -static inline bool mi_page_immediate_available(const mi_page_t* page) { - mi_assert_internal(page != NULL); - return (page->free != NULL); -} - -// is more than 7/8th of a page in use? -static inline bool mi_page_mostly_used(const mi_page_t* page) { - if (page==NULL) return true; - uint16_t frac = page->reserved / 8U; - return (page->reserved - page->used <= frac); -} - -static inline mi_page_queue_t* mi_page_queue(const mi_heap_t* heap, size_t size) { - return &((mi_heap_t*)heap)->pages[_mi_bin(size)]; -} - - - -//----------------------------------------------------------- -// Page flags -//----------------------------------------------------------- -static inline bool mi_page_is_in_full(const mi_page_t* page) { - return page->flags.x.in_full; -} - -static inline void mi_page_set_in_full(mi_page_t* page, bool in_full) { - page->flags.x.in_full = in_full; -} - -static inline bool mi_page_has_aligned(const mi_page_t* page) { - return page->flags.x.has_aligned; -} - -static inline void mi_page_set_has_aligned(mi_page_t* page, bool has_aligned) { - page->flags.x.has_aligned = has_aligned; -} - - -/* ------------------------------------------------------------------- -Encoding/Decoding the free list next pointers - -This is to protect against buffer overflow exploits where the -free list is mutated. Many hardened allocators xor the next pointer `p` -with a secret key `k1`, as `p^k1`. This prevents overwriting with known -values but might be still too weak: if the attacker can guess -the pointer `p` this can reveal `k1` (since `p^k1^p == k1`). -Moreover, if multiple blocks can be read as well, the attacker can -xor both as `(p1^k1) ^ (p2^k1) == p1^p2` which may reveal a lot -about the pointers (and subsequently `k1`). - -Instead mimalloc uses an extra key `k2` and encodes as `((p^k2)<<> (MI_INTPTR_BITS - shift)))); -} -static inline uintptr_t mi_rotr(uintptr_t x, uintptr_t shift) { - shift %= MI_INTPTR_BITS; - return (shift==0 ? x : ((x >> shift) | (x << (MI_INTPTR_BITS - shift)))); -} - -static inline void* mi_ptr_decode(const void* null, const mi_encoded_t x, const uintptr_t* keys) { - void* p = (void*)(mi_rotr(x - keys[0], keys[0]) ^ keys[1]); - return (p==null ? NULL : p); -} - -static inline mi_encoded_t mi_ptr_encode(const void* null, const void* p, const uintptr_t* keys) { - uintptr_t x = (uintptr_t)(p==NULL ? null : p); - return mi_rotl(x ^ keys[1], keys[0]) + keys[0]; -} - -static inline mi_block_t* mi_block_nextx( const void* null, const mi_block_t* block, const uintptr_t* keys ) { - mi_track_mem_defined(block,sizeof(mi_block_t)); - mi_block_t* next; - #ifdef MI_ENCODE_FREELIST - next = (mi_block_t*)mi_ptr_decode(null, block->next, keys); - #else - MI_UNUSED(keys); MI_UNUSED(null); - next = (mi_block_t*)block->next; - #endif - mi_track_mem_noaccess(block,sizeof(mi_block_t)); - return next; -} - -static inline void mi_block_set_nextx(const void* null, mi_block_t* block, const mi_block_t* next, const uintptr_t* keys) { - mi_track_mem_undefined(block,sizeof(mi_block_t)); - #ifdef MI_ENCODE_FREELIST - block->next = mi_ptr_encode(null, next, keys); - #else - MI_UNUSED(keys); MI_UNUSED(null); - block->next = (mi_encoded_t)next; - #endif - mi_track_mem_noaccess(block,sizeof(mi_block_t)); -} - -static inline mi_block_t* mi_block_next(const mi_page_t* page, const mi_block_t* block) { - #ifdef MI_ENCODE_FREELIST - mi_block_t* next = mi_block_nextx(page,block,page->keys); - // check for free list corruption: is `next` at least in the same page? - // TODO: check if `next` is `page->block_size` aligned? - if mi_unlikely(next!=NULL && !mi_is_in_same_page(block, next)) { - _mi_error_message(EFAULT, "corrupted free list entry of size %zub at %p: value 0x%zx\n", mi_page_block_size(page), block, (uintptr_t)next); - next = NULL; - } - return next; - #else - MI_UNUSED(page); - return mi_block_nextx(page,block,NULL); - #endif -} - -static inline void mi_block_set_next(const mi_page_t* page, mi_block_t* block, const mi_block_t* next) { - #ifdef MI_ENCODE_FREELIST - mi_block_set_nextx(page,block,next, page->keys); - #else - MI_UNUSED(page); - mi_block_set_nextx(page,block,next,NULL); - #endif -} - - -// ------------------------------------------------------------------- -// commit mask -// ------------------------------------------------------------------- - -static inline void mi_commit_mask_create_empty(mi_commit_mask_t* cm) { - for (size_t i = 0; i < MI_COMMIT_MASK_FIELD_COUNT; i++) { - cm->mask[i] = 0; - } -} - -static inline void mi_commit_mask_create_full(mi_commit_mask_t* cm) { - for (size_t i = 0; i < MI_COMMIT_MASK_FIELD_COUNT; i++) { - cm->mask[i] = ~((size_t)0); - } -} - -static inline bool mi_commit_mask_is_empty(const mi_commit_mask_t* cm) { - for (size_t i = 0; i < MI_COMMIT_MASK_FIELD_COUNT; i++) { - if (cm->mask[i] != 0) return false; - } - return true; -} - -static inline bool mi_commit_mask_is_full(const mi_commit_mask_t* cm) { - for (size_t i = 0; i < MI_COMMIT_MASK_FIELD_COUNT; i++) { - if (cm->mask[i] != ~((size_t)0)) return false; - } - return true; -} - -// defined in `segment.c`: -size_t _mi_commit_mask_committed_size(const mi_commit_mask_t* cm, size_t total); -size_t _mi_commit_mask_next_run(const mi_commit_mask_t* cm, size_t* idx); - -#define mi_commit_mask_foreach(cm,idx,count) \ - idx = 0; \ - while ((count = _mi_commit_mask_next_run(cm,&idx)) > 0) { - -#define mi_commit_mask_foreach_end() \ - idx += count; \ - } - - - - -// ------------------------------------------------------------------- -// Fast "random" shuffle -// ------------------------------------------------------------------- - -static inline uintptr_t _mi_random_shuffle(uintptr_t x) { - if (x==0) { x = 17; } // ensure we don't get stuck in generating zeros -#if (MI_INTPTR_SIZE==8) - // by Sebastiano Vigna, see: - x ^= x >> 30; - x *= 0xbf58476d1ce4e5b9UL; - x ^= x >> 27; - x *= 0x94d049bb133111ebUL; - x ^= x >> 31; -#elif (MI_INTPTR_SIZE==4) - // by Chris Wellons, see: - x ^= x >> 16; - x *= 0x7feb352dUL; - x ^= x >> 15; - x *= 0x846ca68bUL; - x ^= x >> 16; -#endif - return x; -} - -// ------------------------------------------------------------------- -// Optimize numa node access for the common case (= one node) -// ------------------------------------------------------------------- - -int _mi_os_numa_node_get(mi_os_tld_t* tld); -size_t _mi_os_numa_node_count_get(void); - -extern _Atomic(size_t) _mi_numa_node_count; -static inline int _mi_os_numa_node(mi_os_tld_t* tld) { - if mi_likely(mi_atomic_load_relaxed(&_mi_numa_node_count) == 1) { return 0; } - else return _mi_os_numa_node_get(tld); -} -static inline size_t _mi_os_numa_node_count(void) { - const size_t count = mi_atomic_load_relaxed(&_mi_numa_node_count); - if mi_likely(count > 0) { return count; } - else return _mi_os_numa_node_count_get(); -} - - -// ------------------------------------------------------------------- -// Getting the thread id should be performant as it is called in the -// fast path of `_mi_free` and we specialize for various platforms. -// We only require _mi_threadid() to return a unique id for each thread. -// ------------------------------------------------------------------- -#if defined(_WIN32) - -#define WIN32_LEAN_AND_MEAN -#include -static inline mi_threadid_t _mi_thread_id(void) mi_attr_noexcept { - // Windows: works on Intel and ARM in both 32- and 64-bit - return (uintptr_t)NtCurrentTeb(); -} - -// We use assembly for a fast thread id on the main platforms. The TLS layout depends on -// both the OS and libc implementation so we use specific tests for each main platform. -// If you test on another platform and it works please send a PR :-) -// see also https://akkadia.org/drepper/tls.pdf for more info on the TLS register. -#elif defined(__GNUC__) && ( \ - (defined(__GLIBC__) && (defined(__x86_64__) || defined(__i386__) || defined(__arm__) || defined(__aarch64__))) \ - || (defined(__APPLE__) && (defined(__x86_64__) || defined(__aarch64__))) \ - || (defined(__BIONIC__) && (defined(__x86_64__) || defined(__i386__) || defined(__arm__) || defined(__aarch64__))) \ - || (defined(__FreeBSD__) && (defined(__x86_64__) || defined(__i386__) || defined(__aarch64__))) \ - || (defined(__OpenBSD__) && (defined(__x86_64__) || defined(__i386__) || defined(__aarch64__))) \ - ) - -static inline void* mi_tls_slot(size_t slot) mi_attr_noexcept { - void* res; - const size_t ofs = (slot*sizeof(void*)); - #if defined(__i386__) - __asm__("movl %%gs:%1, %0" : "=r" (res) : "m" (*((void**)ofs)) : ); // x86 32-bit always uses GS - #elif defined(__APPLE__) && defined(__x86_64__) - __asm__("movq %%gs:%1, %0" : "=r" (res) : "m" (*((void**)ofs)) : ); // x86_64 macOSX uses GS - #elif defined(__x86_64__) && (MI_INTPTR_SIZE==4) - __asm__("movl %%fs:%1, %0" : "=r" (res) : "m" (*((void**)ofs)) : ); // x32 ABI - #elif defined(__x86_64__) - __asm__("movq %%fs:%1, %0" : "=r" (res) : "m" (*((void**)ofs)) : ); // x86_64 Linux, BSD uses FS - #elif defined(__arm__) - void** tcb; MI_UNUSED(ofs); - __asm__ volatile ("mrc p15, 0, %0, c13, c0, 3\nbic %0, %0, #3" : "=r" (tcb)); - res = tcb[slot]; - #elif defined(__aarch64__) - void** tcb; MI_UNUSED(ofs); - #if defined(__APPLE__) // M1, issue #343 - __asm__ volatile ("mrs %0, tpidrro_el0\nbic %0, %0, #7" : "=r" (tcb)); - #else - __asm__ volatile ("mrs %0, tpidr_el0" : "=r" (tcb)); - #endif - res = tcb[slot]; - #endif - return res; -} - -// setting a tls slot is only used on macOS for now -static inline void mi_tls_slot_set(size_t slot, void* value) mi_attr_noexcept { - const size_t ofs = (slot*sizeof(void*)); - #if defined(__i386__) - __asm__("movl %1,%%gs:%0" : "=m" (*((void**)ofs)) : "rn" (value) : ); // 32-bit always uses GS - #elif defined(__APPLE__) && defined(__x86_64__) - __asm__("movq %1,%%gs:%0" : "=m" (*((void**)ofs)) : "rn" (value) : ); // x86_64 macOS uses GS - #elif defined(__x86_64__) && (MI_INTPTR_SIZE==4) - __asm__("movl %1,%%fs:%0" : "=m" (*((void**)ofs)) : "rn" (value) : ); // x32 ABI - #elif defined(__x86_64__) - __asm__("movq %1,%%fs:%0" : "=m" (*((void**)ofs)) : "rn" (value) : ); // x86_64 Linux, BSD uses FS - #elif defined(__arm__) - void** tcb; MI_UNUSED(ofs); - __asm__ volatile ("mrc p15, 0, %0, c13, c0, 3\nbic %0, %0, #3" : "=r" (tcb)); - tcb[slot] = value; - #elif defined(__aarch64__) - void** tcb; MI_UNUSED(ofs); - #if defined(__APPLE__) // M1, issue #343 - __asm__ volatile ("mrs %0, tpidrro_el0\nbic %0, %0, #7" : "=r" (tcb)); - #else - __asm__ volatile ("mrs %0, tpidr_el0" : "=r" (tcb)); - #endif - tcb[slot] = value; - #endif -} - -static inline mi_threadid_t _mi_thread_id(void) mi_attr_noexcept { - #if defined(__BIONIC__) - // issue #384, #495: on the Bionic libc (Android), slot 1 is the thread id - // see: https://github.com/aosp-mirror/platform_bionic/blob/c44b1d0676ded732df4b3b21c5f798eacae93228/libc/platform/bionic/tls_defines.h#L86 - return (uintptr_t)mi_tls_slot(1); - #else - // in all our other targets, slot 0 is the thread id - // glibc: https://sourceware.org/git/?p=glibc.git;a=blob_plain;f=sysdeps/x86_64/nptl/tls.h - // apple: https://github.com/apple/darwin-xnu/blob/main/libsyscall/os/tsd.h#L36 - return (uintptr_t)mi_tls_slot(0); - #endif -} - -#else - -// otherwise use portable C, taking the address of a thread local variable (this is still very fast on most platforms). -static inline mi_threadid_t _mi_thread_id(void) mi_attr_noexcept { - return (uintptr_t)&_mi_heap_default; -} - -#endif - - -// ----------------------------------------------------------------------- -// Count bits: trailing or leading zeros (with MI_INTPTR_BITS on all zero) -// ----------------------------------------------------------------------- - -#if defined(__GNUC__) - -#include // LONG_MAX -#define MI_HAVE_FAST_BITSCAN -static inline size_t mi_clz(uintptr_t x) { - if (x==0) return MI_INTPTR_BITS; -#if (INTPTR_MAX == LONG_MAX) - return __builtin_clzl(x); -#else - return __builtin_clzll(x); -#endif -} -static inline size_t mi_ctz(uintptr_t x) { - if (x==0) return MI_INTPTR_BITS; -#if (INTPTR_MAX == LONG_MAX) - return __builtin_ctzl(x); -#else - return __builtin_ctzll(x); -#endif -} - -#elif defined(_MSC_VER) - -#include // LONG_MAX -#define MI_HAVE_FAST_BITSCAN -static inline size_t mi_clz(uintptr_t x) { - if (x==0) return MI_INTPTR_BITS; - unsigned long idx; -#if (INTPTR_MAX == LONG_MAX) - _BitScanReverse(&idx, x); -#else - _BitScanReverse64(&idx, x); -#endif - return ((MI_INTPTR_BITS - 1) - idx); -} -static inline size_t mi_ctz(uintptr_t x) { - if (x==0) return MI_INTPTR_BITS; - unsigned long idx; -#if (INTPTR_MAX == LONG_MAX) - _BitScanForward(&idx, x); -#else - _BitScanForward64(&idx, x); -#endif - return idx; -} - -#else -static inline size_t mi_ctz32(uint32_t x) { - // de Bruijn multiplication, see - static const unsigned char debruijn[32] = { - 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, - 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9 - }; - if (x==0) return 32; - return debruijn[((x & -(int32_t)x) * 0x077CB531UL) >> 27]; -} -static inline size_t mi_clz32(uint32_t x) { - // de Bruijn multiplication, see - static const uint8_t debruijn[32] = { - 31, 22, 30, 21, 18, 10, 29, 2, 20, 17, 15, 13, 9, 6, 28, 1, - 23, 19, 11, 3, 16, 14, 7, 24, 12, 4, 8, 25, 5, 26, 27, 0 - }; - if (x==0) return 32; - x |= x >> 1; - x |= x >> 2; - x |= x >> 4; - x |= x >> 8; - x |= x >> 16; - return debruijn[(uint32_t)(x * 0x07C4ACDDUL) >> 27]; -} - -static inline size_t mi_clz(uintptr_t x) { - if (x==0) return MI_INTPTR_BITS; -#if (MI_INTPTR_BITS <= 32) - return mi_clz32((uint32_t)x); -#else - size_t count = mi_clz32((uint32_t)(x >> 32)); - if (count < 32) return count; - return (32 + mi_clz32((uint32_t)x)); -#endif -} -static inline size_t mi_ctz(uintptr_t x) { - if (x==0) return MI_INTPTR_BITS; -#if (MI_INTPTR_BITS <= 32) - return mi_ctz32((uint32_t)x); -#else - size_t count = mi_ctz32((uint32_t)x); - if (count < 32) return count; - return (32 + mi_ctz32((uint32_t)(x>>32))); -#endif -} - -#endif - -// "bit scan reverse": Return index of the highest bit (or MI_INTPTR_BITS if `x` is zero) -static inline size_t mi_bsr(uintptr_t x) { - return (x==0 ? MI_INTPTR_BITS : MI_INTPTR_BITS - 1 - mi_clz(x)); -} - - -// --------------------------------------------------------------------------------- -// Provide our own `_mi_memcpy` for potential performance optimizations. -// -// For now, only on Windows with msvc/clang-cl we optimize to `rep movsb` if -// we happen to run on x86/x64 cpu's that have "fast short rep movsb" (FSRM) support -// (AMD Zen3+ (~2020) or Intel Ice Lake+ (~2017). See also issue #201 and pr #253. -// --------------------------------------------------------------------------------- - -#if !MI_TRACK_ENABLED && defined(_WIN32) && (defined(_M_IX86) || defined(_M_X64)) -#include -#include -extern bool _mi_cpu_has_fsrm; -static inline void _mi_memcpy(void* dst, const void* src, size_t n) { - if (_mi_cpu_has_fsrm) { - __movsb((unsigned char*)dst, (const unsigned char*)src, n); - } - else { - memcpy(dst, src, n); - } -} -static inline void _mi_memzero(void* dst, size_t n) { - if (_mi_cpu_has_fsrm) { - __stosb((unsigned char*)dst, 0, n); - } - else { - memset(dst, 0, n); - } -} -#else -#include -static inline void _mi_memcpy(void* dst, const void* src, size_t n) { - memcpy(dst, src, n); -} -static inline void _mi_memzero(void* dst, size_t n) { - memset(dst, 0, n); -} -#endif - - -// ------------------------------------------------------------------------------- -// The `_mi_memcpy_aligned` can be used if the pointers are machine-word aligned -// This is used for example in `mi_realloc`. -// ------------------------------------------------------------------------------- - -#if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__) -// On GCC/CLang we provide a hint that the pointers are word aligned. -#include -static inline void _mi_memcpy_aligned(void* dst, const void* src, size_t n) { - mi_assert_internal(((uintptr_t)dst % MI_INTPTR_SIZE == 0) && ((uintptr_t)src % MI_INTPTR_SIZE == 0)); - void* adst = __builtin_assume_aligned(dst, MI_INTPTR_SIZE); - const void* asrc = __builtin_assume_aligned(src, MI_INTPTR_SIZE); - _mi_memcpy(adst, asrc, n); -} - -static inline void _mi_memzero_aligned(void* dst, size_t n) { - mi_assert_internal((uintptr_t)dst % MI_INTPTR_SIZE == 0); - void* adst = __builtin_assume_aligned(dst, MI_INTPTR_SIZE); - _mi_memzero(adst, n); -} -#else -// Default fallback on `_mi_memcpy` -static inline void _mi_memcpy_aligned(void* dst, const void* src, size_t n) { - mi_assert_internal(((uintptr_t)dst % MI_INTPTR_SIZE == 0) && ((uintptr_t)src % MI_INTPTR_SIZE == 0)); - _mi_memcpy(dst, src, n); -} - -static inline void _mi_memzero_aligned(void* dst, size_t n) { - mi_assert_internal((uintptr_t)dst % MI_INTPTR_SIZE == 0); - _mi_memzero(dst, n); -} -#endif - - -#endif diff --git a/src/dashbls/depends/mimalloc/include/mimalloc-new-delete.h b/src/dashbls/depends/mimalloc/include/mimalloc-new-delete.h index 1c12fad2fc23..c16f4a6653d9 100644 --- a/src/dashbls/depends/mimalloc/include/mimalloc-new-delete.h +++ b/src/dashbls/depends/mimalloc/include/mimalloc-new-delete.h @@ -22,17 +22,26 @@ terms of the MIT license. A copy of the license can be found in the file #include #include + #if defined(_MSC_VER) && defined(_Ret_notnull_) && defined(_Post_writable_byte_size_) + // stay consistent with VCRT definitions + #define mi_decl_new(n) mi_decl_nodiscard mi_decl_restrict _Ret_notnull_ _Post_writable_byte_size_(n) + #define mi_decl_new_nothrow(n) mi_decl_nodiscard mi_decl_restrict _Ret_maybenull_ _Success_(return != NULL) _Post_writable_byte_size_(n) + #else + #define mi_decl_new(n) mi_decl_nodiscard mi_decl_restrict + #define mi_decl_new_nothrow(n) mi_decl_nodiscard mi_decl_restrict + #endif + void operator delete(void* p) noexcept { mi_free(p); }; void operator delete[](void* p) noexcept { mi_free(p); }; void operator delete (void* p, const std::nothrow_t&) noexcept { mi_free(p); } void operator delete[](void* p, const std::nothrow_t&) noexcept { mi_free(p); } - void* operator new(std::size_t n) noexcept(false) { return mi_new(n); } - void* operator new[](std::size_t n) noexcept(false) { return mi_new(n); } + mi_decl_new(n) void* operator new(std::size_t n) noexcept(false) { return mi_new(n); } + mi_decl_new(n) void* operator new[](std::size_t n) noexcept(false) { return mi_new(n); } - void* operator new (std::size_t n, const std::nothrow_t& tag) noexcept { (void)(tag); return mi_new_nothrow(n); } - void* operator new[](std::size_t n, const std::nothrow_t& tag) noexcept { (void)(tag); return mi_new_nothrow(n); } + mi_decl_new_nothrow(n) void* operator new (std::size_t n, const std::nothrow_t& tag) noexcept { (void)(tag); return mi_new_nothrow(n); } + mi_decl_new_nothrow(n) void* operator new[](std::size_t n, const std::nothrow_t& tag) noexcept { (void)(tag); return mi_new_nothrow(n); } #if (__cplusplus >= 201402L || _MSC_VER >= 1916) void operator delete (void* p, std::size_t n) noexcept { mi_free_size(p,n); }; @@ -46,7 +55,7 @@ terms of the MIT license. A copy of the license can be found in the file void operator delete[](void* p, std::size_t n, std::align_val_t al) noexcept { mi_free_size_aligned(p, n, static_cast(al)); }; void operator delete (void* p, std::align_val_t al, const std::nothrow_t&) noexcept { mi_free_aligned(p, static_cast(al)); } void operator delete[](void* p, std::align_val_t al, const std::nothrow_t&) noexcept { mi_free_aligned(p, static_cast(al)); } - + void* operator new (std::size_t n, std::align_val_t al) noexcept(false) { return mi_new_aligned(n, static_cast(al)); } void* operator new[](std::size_t n, std::align_val_t al) noexcept(false) { return mi_new_aligned(n, static_cast(al)); } void* operator new (std::size_t n, std::align_val_t al, const std::nothrow_t&) noexcept { return mi_new_aligned_nothrow(n, static_cast(al)); } diff --git a/src/dashbls/depends/mimalloc/include/mimalloc-override.h b/src/dashbls/depends/mimalloc/include/mimalloc-override.h index c63b0b91a7c2..48a8a6226a05 100644 --- a/src/dashbls/depends/mimalloc/include/mimalloc-override.h +++ b/src/dashbls/depends/mimalloc/include/mimalloc-override.h @@ -24,7 +24,7 @@ not accidentally mix pointers from different allocators). #define free(p) mi_free(p) #define strdup(s) mi_strdup(s) -#define strndup(s,n) mi_strndup(s,n) +#define strndup(s,n) mi_strndup(s,n) #define realpath(f,n) mi_realpath(f,n) // Microsoft extensions @@ -43,6 +43,7 @@ not accidentally mix pointers from different allocators). #define reallocf(p,n) mi_reallocf(p,n) #define malloc_size(p) mi_usable_size(p) #define malloc_usable_size(p) mi_usable_size(p) +#define malloc_good_size(sz) mi_malloc_good_size(sz) #define cfree(p) mi_free(p) #define valloc(n) mi_valloc(n) diff --git a/src/dashbls/depends/mimalloc/include/mimalloc-stats.h b/src/dashbls/depends/mimalloc/include/mimalloc-stats.h new file mode 100644 index 000000000000..631f43bbec88 --- /dev/null +++ b/src/dashbls/depends/mimalloc/include/mimalloc-stats.h @@ -0,0 +1,117 @@ +/* ---------------------------------------------------------------------------- +Copyright (c) 2018-2025, Microsoft Research, Daan Leijen +This is free software; you can redistribute it and/or modify it under the +terms of the MIT license. A copy of the license can be found in the file +"LICENSE" at the root of this distribution. +-----------------------------------------------------------------------------*/ +#pragma once +#ifndef MIMALLOC_STATS_H +#define MIMALLOC_STATS_H + +#include +#include + +#define MI_STAT_VERSION 2 // increased on every backward incompatible change + +// count allocation over time +typedef struct mi_stat_count_s { + int64_t total; // total allocated + int64_t peak; // peak allocation + int64_t current; // current allocation +} mi_stat_count_t; + +// counters only increase +typedef struct mi_stat_counter_s { + int64_t total; // total count +} mi_stat_counter_t; + +#define MI_STAT_FIELDS() \ + MI_STAT_COUNT(pages) /* count of mimalloc pages */ \ + MI_STAT_COUNT(reserved) /* reserved memory bytes */ \ + MI_STAT_COUNT(committed) /* committed bytes */ \ + MI_STAT_COUNT(reset) /* reset bytes */ \ + MI_STAT_COUNT(purged) /* purged bytes */ \ + MI_STAT_COUNT(page_committed) /* committed memory inside pages */ \ + MI_STAT_COUNT(pages_abandoned) /* abandonded pages count */ \ + MI_STAT_COUNT(threads) /* number of threads */ \ + MI_STAT_COUNT(malloc_normal) /* allocated bytes <= MI_LARGE_OBJ_SIZE_MAX */ \ + MI_STAT_COUNT(malloc_huge) /* allocated bytes in huge pages */ \ + MI_STAT_COUNT(malloc_requested) /* malloc requested bytes */ \ + \ + MI_STAT_COUNTER(mmap_calls) \ + MI_STAT_COUNTER(commit_calls) \ + MI_STAT_COUNTER(reset_calls) \ + MI_STAT_COUNTER(purge_calls) \ + MI_STAT_COUNTER(arena_count) /* number of memory arena's */ \ + MI_STAT_COUNTER(malloc_normal_count) /* number of blocks <= MI_LARGE_OBJ_SIZE_MAX */ \ + MI_STAT_COUNTER(malloc_huge_count) /* number of huge bloks */ \ + MI_STAT_COUNTER(malloc_guarded_count) /* number of allocations with guard pages */ \ + \ + /* internal statistics */ \ + MI_STAT_COUNTER(arena_rollback_count) \ + MI_STAT_COUNTER(arena_purges) \ + MI_STAT_COUNTER(pages_extended) /* number of page extensions */ \ + MI_STAT_COUNTER(pages_retire) /* number of pages that are retired */ \ + MI_STAT_COUNTER(page_searches) /* searches for a fresh page */ \ + /* only on v1 and v2 */ \ + MI_STAT_COUNT(segments) \ + MI_STAT_COUNT(segments_abandoned) \ + MI_STAT_COUNT(segments_cache) \ + MI_STAT_COUNT(_segments_reserved) \ + /* only on v3 */ \ + MI_STAT_COUNTER(pages_reclaim_on_alloc) \ + MI_STAT_COUNTER(pages_reclaim_on_free) \ + MI_STAT_COUNTER(pages_reabandon_full) \ + MI_STAT_COUNTER(pages_unabandon_busy_wait) \ + + +// Size bins for chunks +typedef enum mi_chunkbin_e { + MI_CBIN_SMALL, // slice_count == 1 + MI_CBIN_OTHER, // slice_count: any other from the other bins, and 1 <= slice_count <= MI_BCHUNK_BITS + MI_CBIN_MEDIUM, // slice_count == 8 + MI_CBIN_LARGE, // slice_count == MI_SIZE_BITS (only used if MI_ENABLE_LARGE_PAGES is 1) + MI_CBIN_NONE, // no bin assigned yet (the chunk is completely free) + MI_CBIN_COUNT +} mi_chunkbin_t; + + +// Define the statistics structure +#define MI_BIN_HUGE (73U) // see types.h +#define MI_STAT_COUNT(stat) mi_stat_count_t stat; +#define MI_STAT_COUNTER(stat) mi_stat_counter_t stat; + +typedef struct mi_stats_s +{ + int version; + + MI_STAT_FIELDS() + + // future extension + mi_stat_count_t _stat_reserved[4]; + mi_stat_counter_t _stat_counter_reserved[4]; + + // size segregated statistics + mi_stat_count_t malloc_bins[MI_BIN_HUGE+1]; // allocation per size bin + mi_stat_count_t page_bins[MI_BIN_HUGE+1]; // pages allocated per size bin + mi_stat_count_t chunk_bins[MI_CBIN_COUNT]; // chunks per page sizes +} mi_stats_t; + +#undef MI_STAT_COUNT +#undef MI_STAT_COUNTER + + +// Exported definitions +#ifdef __cplusplus +extern "C" { +#endif + +mi_decl_export void mi_stats_get( size_t stats_size, mi_stats_t* stats ) mi_attr_noexcept; +mi_decl_export char* mi_stats_get_json( size_t buf_size, char* buf ) mi_attr_noexcept; // use mi_free to free the result if the input buf == NULL +mi_decl_export size_t mi_stats_get_bin_size(size_t bin) mi_attr_noexcept; + +#ifdef __cplusplus +} +#endif + +#endif // MIMALLOC_STATS_H diff --git a/src/dashbls/depends/mimalloc/include/mimalloc-track.h b/src/dashbls/depends/mimalloc/include/mimalloc-track.h deleted file mode 100644 index bb9df4fa35f7..000000000000 --- a/src/dashbls/depends/mimalloc/include/mimalloc-track.h +++ /dev/null @@ -1,43 +0,0 @@ -/* ---------------------------------------------------------------------------- -Copyright (c) 2018-2021, Microsoft Research, Daan Leijen -This is free software; you can redistribute it and/or modify it under the -terms of the MIT license. A copy of the license can be found in the file -"LICENSE" at the root of this distribution. ------------------------------------------------------------------------------*/ -#pragma once -#ifndef MIMALLOC_TRACK_H -#define MIMALLOC_TRACK_H - -// ------------------------------------------------------ -// Track memory ranges with macros for tools like Valgrind -// or other memory checkers. -// ------------------------------------------------------ - -#if MI_VALGRIND - -#define MI_TRACK_ENABLED 1 - -#include -#include - -#define mi_track_malloc(p,size,zero) VALGRIND_MALLOCLIKE_BLOCK(p,size,MI_PADDING_SIZE /*red zone*/,zero) -#define mi_track_resize(p,oldsize,newsize) VALGRIND_RESIZEINPLACE_BLOCK(p,oldsize,newsize,MI_PADDING_SIZE /*red zone*/) -#define mi_track_free(p) VALGRIND_FREELIKE_BLOCK(p,MI_PADDING_SIZE /*red zone*/) -#define mi_track_mem_defined(p,size) VALGRIND_MAKE_MEM_DEFINED(p,size) -#define mi_track_mem_undefined(p,size) VALGRIND_MAKE_MEM_UNDEFINED(p,size) -#define mi_track_mem_noaccess(p,size) VALGRIND_MAKE_MEM_NOACCESS(p,size) - -#else - -#define MI_TRACK_ENABLED 0 - -#define mi_track_malloc(p,size,zero) -#define mi_track_resize(p,oldsize,newsize) -#define mi_track_free(p) -#define mi_track_mem_defined(p,size) -#define mi_track_mem_undefined(p,size) -#define mi_track_mem_noaccess(p,size) - -#endif - -#endif diff --git a/src/dashbls/depends/mimalloc/include/mimalloc-types.h b/src/dashbls/depends/mimalloc/include/mimalloc-types.h deleted file mode 100644 index 800d94136cc7..000000000000 --- a/src/dashbls/depends/mimalloc/include/mimalloc-types.h +++ /dev/null @@ -1,602 +0,0 @@ -/* ---------------------------------------------------------------------------- -Copyright (c) 2018-2021, Microsoft Research, Daan Leijen -This is free software; you can redistribute it and/or modify it under the -terms of the MIT license. A copy of the license can be found in the file -"LICENSE" at the root of this distribution. ------------------------------------------------------------------------------*/ -#pragma once -#ifndef MIMALLOC_TYPES_H -#define MIMALLOC_TYPES_H - -#include // ptrdiff_t -#include // uintptr_t, uint16_t, etc -#include "mimalloc-atomic.h" // _Atomic - -#ifdef _MSC_VER -#pragma warning(disable:4214) // bitfield is not int -#endif - -// Minimal alignment necessary. On most platforms 16 bytes are needed -// due to SSE registers for example. This must be at least `sizeof(void*)` -#ifndef MI_MAX_ALIGN_SIZE -#define MI_MAX_ALIGN_SIZE 16 // sizeof(max_align_t) -#endif - -// ------------------------------------------------------ -// Variants -// ------------------------------------------------------ - -// Define NDEBUG in the release version to disable assertions. -// #define NDEBUG - -// Define MI_VALGRIND to enable valgrind support -// #define MI_VALGRIND 1 - -// Define MI_STAT as 1 to maintain statistics; set it to 2 to have detailed statistics (but costs some performance). -// #define MI_STAT 1 - -// Define MI_SECURE to enable security mitigations -// #define MI_SECURE 1 // guard page around metadata -// #define MI_SECURE 2 // guard page around each mimalloc page -// #define MI_SECURE 3 // encode free lists (detect corrupted free list (buffer overflow), and invalid pointer free) -// #define MI_SECURE 4 // checks for double free. (may be more expensive) - -#if !defined(MI_SECURE) -#define MI_SECURE 0 -#endif - -// Define MI_DEBUG for debug mode -// #define MI_DEBUG 1 // basic assertion checks and statistics, check double free, corrupted free list, and invalid pointer free. -// #define MI_DEBUG 2 // + internal assertion checks -// #define MI_DEBUG 3 // + extensive internal invariant checking (cmake -DMI_DEBUG_FULL=ON) -#if !defined(MI_DEBUG) -#if !defined(NDEBUG) || defined(_DEBUG) -#define MI_DEBUG 2 -#else -#define MI_DEBUG 0 -#endif -#endif - -// Reserve extra padding at the end of each block to be more resilient against heap block overflows. -// The padding can detect byte-precise buffer overflow on free. -#if !defined(MI_PADDING) && (MI_DEBUG>=1 || MI_VALGRIND) -#define MI_PADDING 1 -#endif - - -// Encoded free lists allow detection of corrupted free lists -// and can detect buffer overflows, modify after free, and double `free`s. -#if (MI_SECURE>=3 || MI_DEBUG>=1) -#define MI_ENCODE_FREELIST 1 -#endif - - -// ------------------------------------------------------ -// Platform specific values -// ------------------------------------------------------ - -// ------------------------------------------------------ -// Size of a pointer. -// We assume that `sizeof(void*)==sizeof(intptr_t)` -// and it holds for all platforms we know of. -// -// However, the C standard only requires that: -// p == (void*)((intptr_t)p)) -// but we also need: -// i == (intptr_t)((void*)i) -// or otherwise one might define an intptr_t type that is larger than a pointer... -// ------------------------------------------------------ - -#if INTPTR_MAX > INT64_MAX -# define MI_INTPTR_SHIFT (4) // assume 128-bit (as on arm CHERI for example) -#elif INTPTR_MAX == INT64_MAX -# define MI_INTPTR_SHIFT (3) -#elif INTPTR_MAX == INT32_MAX -# define MI_INTPTR_SHIFT (2) -#else -#error platform pointers must be 32, 64, or 128 bits -#endif - -#if SIZE_MAX == UINT64_MAX -# define MI_SIZE_SHIFT (3) -typedef int64_t mi_ssize_t; -#elif SIZE_MAX == UINT32_MAX -# define MI_SIZE_SHIFT (2) -typedef int32_t mi_ssize_t; -#else -#error platform objects must be 32 or 64 bits -#endif - -#if (SIZE_MAX/2) > LONG_MAX -# define MI_ZU(x) x##ULL -# define MI_ZI(x) x##LL -#else -# define MI_ZU(x) x##UL -# define MI_ZI(x) x##L -#endif - -#define MI_INTPTR_SIZE (1< 4 -#define MI_SEGMENT_SHIFT (10 + MI_SEGMENT_SLICE_SHIFT) // 64MiB -#else -#define MI_SEGMENT_SHIFT ( 7 + MI_SEGMENT_SLICE_SHIFT) // 4MiB on 32-bit -#endif - -#define MI_SMALL_PAGE_SHIFT (MI_SEGMENT_SLICE_SHIFT) // 64KiB -#define MI_MEDIUM_PAGE_SHIFT ( 3 + MI_SMALL_PAGE_SHIFT) // 512KiB - - -// Derived constants -#define MI_SEGMENT_SIZE (MI_ZU(1)<= 655360) -#error "mimalloc internal: define more bins" -#endif -#if (MI_ALIGNMENT_MAX > MI_SEGMENT_SIZE/2) -#error "mimalloc internal: the max aligned boundary is too large for the segment size" -#endif -#if (MI_ALIGNED_MAX % MI_SEGMENT_SLICE_SIZE != 0) -#error "mimalloc internal: the max aligned boundary must be an integral multiple of the segment slice size" -#endif - -// Maximum slice offset (15) -#define MI_MAX_SLICE_OFFSET ((MI_ALIGNMENT_MAX / MI_SEGMENT_SLICE_SIZE) - 1) - -// Used as a special value to encode block sizes in 32 bits. -#define MI_HUGE_BLOCK_SIZE ((uint32_t)(2*MI_GiB)) - -// blocks up to this size are always allocated aligned -#define MI_MAX_ALIGN_GUARANTEE (8*MI_MAX_ALIGN_SIZE) - - - - -// ------------------------------------------------------ -// Mimalloc pages contain allocated blocks -// ------------------------------------------------------ - -// The free lists use encoded next fields -// (Only actually encodes when MI_ENCODED_FREELIST is defined.) -typedef uintptr_t mi_encoded_t; - -// thread id's -typedef size_t mi_threadid_t; - -// free lists contain blocks -typedef struct mi_block_s { - mi_encoded_t next; -} mi_block_t; - - -// The delayed flags are used for efficient multi-threaded free-ing -typedef enum mi_delayed_e { - MI_USE_DELAYED_FREE = 0, // push on the owning heap thread delayed list - MI_DELAYED_FREEING = 1, // temporary: another thread is accessing the owning heap - MI_NO_DELAYED_FREE = 2, // optimize: push on page local thread free queue if another block is already in the heap thread delayed free list - MI_NEVER_DELAYED_FREE = 3 // sticky, only resets on page reclaim -} mi_delayed_t; - - -// The `in_full` and `has_aligned` page flags are put in a union to efficiently -// test if both are false (`full_aligned == 0`) in the `mi_free` routine. -#if !MI_TSAN -typedef union mi_page_flags_s { - uint8_t full_aligned; - struct { - uint8_t in_full : 1; - uint8_t has_aligned : 1; - } x; -} mi_page_flags_t; -#else -// under thread sanitizer, use a byte for each flag to suppress warning, issue #130 -typedef union mi_page_flags_s { - uint16_t full_aligned; - struct { - uint8_t in_full; - uint8_t has_aligned; - } x; -} mi_page_flags_t; -#endif - -// Thread free list. -// We use the bottom 2 bits of the pointer for mi_delayed_t flags -typedef uintptr_t mi_thread_free_t; - -// A page contains blocks of one specific size (`block_size`). -// Each page has three list of free blocks: -// `free` for blocks that can be allocated, -// `local_free` for freed blocks that are not yet available to `mi_malloc` -// `thread_free` for freed blocks by other threads -// The `local_free` and `thread_free` lists are migrated to the `free` list -// when it is exhausted. The separate `local_free` list is necessary to -// implement a monotonic heartbeat. The `thread_free` list is needed for -// avoiding atomic operations in the common case. -// -// -// `used - |thread_free|` == actual blocks that are in use (alive) -// `used - |thread_free| + |free| + |local_free| == capacity` -// -// We don't count `freed` (as |free|) but use `used` to reduce -// the number of memory accesses in the `mi_page_all_free` function(s). -// -// Notes: -// - Access is optimized for `mi_free` and `mi_page_alloc` (in `alloc.c`) -// - Using `uint16_t` does not seem to slow things down -// - The size is 8 words on 64-bit which helps the page index calculations -// (and 10 words on 32-bit, and encoded free lists add 2 words. Sizes 10 -// and 12 are still good for address calculation) -// - To limit the structure size, the `xblock_size` is 32-bits only; for -// blocks > MI_HUGE_BLOCK_SIZE the size is determined from the segment page size -// - `thread_free` uses the bottom bits as a delayed-free flags to optimize -// concurrent frees where only the first concurrent free adds to the owning -// heap `thread_delayed_free` list (see `alloc.c:mi_free_block_mt`). -// The invariant is that no-delayed-free is only set if there is -// at least one block that will be added, or as already been added, to -// the owning heap `thread_delayed_free` list. This guarantees that pages -// will be freed correctly even if only other threads free blocks. -typedef struct mi_page_s { - // "owned" by the segment - uint32_t slice_count; // slices in this page (0 if not a page) - uint32_t slice_offset; // distance from the actual page data slice (0 if a page) - uint8_t is_reset : 1; // `true` if the page memory was reset - uint8_t is_committed : 1; // `true` if the page virtual memory is committed - uint8_t is_zero_init : 1; // `true` if the page was zero initialized - - // layout like this to optimize access in `mi_malloc` and `mi_free` - uint16_t capacity; // number of blocks committed, must be the first field, see `segment.c:page_clear` - uint16_t reserved; // number of blocks reserved in memory - mi_page_flags_t flags; // `in_full` and `has_aligned` flags (8 bits) - uint8_t is_zero : 1; // `true` if the blocks in the free list are zero initialized - uint8_t retire_expire : 7; // expiration count for retired blocks - - mi_block_t* free; // list of available free blocks (`malloc` allocates from this list) - #ifdef MI_ENCODE_FREELIST - uintptr_t keys[2]; // two random keys to encode the free lists (see `_mi_block_next`) - #endif - uint32_t used; // number of blocks in use (including blocks in `local_free` and `thread_free`) - uint32_t xblock_size; // size available in each block (always `>0`) - - mi_block_t* local_free; // list of deferred free blocks by this thread (migrates to `free`) - _Atomic(mi_thread_free_t) xthread_free; // list of deferred free blocks freed by other threads - _Atomic(uintptr_t) xheap; - - struct mi_page_s* next; // next page owned by this thread with the same `block_size` - struct mi_page_s* prev; // previous page owned by this thread with the same `block_size` - - // 64-bit 9 words, 32-bit 12 words, (+2 for secure) - #if MI_INTPTR_SIZE==8 - uintptr_t padding[1]; - #endif -} mi_page_t; - - - -typedef enum mi_page_kind_e { - MI_PAGE_SMALL, // small blocks go into 64KiB pages inside a segment - MI_PAGE_MEDIUM, // medium blocks go into medium pages inside a segment - MI_PAGE_LARGE, // larger blocks go into a page of just one block - MI_PAGE_HUGE, // huge blocks (> 16 MiB) are put into a single page in a single segment. -} mi_page_kind_t; - -typedef enum mi_segment_kind_e { - MI_SEGMENT_NORMAL, // MI_SEGMENT_SIZE size with pages inside. - MI_SEGMENT_HUGE, // > MI_LARGE_SIZE_MAX segment with just one huge page inside. -} mi_segment_kind_t; - -// ------------------------------------------------------ -// A segment holds a commit mask where a bit is set if -// the corresponding MI_COMMIT_SIZE area is committed. -// The MI_COMMIT_SIZE must be a multiple of the slice -// size. If it is equal we have the most fine grained -// decommit (but setting it higher can be more efficient). -// The MI_MINIMAL_COMMIT_SIZE is the minimal amount that will -// be committed in one go which can be set higher than -// MI_COMMIT_SIZE for efficiency (while the decommit mask -// is still tracked in fine-grained MI_COMMIT_SIZE chunks) -// ------------------------------------------------------ - -#define MI_MINIMAL_COMMIT_SIZE (2*MI_MiB) -#define MI_COMMIT_SIZE (MI_SEGMENT_SLICE_SIZE) // 64KiB -#define MI_COMMIT_MASK_BITS (MI_SEGMENT_SIZE / MI_COMMIT_SIZE) -#define MI_COMMIT_MASK_FIELD_BITS MI_SIZE_BITS -#define MI_COMMIT_MASK_FIELD_COUNT (MI_COMMIT_MASK_BITS / MI_COMMIT_MASK_FIELD_BITS) - -#if (MI_COMMIT_MASK_BITS != (MI_COMMIT_MASK_FIELD_COUNT * MI_COMMIT_MASK_FIELD_BITS)) -#error "the segment size must be exactly divisible by the (commit size * size_t bits)" -#endif - -typedef struct mi_commit_mask_s { - size_t mask[MI_COMMIT_MASK_FIELD_COUNT]; -} mi_commit_mask_t; - -typedef mi_page_t mi_slice_t; -typedef int64_t mi_msecs_t; - - -// Segments are large allocated memory blocks (8mb on 64 bit) from -// the OS. Inside segments we allocated fixed size _pages_ that -// contain blocks. -typedef struct mi_segment_s { - size_t memid; // memory id for arena allocation - bool mem_is_pinned; // `true` if we cannot decommit/reset/protect in this memory (i.e. when allocated using large OS pages) - bool mem_is_large; // in large/huge os pages? - bool mem_is_committed; // `true` if the whole segment is eagerly committed - - bool allow_decommit; - mi_msecs_t decommit_expire; - mi_commit_mask_t decommit_mask; - mi_commit_mask_t commit_mask; - - _Atomic(struct mi_segment_s*) abandoned_next; - - // from here is zero initialized - struct mi_segment_s* next; // the list of freed segments in the cache (must be first field, see `segment.c:mi_segment_init`) - - size_t abandoned; // abandoned pages (i.e. the original owning thread stopped) (`abandoned <= used`) - size_t abandoned_visits; // count how often this segment is visited in the abandoned list (to force reclaim it it is too long) - size_t used; // count of pages in use - uintptr_t cookie; // verify addresses in debug mode: `mi_ptr_cookie(segment) == segment->cookie` - - size_t segment_slices; // for huge segments this may be different from `MI_SLICES_PER_SEGMENT` - size_t segment_info_slices; // initial slices we are using segment info and possible guard pages. - - // layout like this to optimize access in `mi_free` - mi_segment_kind_t kind; - _Atomic(mi_threadid_t) thread_id; // unique id of the thread owning this segment - size_t slice_entries; // entries in the `slices` array, at most `MI_SLICES_PER_SEGMENT` - mi_slice_t slices[MI_SLICES_PER_SEGMENT]; -} mi_segment_t; - - -// ------------------------------------------------------ -// Heaps -// Provide first-class heaps to allocate from. -// A heap just owns a set of pages for allocation and -// can only be allocate/reallocate from the thread that created it. -// Freeing blocks can be done from any thread though. -// Per thread, the segments are shared among its heaps. -// Per thread, there is always a default heap that is -// used for allocation; it is initialized to statically -// point to an empty heap to avoid initialization checks -// in the fast path. -// ------------------------------------------------------ - -// Thread local data -typedef struct mi_tld_s mi_tld_t; - -// Pages of a certain block size are held in a queue. -typedef struct mi_page_queue_s { - mi_page_t* first; - mi_page_t* last; - size_t block_size; -} mi_page_queue_t; - -#define MI_BIN_FULL (MI_BIN_HUGE+1) - -// Random context -typedef struct mi_random_cxt_s { - uint32_t input[16]; - uint32_t output[16]; - int output_available; -} mi_random_ctx_t; - - -// In debug mode there is a padding structure at the end of the blocks to check for buffer overflows -#if (MI_PADDING) -typedef struct mi_padding_s { - uint32_t canary; // encoded block value to check validity of the padding (in case of overflow) - uint32_t delta; // padding bytes before the block. (mi_usable_size(p) - delta == exact allocated bytes) -} mi_padding_t; -#define MI_PADDING_SIZE (sizeof(mi_padding_t)) -#define MI_PADDING_WSIZE ((MI_PADDING_SIZE + MI_INTPTR_SIZE - 1) / MI_INTPTR_SIZE) -#else -#define MI_PADDING_SIZE 0 -#define MI_PADDING_WSIZE 0 -#endif - -#define MI_PAGES_DIRECT (MI_SMALL_WSIZE_MAX + MI_PADDING_WSIZE + 1) - - -// A heap owns a set of pages. -struct mi_heap_s { - mi_tld_t* tld; - mi_page_t* pages_free_direct[MI_PAGES_DIRECT]; // optimize: array where every entry points a page with possibly free blocks in the corresponding queue for that size. - mi_page_queue_t pages[MI_BIN_FULL + 1]; // queue of pages for each size class (or "bin") - _Atomic(mi_block_t*) thread_delayed_free; - mi_threadid_t thread_id; // thread this heap belongs too - mi_arena_id_t arena_id; // arena id if the heap belongs to a specific arena (or 0) - uintptr_t cookie; // random cookie to verify pointers (see `_mi_ptr_cookie`) - uintptr_t keys[2]; // two random keys used to encode the `thread_delayed_free` list - mi_random_ctx_t random; // random number context used for secure allocation - size_t page_count; // total number of pages in the `pages` queues. - size_t page_retired_min; // smallest retired index (retired pages are fully free, but still in the page queues) - size_t page_retired_max; // largest retired index into the `pages` array. - mi_heap_t* next; // list of heaps per thread - bool no_reclaim; // `true` if this heap should not reclaim abandoned pages -}; - - - -// ------------------------------------------------------ -// Debug -// ------------------------------------------------------ - -#if !defined(MI_DEBUG_UNINIT) -#define MI_DEBUG_UNINIT (0xD0) -#endif -#if !defined(MI_DEBUG_FREED) -#define MI_DEBUG_FREED (0xDF) -#endif -#if !defined(MI_DEBUG_PADDING) -#define MI_DEBUG_PADDING (0xDE) -#endif - -#if (MI_DEBUG) -// use our own assertion to print without memory allocation -void _mi_assert_fail(const char* assertion, const char* fname, unsigned int line, const char* func ); -#define mi_assert(expr) ((expr) ? (void)0 : _mi_assert_fail(#expr,__FILE__,__LINE__,__func__)) -#else -#define mi_assert(x) -#endif - -#if (MI_DEBUG>1) -#define mi_assert_internal mi_assert -#else -#define mi_assert_internal(x) -#endif - -#if (MI_DEBUG>2) -#define mi_assert_expensive mi_assert -#else -#define mi_assert_expensive(x) -#endif - -// ------------------------------------------------------ -// Statistics -// ------------------------------------------------------ - -#ifndef MI_STAT -#if (MI_DEBUG>0) -#define MI_STAT 2 -#else -#define MI_STAT 0 -#endif -#endif - -typedef struct mi_stat_count_s { - int64_t allocated; - int64_t freed; - int64_t peak; - int64_t current; -} mi_stat_count_t; - -typedef struct mi_stat_counter_s { - int64_t total; - int64_t count; -} mi_stat_counter_t; - -typedef struct mi_stats_s { - mi_stat_count_t segments; - mi_stat_count_t pages; - mi_stat_count_t reserved; - mi_stat_count_t committed; - mi_stat_count_t reset; - mi_stat_count_t page_committed; - mi_stat_count_t segments_abandoned; - mi_stat_count_t pages_abandoned; - mi_stat_count_t threads; - mi_stat_count_t normal; - mi_stat_count_t huge; - mi_stat_count_t large; - mi_stat_count_t malloc; - mi_stat_count_t segments_cache; - mi_stat_counter_t pages_extended; - mi_stat_counter_t mmap_calls; - mi_stat_counter_t commit_calls; - mi_stat_counter_t page_no_retire; - mi_stat_counter_t searches; - mi_stat_counter_t normal_count; - mi_stat_counter_t huge_count; - mi_stat_counter_t large_count; -#if MI_STAT>1 - mi_stat_count_t normal_bins[MI_BIN_HUGE+1]; -#endif -} mi_stats_t; - - -void _mi_stat_increase(mi_stat_count_t* stat, size_t amount); -void _mi_stat_decrease(mi_stat_count_t* stat, size_t amount); -void _mi_stat_counter_increase(mi_stat_counter_t* stat, size_t amount); - -#if (MI_STAT) -#define mi_stat_increase(stat,amount) _mi_stat_increase( &(stat), amount) -#define mi_stat_decrease(stat,amount) _mi_stat_decrease( &(stat), amount) -#define mi_stat_counter_increase(stat,amount) _mi_stat_counter_increase( &(stat), amount) -#else -#define mi_stat_increase(stat,amount) (void)0 -#define mi_stat_decrease(stat,amount) (void)0 -#define mi_stat_counter_increase(stat,amount) (void)0 -#endif - -#define mi_heap_stat_counter_increase(heap,stat,amount) mi_stat_counter_increase( (heap)->tld->stats.stat, amount) -#define mi_heap_stat_increase(heap,stat,amount) mi_stat_increase( (heap)->tld->stats.stat, amount) -#define mi_heap_stat_decrease(heap,stat,amount) mi_stat_decrease( (heap)->tld->stats.stat, amount) - -// ------------------------------------------------------ -// Thread Local data -// ------------------------------------------------------ - -// A "span" is is an available range of slices. The span queues keep -// track of slice spans of at most the given `slice_count` (but more than the previous size class). -typedef struct mi_span_queue_s { - mi_slice_t* first; - mi_slice_t* last; - size_t slice_count; -} mi_span_queue_t; - -#define MI_SEGMENT_BIN_MAX (35) // 35 == mi_segment_bin(MI_SLICES_PER_SEGMENT) - -// OS thread local data -typedef struct mi_os_tld_s { - size_t region_idx; // start point for next allocation - mi_stats_t* stats; // points to tld stats -} mi_os_tld_t; - - -// Segments thread local data -typedef struct mi_segments_tld_s { - mi_span_queue_t spans[MI_SEGMENT_BIN_MAX+1]; // free slice spans inside segments - size_t count; // current number of segments; - size_t peak_count; // peak number of segments - size_t current_size; // current size of all segments - size_t peak_size; // peak size of all segments - mi_stats_t* stats; // points to tld stats - mi_os_tld_t* os; // points to os stats -} mi_segments_tld_t; - -// Thread local data -struct mi_tld_s { - unsigned long long heartbeat; // monotonic heartbeat count - bool recurse; // true if deferred was called; used to prevent infinite recursion. - mi_heap_t* heap_backing; // backing heap of this thread (cannot be deleted) - mi_heap_t* heaps; // list of heaps in this thread (so we can abandon all when the thread terminates) - mi_segments_tld_t segments; // segment tld - mi_os_tld_t os; // os tld - mi_stats_t stats; // statistics -}; - -#endif diff --git a/src/dashbls/depends/mimalloc/include/mimalloc.h b/src/dashbls/depends/mimalloc/include/mimalloc.h index 32eab19ea5a5..aa4222f69f5b 100644 --- a/src/dashbls/depends/mimalloc/include/mimalloc.h +++ b/src/dashbls/depends/mimalloc/include/mimalloc.h @@ -1,5 +1,5 @@ /* ---------------------------------------------------------------------------- -Copyright (c) 2018-2022, Microsoft Research, Daan Leijen +Copyright (c) 2018-2023, Microsoft Research, Daan Leijen This is free software; you can redistribute it and/or modify it under the terms of the MIT license. A copy of the license can be found in the file "LICENSE" at the root of this distribution. @@ -8,7 +8,7 @@ terms of the MIT license. A copy of the license can be found in the file #ifndef MIMALLOC_H #define MIMALLOC_H -#define MI_MALLOC_VERSION 207 // major + 2 digits minor +#define MI_MALLOC_VERSION 315 // major + 2 digits minor // ------------------------------------------------------ // Compiler specific attributes @@ -28,6 +28,8 @@ terms of the MIT license. A copy of the license can be found in the file #define mi_decl_nodiscard [[nodiscard]] #elif (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__) // includes clang, icc, and clang-cl #define mi_decl_nodiscard __attribute__((warn_unused_result)) +#elif defined(_HAS_NODISCARD) + #define mi_decl_nodiscard _NODISCARD #elif (_MSC_VER >= 1700) #define mi_decl_nodiscard _Check_return_ #else @@ -95,7 +97,6 @@ terms of the MIT license. A copy of the license can be found in the file #include // size_t #include // bool -#include // INTPTR_MAX #ifdef __cplusplus extern "C" { @@ -152,26 +153,26 @@ mi_decl_export void mi_stats_reset(void) mi_attr_noexcept; mi_decl_export void mi_stats_merge(void) mi_attr_noexcept; mi_decl_export void mi_stats_print(void* out) mi_attr_noexcept; // backward compatibility: `out` is ignored and should be NULL mi_decl_export void mi_stats_print_out(mi_output_fun* out, void* arg) mi_attr_noexcept; +mi_decl_export void mi_thread_stats_print_out(mi_output_fun* out, void* arg) mi_attr_noexcept; +mi_decl_export void mi_options_print(void) mi_attr_noexcept; + +mi_decl_export void mi_process_info(size_t* elapsed_msecs, size_t* user_msecs, size_t* system_msecs, + size_t* current_rss, size_t* peak_rss, + size_t* current_commit, size_t* peak_commit, size_t* page_faults) mi_attr_noexcept; + +// Generally do not use the following as these are usually called automatically mi_decl_export void mi_process_init(void) mi_attr_noexcept; +mi_decl_export void mi_cdecl mi_process_done(void) mi_attr_noexcept; mi_decl_export void mi_thread_init(void) mi_attr_noexcept; mi_decl_export void mi_thread_done(void) mi_attr_noexcept; -mi_decl_export void mi_thread_stats_print_out(mi_output_fun* out, void* arg) mi_attr_noexcept; -mi_decl_export void mi_process_info(size_t* elapsed_msecs, size_t* user_msecs, size_t* system_msecs, - size_t* current_rss, size_t* peak_rss, - size_t* current_commit, size_t* peak_commit, size_t* page_faults) mi_attr_noexcept; // ------------------------------------------------------------------------------------- // Aligned allocation // Note that `alignment` always follows `size` for consistency with unaligned // allocation, but unfortunately this differs from `posix_memalign` and `aligned_alloc`. // ------------------------------------------------------------------------------------- -#if (INTPTR_MAX > INT32_MAX) -#define MI_ALIGNMENT_MAX (16*1024*1024UL) // maximum supported alignment is 16MiB -#else -#define MI_ALIGNMENT_MAX (1024*1024UL) // maximum supported alignment for 32-bit systems is 1MiB -#endif mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_malloc_aligned(size_t size, size_t alignment) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(1) mi_attr_alloc_align(2); mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_malloc_aligned_at(size_t size, size_t alignment, size_t offset) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(1); @@ -262,37 +263,89 @@ typedef struct mi_heap_area_s { size_t used; // number of allocated blocks size_t block_size; // size in bytes of each block size_t full_block_size; // size in bytes of a full block including padding and metadata. + int heap_tag; // heap tag associated with this area } mi_heap_area_t; typedef bool (mi_cdecl mi_block_visit_fun)(const mi_heap_t* heap, const mi_heap_area_t* area, void* block, size_t block_size, void* arg); -mi_decl_export bool mi_heap_visit_blocks(const mi_heap_t* heap, bool visit_all_blocks, mi_block_visit_fun* visitor, void* arg); +mi_decl_export bool mi_heap_visit_blocks(const mi_heap_t* heap, bool visit_blocks, mi_block_visit_fun* visitor, void* arg); -// Experimental +// Advanced mi_decl_nodiscard mi_decl_export bool mi_is_in_heap_region(const void* p) mi_attr_noexcept; mi_decl_nodiscard mi_decl_export bool mi_is_redirected(void) mi_attr_noexcept; -mi_decl_export int mi_reserve_huge_os_pages_interleave(size_t pages, size_t numa_nodes, size_t timeout_msecs) mi_attr_noexcept; -mi_decl_export int mi_reserve_huge_os_pages_at(size_t pages, int numa_node, size_t timeout_msecs) mi_attr_noexcept; +mi_decl_export int mi_reserve_huge_os_pages_interleave(size_t pages, size_t numa_nodes, size_t timeout_msecs) mi_attr_noexcept; +mi_decl_export int mi_reserve_huge_os_pages_at(size_t pages, int numa_node, size_t timeout_msecs) mi_attr_noexcept; -mi_decl_export int mi_reserve_os_memory(size_t size, bool commit, bool allow_large) mi_attr_noexcept; -mi_decl_export bool mi_manage_os_memory(void* start, size_t size, bool is_committed, bool is_large, bool is_zero, int numa_node) mi_attr_noexcept; +mi_decl_export int mi_reserve_os_memory(size_t size, bool commit, bool allow_large) mi_attr_noexcept; +mi_decl_export bool mi_manage_os_memory(void* start, size_t size, bool is_committed, bool is_pinned /* cannot decommit/reset? */, bool is_zero, int numa_node) mi_attr_noexcept; -mi_decl_export void mi_debug_show_arenas(void) mi_attr_noexcept; +mi_decl_export void mi_debug_show_arenas(void) mi_attr_noexcept; +mi_decl_export void mi_arenas_print(void) mi_attr_noexcept; +mi_decl_export size_t mi_arena_min_alignment(void); -// Experimental: heaps associated with specific memory arena's -typedef int mi_arena_id_t; -mi_decl_export void* mi_arena_area(mi_arena_id_t arena_id, size_t* size); -mi_decl_export int mi_reserve_huge_os_pages_at_ex(size_t pages, int numa_node, size_t timeout_msecs, bool exclusive, mi_arena_id_t* arena_id) mi_attr_noexcept; -mi_decl_export int mi_reserve_os_memory_ex(size_t size, bool commit, bool allow_large, bool exclusive, mi_arena_id_t* arena_id) mi_attr_noexcept; -mi_decl_export bool mi_manage_os_memory_ex(void* start, size_t size, bool is_committed, bool is_large, bool is_zero, int numa_node, bool exclusive, mi_arena_id_t* arena_id) mi_attr_noexcept; +// Advanced: heaps associated with specific memory arena's +typedef void* mi_arena_id_t; +mi_decl_export void* mi_arena_area(mi_arena_id_t arena_id, size_t* size); +mi_decl_export int mi_reserve_huge_os_pages_at_ex(size_t pages, int numa_node, size_t timeout_msecs, bool exclusive, mi_arena_id_t* arena_id) mi_attr_noexcept; +mi_decl_export int mi_reserve_os_memory_ex(size_t size, bool commit, bool allow_large, bool exclusive, mi_arena_id_t* arena_id) mi_attr_noexcept; +mi_decl_export bool mi_manage_os_memory_ex(void* start, size_t size, bool is_committed, bool is_pinned, bool is_zero, int numa_node, bool exclusive, mi_arena_id_t* arena_id) mi_attr_noexcept; -#if MI_MALLOC_VERSION >= 200 +#if MI_MALLOC_VERSION >= 182 +// Create a heap that only allocates in the specified arena mi_decl_nodiscard mi_decl_export mi_heap_t* mi_heap_new_in_arena(mi_arena_id_t arena_id); #endif + +// Advanced: allow sub-processes whose memory areas stay separated (and no reclamation between them) +// Used for example for separate interpreters in one process. +typedef void* mi_subproc_id_t; +mi_decl_export mi_subproc_id_t mi_subproc_main(void); +mi_decl_export mi_subproc_id_t mi_subproc_new(void); +mi_decl_export void mi_subproc_delete(mi_subproc_id_t subproc); +mi_decl_export void mi_subproc_add_current_thread(mi_subproc_id_t subproc); // this should be called right after a thread is created (and no allocation has taken place yet) + +// Advanced: visit abandoned heap areas (that are not owned by a specific heap) +mi_decl_export bool mi_abandoned_visit_blocks(mi_subproc_id_t subproc_id, int heap_tag, bool visit_blocks, mi_block_visit_fun* visitor, void* arg); + +// Experimental: set numa-affinity of a heap +mi_decl_export void mi_heap_set_numa_affinity(mi_heap_t* heap, int numa_node); + +// Experimental: objects followed by a guard page. +// Setting the sample rate on a specific heap can be used to test parts of the program more +// specifically (in combination with `mi_heap_set_default`). +// A sample rate of 0 disables guarded objects, while 1 uses a guard page for every object. +// A seed of 0 uses a random start point. Only objects within the size bound are eligable for guard pages. +mi_decl_export void mi_heap_guarded_set_sample_rate(mi_heap_t* heap, size_t sample_rate, size_t seed); +mi_decl_export void mi_heap_guarded_set_size_bound(mi_heap_t* heap, size_t min, size_t max); + +// Experimental: communicate that the thread is part of a threadpool +mi_decl_export void mi_thread_set_in_threadpool(void) mi_attr_noexcept; + +// Experimental: create a new heap with a specified heap tag. Set `allow_destroy` to false to allow the thread +// to reclaim abandoned memory (with a compatible heap_tag and arena_id) but in that case `mi_heap_destroy` will +// fall back to `mi_heap_delete`. +mi_decl_nodiscard mi_decl_export mi_heap_t* mi_heap_new_ex(int heap_tag, bool allow_destroy, mi_arena_id_t arena_id); + // deprecated -mi_decl_export int mi_reserve_huge_os_pages(size_t pages, double max_secs, size_t* pages_reserved) mi_attr_noexcept; +mi_decl_export int mi_reserve_huge_os_pages(size_t pages, double max_secs, size_t* pages_reserved) mi_attr_noexcept; +mi_decl_export void mi_collect_reduce(size_t target_thread_owned) mi_attr_noexcept; + + + +// experimental +typedef bool (mi_cdecl mi_commit_fun_t)(bool commit, void* start, size_t size, bool* is_zero, void* user_arg); +mi_decl_export bool mi_manage_memory(void* start, size_t size, bool is_committed, bool is_pinned, bool is_zero, int numa_node, bool exclusive, + mi_commit_fun_t* commit_fun, void* commit_fun_arg, mi_arena_id_t* arena_id) mi_attr_noexcept; + +mi_decl_export bool mi_arena_unload(mi_arena_id_t arena_id, void** base, size_t* accessed_size, size_t* size); +mi_decl_export bool mi_arena_reload(void* start, size_t size, mi_commit_fun_t* commit_fun, void* commit_fun_arg, mi_arena_id_t* arena_id); +mi_decl_export bool mi_heap_reload(mi_heap_t* heap, mi_arena_id_t arena); +mi_decl_export void mi_heap_unload(mi_heap_t* heap); + + +// Is a pointer contained in the given arena area? +mi_decl_export bool mi_arena_contains(mi_arena_id_t arena_id, const void* p); // ------------------------------------------------------ @@ -320,34 +373,58 @@ mi_decl_export int mi_reserve_huge_os_pages(size_t pages, double max_secs, size typedef enum mi_option_e { // stable options - mi_option_show_errors, - mi_option_show_stats, - mi_option_verbose, - // some of the following options are experimental - // (deprecated options are kept for binary backward compatibility with v1.x versions) - mi_option_eager_commit, - mi_option_deprecated_eager_region_commit, - mi_option_deprecated_reset_decommits, - mi_option_large_os_pages, // use large (2MiB) OS pages, implies eager commit - mi_option_reserve_huge_os_pages, // reserve N huge OS pages (1GiB) at startup - mi_option_reserve_huge_os_pages_at, // reserve huge OS pages at a specific NUMA node - mi_option_reserve_os_memory, // reserve specified amount of OS memory at startup + mi_option_show_errors, // print error messages + mi_option_show_stats, // print statistics on termination + mi_option_verbose, // print verbose messages + // advanced options + mi_option_eager_commit, // eager commit segments? (after `eager_commit_delay` segments) (=1) + mi_option_arena_eager_commit, // eager commit arenas? Use 2 to enable just on overcommit systems (=2) + mi_option_purge_decommits, // should a memory purge decommit? (=1). Set to 0 to use memory reset on a purge (instead of decommit) + mi_option_allow_large_os_pages, // allow large (2 or 4 MiB) OS pages, implies eager commit. If false, also disables THP for the process. + mi_option_reserve_huge_os_pages, // reserve N huge OS pages (1GiB pages) at startup + mi_option_reserve_huge_os_pages_at, // reserve huge OS pages at a specific NUMA node + mi_option_reserve_os_memory, // reserve specified amount of OS memory in an arena at startup (internally, this value is in KiB; use `mi_option_get_size`) mi_option_deprecated_segment_cache, - mi_option_page_reset, - mi_option_abandoned_page_decommit, + mi_option_deprecated_page_reset, + mi_option_abandoned_page_purge, // immediately purge delayed purges on thread termination mi_option_deprecated_segment_reset, - mi_option_eager_commit_delay, - mi_option_decommit_delay, - mi_option_use_numa_nodes, // 0 = use available numa nodes, otherwise use at most N nodes. - mi_option_limit_os_alloc, // 1 = do not use OS memory for allocation (but only reserved arenas) - mi_option_os_tag, - mi_option_max_errors, - mi_option_max_warnings, - mi_option_max_segment_reclaim, - mi_option_allow_decommit, - mi_option_segment_decommit_delay, - mi_option_decommit_extend_delay, - _mi_option_last + mi_option_eager_commit_delay, // the first N segments per thread are not eagerly committed (but per page in the segment on demand) + mi_option_purge_delay, // memory purging is delayed by N milli seconds; use 0 for immediate purging or -1 for no purging at all. (=10) + mi_option_use_numa_nodes, // 0 = use all available numa nodes, otherwise use at most N nodes. + mi_option_disallow_os_alloc, // 1 = do not use OS memory for allocation (but only programmatically reserved arenas) + mi_option_os_tag, // tag used for OS logging (macOS only for now) (=100) + mi_option_max_errors, // issue at most N error messages + mi_option_max_warnings, // issue at most N warning messages + mi_option_deprecated_max_segment_reclaim, // max. percentage of the abandoned segments can be reclaimed per try (=10%) + mi_option_destroy_on_exit, // if set, release all memory on exit; sometimes used for dynamic unloading but can be unsafe + mi_option_arena_reserve, // initial memory size for arena reservation (= 1 GiB on 64-bit) (internally, this value is in KiB; use `mi_option_get_size`) + mi_option_arena_purge_mult, // multiplier for `purge_delay` for the purging delay for arenas (=10) + mi_option_deprecated_purge_extend_delay, + mi_option_disallow_arena_alloc, // 1 = do not use arena's for allocation (except if using specific arena id's) + mi_option_retry_on_oom, // retry on out-of-memory for N milli seconds (=400), set to 0 to disable retries. (only on windows) + mi_option_visit_abandoned, // allow visiting heap blocks from abandoned threads (=0) + mi_option_guarded_min, // only used when building with MI_GUARDED: minimal rounded object size for guarded objects (=0) + mi_option_guarded_max, // only used when building with MI_GUARDED: maximal rounded object size for guarded objects (=0) + mi_option_guarded_precise, // disregard minimal alignment requirement to always place guarded blocks exactly in front of a guard page (=0) + mi_option_guarded_sample_rate, // 1 out of N allocations in the min/max range will be guarded (=1000) + mi_option_guarded_sample_seed, // can be set to allow for a (more) deterministic re-execution when a guard page is triggered (=0) + mi_option_generic_collect, // collect heaps every N (=10000) generic allocation calls + mi_option_page_reclaim_on_free, // reclaim abandoned pages on a free (=0). -1 disallowr always, 0 allows if the page originated from the current heap, 1 allow always + mi_option_page_full_retain, // retain N full (small) pages per size class (=2) + mi_option_page_max_candidates, // max candidate pages to consider for allocation (=4) + mi_option_max_vabits, // max user space virtual address bits to consider (=48) + mi_option_pagemap_commit, // commit the full pagemap (to always catch invalid pointer uses) (=0) + mi_option_page_commit_on_demand, // commit page memory on-demand + mi_option_page_max_reclaim, // don't reclaim pages of the same originating heap if we already own N pages (in that size class) (=-1 (unlimited)) + mi_option_page_cross_thread_max_reclaim, // don't reclaim pages across threads if we already own N pages (in that size class) (=16) + _mi_option_last, + // legacy option names + mi_option_large_os_pages = mi_option_allow_large_os_pages, + mi_option_eager_region_commit = mi_option_arena_eager_commit, + mi_option_reset_decommits = mi_option_purge_decommits, + mi_option_reset_delay = mi_option_purge_delay, + mi_option_abandoned_page_reset = mi_option_abandoned_page_purge, + mi_option_limit_os_alloc = mi_option_disallow_os_alloc } mi_option_t; @@ -357,8 +434,9 @@ mi_decl_export void mi_option_disable(mi_option_t option); mi_decl_export void mi_option_set_enabled(mi_option_t option, bool enable); mi_decl_export void mi_option_set_enabled_default(mi_option_t option, bool enable); -mi_decl_nodiscard mi_decl_export long mi_option_get(mi_option_t option); -mi_decl_nodiscard mi_decl_export long mi_option_get_clamp(mi_option_t option, long min, long max); +mi_decl_nodiscard mi_decl_export long mi_option_get(mi_option_t option); +mi_decl_nodiscard mi_decl_export long mi_option_get_clamp(mi_option_t option, long min, long max); +mi_decl_nodiscard mi_decl_export size_t mi_option_get_size(mi_option_t option); mi_decl_export void mi_option_set(mi_option_t option, long value); mi_decl_export void mi_option_set_default(mi_option_t option, long value); @@ -405,6 +483,9 @@ mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_new_n(size_t count, s mi_decl_nodiscard mi_decl_export void* mi_new_realloc(void* p, size_t newsize) mi_attr_alloc_size(2); mi_decl_nodiscard mi_decl_export void* mi_new_reallocn(void* p, size_t newcount, size_t size) mi_attr_alloc_size2(2, 3); +mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_heap_alloc_new(mi_heap_t* heap, size_t size) mi_attr_malloc mi_attr_alloc_size(2); +mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_heap_alloc_new_n(mi_heap_t* heap, size_t count, size_t size) mi_attr_malloc mi_attr_alloc_size2(2, 3); + #ifdef __cplusplus } #endif @@ -422,7 +503,7 @@ mi_decl_nodiscard mi_decl_export void* mi_new_reallocn(void* p, size_t newcount, #include // std::forward #endif -template struct mi_stl_allocator { +template struct _mi_stl_allocator_common { typedef T value_type; typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; @@ -430,6 +511,27 @@ template struct mi_stl_allocator { typedef value_type const& const_reference; typedef value_type* pointer; typedef value_type const* const_pointer; + + #if ((__cplusplus >= 201103L) || (_MSC_VER > 1900)) // C++11 + using propagate_on_container_copy_assignment = std::true_type; + using propagate_on_container_move_assignment = std::true_type; + using propagate_on_container_swap = std::true_type; + template void construct(U* p, Args&& ...args) { ::new(p) U(std::forward(args)...); } + template void destroy(U* p) mi_attr_noexcept { p->~U(); } + #else + void construct(pointer p, value_type const& val) { ::new(p) value_type(val); } + void destroy(pointer p) { p->~value_type(); } + #endif + + size_type max_size() const mi_attr_noexcept { return (PTRDIFF_MAX/sizeof(value_type)); } + pointer address(reference x) const { return &x; } + const_pointer address(const_reference x) const { return &x; } +}; + +template struct mi_stl_allocator : public _mi_stl_allocator_common { + using typename _mi_stl_allocator_common::size_type; + using typename _mi_stl_allocator_common::value_type; + using typename _mi_stl_allocator_common::pointer; template struct rebind { typedef mi_stl_allocator other; }; mi_stl_allocator() mi_attr_noexcept = default; @@ -446,24 +548,91 @@ template struct mi_stl_allocator { #endif #if ((__cplusplus >= 201103L) || (_MSC_VER > 1900)) // C++11 - using propagate_on_container_copy_assignment = std::true_type; - using propagate_on_container_move_assignment = std::true_type; - using propagate_on_container_swap = std::true_type; - using is_always_equal = std::true_type; - template void construct(U* p, Args&& ...args) { ::new(p) U(std::forward(args)...); } - template void destroy(U* p) mi_attr_noexcept { p->~U(); } - #else - void construct(pointer p, value_type const& val) { ::new(p) value_type(val); } - void destroy(pointer p) { p->~value_type(); } + using is_always_equal = std::true_type; #endif - - size_type max_size() const mi_attr_noexcept { return (PTRDIFF_MAX/sizeof(value_type)); } - pointer address(reference x) const { return &x; } - const_pointer address(const_reference x) const { return &x; } }; template bool operator==(const mi_stl_allocator& , const mi_stl_allocator& ) mi_attr_noexcept { return true; } template bool operator!=(const mi_stl_allocator& , const mi_stl_allocator& ) mi_attr_noexcept { return false; } + + +#if (__cplusplus >= 201103L) || (_MSC_VER >= 1900) // C++11 +#define MI_HAS_HEAP_STL_ALLOCATOR 1 + +#include // std::shared_ptr + +// Common base class for STL allocators in a specific heap +template struct _mi_heap_stl_allocator_common : public _mi_stl_allocator_common { + using typename _mi_stl_allocator_common::size_type; + using typename _mi_stl_allocator_common::value_type; + using typename _mi_stl_allocator_common::pointer; + + _mi_heap_stl_allocator_common(mi_heap_t* hp) : heap(hp, [](mi_heap_t*) {}) {} /* will not delete nor destroy the passed in heap */ + + #if (__cplusplus >= 201703L) // C++17 + mi_decl_nodiscard T* allocate(size_type count) { return static_cast(mi_heap_alloc_new_n(this->heap.get(), count, sizeof(T))); } + mi_decl_nodiscard T* allocate(size_type count, const void*) { return allocate(count); } + #else + mi_decl_nodiscard pointer allocate(size_type count, const void* = 0) { return static_cast(mi_heap_alloc_new_n(this->heap.get(), count, sizeof(value_type))); } + #endif + + #if ((__cplusplus >= 201103L) || (_MSC_VER > 1900)) // C++11 + using is_always_equal = std::false_type; + #endif + + void collect(bool force) { mi_heap_collect(this->heap.get(), force); } + template bool is_equal(const _mi_heap_stl_allocator_common& x) const { return (this->heap == x.heap); } + +protected: + std::shared_ptr heap; + template friend struct _mi_heap_stl_allocator_common; + + _mi_heap_stl_allocator_common() { + mi_heap_t* hp = mi_heap_new(); + this->heap.reset(hp, (_mi_destroy ? &heap_destroy : &heap_delete)); /* calls heap_delete/destroy when the refcount drops to zero */ + } + _mi_heap_stl_allocator_common(const _mi_heap_stl_allocator_common& x) mi_attr_noexcept : heap(x.heap) { } + template _mi_heap_stl_allocator_common(const _mi_heap_stl_allocator_common& x) mi_attr_noexcept : heap(x.heap) { } + +private: + static void heap_delete(mi_heap_t* hp) { if (hp != NULL) { mi_heap_delete(hp); } } + static void heap_destroy(mi_heap_t* hp) { if (hp != NULL) { mi_heap_destroy(hp); } } +}; + +// STL allocator allocation in a specific heap +template struct mi_heap_stl_allocator : public _mi_heap_stl_allocator_common { + using typename _mi_heap_stl_allocator_common::size_type; + mi_heap_stl_allocator() : _mi_heap_stl_allocator_common() { } // creates fresh heap that is deleted when the destructor is called + mi_heap_stl_allocator(mi_heap_t* hp) : _mi_heap_stl_allocator_common(hp) { } // no delete nor destroy on the passed in heap + template mi_heap_stl_allocator(const mi_heap_stl_allocator& x) mi_attr_noexcept : _mi_heap_stl_allocator_common(x) { } + + mi_heap_stl_allocator select_on_container_copy_construction() const { return *this; } + void deallocate(T* p, size_type) { mi_free(p); } + template struct rebind { typedef mi_heap_stl_allocator other; }; +}; + +template bool operator==(const mi_heap_stl_allocator& x, const mi_heap_stl_allocator& y) mi_attr_noexcept { return (x.is_equal(y)); } +template bool operator!=(const mi_heap_stl_allocator& x, const mi_heap_stl_allocator& y) mi_attr_noexcept { return (!x.is_equal(y)); } + + +// STL allocator allocation in a specific heap, where `free` does nothing and +// the heap is destroyed in one go on destruction -- use with care! +template struct mi_heap_destroy_stl_allocator : public _mi_heap_stl_allocator_common { + using typename _mi_heap_stl_allocator_common::size_type; + mi_heap_destroy_stl_allocator() : _mi_heap_stl_allocator_common() { } // creates fresh heap that is destroyed when the destructor is called + mi_heap_destroy_stl_allocator(mi_heap_t* hp) : _mi_heap_stl_allocator_common(hp) { } // no delete nor destroy on the passed in heap + template mi_heap_destroy_stl_allocator(const mi_heap_destroy_stl_allocator& x) mi_attr_noexcept : _mi_heap_stl_allocator_common(x) { } + + mi_heap_destroy_stl_allocator select_on_container_copy_construction() const { return *this; } + void deallocate(T*, size_type) { /* do nothing as we destroy the heap on destruct. */ } + template struct rebind { typedef mi_heap_destroy_stl_allocator other; }; +}; + +template bool operator==(const mi_heap_destroy_stl_allocator& x, const mi_heap_destroy_stl_allocator& y) mi_attr_noexcept { return (x.is_equal(y)); } +template bool operator!=(const mi_heap_destroy_stl_allocator& x, const mi_heap_destroy_stl_allocator& y) mi_attr_noexcept { return (!x.is_equal(y)); } + +#endif // C++11 + #endif // __cplusplus #endif diff --git a/src/dashbls/depends/mimalloc/include/mimalloc-atomic.h b/src/dashbls/depends/mimalloc/include/mimalloc/atomic.h similarity index 59% rename from src/dashbls/depends/mimalloc/include/mimalloc-atomic.h rename to src/dashbls/depends/mimalloc/include/mimalloc/atomic.h index 7ad5da585133..592afb16e97f 100644 --- a/src/dashbls/depends/mimalloc/include/mimalloc-atomic.h +++ b/src/dashbls/depends/mimalloc/include/mimalloc/atomic.h @@ -1,45 +1,64 @@ /* ---------------------------------------------------------------------------- -Copyright (c) 2018-2021 Microsoft Research, Daan Leijen +Copyright (c) 2018-2024 Microsoft Research, Daan Leijen This is free software; you can redistribute it and/or modify it under the terms of the MIT license. A copy of the license can be found in the file "LICENSE" at the root of this distribution. -----------------------------------------------------------------------------*/ #pragma once -#ifndef MIMALLOC_ATOMIC_H -#define MIMALLOC_ATOMIC_H +#ifndef MI_ATOMIC_H +#define MI_ATOMIC_H + +// include windows.h or pthreads.h +#if defined(_WIN32) +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#elif !defined(__wasi__) && (!defined(__EMSCRIPTEN__) || defined(__EMSCRIPTEN_PTHREADS__)) +#define MI_USE_PTHREADS +#include +#endif // -------------------------------------------------------------------------------------------- // Atomics // We need to be portable between C, C++, and MSVC. -// We base the primitives on the C/C++ atomics and create a mimimal wrapper for MSVC in C compilation mode. -// This is why we try to use only `uintptr_t` and `*` as atomic types. -// To gain better insight in the range of used atomics, we use explicitly named memory order operations +// We base the primitives on the C/C++ atomics and create a minimal wrapper for MSVC in C compilation mode. +// This is why we try to use only `uintptr_t` and `*` as atomic types. +// To gain better insight in the range of used atomics, we use explicitly named memory order operations // instead of passing the memory order as a parameter. // ----------------------------------------------------------------------------------------------- #if defined(__cplusplus) // Use C++ atomics #include -#define _Atomic(tp) std::atomic -#define mi_atomic(name) std::atomic_##name -#define mi_memory_order(name) std::memory_order_##name -#if !defined(ATOMIC_VAR_INIT) || (__cplusplus >= 202002L) // c++20, see issue #571 - #define MI_ATOMIC_VAR_INIT(x) x +#define _Atomic(tp) std::atomic +#define mi_atomic(name) std::atomic_##name +#define mi_memory_order(name) std::memory_order_##name +#if (__cplusplus >= 202002L) // c++20, see issue #571 + #define MI_ATOMIC_VAR_INIT(x) x +#elif !defined(ATOMIC_VAR_INIT) + #define MI_ATOMIC_VAR_INIT(x) x #else - #define MI_ATOMIC_VAR_INIT(x) ATOMIC_VAR_INIT(x) + #define MI_ATOMIC_VAR_INIT(x) ATOMIC_VAR_INIT(x) #endif #elif defined(_MSC_VER) // Use MSVC C wrapper for C11 atomics -#define _Atomic(tp) tp -#define MI_ATOMIC_VAR_INIT(x) x -#define mi_atomic(name) mi_atomic_##name -#define mi_memory_order(name) mi_memory_order_##name +#define _Atomic(tp) tp +#define MI_ATOMIC_VAR_INIT(x) x +#define mi_atomic(name) mi_atomic_##name +#define mi_memory_order(name) mi_memory_order_##name #else // Use C11 atomics #include -#define mi_atomic(name) atomic_##name -#define mi_memory_order(name) memory_order_##name -#define MI_ATOMIC_VAR_INIT(x) ATOMIC_VAR_INIT(x) +#define mi_atomic(name) atomic_##name +#define mi_memory_order(name) memory_order_##name +#if (__STDC_VERSION__ >= 201710L) // c17, see issue #735 + #define MI_ATOMIC_VAR_INIT(x) x +#elif !defined(ATOMIC_VAR_INIT) + #define MI_ATOMIC_VAR_INIT(x) x +#else + #define MI_ATOMIC_VAR_INIT(x) ATOMIC_VAR_INIT(x) +#endif #endif // Various defines for all used memory orders in mimalloc @@ -53,18 +72,24 @@ terms of the MIT license. A copy of the license can be found in the file #define mi_atomic_load_relaxed(p) mi_atomic(load_explicit)(p,mi_memory_order(relaxed)) #define mi_atomic_store_release(p,x) mi_atomic(store_explicit)(p,x,mi_memory_order(release)) #define mi_atomic_store_relaxed(p,x) mi_atomic(store_explicit)(p,x,mi_memory_order(relaxed)) +#define mi_atomic_exchange_relaxed(p,x) mi_atomic(exchange_explicit)(p,x,mi_memory_order(relaxed)) #define mi_atomic_exchange_release(p,x) mi_atomic(exchange_explicit)(p,x,mi_memory_order(release)) #define mi_atomic_exchange_acq_rel(p,x) mi_atomic(exchange_explicit)(p,x,mi_memory_order(acq_rel)) + +#define mi_atomic_cas_weak_relaxed(p,exp,des) mi_atomic_cas_weak(p,exp,des,mi_memory_order(relaxed),mi_memory_order(relaxed)) #define mi_atomic_cas_weak_release(p,exp,des) mi_atomic_cas_weak(p,exp,des,mi_memory_order(release),mi_memory_order(relaxed)) #define mi_atomic_cas_weak_acq_rel(p,exp,des) mi_atomic_cas_weak(p,exp,des,mi_memory_order(acq_rel),mi_memory_order(acquire)) +#define mi_atomic_cas_strong_relaxed(p,exp,des) mi_atomic_cas_strong(p,exp,des,mi_memory_order(relaxed),mi_memory_order(relaxed)) #define mi_atomic_cas_strong_release(p,exp,des) mi_atomic_cas_strong(p,exp,des,mi_memory_order(release),mi_memory_order(relaxed)) #define mi_atomic_cas_strong_acq_rel(p,exp,des) mi_atomic_cas_strong(p,exp,des,mi_memory_order(acq_rel),mi_memory_order(acquire)) #define mi_atomic_add_relaxed(p,x) mi_atomic(fetch_add_explicit)(p,x,mi_memory_order(relaxed)) -#define mi_atomic_sub_relaxed(p,x) mi_atomic(fetch_sub_explicit)(p,x,mi_memory_order(relaxed)) #define mi_atomic_add_acq_rel(p,x) mi_atomic(fetch_add_explicit)(p,x,mi_memory_order(acq_rel)) +#define mi_atomic_sub_relaxed(p,x) mi_atomic(fetch_sub_explicit)(p,x,mi_memory_order(relaxed)) #define mi_atomic_sub_acq_rel(p,x) mi_atomic(fetch_sub_explicit)(p,x,mi_memory_order(acq_rel)) +#define mi_atomic_and_relaxed(p,x) mi_atomic(fetch_and_explicit)(p,x,mi_memory_order(relaxed)) #define mi_atomic_and_acq_rel(p,x) mi_atomic(fetch_and_explicit)(p,x,mi_memory_order(acq_rel)) +#define mi_atomic_or_relaxed(p,x) mi_atomic(fetch_or_explicit)(p,x,mi_memory_order(relaxed)) #define mi_atomic_or_acq_rel(p,x) mi_atomic(fetch_or_explicit)(p,x,mi_memory_order(acq_rel)) #define mi_atomic_increment_relaxed(p) mi_atomic_add_relaxed(p,(uintptr_t)1) @@ -91,6 +116,8 @@ static inline intptr_t mi_atomic_subi(_Atomic(intptr_t)*p, intptr_t sub); #define mi_atomic_cas_ptr_weak_release(tp,p,exp,des) mi_atomic_cas_weak_release(p,exp,(tp*)des) #define mi_atomic_cas_ptr_weak_acq_rel(tp,p,exp,des) mi_atomic_cas_weak_acq_rel(p,exp,(tp*)des) #define mi_atomic_cas_ptr_strong_release(tp,p,exp,des) mi_atomic_cas_strong_release(p,exp,(tp*)des) +#define mi_atomic_cas_ptr_strong_acq_rel(tp,p,exp,des) mi_atomic_cas_strong_acq_rel(p,exp,(tp*)des) +#define mi_atomic_exchange_ptr_relaxed(tp,p,x) mi_atomic_exchange_relaxed(p,(tp*)x) #define mi_atomic_exchange_ptr_release(tp,p,x) mi_atomic_exchange_release(p,(tp*)x) #define mi_atomic_exchange_ptr_acq_rel(tp,p,x) mi_atomic_exchange_acq_rel(p,(tp*)x) #else @@ -99,6 +126,8 @@ static inline intptr_t mi_atomic_subi(_Atomic(intptr_t)*p, intptr_t sub); #define mi_atomic_cas_ptr_weak_release(tp,p,exp,des) mi_atomic_cas_weak_release(p,exp,des) #define mi_atomic_cas_ptr_weak_acq_rel(tp,p,exp,des) mi_atomic_cas_weak_acq_rel(p,exp,des) #define mi_atomic_cas_ptr_strong_release(tp,p,exp,des) mi_atomic_cas_strong_release(p,exp,des) +#define mi_atomic_cas_ptr_strong_acq_rel(tp,p,exp,des) mi_atomic_cas_strong_acq_rel(p,exp,des) +#define mi_atomic_exchange_ptr_relaxed(tp,p,x) mi_atomic_exchange_relaxed(p,x) #define mi_atomic_exchange_ptr_release(tp,p,x) mi_atomic_exchange_release(p,x) #define mi_atomic_exchange_ptr_acq_rel(tp,p,x) mi_atomic_exchange_acq_rel(p,x) #endif @@ -107,24 +136,30 @@ static inline intptr_t mi_atomic_subi(_Atomic(intptr_t)*p, intptr_t sub); static inline int64_t mi_atomic_addi64_relaxed(volatile int64_t* p, int64_t add) { return mi_atomic(fetch_add_explicit)((_Atomic(int64_t)*)p, add, mi_memory_order(relaxed)); } +static inline void mi_atomic_void_addi64_relaxed(volatile int64_t* p, const volatile int64_t* padd) { + const int64_t add = mi_atomic_load_relaxed((_Atomic(int64_t)*)padd); + if (add != 0) { + mi_atomic(fetch_add_explicit)((_Atomic(int64_t)*)p, add, mi_memory_order(relaxed)); + } +} static inline void mi_atomic_maxi64_relaxed(volatile int64_t* p, int64_t x) { int64_t current = mi_atomic_load_relaxed((_Atomic(int64_t)*)p); while (current < x && !mi_atomic_cas_weak_release((_Atomic(int64_t)*)p, ¤t, x)) { /* nothing */ }; } // Used by timers -#define mi_atomic_loadi64_acquire(p) mi_atomic(load_explicit)(p,mi_memory_order(acquire)) -#define mi_atomic_loadi64_relaxed(p) mi_atomic(load_explicit)(p,mi_memory_order(relaxed)) -#define mi_atomic_storei64_release(p,x) mi_atomic(store_explicit)(p,x,mi_memory_order(release)) -#define mi_atomic_storei64_relaxed(p,x) mi_atomic(store_explicit)(p,x,mi_memory_order(relaxed)) +#define mi_atomic_loadi64_acquire(p) mi_atomic(load_explicit)(p,mi_memory_order(acquire)) +#define mi_atomic_loadi64_relaxed(p) mi_atomic(load_explicit)(p,mi_memory_order(relaxed)) +#define mi_atomic_storei64_release(p,x) mi_atomic(store_explicit)(p,x,mi_memory_order(release)) +#define mi_atomic_storei64_relaxed(p,x) mi_atomic(store_explicit)(p,x,mi_memory_order(relaxed)) +#define mi_atomic_casi64_strong_acq_rel(p,e,d) mi_atomic_cas_strong_acq_rel(p,e,d) +#define mi_atomic_addi64_acq_rel(p,i) mi_atomic_add_acq_rel(p,i) #elif defined(_MSC_VER) -// MSVC C compilation wrapper that uses Interlocked operations to model C11 atomics. -#define WIN32_LEAN_AND_MEAN -#include +// Legacy MSVC plain C compilation wrapper that uses Interlocked operations to model C11 atomics. #include #ifdef _WIN64 typedef LONG64 msc_intptr_t; @@ -189,7 +224,7 @@ static inline uintptr_t mi_atomic_load_explicit(_Atomic(uintptr_t) const* p, mi_ #else uintptr_t x = *p; if (mo > mi_memory_order_relaxed) { - while (!mi_atomic_compare_exchange_weak_explicit(p, &x, x, mo, mi_memory_order_relaxed)) { /* nothing */ }; + while (!mi_atomic_compare_exchange_weak_explicit((_Atomic(uintptr_t)*)p, &x, x, mo, mi_memory_order_relaxed)) { /* nothing */ }; } return x; #endif @@ -238,6 +273,14 @@ static inline int64_t mi_atomic_addi64_relaxed(volatile _Atomic(int64_t)*p, int6 return current; #endif } + +static inline void mi_atomic_void_addi64_relaxed(volatile int64_t* p, const volatile int64_t* padd) { + const int64_t add = *padd; + if (add != 0) { + mi_atomic_addi64_relaxed((volatile _Atomic(int64_t)*)p, add); + } +} + static inline void mi_atomic_maxi64_relaxed(volatile _Atomic(int64_t)*p, int64_t x) { int64_t current; do { @@ -245,6 +288,21 @@ static inline void mi_atomic_maxi64_relaxed(volatile _Atomic(int64_t)*p, int64_t } while (current < x && _InterlockedCompareExchange64(p, x, current) != current); } +static inline void mi_atomic_addi64_acq_rel(volatile _Atomic(int64_t*)p, int64_t i) { + mi_atomic_addi64_relaxed(p, i); +} + +static inline bool mi_atomic_casi64_strong_acq_rel(volatile _Atomic(int64_t*)p, int64_t* exp, int64_t des) { + int64_t read = _InterlockedCompareExchange64(p, des, *exp); + if (read == *exp) { + return true; + } + else { + *exp = read; + return false; + } +} + // The pointer macros cast to `uintptr_t`. #define mi_atomic_load_ptr_acquire(tp,p) (tp*)mi_atomic_load_acquire((_Atomic(uintptr_t)*)(p)) #define mi_atomic_load_ptr_relaxed(tp,p) (tp*)mi_atomic_load_relaxed((_Atomic(uintptr_t)*)(p)) @@ -253,6 +311,8 @@ static inline void mi_atomic_maxi64_relaxed(volatile _Atomic(int64_t)*p, int64_t #define mi_atomic_cas_ptr_weak_release(tp,p,exp,des) mi_atomic_cas_weak_release((_Atomic(uintptr_t)*)(p),(uintptr_t*)exp,(uintptr_t)des) #define mi_atomic_cas_ptr_weak_acq_rel(tp,p,exp,des) mi_atomic_cas_weak_acq_rel((_Atomic(uintptr_t)*)(p),(uintptr_t*)exp,(uintptr_t)des) #define mi_atomic_cas_ptr_strong_release(tp,p,exp,des) mi_atomic_cas_strong_release((_Atomic(uintptr_t)*)(p),(uintptr_t*)exp,(uintptr_t)des) +#define mi_atomic_cas_ptr_strong_acq_rel(tp,p,exp,des) mi_atomic_cas_strong_acq_rel((_Atomic(uintptr_t)*)(p),(uintptr_t*)exp,(uintptr_t)des) +#define mi_atomic_exchange_ptr_relaxed(tp,p,x) (tp*)mi_atomic_exchange_relaxed((_Atomic(uintptr_t)*)(p),(uintptr_t)x) #define mi_atomic_exchange_ptr_release(tp,p,x) (tp*)mi_atomic_exchange_release((_Atomic(uintptr_t)*)(p),(uintptr_t)x) #define mi_atomic_exchange_ptr_acq_rel(tp,p,x) (tp*)mi_atomic_exchange_acq_rel((_Atomic(uintptr_t)*)(p),(uintptr_t)x) @@ -275,15 +335,41 @@ static inline intptr_t mi_atomic_subi(_Atomic(intptr_t)*p, intptr_t sub) { return (intptr_t)mi_atomic_addi(p, -sub); } -// Yield + +// ---------------------------------------------------------------------- +// Once and Guard +// ---------------------------------------------------------------------- + +typedef _Atomic(uintptr_t) mi_atomic_once_t; + +// Returns true only on the first invocation +static inline bool mi_atomic_once( mi_atomic_once_t* once ) { + if (mi_atomic_load_relaxed(once) != 0) return false; // quick test + uintptr_t expected = 0; + return mi_atomic_cas_strong_acq_rel(once, &expected, (uintptr_t)1); // try to set to 1 +} + +typedef _Atomic(uintptr_t) mi_atomic_guard_t; + +// Allows only one thread to execute at a time +#define mi_atomic_guard(guard) \ + uintptr_t _mi_guard_expected = 0; \ + for(bool _mi_guard_once = true; \ + _mi_guard_once && mi_atomic_cas_strong_acq_rel(guard,&_mi_guard_expected,(uintptr_t)1); \ + (mi_atomic_store_release(guard,(uintptr_t)0), _mi_guard_once = false) ) + + + +// ---------------------------------------------------------------------- +// Yield +// ---------------------------------------------------------------------- + #if defined(__cplusplus) #include static inline void mi_atomic_yield(void) { std::this_thread::yield(); } #elif defined(_WIN32) -#define WIN32_LEAN_AND_MEAN -#include static inline void mi_atomic_yield(void) { YieldProcessor(); } @@ -293,8 +379,9 @@ static inline void mi_atomic_yield(void) { _mm_pause(); } #elif (defined(__GNUC__) || defined(__clang__)) && \ - (defined(__x86_64__) || defined(__i386__) || defined(__arm__) || defined(__armel__) || defined(__ARMEL__) || \ - defined(__aarch64__) || defined(__powerpc__) || defined(__ppc__) || defined(__PPC__)) + (defined(__x86_64__) || defined(__i386__) || \ + defined(__aarch64__) || defined(__arm__) || \ + defined(__powerpc__) || defined(__ppc__) || defined(__PPC__) || defined(__POWERPC__)) #if defined(__x86_64__) || defined(__i386__) static inline void mi_atomic_yield(void) { __asm__ volatile ("pause" ::: "memory"); @@ -303,19 +390,27 @@ static inline void mi_atomic_yield(void) { static inline void mi_atomic_yield(void) { __asm__ volatile("wfe"); } -#elif (defined(__arm__) && __ARM_ARCH__ >= 7) +#elif defined(__arm__) +#if __ARM_ARCH >= 7 static inline void mi_atomic_yield(void) { __asm__ volatile("yield" ::: "memory"); } -#elif defined(__powerpc__) || defined(__ppc__) || defined(__PPC__) +#else static inline void mi_atomic_yield(void) { - __asm__ __volatile__ ("or 27,27,27" ::: "memory"); + __asm__ volatile ("nop" ::: "memory"); } -#elif defined(__armel__) || defined(__ARMEL__) +#endif +#elif defined(__powerpc__) || defined(__ppc__) || defined(__PPC__) || defined(__POWERPC__) +#ifdef __APPLE__ static inline void mi_atomic_yield(void) { - __asm__ volatile ("nop" ::: "memory"); + __asm__ volatile ("or r27,r27,r27" ::: "memory"); +} +#else +static inline void mi_atomic_yield(void) { + __asm__ __volatile__ ("or 27,27,27" ::: "memory"); } #endif +#endif #elif defined(__sun) // Fallback for other archs #include @@ -335,4 +430,133 @@ static inline void mi_atomic_yield(void) { #endif -#endif // __MIMALLOC_ATOMIC_H +// ---------------------------------------------------------------------- +// Locks +// These should be light-weight in-process only locks. +// Only used for reserving arena's and to maintain the abandoned list. +// ---------------------------------------------------------------------- +#if _MSC_VER +#pragma warning(disable:26110) // unlock with holding lock +#endif + +#define mi_lock(lock) for(bool _go = (mi_lock_acquire(lock),true); _go; (mi_lock_release(lock), _go=false) ) + +#if defined(_WIN32) + +#if 1 +#define mi_lock_t SRWLOCK // slim reader-writer lock + +static inline bool mi_lock_try_acquire(mi_lock_t* lock) { + return TryAcquireSRWLockExclusive(lock); +} +static inline void mi_lock_acquire(mi_lock_t* lock) { + AcquireSRWLockExclusive(lock); +} +static inline void mi_lock_release(mi_lock_t* lock) { + ReleaseSRWLockExclusive(lock); +} +static inline void mi_lock_init(mi_lock_t* lock) { + InitializeSRWLock(lock); +} +static inline void mi_lock_done(mi_lock_t* lock) { + (void)(lock); +} + +#else +#define mi_lock_t CRITICAL_SECTION + +static inline bool mi_lock_try_acquire(mi_lock_t* lock) { + return TryEnterCriticalSection(lock); +} +static inline void mi_lock_acquire(mi_lock_t* lock) { + EnterCriticalSection(lock); +} +static inline void mi_lock_release(mi_lock_t* lock) { + LeaveCriticalSection(lock); +} +static inline void mi_lock_init(mi_lock_t* lock) { + InitializeCriticalSection(lock); +} +static inline void mi_lock_done(mi_lock_t* lock) { + DeleteCriticalSection(lock); +} + +#endif + +#elif defined(MI_USE_PTHREADS) + +void _mi_error_message(int err, const char* fmt, ...); + +#define mi_lock_t pthread_mutex_t + +static inline bool mi_lock_try_acquire(mi_lock_t* lock) { + return (pthread_mutex_trylock(lock) == 0); +} +static inline void mi_lock_acquire(mi_lock_t* lock) { + const int err = pthread_mutex_lock(lock); + if (err != 0) { + _mi_error_message(err, "internal error: lock cannot be acquired\n"); + } +} +static inline void mi_lock_release(mi_lock_t* lock) { + pthread_mutex_unlock(lock); +} +static inline void mi_lock_init(mi_lock_t* lock) { + pthread_mutex_init(lock, NULL); +} +static inline void mi_lock_done(mi_lock_t* lock) { + pthread_mutex_destroy(lock); +} + +#elif defined(__cplusplus) + +#include +#define mi_lock_t std::mutex + +static inline bool mi_lock_try_acquire(mi_lock_t* lock) { + return lock->try_lock(); +} +static inline void mi_lock_acquire(mi_lock_t* lock) { + lock->lock(); +} +static inline void mi_lock_release(mi_lock_t* lock) { + lock->unlock(); +} +static inline void mi_lock_init(mi_lock_t* lock) { + (void)(lock); +} +static inline void mi_lock_done(mi_lock_t* lock) { + (void)(lock); +} + +#else + +// fall back to poor man's locks. +// this should only be the case in a single-threaded environment (like __wasi__) + +#define mi_lock_t _Atomic(uintptr_t) + +static inline bool mi_lock_try_acquire(mi_lock_t* lock) { + uintptr_t expected = 0; + return mi_atomic_cas_strong_acq_rel(lock, &expected, (uintptr_t)1); +} +static inline void mi_lock_acquire(mi_lock_t* lock) { + for (int i = 0; i < 1000; i++) { // for at most 1000 tries? + if (mi_lock_try_acquire(lock)) return; + mi_atomic_yield(); + } +} +static inline void mi_lock_release(mi_lock_t* lock) { + mi_atomic_store_release(lock, (uintptr_t)0); +} +static inline void mi_lock_init(mi_lock_t* lock) { + mi_lock_release(lock); +} +static inline void mi_lock_done(mi_lock_t* lock) { + (void)(lock); +} + +#endif + + +#endif // MI_ATOMIC_H diff --git a/src/dashbls/depends/mimalloc/include/mimalloc/bits.h b/src/dashbls/depends/mimalloc/include/mimalloc/bits.h new file mode 100644 index 000000000000..1d4063bb5994 --- /dev/null +++ b/src/dashbls/depends/mimalloc/include/mimalloc/bits.h @@ -0,0 +1,377 @@ +/* ---------------------------------------------------------------------------- +Copyright (c) 2019-2024 Microsoft Research, Daan Leijen +This is free software; you can redistribute it and/or modify it under the +terms of the MIT license. A copy of the license can be found in the file +"LICENSE" at the root of this distribution. +-----------------------------------------------------------------------------*/ + +/* ---------------------------------------------------------------------------- + Bit operation, and platform dependent definition (MI_INTPTR_SIZE etc) +---------------------------------------------------------------------------- */ + +#pragma once +#ifndef MI_BITS_H +#define MI_BITS_H + + +// ------------------------------------------------------ +// Size of a pointer. +// We assume that `sizeof(void*)==sizeof(intptr_t)` +// and it holds for all platforms we know of. +// +// However, the C standard only requires that: +// p == (void*)((intptr_t)p)) +// but we also need: +// i == (intptr_t)((void*)i) +// or otherwise one might define an intptr_t type that is larger than a pointer... +// ------------------------------------------------------ + +#if INTPTR_MAX > INT64_MAX +# define MI_INTPTR_SHIFT (4) // assume 128-bit (as on arm CHERI for example) +#elif INTPTR_MAX == INT64_MAX +# define MI_INTPTR_SHIFT (3) +#elif INTPTR_MAX == INT32_MAX +# define MI_INTPTR_SHIFT (2) +#else +#error platform pointers must be 32, 64, or 128 bits +#endif + +#if (INTPTR_MAX) > LONG_MAX +# define MI_PU(x) x##ULL +#else +# define MI_PU(x) x##UL +#endif + +#if SIZE_MAX == UINT64_MAX +# define MI_SIZE_SHIFT (3) +typedef int64_t mi_ssize_t; +#elif SIZE_MAX == UINT32_MAX +# define MI_SIZE_SHIFT (2) +typedef int32_t mi_ssize_t; +#else +#error platform objects must be 32 or 64 bits in size +#endif + +#if (SIZE_MAX/2) > LONG_MAX +# define MI_ZU(x) x##ULL +#else +# define MI_ZU(x) x##UL +#endif + +#define MI_INTPTR_SIZE (1< +#elif MI_ARCH_ARM64 && MI_OPT_SIMD +#include +#endif +#if defined(_MSC_VER) && (MI_ARCH_X64 || MI_ARCH_X86 || MI_ARCH_ARM64 || MI_ARCH_ARM32) +#include +#endif + +#if MI_ARCH_X64 && defined(__AVX2__) && !defined(__BMI2__) // msvc +#define __BMI2__ 1 +#endif +#if MI_ARCH_X64 && (defined(__AVX2__) || defined(__BMI2__)) && !defined(__BMI1__) // msvc +#define __BMI1__ 1 +#endif + +// Define big endian if needed +// #define MI_BIG_ENDIAN 1 + +// maximum virtual address bits in a user-space pointer +#if MI_DEFAULT_VIRTUAL_ADDRESS_BITS > 0 +#define MI_MAX_VABITS MI_DEFAULT_VIRTUAL_ADDRESS_BITS +#elif MI_ARCH_X64 +#define MI_MAX_VABITS (47) +#elif MI_INTPTR_SIZE > 4 +#define MI_MAX_VABITS (48) +#else +#define MI_MAX_VABITS (32) +#endif + + +// use a flat page-map (or a 2-level one) +#ifndef MI_PAGE_MAP_FLAT +#if MI_MAX_VABITS <= 40 && !MI_SECURE && !defined(__APPLE__) +#define MI_PAGE_MAP_FLAT 1 +#else +#define MI_PAGE_MAP_FLAT 0 +#endif +#endif + +#if MI_PAGE_MAP_FLAT && MI_SECURE +#error should not use MI_PAGE_MAP_FLAT with a secure build +#endif + + +/* -------------------------------------------------------------------------------- + Builtin's +-------------------------------------------------------------------------------- */ + +#if defined(__GNUC__) || defined(__clang__) +#define mi_unlikely(x) (__builtin_expect(!!(x),false)) +#define mi_likely(x) (__builtin_expect(!!(x),true)) +#elif (defined(__cplusplus) && (__cplusplus >= 202002L)) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L) +#define mi_unlikely(x) (x) [[unlikely]] +#define mi_likely(x) (x) [[likely]] +#else +#define mi_unlikely(x) (x) +#define mi_likely(x) (x) +#endif + + +#ifndef __has_builtin +#define __has_builtin(x) 0 +#endif + +#define mi_builtin(name) __builtin_##name +#define mi_has_builtin(name) __has_builtin(__builtin_##name) + +#if (LONG_MAX == INT32_MAX) +#define mi_builtin32(name) mi_builtin(name##l) +#define mi_has_builtin32(name) mi_has_builtin(name##l) +#else +#define mi_builtin32(name) mi_builtin(name) +#define mi_has_builtin32(name) mi_has_builtin(name) +#endif +#if (LONG_MAX == INT64_MAX) +#define mi_builtin64(name) mi_builtin(name##l) +#define mi_has_builtin64(name) mi_has_builtin(name##l) +#else +#define mi_builtin64(name) mi_builtin(name##ll) +#define mi_has_builtin64(name) mi_has_builtin(name##ll) +#endif + +#if (MI_SIZE_BITS == 32) +#define mi_builtinz(name) mi_builtin32(name) +#define mi_has_builtinz(name) mi_has_builtin32(name) +#define mi_msc_builtinz(name) name +#elif (MI_SIZE_BITS == 64) +#define mi_builtinz(name) mi_builtin64(name) +#define mi_has_builtinz(name) mi_has_builtin64(name) +#define mi_msc_builtinz(name) name##64 +#endif + +/* -------------------------------------------------------------------------------- + Popcount and count trailing/leading zero's +-------------------------------------------------------------------------------- */ + +size_t _mi_popcount_generic(size_t x); +extern bool _mi_cpu_has_popcnt; + +static inline size_t mi_popcount(size_t x) { + #if defined(__GNUC__) && (MI_ARCH_X64 || MI_ARCH_X86) + #if !defined(__BMI1__) + if mi_unlikely(!_mi_cpu_has_popcnt) { return _mi_popcount_generic(x); } + #endif + size_t r; + __asm ("popcnt\t%1,%0" : "=r"(r) : "r"(x) : "cc"); + return r; + #elif defined(_MSC_VER) && (MI_ARCH_X64 || MI_ARCH_X86) + #if !defined(__BMI1__) + if mi_unlikely(!_mi_cpu_has_popcnt) { return _mi_popcount_generic(x); } + #endif + return (size_t)mi_msc_builtinz(__popcnt)(x); + #elif defined(_MSC_VER) && MI_ARCH_ARM64 + return (size_t)mi_msc_builtinz(__popcnt)(x); + #elif mi_has_builtinz(popcount) + return mi_builtinz(popcount)(x); + #else + #define MI_HAS_FAST_POPCOUNT 0 + return _mi_popcount_generic(x); + #endif +} + +#ifndef MI_HAS_FAST_POPCOUNT +#define MI_HAS_FAST_POPCOUNT 1 +#endif + + + +size_t _mi_clz_generic(size_t x); +size_t _mi_ctz_generic(size_t x); + +static inline size_t mi_ctz(size_t x) { + #if defined(__GNUC__) && MI_ARCH_X64 && defined(__BMI1__) + size_t r; + __asm ("tzcnt\t%1, %0" : "=r"(r) : "r"(x) : "cc"); + return r; + #elif defined(__GNUC__) && MI_ARCH_X64 + // tzcnt is interpreted as bsf if BMI1 is not supported (pre-haswell) + // if the argument is zero: + // - tzcnt: sets carry-flag, and returns MI_SIZE_BITS + // - bsf : sets zero-flag, and leaves the destination _unmodified_ (on both AMD and Intel now, see ) + // so we always initialize r to MI_SIZE_BITS to work correctly on all cpu's without branching + size_t r = MI_SIZE_BITS; + __asm ("tzcnt\t%1, %0" : "+r"(r) : "r"(x) : "cc"); // use '+r' to keep the assignment to r in case this becomes bsf on older cpu's + return r; + #elif mi_has_builtinz(ctz) + return (x!=0 ? (size_t)mi_builtinz(ctz)(x) : MI_SIZE_BITS); + #elif defined(_MSC_VER) && MI_ARCH_X64 && defined(__BMI1__) + return (x!=0 ? _tzcnt_u64(x) : MI_SIZE_BITS); // ensure it still works on non-BMI1 cpu's as well + #elif defined(_MSC_VER) && (MI_ARCH_X64 || MI_ARCH_X86 || MI_ARCH_ARM64 || MI_ARCH_ARM32) + if (x==0) return MI_SIZE_BITS; // test explicitly for `x==0` to avoid codegen bug (issue #1071) + unsigned long idx; mi_msc_builtinz(_BitScanForward)(&idx, x); + return (size_t)idx; + #elif defined(__GNUC__) && MI_ARCH_X86 + size_t r = MI_SIZE_BITS; + __asm ("bsf\t%1, %0" : "+r"(r) : "r"(x) : "cc"); + return r; + #elif MI_HAS_FAST_POPCOUNT + return (x!=0 ? (mi_popcount(x^(x-1))-1) : MI_SIZE_BITS); + #else + #define MI_HAS_FAST_BITSCAN 0 + return (x!=0 ? _mi_ctz_generic(x) : MI_SIZE_BITS); + #endif +} + +static inline size_t mi_clz(size_t x) { + // we don't optimize anymore to lzcnt as there are still non BMI1 cpu's around (like Intel Celeron, see issue #1016) + // on pre-haswell cpu's lzcnt gets executed as bsr which is not equivalent (at it returns the bit position) + #if defined(__GNUC__) && MI_ARCH_X64 && defined(__BMI1__) // on x64 lzcnt is defined for 0 + size_t r; + __asm ("lzcnt\t%1, %0" : "=r"(r) : "r"(x) : "cc"); + return r; + #elif mi_has_builtinz(clz) + return (x!=0 ? (size_t)mi_builtinz(clz)(x) : MI_SIZE_BITS); + #elif defined(_MSC_VER) && (MI_ARCH_X64 || MI_ARCH_X86 || MI_ARCH_ARM64 || MI_ARCH_ARM32) + if (x==0) return MI_SIZE_BITS; // test explicitly for `x==0` to avoid codegen bug (issue #1071) + unsigned long idx; mi_msc_builtinz(_BitScanReverse)(&idx, x); + return (MI_SIZE_BITS - 1 - (size_t)idx); + #elif defined(__GNUC__) && (MI_ARCH_X64 || MI_ARCH_X86) + if (x==0) return MI_SIZE_BITS; + size_t r; + __asm ("bsr\t%1, %0" : "=r"(r) : "r"(x) : "cc"); + return (MI_SIZE_BITS - 1 - r); + #else + #define MI_HAS_FAST_BITSCAN 0 + return (x!=0 ? _mi_clz_generic(x) : MI_SIZE_BITS); + #endif +} + +#ifndef MI_HAS_FAST_BITSCAN +#define MI_HAS_FAST_BITSCAN 1 +#endif + +/* -------------------------------------------------------------------------------- + find trailing/leading zero (bit scan forward/reverse) +-------------------------------------------------------------------------------- */ + +// Bit scan forward: find the least significant bit that is set (i.e. count trailing zero's) +// return false if `x==0` (with `*idx` undefined) and true otherwise, +// with the `idx` is set to the bit index (`0 <= *idx < MI_BFIELD_BITS`). +static inline bool mi_bsf(size_t x, size_t* idx) { + #if defined(__GNUC__) && MI_ARCH_X64 && defined(__BMI1__) && (!defined(__clang_major__) || __clang_major__ >= 9) + // on x64 the carry flag is set on zero which gives better codegen + bool is_zero; + __asm ( "tzcnt\t%2, %1" : "=@ccc"(is_zero), "=r"(*idx) : "r"(x) : "cc" ); + return !is_zero; + #elif defined(_MSC_VER) && (MI_ARCH_X64 || MI_ARCH_X86 || MI_ARCH_ARM64 || MI_ARCH_ARM32) + if (x==0) return false; // test explicitly for `x==0` to avoid codegen bug (issue #1071) + unsigned long i; mi_msc_builtinz(_BitScanForward)(&i, x); + *idx = (size_t)i; + return true; + #else + return (x!=0 ? (*idx = mi_ctz(x), true) : false); + #endif +} + +// Bit scan reverse: find the most significant bit that is set +// return false if `x==0` (with `*idx` undefined) and true otherwise, +// with the `idx` is set to the bit index (`0 <= *idx < MI_BFIELD_BITS`). +static inline bool mi_bsr(size_t x, size_t* idx) { + #if defined(_MSC_VER) && (MI_ARCH_X64 || MI_ARCH_X86 || MI_ARCH_ARM64 || MI_ARCH_ARM32) + if (x==0) return false; // test explicitly for `x==0` to avoid codegen bug (issue #1071) + unsigned long i; mi_msc_builtinz(_BitScanReverse)(&i, x); + *idx = (size_t)i; + return true; + #else + return (x!=0 ? (*idx = MI_SIZE_BITS - 1 - mi_clz(x), true) : false); + #endif +} + + +/* -------------------------------------------------------------------------------- + rotate +-------------------------------------------------------------------------------- */ + +static inline size_t mi_rotr(size_t x, size_t r) { + #if (mi_has_builtin(rotateright64) && MI_SIZE_BITS==64) + return mi_builtin(rotateright64)(x,r); + #elif (mi_has_builtin(rotateright32) && MI_SIZE_BITS==32) + return mi_builtin(rotateright32)(x,r); + #elif defined(_MSC_VER) && (MI_ARCH_X64 || MI_ARCH_ARM64) + return _rotr64(x, (int)r); + #elif defined(_MSC_VER) && (MI_ARCH_X86 || MI_ARCH_ARM32) + return _lrotr(x,(int)r); + #else + // The term `(-rshift)&(BITS-1)` is written instead of `BITS - rshift` to + // avoid UB when `rshift==0`. See + const unsigned int rshift = (unsigned int)(r) & (MI_SIZE_BITS-1); + return ((x >> rshift) | (x << ((-rshift) & (MI_SIZE_BITS-1)))); + #endif +} + +static inline size_t mi_rotl(size_t x, size_t r) { + #if (mi_has_builtin(rotateleft64) && MI_SIZE_BITS==64) + return mi_builtin(rotateleft64)(x,r); + #elif (mi_has_builtin(rotateleft32) && MI_SIZE_BITS==32) + return mi_builtin(rotateleft32)(x,r); + #elif defined(_MSC_VER) && (MI_ARCH_X64 || MI_ARCH_ARM64) + return _rotl64(x, (int)r); + #elif defined(_MSC_VER) && (MI_ARCH_X86 || MI_ARCH_ARM32) + return _lrotl(x, (int)r); + #else + // The term `(-rshift)&(BITS-1)` is written instead of `BITS - rshift` to + // avoid UB when `rshift==0`. See + const unsigned int rshift = (unsigned int)(r) & (MI_SIZE_BITS-1); + return ((x << rshift) | (x >> ((-rshift) & (MI_SIZE_BITS-1)))); + #endif +} + +static inline uint32_t mi_rotl32(uint32_t x, uint32_t r) { + #if mi_has_builtin(rotateleft32) + return mi_builtin(rotateleft32)(x,r); + #elif defined(_MSC_VER) && (MI_ARCH_X64 || MI_ARCH_X86 || MI_ARCH_ARM64 || MI_ARCH_ARM32) + return _lrotl(x, (int)r); + #else + // The term `(-rshift)&(BITS-1)` is written instead of `BITS - rshift` to + // avoid UB when `rshift==0`. See + const unsigned int rshift = (unsigned int)(r) & 31; + return ((x << rshift) | (x >> ((-rshift) & 31))); + #endif +} + + +#endif // MI_BITS_H diff --git a/src/dashbls/depends/mimalloc/include/mimalloc/internal.h b/src/dashbls/depends/mimalloc/include/mimalloc/internal.h new file mode 100644 index 000000000000..62387dc348d0 --- /dev/null +++ b/src/dashbls/depends/mimalloc/include/mimalloc/internal.h @@ -0,0 +1,1203 @@ +/* ---------------------------------------------------------------------------- +Copyright (c) 2018-2023, Microsoft Research, Daan Leijen +This is free software; you can redistribute it and/or modify it under the +terms of the MIT license. A copy of the license can be found in the file +"LICENSE" at the root of this distribution. +-----------------------------------------------------------------------------*/ +#pragma once +#ifndef MI_INTERNAL_H +#define MI_INTERNAL_H + +// -------------------------------------------------------------------------- +// This file contains the internal API's of mimalloc and various utility +// functions and macros. +// -------------------------------------------------------------------------- + +#include "types.h" +#include "track.h" +#include "bits.h" + + +// -------------------------------------------------------------------------- +// Compiler defines +// -------------------------------------------------------------------------- + +#if (MI_DEBUG>0) +#define mi_trace_message(...) _mi_trace_message(__VA_ARGS__) +#else +#define mi_trace_message(...) +#endif + +#define mi_decl_cache_align mi_decl_align(64) + +#if defined(_MSC_VER) +#pragma warning(disable:4127) // suppress constant conditional warning (due to MI_SECURE paths) +#pragma warning(disable:26812) // unscoped enum warning +#define mi_decl_noinline __declspec(noinline) +#define mi_decl_thread __declspec(thread) +#define mi_decl_align(a) __declspec(align(a)) +#define mi_decl_noreturn __declspec(noreturn) +#define mi_decl_weak +#define mi_decl_hidden +#define mi_decl_cold +#elif (defined(__GNUC__) && (__GNUC__ >= 3)) || defined(__clang__) // includes clang and icc +#define mi_decl_noinline __attribute__((noinline)) +#define mi_decl_thread __thread +#define mi_decl_align(a) __attribute__((aligned(a))) +#define mi_decl_noreturn __attribute__((noreturn)) +#define mi_decl_weak __attribute__((weak)) +#define mi_decl_hidden __attribute__((visibility("hidden"))) +#if (__GNUC__ >= 4) || defined(__clang__) +#define mi_decl_cold __attribute__((cold)) +#else +#define mi_decl_cold +#endif +#elif __cplusplus >= 201103L // c++11 +#define mi_decl_noinline +#define mi_decl_thread thread_local +#define mi_decl_align(a) alignas(a) +#define mi_decl_noreturn [[noreturn]] +#define mi_decl_weak +#define mi_decl_hidden +#define mi_decl_cold +#else +#define mi_decl_noinline +#define mi_decl_thread __thread // hope for the best :-) +#define mi_decl_align(a) +#define mi_decl_noreturn +#define mi_decl_weak +#define mi_decl_hidden +#define mi_decl_cold +#endif + +#if defined(__GNUC__) || defined(__clang__) +#define mi_unlikely(x) (__builtin_expect(!!(x),false)) +#define mi_likely(x) (__builtin_expect(!!(x),true)) +#elif (defined(__cplusplus) && (__cplusplus >= 202002L)) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L) +#define mi_unlikely(x) (x) [[unlikely]] +#define mi_likely(x) (x) [[likely]] +#else +#define mi_unlikely(x) (x) +#define mi_likely(x) (x) +#endif + +#ifndef __has_builtin +#define __has_builtin(x) 0 +#endif + +#if defined(__cplusplus) +#define mi_decl_externc extern "C" +#else +#define mi_decl_externc +#endif + +#if (defined(__GNUC__) && (__GNUC__ >= 7)) || defined(__clang__) // includes clang and icc +#define mi_decl_maybe_unused __attribute__((unused)) +#elif __cplusplus >= 201703L // c++17 +#define mi_decl_maybe_unused [[maybe_unused]] +#else +#define mi_decl_maybe_unused +#endif + +#if defined(__cplusplus) +#define mi_decl_externc extern "C" +#else +#define mi_decl_externc +#endif + + +#if defined(__EMSCRIPTEN__) && !defined(__wasi__) +#define __wasi__ +#endif + + +// -------------------------------------------------------------------------- +// Internal functions +// -------------------------------------------------------------------------- + + +// "libc.c" +#include +int _mi_vsnprintf(char* buf, size_t bufsize, const char* fmt, va_list args); +int _mi_snprintf(char* buf, size_t buflen, const char* fmt, ...); +char _mi_toupper(char c); +int _mi_strnicmp(const char* s, const char* t, size_t n); +void _mi_strlcpy(char* dest, const char* src, size_t dest_size); +void _mi_strlcat(char* dest, const char* src, size_t dest_size); +size_t _mi_strlen(const char* s); +size_t _mi_strnlen(const char* s, size_t max_len); +bool _mi_getenv(const char* name, char* result, size_t result_size); + +// "options.c" +void _mi_fputs(mi_output_fun* out, void* arg, const char* prefix, const char* message); +void _mi_fprintf(mi_output_fun* out, void* arg, const char* fmt, ...); +void _mi_raw_message(const char* fmt, ...); +void _mi_message(const char* fmt, ...); +void _mi_warning_message(const char* fmt, ...); +void _mi_verbose_message(const char* fmt, ...); +void _mi_trace_message(const char* fmt, ...); +void _mi_options_init(void); +long _mi_option_get_fast(mi_option_t option); +void _mi_error_message(int err, const char* fmt, ...); + +// random.c +void _mi_random_init(mi_random_ctx_t* ctx); +void _mi_random_init_weak(mi_random_ctx_t* ctx); +void _mi_random_reinit_if_weak(mi_random_ctx_t * ctx); +void _mi_random_split(mi_random_ctx_t* ctx, mi_random_ctx_t* new_ctx); +uintptr_t _mi_random_next(mi_random_ctx_t* ctx); +uintptr_t _mi_heap_random_next(mi_heap_t* heap); +uintptr_t _mi_os_random_weak(uintptr_t extra_seed); +static inline uintptr_t _mi_random_shuffle(uintptr_t x); + +// init.c +extern mi_decl_hidden mi_decl_cache_align const mi_page_t _mi_page_empty; +void _mi_auto_process_init(void); +void mi_cdecl _mi_auto_process_done(void) mi_attr_noexcept; +bool _mi_is_redirected(void); +bool _mi_allocator_init(const char** message); +void _mi_allocator_done(void); +bool _mi_is_main_thread(void); +size_t _mi_current_thread_count(void); +bool _mi_preloading(void); // true while the C runtime is not initialized yet +void _mi_thread_done(mi_heap_t* heap); + +mi_subproc_t* _mi_subproc(void); +mi_subproc_t* _mi_subproc_main(void); +mi_subproc_t* _mi_subproc_from_id(mi_subproc_id_t subproc_id); +mi_threadid_t _mi_thread_id(void) mi_attr_noexcept; +size_t _mi_thread_seq_id(void) mi_attr_noexcept; +mi_tld_t* _mi_thread_tld(void) mi_attr_noexcept; +void _mi_heap_guarded_init(mi_heap_t* heap); +mi_heap_t* _mi_heap_main_get(void); + +// os.c +void _mi_os_init(void); // called from process init +void* _mi_os_alloc(size_t size, mi_memid_t* memid); +void* _mi_os_zalloc(size_t size, mi_memid_t* memid); +void _mi_os_free(void* p, size_t size, mi_memid_t memid); +void _mi_os_free_ex(void* p, size_t size, bool still_committed, mi_memid_t memid, mi_subproc_t* subproc ); + +size_t _mi_os_page_size(void); +size_t _mi_os_guard_page_size(void); +size_t _mi_os_good_alloc_size(size_t size); +bool _mi_os_has_overcommit(void); +bool _mi_os_has_virtual_reserve(void); +size_t _mi_os_virtual_address_bits(void); + +bool _mi_os_reset(void* addr, size_t size); +bool _mi_os_decommit(void* addr, size_t size); +void _mi_os_reuse(void* p, size_t size); +mi_decl_nodiscard bool _mi_os_commit(void* p, size_t size, bool* is_zero); +mi_decl_nodiscard bool _mi_os_commit_ex(void* addr, size_t size, bool* is_zero, size_t stat_size); +mi_decl_nodiscard bool _mi_os_protect(void* addr, size_t size); +bool _mi_os_unprotect(void* addr, size_t size); +bool _mi_os_purge(void* p, size_t size); +bool _mi_os_purge_ex(void* p, size_t size, bool allow_reset, size_t stats_size, mi_commit_fun_t* commit_fun, void* commit_fun_arg); + +size_t _mi_os_secure_guard_page_size(void); +bool _mi_os_secure_guard_page_set_at(void* addr, mi_memid_t memid); +bool _mi_os_secure_guard_page_set_before(void* addr, mi_memid_t memid); +bool _mi_os_secure_guard_page_reset_at(void* addr, mi_memid_t memid); +bool _mi_os_secure_guard_page_reset_before(void* addr, mi_memid_t memid); + +int _mi_os_numa_node(void); +int _mi_os_numa_node_count(void); + +void* _mi_os_alloc_aligned(size_t size, size_t alignment, bool commit, bool allow_large, mi_memid_t* memid); +void* _mi_os_alloc_aligned_at_offset(size_t size, size_t alignment, size_t align_offset, bool commit, bool allow_large, mi_memid_t* memid); + +void* _mi_os_get_aligned_hint(size_t try_alignment, size_t size); +bool _mi_os_use_large_page(size_t size, size_t alignment); +size_t _mi_os_large_page_size(void); +void* _mi_os_alloc_huge_os_pages(size_t pages, int numa_node, mi_msecs_t max_secs, size_t* pages_reserved, size_t* psize, mi_memid_t* memid); + + +// arena.c +mi_arena_id_t _mi_arena_id_none(void); +mi_arena_t* _mi_arena_from_id(mi_arena_id_t id); +bool _mi_arena_memid_is_suitable(mi_memid_t memid, mi_arena_t* request_arena); + +void* _mi_arenas_alloc(mi_subproc_t* subproc, size_t size, bool commit, bool allow_pinned, mi_arena_t* req_arena, size_t tseq, int numa_node, mi_memid_t* memid); +void* _mi_arenas_alloc_aligned(mi_subproc_t* subproc, size_t size, size_t alignment, size_t align_offset, bool commit, bool allow_pinned, mi_arena_t* req_arena, size_t tseq, int numa_node, mi_memid_t* memid); +void _mi_arenas_free(void* p, size_t size, mi_memid_t memid); +bool _mi_arenas_contain(const void* p); +void _mi_arenas_collect(bool force_purge, bool visit_all, mi_tld_t* tld); +void _mi_arenas_unsafe_destroy_all(mi_tld_t* tld); + +mi_page_t* _mi_arenas_page_alloc(mi_heap_t* heap, size_t block_size, size_t page_alignment); +void _mi_arenas_page_free(mi_page_t* page, mi_tld_t* tld); +void _mi_arenas_page_abandon(mi_page_t* page, mi_tld_t* tld); +void _mi_arenas_page_unabandon(mi_page_t* page); +bool _mi_arenas_page_try_reabandon_to_mapped(mi_page_t* page); + +// arena-meta.c +void* _mi_meta_zalloc( size_t size, mi_memid_t* memid ); +void _mi_meta_free(void* p, size_t size, mi_memid_t memid); +bool _mi_meta_is_meta_page(void* p); + +// "page-map.c" +bool _mi_page_map_init(void); +void _mi_page_map_register(mi_page_t* page); +void _mi_page_map_unregister(mi_page_t* page); +void _mi_page_map_unregister_range(void* start, size_t size); +mi_page_t* _mi_safe_ptr_page(const void* p); +void _mi_page_map_unsafe_destroy(mi_subproc_t* subproc); + +// "page.c" +void* _mi_malloc_generic(mi_heap_t* heap, size_t size, bool zero, size_t huge_alignment) mi_attr_noexcept mi_attr_malloc; + +void _mi_page_retire(mi_page_t* page) mi_attr_noexcept; // free the page if there are no other pages with many free blocks +void _mi_page_unfull(mi_page_t* page); +void _mi_page_free(mi_page_t* page, mi_page_queue_t* pq); // free the page +void _mi_page_abandon(mi_page_t* page, mi_page_queue_t* pq); // abandon the page, to be picked up by another thread... +void _mi_heap_collect_retired(mi_heap_t* heap, bool force); + +size_t _mi_page_queue_append(mi_heap_t* heap, mi_page_queue_t* pq, mi_page_queue_t* append); +void _mi_deferred_free(mi_heap_t* heap, bool force); + +void _mi_page_free_collect(mi_page_t* page, bool force); +void _mi_page_free_collect_partly(mi_page_t* page, mi_block_t* head); +mi_decl_nodiscard bool _mi_page_init(mi_heap_t* heap, mi_page_t* page); +bool _mi_page_queue_is_valid(mi_heap_t* heap, const mi_page_queue_t* pq); + +size_t _mi_page_bin(const mi_page_t* page); // for stats +size_t _mi_bin_size(size_t bin); // for stats +size_t _mi_bin(size_t size); // for stats + +// "heap.c" +mi_heap_t* _mi_heap_create(int heap_tag, bool allow_destroy, mi_arena_id_t arena_id, mi_tld_t* tld); +void _mi_heap_init(mi_heap_t* heap, mi_arena_id_t arena_id, bool noreclaim, uint8_t tag, mi_tld_t* tld); +void _mi_heap_destroy_pages(mi_heap_t* heap); +void _mi_heap_collect_abandon(mi_heap_t* heap); +void _mi_heap_set_default_direct(mi_heap_t* heap); +bool _mi_heap_memid_is_suitable(mi_heap_t* heap, mi_memid_t memid); +void _mi_heap_unsafe_destroy_all(mi_heap_t* heap); +mi_heap_t* _mi_heap_by_tag(mi_heap_t* heap, uint8_t tag); +void _mi_heap_area_init(mi_heap_area_t* area, mi_page_t* page); +bool _mi_heap_area_visit_blocks(const mi_heap_area_t* area, mi_page_t* page, mi_block_visit_fun* visitor, void* arg); +void _mi_heap_page_reclaim(mi_heap_t* heap, mi_page_t* page); + +// "stats.c" +void _mi_stats_init(void); +void _mi_stats_done(mi_stats_t* stats); +void _mi_stats_print(mi_stats_t* stats, mi_output_fun* out, void* arg) mi_attr_noexcept; +void _mi_stats_merge_thread(mi_tld_t* tld); +void _mi_stats_merge_from(mi_stats_t* to, mi_stats_t* from); +mi_msecs_t _mi_clock_now(void); +mi_msecs_t _mi_clock_end(mi_msecs_t start); +mi_msecs_t _mi_clock_start(void); + +// "alloc.c" +void* _mi_page_malloc_zero(mi_heap_t* heap, mi_page_t* page, size_t size, bool zero) mi_attr_noexcept; // called from `_mi_malloc_generic` +void* _mi_page_malloc(mi_heap_t* heap, mi_page_t* page, size_t size) mi_attr_noexcept; // called from `_mi_heap_malloc_aligned` +void* _mi_page_malloc_zeroed(mi_heap_t* heap, mi_page_t* page, size_t size) mi_attr_noexcept; // called from `_mi_heap_malloc_aligned` +void* _mi_heap_malloc_zero(mi_heap_t* heap, size_t size, bool zero) mi_attr_noexcept; +void* _mi_heap_malloc_zero_ex(mi_heap_t* heap, size_t size, bool zero, size_t huge_alignment) mi_attr_noexcept; // called from `_mi_heap_malloc_aligned` +void* _mi_heap_realloc_zero(mi_heap_t* heap, void* p, size_t newsize, bool zero) mi_attr_noexcept; +mi_block_t* _mi_page_ptr_unalign(const mi_page_t* page, const void* p); +void _mi_padding_shrink(const mi_page_t* page, const mi_block_t* block, const size_t min_size); + +#if MI_DEBUG>1 +bool _mi_page_is_valid(mi_page_t* page); +#endif + + +// ------------------------------------------------------ +// Assertions +// ------------------------------------------------------ + +#if (MI_DEBUG) +// use our own assertion to print without memory allocation +mi_decl_noreturn mi_decl_cold void _mi_assert_fail(const char* assertion, const char* fname, unsigned int line, const char* func) mi_attr_noexcept; +#define mi_assert(expr) ((expr) ? (void)0 : _mi_assert_fail(#expr,__FILE__,__LINE__,__func__)) +#else +#define mi_assert(x) +#endif + +#if (MI_DEBUG>1) +#define mi_assert_internal mi_assert +#else +#define mi_assert_internal(x) +#endif + +#if (MI_DEBUG>2) +#define mi_assert_expensive mi_assert +#else +#define mi_assert_expensive(x) +#endif + + +/* ----------------------------------------------------------- + Statistics (in `stats.c`) +----------------------------------------------------------- */ + +// add to stat keeping track of the peak +void __mi_stat_increase(mi_stat_count_t* stat, size_t amount); +void __mi_stat_decrease(mi_stat_count_t* stat, size_t amount); +void __mi_stat_increase_mt(mi_stat_count_t* stat, size_t amount); +void __mi_stat_decrease_mt(mi_stat_count_t* stat, size_t amount); + +// adjust stat in special cases to compensate for double counting (and does not adjust peak values and can decrease the total) +void __mi_stat_adjust_increase(mi_stat_count_t* stat, size_t amount); +void __mi_stat_adjust_decrease(mi_stat_count_t* stat, size_t amount); +void __mi_stat_adjust_increase_mt(mi_stat_count_t* stat, size_t amount); +void __mi_stat_adjust_decrease_mt(mi_stat_count_t* stat, size_t amount); + +// counters can just be increased +void __mi_stat_counter_increase(mi_stat_counter_t* stat, size_t amount); +void __mi_stat_counter_increase_mt(mi_stat_counter_t* stat, size_t amount); + +#define mi_subproc_stat_counter_increase(subproc,stat,amount) __mi_stat_counter_increase_mt( &(subproc)->stats.stat, amount) +#define mi_subproc_stat_increase(subproc,stat,amount) __mi_stat_increase_mt( &(subproc)->stats.stat, amount) +#define mi_subproc_stat_decrease(subproc,stat,amount) __mi_stat_decrease_mt( &(subproc)->stats.stat, amount) +#define mi_subproc_stat_adjust_increase(subproc,stat,amnt) __mi_stat_adjust_increase_mt( &(subproc)->stats.stat, amnt) +#define mi_subproc_stat_adjust_decrease(subproc,stat,amnt) __mi_stat_adjust_decrease_mt( &(subproc)->stats.stat, amnt) + +#define mi_tld_stat_counter_increase(tld,stat,amount) __mi_stat_counter_increase( &(tld)->stats.stat, amount) +#define mi_tld_stat_increase(tld,stat,amount) __mi_stat_increase( &(tld)->stats.stat, amount) +#define mi_tld_stat_decrease(tld,stat,amount) __mi_stat_decrease( &(tld)->stats.stat, amount) +#define mi_tld_stat_adjust_increase(tld,stat,amnt) __mi_stat_adjust_increase( &(tld)->stats.stat, amnt) +#define mi_tld_stat_adjust_decrease(tld,stat,amnt) __mi_stat_adjust_decrease( &(tld)->stats.stat, amnt) + +#define mi_os_stat_counter_increase(stat,amount) mi_subproc_stat_counter_increase(_mi_subproc(),stat,amount) +#define mi_os_stat_increase(stat,amount) mi_subproc_stat_increase(_mi_subproc(),stat,amount) +#define mi_os_stat_decrease(stat,amount) mi_subproc_stat_decrease(_mi_subproc(),stat,amount) + +#define mi_heap_stat_counter_increase(heap,stat,amount) mi_tld_stat_counter_increase(heap->tld, stat, amount) +#define mi_heap_stat_increase(heap,stat,amount) mi_tld_stat_increase( heap->tld, stat, amount) +#define mi_heap_stat_decrease(heap,stat,amount) mi_tld_stat_decrease( heap->tld, stat, amount) +#define mi_heap_stat_adjust_decrease(heap,stat,amount) mi_tld_stat_adjust_decrease( heap->tld, stat, amount) + +/* ----------------------------------------------------------- + Options (exposed for the debugger) +----------------------------------------------------------- */ +typedef enum mi_option_init_e { + MI_OPTION_UNINIT, // not yet initialized + MI_OPTION_DEFAULTED, // not found in the environment, use default value + MI_OPTION_INITIALIZED // found in environment or set explicitly +} mi_option_init_t; + +typedef struct mi_option_desc_s { + long value; // the value + mi_option_init_t init; // is it initialized yet? (from the environment) + mi_option_t option; // for debugging: the option index should match the option + const char* name; // option name without `mimalloc_` prefix + const char* legacy_name; // potential legacy option name +} mi_option_desc_t; + + + +/* ----------------------------------------------------------- + Inlined definitions +----------------------------------------------------------- */ +#define MI_UNUSED(x) (void)(x) +#if (MI_DEBUG>0) +#define MI_UNUSED_RELEASE(x) +#else +#define MI_UNUSED_RELEASE(x) MI_UNUSED(x) +#endif + +#define MI_INIT4(x) x(),x(),x(),x() +#define MI_INIT8(x) MI_INIT4(x),MI_INIT4(x) +#define MI_INIT16(x) MI_INIT8(x),MI_INIT8(x) +#define MI_INIT32(x) MI_INIT16(x),MI_INIT16(x) +#define MI_INIT64(x) MI_INIT32(x),MI_INIT32(x) +#define MI_INIT128(x) MI_INIT64(x),MI_INIT64(x) +#define MI_INIT256(x) MI_INIT128(x),MI_INIT128(x) + +#define MI_INIT74(x) MI_INIT64(x),MI_INIT8(x),x(),x() +#define MI_INIT5(x) MI_INIT4(x),x() + +#include +// initialize a local variable to zero; use memset as compilers optimize constant sized memset's +#define _mi_memzero_var(x) memset(&x,0,sizeof(x)) + +// Is `x` a power of two? (0 is considered a power of two) +static inline bool _mi_is_power_of_two(uintptr_t x) { + return ((x & (x - 1)) == 0); +} + +// Is a pointer aligned? +static inline bool _mi_is_aligned(void* p, size_t alignment) { + mi_assert_internal(alignment != 0); + return (((uintptr_t)p % alignment) == 0); +} + +// Align upwards +static inline uintptr_t _mi_align_up(uintptr_t sz, size_t alignment) { + mi_assert_internal(alignment != 0); + uintptr_t mask = alignment - 1; + if ((alignment & mask) == 0) { // power of two? + return ((sz + mask) & ~mask); + } + else { + return (((sz + mask)/alignment)*alignment); + } +} + + +// Align a pointer upwards +static inline uint8_t* _mi_align_up_ptr(void* p, size_t alignment) { + return (uint8_t*)_mi_align_up((uintptr_t)p, alignment); +} + + +static inline uintptr_t _mi_align_down(uintptr_t sz, size_t alignment) { + mi_assert_internal(alignment != 0); + uintptr_t mask = alignment - 1; + if ((alignment & mask) == 0) { // power of two? + return (sz & ~mask); + } + else { + return ((sz / alignment) * alignment); + } +} + +static inline void* mi_align_down_ptr(void* p, size_t alignment) { + return (void*)_mi_align_down((uintptr_t)p, alignment); +} + +// Divide upwards: `s <= _mi_divide_up(s,d)*d < s+d`. +static inline uintptr_t _mi_divide_up(uintptr_t size, size_t divider) { + mi_assert_internal(divider != 0); + return (divider == 0 ? size : ((size + divider - 1) / divider)); +} + + +// clamp an integer +static inline size_t _mi_clamp(size_t sz, size_t min, size_t max) { + if (sz < min) return min; + else if (sz > max) return max; + else return sz; +} + +// Is memory zero initialized? +static inline bool mi_mem_is_zero(const void* p, size_t size) { + for (size_t i = 0; i < size; i++) { + if (((uint8_t*)p)[i] != 0) return false; + } + return true; +} + +// Align a byte size to a size in _machine words_, +// i.e. byte size == `wsize*sizeof(void*)`. +static inline size_t _mi_wsize_from_size(size_t size) { + mi_assert_internal(size <= SIZE_MAX - sizeof(uintptr_t)); + return (size + sizeof(uintptr_t) - 1) / sizeof(uintptr_t); +} + +// Overflow detecting multiply +#if __has_builtin(__builtin_umul_overflow) || (defined(__GNUC__) && (__GNUC__ >= 5)) +#include // UINT_MAX, ULONG_MAX +#if defined(_CLOCK_T) // for Illumos +#undef _CLOCK_T +#endif +static inline bool mi_mul_overflow(size_t count, size_t size, size_t* total) { + #if (SIZE_MAX == ULONG_MAX) + return __builtin_umull_overflow(count, size, (unsigned long *)total); + #elif (SIZE_MAX == UINT_MAX) + return __builtin_umul_overflow(count, size, (unsigned int *)total); + #else + return __builtin_umulll_overflow(count, size, (unsigned long long *)total); + #endif +} +#else /* __builtin_umul_overflow is unavailable */ +static inline bool mi_mul_overflow(size_t count, size_t size, size_t* total) { + #define MI_MUL_COULD_OVERFLOW ((size_t)1 << (4*sizeof(size_t))) // sqrt(SIZE_MAX) + *total = count * size; + // note: gcc/clang optimize this to directly check the overflow flag + return ((size >= MI_MUL_COULD_OVERFLOW || count >= MI_MUL_COULD_OVERFLOW) && size > 0 && (SIZE_MAX / size) < count); +} +#endif + +// Safe multiply `count*size` into `total`; return `true` on overflow. +static inline bool mi_count_size_overflow(size_t count, size_t size, size_t* total) { + if (count==1) { // quick check for the case where count is one (common for C++ allocators) + *total = size; + return false; + } + else if mi_unlikely(mi_mul_overflow(count, size, total)) { + #if MI_DEBUG > 0 + _mi_error_message(EOVERFLOW, "allocation request is too large (%zu * %zu bytes)\n", count, size); + #endif + *total = SIZE_MAX; + return true; + } + else return false; +} + + +/*---------------------------------------------------------------------------------------- + Heap functions +------------------------------------------------------------------------------------------- */ + +extern mi_decl_hidden const mi_heap_t _mi_heap_empty; // read-only empty heap, initial value of the thread local default heap + +static inline bool mi_heap_is_backing(const mi_heap_t* heap) { + return (heap->tld->heap_backing == heap); +} + +static inline bool mi_heap_is_initialized(const mi_heap_t* heap) { + mi_assert_internal(heap != NULL); + return (heap != NULL && heap != &_mi_heap_empty); +} + +static inline mi_page_t* _mi_heap_get_free_small_page(mi_heap_t* heap, size_t size) { + mi_assert_internal(size <= (MI_SMALL_SIZE_MAX + MI_PADDING_SIZE)); + const size_t idx = _mi_wsize_from_size(size); + mi_assert_internal(idx < MI_PAGES_DIRECT); + return heap->pages_free_direct[idx]; +} + + +//static inline uintptr_t _mi_ptr_cookie(const void* p) { +// extern mi_heap_t _mi_heap_main; +// mi_assert_internal(_mi_heap_main.cookie != 0); +// return ((uintptr_t)p ^ _mi_heap_main.cookie); +//} + + +/* ----------------------------------------------------------- + The page map maps addresses to `mi_page_t` pointers +----------------------------------------------------------- */ + +#if MI_PAGE_MAP_FLAT + +// flat page-map committed on demand, using one byte per slice (64 KiB). +// single indirection and low commit, but large initial virtual reserve (4 GiB with 48 bit virtual addresses) +// used by default on <= 40 bit virtual address spaces. +extern mi_decl_hidden uint8_t* _mi_page_map; + +static inline size_t _mi_page_map_index(const void* p) { + return (size_t)((uintptr_t)p >> MI_ARENA_SLICE_SHIFT); +} + +static inline mi_page_t* _mi_ptr_page_ex(const void* p, bool* valid) { + const size_t idx = _mi_page_map_index(p); + const size_t ofs = _mi_page_map[idx]; + if (valid != NULL) { *valid = (ofs != 0); } + return (mi_page_t*)((((uintptr_t)p >> MI_ARENA_SLICE_SHIFT) + 1 - ofs) << MI_ARENA_SLICE_SHIFT); +} + +static inline mi_page_t* _mi_checked_ptr_page(const void* p) { + bool valid; + mi_page_t* const page = _mi_ptr_page_ex(p, &valid); + return (valid ? page : NULL); +} + +static inline mi_page_t* _mi_unchecked_ptr_page(const void* p) { + return _mi_ptr_page_ex(p, NULL); +} + +#else + +// 2-level page map: +// double indirection, but low commit and low virtual reserve. +// +// the page-map is usually 4 MiB (for 48 bit virtual addresses) and points to sub maps of 64 KiB. +// the page-map is committed on-demand (in 64 KiB parts) (and sub-maps are committed on-demand as well) +// one sub page-map = 64 KiB => covers 2^(16-3) * 2^16 = 2^29 = 512 MiB address space +// the page-map needs 48-(16+13) = 19 bits => 2^19 sub map pointers = 2^22 bytes = 4 MiB reserved size. +#define MI_PAGE_MAP_SUB_SHIFT (13) +#define MI_PAGE_MAP_SUB_COUNT (MI_ZU(1) << MI_PAGE_MAP_SUB_SHIFT) +#define MI_PAGE_MAP_SHIFT (MI_MAX_VABITS - MI_PAGE_MAP_SUB_SHIFT - MI_ARENA_SLICE_SHIFT) +#define MI_PAGE_MAP_COUNT (MI_ZU(1) << MI_PAGE_MAP_SHIFT) + +extern mi_decl_hidden _Atomic(mi_page_t**)* _mi_page_map; + +static inline size_t _mi_page_map_index(const void* p, size_t* sub_idx) { + const size_t u = (size_t)((uintptr_t)p / MI_ARENA_SLICE_SIZE); + if (sub_idx != NULL) { *sub_idx = u % MI_PAGE_MAP_SUB_COUNT; } + return (u / MI_PAGE_MAP_SUB_COUNT); +} + +static inline mi_page_t** _mi_page_map_at(size_t idx) { + return mi_atomic_load_ptr_relaxed(mi_page_t*, &_mi_page_map[idx]); +} + +static inline mi_page_t* _mi_unchecked_ptr_page(const void* p) { + size_t sub_idx; + const size_t idx = _mi_page_map_index(p, &sub_idx); + return (_mi_page_map_at(idx))[sub_idx]; // NULL if p==NULL +} + +static inline mi_page_t* _mi_checked_ptr_page(const void* p) { + size_t sub_idx; + const size_t idx = _mi_page_map_index(p, &sub_idx); + mi_page_t** const sub = _mi_page_map_at(idx); + if mi_unlikely(sub == NULL) return NULL; + return sub[sub_idx]; +} + +#endif + + +static inline mi_page_t* _mi_ptr_page(const void* p) { + mi_assert_internal(p==NULL || mi_is_in_heap_region(p)); + #if MI_DEBUG || MI_SECURE || defined(__APPLE__) + return _mi_checked_ptr_page(p); + #else + return _mi_unchecked_ptr_page(p); + #endif +} + + +// Get the block size of a page +static inline size_t mi_page_block_size(const mi_page_t* page) { + mi_assert_internal(page->block_size > 0); + return page->block_size; +} + +// Page start +static inline uint8_t* mi_page_start(const mi_page_t* page) { + return page->page_start; +} + +static inline size_t mi_page_size(const mi_page_t* page) { + return mi_page_block_size(page) * page->reserved; +} + +static inline uint8_t* mi_page_area(const mi_page_t* page, size_t* size) { + if (size) { *size = mi_page_size(page); } + return mi_page_start(page); +} + +static inline size_t mi_page_info_size(void) { + return _mi_align_up(sizeof(mi_page_t), MI_MAX_ALIGN_SIZE); +} + +static inline bool mi_page_contains_address(const mi_page_t* page, const void* p) { + size_t psize; + uint8_t* start = mi_page_area(page, &psize); + return (start <= (uint8_t*)p && (uint8_t*)p < start + psize); +} + +static inline bool mi_page_is_in_arena(const mi_page_t* page) { + return (page->memid.memkind == MI_MEM_ARENA); +} + +static inline bool mi_page_is_singleton(const mi_page_t* page) { + return (page->reserved == 1); +} + +// Get the usable block size of a page without fixed padding. +// This may still include internal padding due to alignment and rounding up size classes. +static inline size_t mi_page_usable_block_size(const mi_page_t* page) { + return mi_page_block_size(page) - MI_PADDING_SIZE; +} + +// This may change if we locate page info outside the page data slices +static inline uint8_t* mi_page_slice_start(const mi_page_t* page) { + return (uint8_t*)page; +} + +// This gives the offset relative to the start slice of a page. This may change if we ever +// locate page info outside the page-data itself. +static inline size_t mi_page_slice_offset_of(const mi_page_t* page, size_t offset_relative_to_page_start) { + return (page->page_start - mi_page_slice_start(page)) + offset_relative_to_page_start; +} + +static inline size_t mi_page_committed(const mi_page_t* page) { + return (page->slice_committed == 0 ? mi_page_size(page) : page->slice_committed - (page->page_start - mi_page_slice_start(page))); +} + +static inline mi_heap_t* mi_page_heap(const mi_page_t* page) { + return page->heap; +} + + +// are all blocks in a page freed? +// note: needs up-to-date used count, (as the `xthread_free` list may not be empty). see `_mi_page_collect_free`. +static inline bool mi_page_all_free(const mi_page_t* page) { + mi_assert_internal(page != NULL); + return (page->used == 0); +} + +// are there immediately available blocks, i.e. blocks available on the free list. +static inline bool mi_page_immediate_available(const mi_page_t* page) { + mi_assert_internal(page != NULL); + return (page->free != NULL); +} + + +// is the page not yet used up to its reserved space? +static inline bool mi_page_is_expandable(const mi_page_t* page) { + mi_assert_internal(page != NULL); + mi_assert_internal(page->capacity <= page->reserved); + return (page->capacity < page->reserved); +} + + +static inline bool mi_page_is_full(mi_page_t* page) { + bool full = (page->reserved == page->used); + mi_assert_internal(!full || page->free == NULL); + return full; +} + +// is more than 7/8th of a page in use? +static inline bool mi_page_is_mostly_used(const mi_page_t* page) { + if (page==NULL) return true; + uint16_t frac = page->reserved / 8U; + return (page->reserved - page->used <= frac); +} + +// is more than (n-1)/n'th of a page in use? +static inline bool mi_page_is_used_at_frac(const mi_page_t* page, uint16_t n) { + if (page==NULL) return true; + uint16_t frac = page->reserved / n; + return (page->reserved - page->used <= frac); +} + + +static inline bool mi_page_is_huge(const mi_page_t* page) { + return (mi_page_is_singleton(page) && + (page->block_size > MI_LARGE_MAX_OBJ_SIZE || + (mi_memkind_is_os(page->memid.memkind) && page->memid.mem.os.base < (void*)page))); +} + +static inline mi_page_queue_t* mi_page_queue(const mi_heap_t* heap, size_t size) { + mi_page_queue_t* const pq = &((mi_heap_t*)heap)->pages[_mi_bin(size)]; + if (size <= MI_LARGE_MAX_OBJ_SIZE) { mi_assert_internal(pq->block_size <= MI_LARGE_MAX_OBJ_SIZE); } + return pq; +} + + +//----------------------------------------------------------- +// Page thread id and flags +//----------------------------------------------------------- + +// Thread id of thread that owns this page (with flags in the bottom 2 bits) +static inline mi_threadid_t mi_page_xthread_id(const mi_page_t* page) { + return mi_atomic_load_relaxed(&((mi_page_t*)page)->xthread_id); +} + +// Plain thread id of the thread that owns this page +static inline mi_threadid_t mi_page_thread_id(const mi_page_t* page) { + return (mi_page_xthread_id(page) & ~MI_PAGE_FLAG_MASK); +} + +static inline mi_page_flags_t mi_page_flags(const mi_page_t* page) { + return (mi_page_xthread_id(page) & MI_PAGE_FLAG_MASK); +} + +static inline void mi_page_flags_set(mi_page_t* page, bool set, mi_page_flags_t newflag) { + if (set) { mi_atomic_or_relaxed(&page->xthread_id, newflag); } + else { mi_atomic_and_relaxed(&page->xthread_id, ~newflag); } +} + +static inline bool mi_page_is_in_full(const mi_page_t* page) { + return ((mi_page_flags(page) & MI_PAGE_IN_FULL_QUEUE) != 0); +} + +static inline void mi_page_set_in_full(mi_page_t* page, bool in_full) { + mi_page_flags_set(page, in_full, MI_PAGE_IN_FULL_QUEUE); +} + +static inline bool mi_page_has_aligned(const mi_page_t* page) { + return ((mi_page_flags(page) & MI_PAGE_HAS_ALIGNED) != 0); +} + +static inline void mi_page_set_has_aligned(mi_page_t* page, bool has_aligned) { + mi_page_flags_set(page, has_aligned, MI_PAGE_HAS_ALIGNED); +} + +static inline void mi_page_set_heap(mi_page_t* page, mi_heap_t* heap) { + // mi_assert_internal(!mi_page_is_in_full(page)); // can happen when destroying pages on heap_destroy + const mi_threadid_t tid = (heap == NULL ? MI_THREADID_ABANDONED : heap->tld->thread_id) | mi_page_flags(page); + if (heap != NULL) { + page->heap = heap; + page->heap_tag = heap->tag; + } + else { + page->heap = NULL; + } + mi_atomic_store_release(&page->xthread_id, tid); +} + +static inline bool mi_page_is_abandoned(const mi_page_t* page) { + // note: the xheap field of an abandoned heap is set to the subproc (for fast reclaim-on-free) + return (mi_page_thread_id(page) <= MI_THREADID_ABANDONED_MAPPED); +} + +static inline bool mi_page_is_abandoned_mapped(const mi_page_t* page) { + return (mi_page_thread_id(page) == MI_THREADID_ABANDONED_MAPPED); +} + +static inline void mi_page_set_abandoned_mapped(mi_page_t* page) { + mi_assert_internal(mi_page_is_abandoned(page)); + mi_atomic_or_relaxed(&page->xthread_id, MI_THREADID_ABANDONED_MAPPED); +} + +static inline void mi_page_clear_abandoned_mapped(mi_page_t* page) { + mi_assert_internal(mi_page_is_abandoned_mapped(page)); + mi_atomic_and_relaxed(&page->xthread_id, MI_PAGE_FLAG_MASK); +} + +//----------------------------------------------------------- +// Thread free list and ownership +//----------------------------------------------------------- + +// Thread free flag helpers +static inline mi_block_t* mi_tf_block(mi_thread_free_t tf) { + return (mi_block_t*)(tf & ~1); +} +static inline bool mi_tf_is_owned(mi_thread_free_t tf) { + return ((tf & 1) == 1); +} +static inline mi_thread_free_t mi_tf_create(mi_block_t* block, bool owned) { + return (mi_thread_free_t)((uintptr_t)block | (owned ? 1 : 0)); +} + +// Thread free access +static inline mi_block_t* mi_page_thread_free(const mi_page_t* page) { + return mi_tf_block(mi_atomic_load_relaxed(&((mi_page_t*)page)->xthread_free)); +} + +// are there any available blocks? +static inline bool mi_page_has_any_available(const mi_page_t* page) { + mi_assert_internal(page != NULL && page->reserved > 0); + return (page->used < page->reserved || (mi_page_thread_free(page) != NULL)); +} + + +// Owned? +static inline bool mi_page_is_owned(const mi_page_t* page) { + return mi_tf_is_owned(mi_atomic_load_relaxed(&((mi_page_t*)page)->xthread_free)); +} + +// Unown a page that is currently owned +static inline void _mi_page_unown_unconditional(mi_page_t* page) { + mi_assert_internal(mi_page_is_owned(page)); + mi_assert_internal(mi_page_thread_id(page)==0); + const uintptr_t old = mi_atomic_and_acq_rel(&page->xthread_free, ~((uintptr_t)1)); + mi_assert_internal((old&1)==1); MI_UNUSED(old); +} + +// get ownership if it is not yet owned +static inline bool mi_page_try_claim_ownership(mi_page_t* page) { + const uintptr_t old = mi_atomic_or_acq_rel(&page->xthread_free, 1); + return ((old&1)==0); +} + +// release ownership of a page. This may free the page if all blocks were concurrently +// freed in the meantime. Returns true if the page was freed. +static inline bool _mi_page_unown(mi_page_t* page) { + mi_assert_internal(mi_page_is_owned(page)); + mi_assert_internal(mi_page_is_abandoned(page)); + mi_thread_free_t tf_new; + mi_thread_free_t tf_old = mi_atomic_load_relaxed(&page->xthread_free); + do { + mi_assert_internal(mi_tf_is_owned(tf_old)); + while mi_unlikely(mi_tf_block(tf_old) != NULL) { + _mi_page_free_collect(page, false); // update used + if (mi_page_all_free(page)) { // it may become free just before unowning it + _mi_arenas_page_unabandon(page); + _mi_arenas_page_free(page,NULL); + return true; + } + tf_old = mi_atomic_load_relaxed(&page->xthread_free); + } + mi_assert_internal(mi_tf_block(tf_old)==NULL); + tf_new = mi_tf_create(NULL, false); + } while (!mi_atomic_cas_weak_acq_rel(&page->xthread_free, &tf_old, tf_new)); + return false; +} + + +/* ------------------------------------------------------------------- + Guarded objects +------------------------------------------------------------------- */ +#if MI_GUARDED + +// we always align guarded pointers in a block at an offset +// the block `next` field is then used as a tag to distinguish regular offset aligned blocks from guarded ones +#define MI_BLOCK_TAG_ALIGNED ((mi_encoded_t)(0)) +#define MI_BLOCK_TAG_GUARDED (~MI_BLOCK_TAG_ALIGNED) + +static inline bool mi_block_ptr_is_guarded(const mi_block_t* block, const void* p) { + const ptrdiff_t offset = (uint8_t*)p - (uint8_t*)block; + return (offset >= (ptrdiff_t)(sizeof(mi_block_t)) && block->next == MI_BLOCK_TAG_GUARDED); +} + +static inline bool mi_heap_malloc_use_guarded(mi_heap_t* heap, size_t size) { + // this code is written to result in fast assembly as it is on the hot path for allocation + const size_t count = heap->guarded_sample_count - 1; // if the rate was 0, this will underflow and count for a long time.. + if mi_likely(count != 0) { + // no sample + heap->guarded_sample_count = count; + return false; + } + else if (size >= heap->guarded_size_min && size <= heap->guarded_size_max) { + // use guarded allocation + heap->guarded_sample_count = heap->guarded_sample_rate; // reset + return (heap->guarded_sample_rate != 0); + } + else { + // failed size criteria, rewind count (but don't write to an empty heap) + if (heap->guarded_sample_rate != 0) { heap->guarded_sample_count = 1; } + return false; + } +} + +mi_decl_restrict void* _mi_heap_malloc_guarded(mi_heap_t* heap, size_t size, bool zero) mi_attr_noexcept; + +#endif + + +/* ------------------------------------------------------------------- +Encoding/Decoding the free list next pointers + +This is to protect against buffer overflow exploits where the +free list is mutated. Many hardened allocators xor the next pointer `p` +with a secret key `k1`, as `p^k1`. This prevents overwriting with known +values but might be still too weak: if the attacker can guess +the pointer `p` this can reveal `k1` (since `p^k1^p == k1`). +Moreover, if multiple blocks can be read as well, the attacker can +xor both as `(p1^k1) ^ (p2^k1) == p1^p2` which may reveal a lot +about the pointers (and subsequently `k1`). + +Instead mimalloc uses an extra key `k2` and encodes as `((p^k2)<<next, keys); + #else + MI_UNUSED(keys); MI_UNUSED(null); + next = (mi_block_t*)block->next; + #endif + mi_track_mem_noaccess(block,sizeof(mi_block_t)); + return next; +} + +static inline void mi_block_set_nextx(const void* null, mi_block_t* block, const mi_block_t* next, const uintptr_t* keys) { + mi_track_mem_undefined(block,sizeof(mi_block_t)); + #ifdef MI_ENCODE_FREELIST + block->next = mi_ptr_encode(null, next, keys); + #else + MI_UNUSED(keys); MI_UNUSED(null); + block->next = (mi_encoded_t)next; + #endif + mi_track_mem_noaccess(block,sizeof(mi_block_t)); +} + +static inline mi_block_t* mi_block_next(const mi_page_t* page, const mi_block_t* block) { + #ifdef MI_ENCODE_FREELIST + mi_block_t* next = mi_block_nextx(page,block,page->keys); + // check for free list corruption: is `next` at least in the same page? + // TODO: check if `next` is `page->block_size` aligned? + if mi_unlikely(next!=NULL && !mi_is_in_same_page(block, next)) { + _mi_error_message(EFAULT, "corrupted free list entry of size %zub at %p: value 0x%zx\n", mi_page_block_size(page), block, (uintptr_t)next); + next = NULL; + } + return next; + #else + MI_UNUSED(page); + return mi_block_nextx(page,block,NULL); + #endif +} + +static inline void mi_block_set_next(const mi_page_t* page, mi_block_t* block, const mi_block_t* next) { + #ifdef MI_ENCODE_FREELIST + mi_block_set_nextx(page,block,next, page->keys); + #else + MI_UNUSED(page); + mi_block_set_nextx(page,block,next,NULL); + #endif +} + +/* ----------------------------------------------------------- + arena blocks +----------------------------------------------------------- */ + +// Blocks needed for a given byte size +static inline size_t mi_slice_count_of_size(size_t size) { + return _mi_divide_up(size, MI_ARENA_SLICE_SIZE); +} + +// Byte size of a number of blocks +static inline size_t mi_size_of_slices(size_t bcount) { + return (bcount * MI_ARENA_SLICE_SIZE); +} + + +/* ----------------------------------------------------------- + memory id's +----------------------------------------------------------- */ + +static inline mi_memid_t _mi_memid_create(mi_memkind_t memkind) { + mi_memid_t memid; + _mi_memzero_var(memid); + memid.memkind = memkind; + return memid; +} + +static inline mi_memid_t _mi_memid_none(void) { + return _mi_memid_create(MI_MEM_NONE); +} + +static inline mi_memid_t _mi_memid_create_os(void* base, size_t size, bool committed, bool is_zero, bool is_large) { + mi_memid_t memid = _mi_memid_create(MI_MEM_OS); + memid.mem.os.base = base; + memid.mem.os.size = size; + memid.initially_committed = committed; + memid.initially_zero = is_zero; + memid.is_pinned = is_large; + return memid; +} + +static inline mi_memid_t _mi_memid_create_meta(void* mpage, size_t block_idx, size_t block_count) { + mi_memid_t memid = _mi_memid_create(MI_MEM_META); + memid.mem.meta.meta_page = mpage; + memid.mem.meta.block_index = (uint32_t)block_idx; + memid.mem.meta.block_count = (uint32_t)block_count; + memid.initially_committed = true; + memid.initially_zero = true; + memid.is_pinned = true; + return memid; +} + + +// ------------------------------------------------------------------- +// Fast "random" shuffle +// ------------------------------------------------------------------- + +static inline uintptr_t _mi_random_shuffle(uintptr_t x) { + if (x==0) { x = 17; } // ensure we don't get stuck in generating zeros +#if (MI_INTPTR_SIZE>=8) + // by Sebastiano Vigna, see: + x ^= x >> 30; + x *= 0xbf58476d1ce4e5b9UL; + x ^= x >> 27; + x *= 0x94d049bb133111ebUL; + x ^= x >> 31; +#elif (MI_INTPTR_SIZE==4) + // by Chris Wellons, see: + x ^= x >> 16; + x *= 0x7feb352dUL; + x ^= x >> 15; + x *= 0x846ca68bUL; + x ^= x >> 16; +#endif + return x; +} + + +// --------------------------------------------------------------------------------- +// Provide our own `_mi_memcpy` for potential performance optimizations. +// +// For now, only on Windows with msvc/clang-cl we optimize to `rep movsb` if +// we happen to run on x86/x64 cpu's that have "fast short rep movsb" (FSRM) support +// (AMD Zen3+ (~2020) or Intel Ice Lake+ (~2017). See also issue #201 and pr #253. +// --------------------------------------------------------------------------------- + +#if !MI_TRACK_ENABLED && defined(_WIN32) && (MI_ARCH_X64 || MI_ARCH_X86) +extern mi_decl_hidden bool _mi_cpu_has_fsrm; +extern mi_decl_hidden bool _mi_cpu_has_erms; + +static inline void _mi_memcpy(void* dst, const void* src, size_t n) { + if ((_mi_cpu_has_fsrm && n <= 128) || (_mi_cpu_has_erms && n > 128)) { + __movsb((unsigned char*)dst, (const unsigned char*)src, n); + } + else { + memcpy(dst, src, n); + } +} +static inline void _mi_memset(void* dst, int val, size_t n) { + if ((_mi_cpu_has_fsrm && n <= 128) || (_mi_cpu_has_erms && n > 128)) { + __stosb((unsigned char*)dst, (uint8_t)val, n); + } + else { + memset(dst, val, n); + } +} +#else +static inline void _mi_memcpy(void* dst, const void* src, size_t n) { + memcpy(dst, src, n); +} +static inline void _mi_memset(void* dst, int val, size_t n) { + memset(dst, val, n); +} +#endif + +// ------------------------------------------------------------------------------- +// The `_mi_memcpy_aligned` can be used if the pointers are machine-word aligned +// This is used for example in `mi_realloc`. +// ------------------------------------------------------------------------------- + +#if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__) +// On GCC/CLang we provide a hint that the pointers are word aligned. +static inline void _mi_memcpy_aligned(void* dst, const void* src, size_t n) { + mi_assert_internal(((uintptr_t)dst % MI_INTPTR_SIZE == 0) && ((uintptr_t)src % MI_INTPTR_SIZE == 0)); + void* adst = __builtin_assume_aligned(dst, MI_INTPTR_SIZE); + const void* asrc = __builtin_assume_aligned(src, MI_INTPTR_SIZE); + _mi_memcpy(adst, asrc, n); +} + +static inline void _mi_memset_aligned(void* dst, int val, size_t n) { + mi_assert_internal((uintptr_t)dst % MI_INTPTR_SIZE == 0); + void* adst = __builtin_assume_aligned(dst, MI_INTPTR_SIZE); + _mi_memset(adst, val, n); +} +#else +// Default fallback on `_mi_memcpy` +static inline void _mi_memcpy_aligned(void* dst, const void* src, size_t n) { + mi_assert_internal(((uintptr_t)dst % MI_INTPTR_SIZE == 0) && ((uintptr_t)src % MI_INTPTR_SIZE == 0)); + _mi_memcpy(dst, src, n); +} + +static inline void _mi_memset_aligned(void* dst, int val, size_t n) { + mi_assert_internal((uintptr_t)dst % MI_INTPTR_SIZE == 0); + _mi_memset(dst, val, n); +} +#endif + +static inline void _mi_memzero(void* dst, size_t n) { + _mi_memset(dst, 0, n); +} + +static inline void _mi_memzero_aligned(void* dst, size_t n) { + _mi_memset_aligned(dst, 0, n); +} + + +#endif // MI_INTERNAL_H diff --git a/src/dashbls/depends/mimalloc/include/mimalloc/prim.h b/src/dashbls/depends/mimalloc/include/mimalloc/prim.h new file mode 100644 index 000000000000..daddaf8b1cd5 --- /dev/null +++ b/src/dashbls/depends/mimalloc/include/mimalloc/prim.h @@ -0,0 +1,431 @@ +/* ---------------------------------------------------------------------------- +Copyright (c) 2018-2024, Microsoft Research, Daan Leijen +This is free software; you can redistribute it and/or modify it under the +terms of the MIT license. A copy of the license can be found in the file +"LICENSE" at the root of this distribution. +-----------------------------------------------------------------------------*/ +#pragma once +#ifndef MI_PRIM_H +#define MI_PRIM_H + + +// -------------------------------------------------------------------------- +// This file specifies the primitive portability API. +// Each OS/host needs to implement these primitives, see `src/prim` +// for implementations on Window, macOS, WASI, and Linux/Unix. +// +// note: on all primitive functions, we always have result parameters != NULL, and: +// addr != NULL and page aligned +// size > 0 and page aligned +// the return value is an error code as an `int` where 0 is success +// -------------------------------------------------------------------------- + +// OS memory configuration +typedef struct mi_os_mem_config_s { + size_t page_size; // default to 4KiB + size_t large_page_size; // 0 if not supported, usually 2MiB (4MiB on Windows) + size_t alloc_granularity; // smallest allocation size (usually 4KiB, on Windows 64KiB) + size_t physical_memory_in_kib; // physical memory size in KiB + size_t virtual_address_bits; // usually 48 or 56 bits on 64-bit systems. (used to determine secure randomization) + bool has_overcommit; // can we reserve more memory than can be actually committed? + bool has_partial_free; // can allocated blocks be freed partially? (true for mmap, false for VirtualAlloc) + bool has_virtual_reserve; // supports virtual address space reservation? (if true we can reserve virtual address space without using commit or physical memory) +} mi_os_mem_config_t; + +// Initialize +void _mi_prim_mem_init( mi_os_mem_config_t* config ); + +// Free OS memory +int _mi_prim_free(void* addr, size_t size ); + +// Allocate OS memory. Return NULL on error. +// The `try_alignment` is just a hint and the returned pointer does not have to be aligned. +// If `commit` is false, the virtual memory range only needs to be reserved (with no access) +// which will later be committed explicitly using `_mi_prim_commit`. +// `is_zero` is set to true if the memory was zero initialized (as on most OS's) +// The `hint_addr` address is either `NULL` or a preferred allocation address but can be ignored. +// pre: !commit => !allow_large +// try_alignment >= _mi_os_page_size() and a power of 2 +int _mi_prim_alloc(void* hint_addr, size_t size, size_t try_alignment, bool commit, bool allow_large, bool* is_large, bool* is_zero, void** addr); + +// Commit memory. Returns error code or 0 on success. +// For example, on Linux this would make the memory PROT_READ|PROT_WRITE. +// `is_zero` is set to true if the memory was zero initialized (e.g. on Windows) +int _mi_prim_commit(void* addr, size_t size, bool* is_zero); + +// Decommit memory. Returns error code or 0 on success. The `needs_recommit` result is true +// if the memory would need to be re-committed. For example, on Windows this is always true, +// but on Linux we could use MADV_DONTNEED to decommit which does not need a recommit. +// pre: needs_recommit != NULL +int _mi_prim_decommit(void* addr, size_t size, bool* needs_recommit); + +// Reset memory. The range keeps being accessible but the content might be reset to zero at any moment. +// Returns error code or 0 on success. +int _mi_prim_reset(void* addr, size_t size); + +// Reuse memory. This is called for memory that is already committed but +// may have been reset (`_mi_prim_reset`) or decommitted (`_mi_prim_decommit`) where `needs_recommit` was false. +// Returns error code or 0 on success. On most platforms this is a no-op. +int _mi_prim_reuse(void* addr, size_t size); + +// Protect memory. Returns error code or 0 on success. +int _mi_prim_protect(void* addr, size_t size, bool protect); + +// Allocate huge (1GiB) pages possibly associated with a NUMA node. +// `is_zero` is set to true if the memory was zero initialized (as on most OS's) +// pre: size > 0 and a multiple of 1GiB. +// numa_node is either negative (don't care), or a numa node number. +int _mi_prim_alloc_huge_os_pages(void* hint_addr, size_t size, int numa_node, bool* is_zero, void** addr); + +// Return the current NUMA node +size_t _mi_prim_numa_node(void); + +// Return the number of logical NUMA nodes +size_t _mi_prim_numa_node_count(void); + +// Clock ticks +mi_msecs_t _mi_prim_clock_now(void); + +// Return process information (only for statistics) +typedef struct mi_process_info_s { + mi_msecs_t elapsed; + mi_msecs_t utime; + mi_msecs_t stime; + size_t current_rss; + size_t peak_rss; + size_t current_commit; + size_t peak_commit; + size_t page_faults; +} mi_process_info_t; + +void _mi_prim_process_info(mi_process_info_t* pinfo); + +// Default stderr output. (only for warnings etc. with verbose enabled) +// msg != NULL && _mi_strlen(msg) > 0 +void _mi_prim_out_stderr( const char* msg ); + +// Get an environment variable. (only for options) +// name != NULL, result != NULL, result_size >= 64 +bool _mi_prim_getenv(const char* name, char* result, size_t result_size); + + +// Fill a buffer with strong randomness; return `false` on error or if +// there is no strong randomization available. +bool _mi_prim_random_buf(void* buf, size_t buf_len); + +// Called on the first thread start, and should ensure `_mi_thread_done` is called on thread termination. +void _mi_prim_thread_init_auto_done(void); + +// Called on process exit and may take action to clean up resources associated with the thread auto done. +void _mi_prim_thread_done_auto_done(void); + +// Called when the default heap for a thread changes +void _mi_prim_thread_associate_default_heap(mi_heap_t* heap); + +// Is this thread part of a thread pool? +bool _mi_prim_thread_is_in_threadpool(void); + + +//------------------------------------------------------------------- +// Access to TLS (thread local storage) slots. +// We need fast access to both a unique thread id (in `free.c:mi_free`) and +// to a thread-local heap pointer (in `alloc.c:mi_malloc`). +// To achieve this we use specialized code for various platforms. +//------------------------------------------------------------------- + +// On some libc + platform combinations we can directly access a thread-local storage (TLS) slot. +// The TLS layout depends on both the OS and libc implementation so we use specific tests for each main platform. +// If you test on another platform and it works please send a PR :-) +// see also https://akkadia.org/drepper/tls.pdf for more info on the TLS register. +// +// Note: we would like to prefer `__builtin_thread_pointer()` nowadays instead of using assembly, +// but unfortunately we can not detect support reliably (see issue #883) +// We also use it on Apple OS as we use a TLS slot for the default heap there. +#if defined(__GNUC__) && ( \ + (defined(__GLIBC__) && (defined(__x86_64__) || defined(__i386__) || (defined(__arm__) && __ARM_ARCH >= 7) || defined(__aarch64__))) \ + || (defined(__APPLE__) && (defined(__x86_64__) || defined(__aarch64__) || defined(__POWERPC__))) \ + || (defined(__BIONIC__) && (defined(__x86_64__) || defined(__i386__) || (defined(__arm__) && __ARM_ARCH >= 7) || defined(__aarch64__))) \ + || (defined(__FreeBSD__) && (defined(__x86_64__) || defined(__i386__) || defined(__aarch64__))) \ + || (defined(__OpenBSD__) && (defined(__x86_64__) || defined(__i386__) || defined(__aarch64__))) \ + ) + +#define MI_HAS_TLS_SLOT 1 + +static inline void* mi_prim_tls_slot(size_t slot) mi_attr_noexcept { + void* res; + const size_t ofs = (slot*sizeof(void*)); + #if defined(__i386__) + __asm__("movl %%gs:%1, %0" : "=r" (res) : "m" (*((void**)ofs)) : ); // x86 32-bit always uses GS + #elif defined(__APPLE__) && defined(__x86_64__) + __asm__("movq %%gs:%1, %0" : "=r" (res) : "m" (*((void**)ofs)) : ); // x86_64 macOSX uses GS + #elif defined(__x86_64__) && (MI_INTPTR_SIZE==4) + __asm__("movl %%fs:%1, %0" : "=r" (res) : "m" (*((void**)ofs)) : ); // x32 ABI + #elif defined(__x86_64__) + __asm__("movq %%fs:%1, %0" : "=r" (res) : "m" (*((void**)ofs)) : ); // x86_64 Linux, BSD uses FS + #elif defined(__arm__) + void** tcb; MI_UNUSED(ofs); + __asm__ volatile ("mrc p15, 0, %0, c13, c0, 3\nbic %0, %0, #3" : "=r" (tcb)); + res = tcb[slot]; + #elif defined(__aarch64__) + void** tcb; MI_UNUSED(ofs); + #if defined(__APPLE__) // M1, issue #343 + __asm__ volatile ("mrs %0, tpidrro_el0\nbic %0, %0, #7" : "=r" (tcb)); + #else + __asm__ volatile ("mrs %0, tpidr_el0" : "=r" (tcb)); + #endif + res = tcb[slot]; + #elif defined(__APPLE__) && defined(__POWERPC__) // ppc, issue #781 + MI_UNUSED(ofs); + res = pthread_getspecific(slot); + #endif + return res; +} + +// setting a tls slot is only used on macOS for now +static inline void mi_prim_tls_slot_set(size_t slot, void* value) mi_attr_noexcept { + const size_t ofs = (slot*sizeof(void*)); + #if defined(__i386__) + __asm__("movl %1,%%gs:%0" : "=m" (*((void**)ofs)) : "rn" (value) : ); // 32-bit always uses GS + #elif defined(__APPLE__) && defined(__x86_64__) + __asm__("movq %1,%%gs:%0" : "=m" (*((void**)ofs)) : "rn" (value) : ); // x86_64 macOS uses GS + #elif defined(__x86_64__) && (MI_INTPTR_SIZE==4) + __asm__("movl %1,%%fs:%0" : "=m" (*((void**)ofs)) : "rn" (value) : ); // x32 ABI + #elif defined(__x86_64__) + __asm__("movq %1,%%fs:%0" : "=m" (*((void**)ofs)) : "rn" (value) : ); // x86_64 Linux, BSD uses FS + #elif defined(__arm__) + void** tcb; MI_UNUSED(ofs); + __asm__ volatile ("mrc p15, 0, %0, c13, c0, 3\nbic %0, %0, #3" : "=r" (tcb)); + tcb[slot] = value; + #elif defined(__aarch64__) + void** tcb; MI_UNUSED(ofs); + #if defined(__APPLE__) // M1, issue #343 + __asm__ volatile ("mrs %0, tpidrro_el0\nbic %0, %0, #7" : "=r" (tcb)); + #else + __asm__ volatile ("mrs %0, tpidr_el0" : "=r" (tcb)); + #endif + tcb[slot] = value; + #elif defined(__APPLE__) && defined(__POWERPC__) // ppc, issue #781 + MI_UNUSED(ofs); + pthread_setspecific(slot, value); + #endif +} + +#elif _WIN32 && MI_WIN_USE_FIXED_TLS && !defined(MI_WIN_USE_FLS) + +// On windows we can store the thread-local heap at a fixed TLS slot to avoid +// thread-local initialization checks in the fast path. +// We allocate a user TLS slot at process initialization (see `windows/prim.c`) +// and store the offset `_mi_win_tls_offset`. +#define MI_HAS_TLS_SLOT 1 // 2 = we can reliably initialize the slot (saving a test on each malloc) + +extern mi_decl_hidden size_t _mi_win_tls_offset; + +#if MI_WIN_USE_FIXED_TLS > 1 +#define MI_TLS_SLOT (MI_WIN_USE_FIXED_TLS) +#elif MI_SIZE_SIZE == 4 +#define MI_TLS_SLOT (0x0E10 + _mi_win_tls_offset) // User TLS slots +#else +#define MI_TLS_SLOT (0x1480 + _mi_win_tls_offset) // User TLS slots +#endif + +static inline void* mi_prim_tls_slot(size_t slot) mi_attr_noexcept { + #if (_M_X64 || _M_AMD64) && !defined(_M_ARM64EC) + return (void*)__readgsqword((unsigned long)slot); // direct load at offset from gs + #elif _M_IX86 && !defined(_M_ARM64EC) + return (void*)__readfsdword((unsigned long)slot); // direct load at offset from fs + #else + return ((void**)NtCurrentTeb())[slot / sizeof(void*)]; + #endif +} +static inline void mi_prim_tls_slot_set(size_t slot, void* value) mi_attr_noexcept { + ((void**)NtCurrentTeb())[slot / sizeof(void*)] = value; +} + +#endif + + + +//------------------------------------------------------------------- +// Get a fast unique thread id. +// +// Getting the thread id should be performant as it is called in the +// fast path of `_mi_free` and we specialize for various platforms as +// inlined definitions. Regular code should call `init.c:_mi_thread_id()`. +// We only require _mi_prim_thread_id() to return a unique id +// for each thread (unequal to zero). +//------------------------------------------------------------------- + + +// Do we have __builtin_thread_pointer? This would be the preferred way to get a unique thread id +// but unfortunately, it seems we cannot test for this reliably at this time (see issue #883) +// Nevertheless, it seems needed on older graviton platforms (see issue #851). +// For now, we only enable this for specific platforms. +#if !defined(__APPLE__) /* on apple (M1) the wrong register is read (tpidr_el0 instead of tpidrro_el0) so fall back to TLS slot assembly ()*/ \ + && !defined(__CYGWIN__) \ + && !defined(MI_LIBC_MUSL) \ + && (!defined(__clang_major__) || __clang_major__ >= 14) /* older clang versions emit bad code; fall back to using the TLS slot () */ + #if (defined(__GNUC__) && (__GNUC__ >= 7) && defined(__aarch64__)) /* aarch64 for older gcc versions (issue #851) */ \ + || (defined(__GNUC__) && (__GNUC__ >= 11) && defined(__x86_64__)) \ + || (defined(__clang_major__) && (__clang_major__ >= 14) && (defined(__aarch64__) || defined(__x86_64__))) + #define MI_USE_BUILTIN_THREAD_POINTER 1 + #endif +#endif + + + +// defined in `init.c`; do not use these directly +extern mi_decl_hidden mi_decl_thread mi_heap_t* _mi_heap_default; // default heap to allocate from +extern mi_decl_hidden bool _mi_process_is_initialized; // has mi_process_init been called? + +static inline mi_threadid_t __mi_prim_thread_id(void) mi_attr_noexcept; + +static inline mi_threadid_t _mi_prim_thread_id(void) mi_attr_noexcept { + const mi_threadid_t tid = __mi_prim_thread_id(); + mi_assert_internal(tid > 1); + mi_assert_internal((tid & MI_PAGE_FLAG_MASK) == 0); // bottom 2 bits are clear? + return tid; +} + +// Get a unique id for the current thread. +#if defined(MI_PRIM_THREAD_ID) + +static inline mi_threadid_t __mi_prim_thread_id(void) mi_attr_noexcept { + return MI_PRIM_THREAD_ID(); // used for example by CPython for a free threaded build (see python/cpython#115488) +} + +#elif defined(_WIN32) + +static inline mi_threadid_t __mi_prim_thread_id(void) mi_attr_noexcept { + // Windows: works on Intel and ARM in both 32- and 64-bit + return (uintptr_t)NtCurrentTeb(); +} + +#elif MI_USE_BUILTIN_THREAD_POINTER + +static inline mi_threadid_t __mi_prim_thread_id(void) mi_attr_noexcept { + // Works on most Unix based platforms with recent compilers + return (uintptr_t)__builtin_thread_pointer(); +} + +#elif MI_HAS_TLS_SLOT + +static inline mi_threadid_t __mi_prim_thread_id(void) mi_attr_noexcept { + #if defined(__BIONIC__) + // issue #384, #495: on the Bionic libc (Android), slot 1 is the thread id + // see: https://github.com/aosp-mirror/platform_bionic/blob/c44b1d0676ded732df4b3b21c5f798eacae93228/libc/platform/bionic/tls_defines.h#L86 + return (uintptr_t)mi_prim_tls_slot(1); + #else + // in all our other targets, slot 0 is the thread id + // glibc: https://sourceware.org/git/?p=glibc.git;a=blob_plain;f=sysdeps/x86_64/nptl/tls.h + // apple: https://github.com/apple/darwin-xnu/blob/main/libsyscall/os/tsd.h#L36 + return (uintptr_t)mi_prim_tls_slot(0); + #endif +} + +#else + +// otherwise use portable C, taking the address of a thread local variable (this is still very fast on most platforms). +static inline mi_threadid_t __mi_prim_thread_id(void) mi_attr_noexcept { + return (uintptr_t)&_mi_heap_default; +} + +#endif + + + +/* ---------------------------------------------------------------------------------------- +Get the thread local default heap: `_mi_prim_get_default_heap()` + +This is inlined here as it is on the fast path for allocation functions. + +On most platforms (Windows, Linux, FreeBSD, NetBSD, etc), this just returns a +__thread local variable (`_mi_heap_default`). With the initial-exec TLS model this ensures +that the storage will always be available (allocated on the thread stacks). + +On some platforms though we cannot use that when overriding `malloc` since the underlying +TLS implementation (or the loader) will call itself `malloc` on a first access and recurse. +We try to circumvent this in an efficient way: +- macOSX : we use an unused TLS slot from the OS allocated slots (MI_TLS_SLOT). On OSX, the + loader itself calls `malloc` even before the modules are initialized. +- OpenBSD: we use an unused slot from the pthread block (MI_TLS_PTHREAD_SLOT_OFS). +- DragonFly: defaults are working but seem slow compared to freeBSD (see PR #323) +------------------------------------------------------------------------------------------- */ + +static inline mi_heap_t* mi_prim_get_default_heap(void); + +#if defined(MI_MALLOC_OVERRIDE) +#if defined(__APPLE__) // macOS + #define MI_TLS_SLOT 89 // seems unused? + // other possible unused ones are 9, 29, __PTK_FRAMEWORK_JAVASCRIPTCORE_KEY4 (94), __PTK_FRAMEWORK_GC_KEY9 (112) and __PTK_FRAMEWORK_OLDGC_KEY9 (89) + // see +#elif defined(__OpenBSD__) + // use end bytes of a name; goes wrong if anyone uses names > 23 characters (ptrhread specifies 16) + // see + #define MI_TLS_PTHREAD_SLOT_OFS (6*sizeof(int) + 4*sizeof(void*) + 24) + // #elif defined(__DragonFly__) + // #warning "mimalloc is not working correctly on DragonFly yet." + // #define MI_TLS_PTHREAD_SLOT_OFS (4 + 1*sizeof(void*)) // offset `uniqueid` (also used by gdb?) +#elif defined(__ANDROID__) + // See issue #381 + #define MI_TLS_PTHREAD +#endif +#endif + + +#if MI_TLS_SLOT +# if !defined(MI_HAS_TLS_SLOT) +# error "trying to use a TLS slot for the default heap, but the mi_prim_tls_slot primitives are not defined" +# endif + +static inline mi_heap_t* mi_prim_get_default_heap(void) { + mi_heap_t* heap = (mi_heap_t*)mi_prim_tls_slot(MI_TLS_SLOT); + #if MI_HAS_TLS_SLOT == 1 // check if the TLS slot is initialized + if mi_unlikely(heap == NULL) { + #ifdef __GNUC__ + __asm(""); // prevent conditional load of the address of _mi_heap_empty + #endif + heap = (mi_heap_t*)&_mi_heap_empty; + } + #endif + return heap; +} + +#elif defined(MI_TLS_PTHREAD_SLOT_OFS) + +static inline mi_heap_t** mi_prim_tls_pthread_heap_slot(void) { + pthread_t self = pthread_self(); + #if defined(__DragonFly__) + if (self==NULL) return NULL; + #endif + return (mi_heap_t**)((uint8_t*)self + MI_TLS_PTHREAD_SLOT_OFS); +} + +static inline mi_heap_t* mi_prim_get_default_heap(void) { + mi_heap_t** pheap = mi_prim_tls_pthread_heap_slot(); + if mi_unlikely(pheap == NULL) return _mi_heap_main_get(); + mi_heap_t* heap = *pheap; + if mi_unlikely(heap == NULL) return (mi_heap_t*)&_mi_heap_empty; + return heap; +} + +#elif defined(MI_TLS_PTHREAD) + +extern mi_decl_hidden pthread_key_t _mi_heap_default_key; +static inline mi_heap_t* mi_prim_get_default_heap(void) { + mi_heap_t* heap = (mi_unlikely(_mi_heap_default_key == (pthread_key_t)(-1)) ? _mi_heap_main_get() : (mi_heap_t*)pthread_getspecific(_mi_heap_default_key)); + return (mi_unlikely(heap == NULL) ? (mi_heap_t*)&_mi_heap_empty : heap); +} + +#else // default using a thread local variable; used on most platforms. + +static inline mi_heap_t* mi_prim_get_default_heap(void) { + #if defined(MI_TLS_RECURSE_GUARD) + if (mi_unlikely(!_mi_process_is_initialized)) return _mi_heap_main_get(); + #endif + return _mi_heap_default; +} + +#endif // mi_prim_get_default_heap() + + +#endif // MI_PRIM_H diff --git a/src/dashbls/depends/mimalloc/include/mimalloc/track.h b/src/dashbls/depends/mimalloc/include/mimalloc/track.h new file mode 100644 index 000000000000..199308a64a86 --- /dev/null +++ b/src/dashbls/depends/mimalloc/include/mimalloc/track.h @@ -0,0 +1,145 @@ +/* ---------------------------------------------------------------------------- +Copyright (c) 2018-2023, Microsoft Research, Daan Leijen +This is free software; you can redistribute it and/or modify it under the +terms of the MIT license. A copy of the license can be found in the file +"LICENSE" at the root of this distribution. +-----------------------------------------------------------------------------*/ +#pragma once +#ifndef MI_TRACK_H +#define MI_TRACK_H + +/* ------------------------------------------------------------------------------------------------------ +Track memory ranges with macros for tools like Valgrind address sanitizer, or other memory checkers. +These can be defined for tracking allocation: + + #define mi_track_malloc_size(p,reqsize,size,zero) + #define mi_track_free_size(p,_size) + +The macros are set up such that the size passed to `mi_track_free_size` +always matches the size of `mi_track_malloc_size`. (currently, `size == mi_usable_size(p)`). +The `reqsize` is what the user requested, and `size >= reqsize`. +The `size` is either byte precise (and `size==reqsize`) if `MI_PADDING` is enabled, +or otherwise it is the usable block size which may be larger than the original request. +Use `_mi_block_size_of(void* p)` to get the full block size that was allocated (including padding etc). +The `zero` parameter is `true` if the allocated block is zero initialized. + +Optional: + + #define mi_track_align(p,alignedp,offset,size) + #define mi_track_resize(p,oldsize,newsize) + #define mi_track_init() + +The `mi_track_align` is called right after a `mi_track_malloc` for aligned pointers in a block. +The corresponding `mi_track_free` still uses the block start pointer and original size (corresponding to the `mi_track_malloc`). +The `mi_track_resize` is currently unused but could be called on reallocations within a block. +`mi_track_init` is called at program start. + +The following macros are for tools like asan and valgrind to track whether memory is +defined, undefined, or not accessible at all: + + #define mi_track_mem_defined(p,size) + #define mi_track_mem_undefined(p,size) + #define mi_track_mem_noaccess(p,size) + +-------------------------------------------------------------------------------------------------------*/ + +#if MI_TRACK_VALGRIND +// valgrind tool + +#define MI_TRACK_ENABLED 1 +#define MI_TRACK_HEAP_DESTROY 1 // track free of individual blocks on heap_destroy +#define MI_TRACK_TOOL "valgrind" + +#include +#include + +#define mi_track_malloc_size(p,reqsize,size,zero) VALGRIND_MALLOCLIKE_BLOCK(p,size,MI_PADDING_SIZE /*red zone*/,zero) +#define mi_track_free_size(p,_size) VALGRIND_FREELIKE_BLOCK(p,MI_PADDING_SIZE /*red zone*/) +#define mi_track_resize(p,oldsize,newsize) VALGRIND_RESIZEINPLACE_BLOCK(p,oldsize,newsize,MI_PADDING_SIZE /*red zone*/) +#define mi_track_mem_defined(p,size) VALGRIND_MAKE_MEM_DEFINED(p,size) +#define mi_track_mem_undefined(p,size) VALGRIND_MAKE_MEM_UNDEFINED(p,size) +#define mi_track_mem_noaccess(p,size) VALGRIND_MAKE_MEM_NOACCESS(p,size) + +#elif MI_TRACK_ASAN +// address sanitizer + +#define MI_TRACK_ENABLED 1 +#define MI_TRACK_HEAP_DESTROY 0 +#define MI_TRACK_TOOL "asan" + +#include + +#define mi_track_malloc_size(p,reqsize,size,zero) ASAN_UNPOISON_MEMORY_REGION(p,size) +#define mi_track_free_size(p,size) ASAN_POISON_MEMORY_REGION(p,size) +#define mi_track_mem_defined(p,size) ASAN_UNPOISON_MEMORY_REGION(p,size) +#define mi_track_mem_undefined(p,size) ASAN_UNPOISON_MEMORY_REGION(p,size) +#define mi_track_mem_noaccess(p,size) ASAN_POISON_MEMORY_REGION(p,size) + +#elif MI_TRACK_ETW +// windows event tracing + +#define MI_TRACK_ENABLED 1 +#define MI_TRACK_HEAP_DESTROY 1 +#define MI_TRACK_TOOL "ETW" + +#include "../src/prim/windows/etw.h" + +#define mi_track_init() EventRegistermicrosoft_windows_mimalloc(); +#define mi_track_malloc_size(p,reqsize,size,zero) EventWriteETW_MI_ALLOC((UINT64)(p), size) +#define mi_track_free_size(p,size) EventWriteETW_MI_FREE((UINT64)(p), size) + +#else +// no tracking + +#define MI_TRACK_ENABLED 0 +#define MI_TRACK_HEAP_DESTROY 0 +#define MI_TRACK_TOOL "none" + +#define mi_track_malloc_size(p,reqsize,size,zero) +#define mi_track_free_size(p,_size) + +#endif + +// ------------------- +// Utility definitions + +#ifndef mi_track_resize +#define mi_track_resize(p,oldsize,newsize) mi_track_free_size(p,oldsize); mi_track_malloc(p,newsize,false) +#endif + +#ifndef mi_track_align +#define mi_track_align(p,alignedp,offset,size) mi_track_mem_noaccess(p,offset) +#endif + +#ifndef mi_track_init +#define mi_track_init() +#endif + +#ifndef mi_track_mem_defined +#define mi_track_mem_defined(p,size) +#endif + +#ifndef mi_track_mem_undefined +#define mi_track_mem_undefined(p,size) +#endif + +#ifndef mi_track_mem_noaccess +#define mi_track_mem_noaccess(p,size) +#endif + + +#if MI_PADDING +#define mi_track_malloc(p,reqsize,zero) \ + if ((p)!=NULL) { \ + mi_assert_internal(mi_usable_size(p)==(reqsize)); \ + mi_track_malloc_size(p,reqsize,reqsize,zero); \ + } +#else +#define mi_track_malloc(p,reqsize,zero) \ + if ((p)!=NULL) { \ + mi_assert_internal(mi_usable_size(p)>=(reqsize)); \ + mi_track_malloc_size(p,reqsize,mi_usable_size(p),zero); \ + } +#endif + +#endif // MI_TRACK_H diff --git a/src/dashbls/depends/mimalloc/include/mimalloc/types.h b/src/dashbls/depends/mimalloc/include/mimalloc/types.h new file mode 100644 index 000000000000..00b05e1d4ce8 --- /dev/null +++ b/src/dashbls/depends/mimalloc/include/mimalloc/types.h @@ -0,0 +1,614 @@ +/* ---------------------------------------------------------------------------- +Copyright (c) 2018-2024, Microsoft Research, Daan Leijen +This is free software; you can redistribute it and/or modify it under the +terms of the MIT license. A copy of the license can be found in the file +"LICENSE" at the root of this distribution. +-----------------------------------------------------------------------------*/ +#pragma once +#ifndef MI_TYPES_H +#define MI_TYPES_H + +// -------------------------------------------------------------------------- +// This file contains the main type definitions for mimalloc: +// mi_heap_t : all data for a thread-local heap, contains +// lists of all managed heap pages. +// mi_page_t : a mimalloc page (usually 64KiB or 512KiB) from +// where objects of a single size are allocated. +// Note: we write "OS page" for OS memory pages while +// using plain "page" for mimalloc pages (`mi_page_t`). +// -------------------------------------------------------------------------- + + +#include +#include // ptrdiff_t +#include // uintptr_t, uint16_t, etc +#include // SIZE_MAX etc. +#include // error codes +#include "bits.h" // size defines (MI_INTPTR_SIZE etc), bit operations +#include "atomic.h" // _Atomic primitives + +// Minimal alignment necessary. On most platforms 16 bytes are needed +// due to SSE registers for example. This must be at least `sizeof(void*)` +#ifndef MI_MAX_ALIGN_SIZE +#define MI_MAX_ALIGN_SIZE 16 // sizeof(max_align_t) +#endif + +// ------------------------------------------------------ +// Variants +// ------------------------------------------------------ + +// Define NDEBUG in the release version to disable assertions. +// #define NDEBUG + +// Define MI_TRACK_ to enable tracking support +// #define MI_TRACK_VALGRIND 1 +// #define MI_TRACK_ASAN 1 +// #define MI_TRACK_ETW 1 + +// Define MI_STAT as 1 to maintain statistics; set it to 2 to have detailed statistics (but costs some performance). +// #define MI_STAT 1 + +// Define MI_SECURE to enable security mitigations. Level 1 has minimal performance impact, +// but protects most metadata with guard pages: +// #define MI_SECURE 1 // guard page around metadata; check pointer validity on free +// +// Level 2 has more performance impact but protect well against various buffer overflows +// by surrounding all mimalloc pages with guard pages: +// #define MI_SECURE 2 // guard page around each mimalloc page (can fragment VMA's with large heaps..) +// +// The next two levels can have more performance cost: +// #define MI_SECURE 3 // randomize allocations, encode free lists (detect corrupted free list (buffer overflow), and invalid pointer free) +// #define MI_SECURE 4 // checks for double free. (may be more expensive) + +#if !defined(MI_SECURE) +#define MI_SECURE 0 +#endif + +// Define MI_DEBUG for debug mode +// #define MI_DEBUG 1 // basic assertion checks and statistics, check double free, corrupted free list, and invalid pointer free. +// #define MI_DEBUG 2 // + internal assertion checks +// #define MI_DEBUG 3 // + extensive internal invariant checking (cmake -DMI_DEBUG_FULL=ON) +#if !defined(MI_DEBUG) +#if defined(MI_BUILD_RELEASE) || defined(NDEBUG) +#define MI_DEBUG 0 +#else +#define MI_DEBUG 2 +#endif +#endif + +// Statistics (0=only essential, 1=normal, 2=more fine-grained (expensive) tracking) +#ifndef MI_STAT +#if (MI_DEBUG>0) +#define MI_STAT 2 +#else +#define MI_STAT 0 +#endif +#endif + +// Use guard pages behind objects of a certain size (set by the MIMALLOC_DEBUG_GUARDED_MIN/MAX options) +// Padding should be disabled when using guard pages +// #define MI_GUARDED 1 +#if defined(MI_GUARDED) +#define MI_PADDING 0 +#endif + +// Reserve extra padding at the end of each block to be more resilient against heap block overflows. +// The padding can detect buffer overflow on free. +#if !defined(MI_PADDING) && (MI_SECURE>=3 || MI_DEBUG>=1 || (MI_TRACK_VALGRIND || MI_TRACK_ASAN || MI_TRACK_ETW)) +#define MI_PADDING 1 +#endif + +// Check padding bytes; allows byte-precise buffer overflow detection +#if !defined(MI_PADDING_CHECK) && MI_PADDING && (MI_SECURE>=3 || MI_DEBUG>=1) +#define MI_PADDING_CHECK 1 +#endif + + +// Encoded free lists allow detection of corrupted free lists +// and can detect buffer overflows, modify after free, and double `free`s. +#if (MI_SECURE>=3 || MI_DEBUG>=1) +#define MI_ENCODE_FREELIST 1 +#endif + +// Enable large pages for objects between 64KiB and 512KiB. +// Disabled by default as for many workloads the block sizes above 64 KiB are quite random which can lead to too many partially used large pages. +#ifndef MI_ENABLE_LARGE_PAGES +#define MI_ENABLE_LARGE_PAGES 0 +#endif + +// -------------------------------------------------------------- +// Sizes of internal data-structures +// (comments specify sizes on 64-bit, usually 32-bit is halved) +// -------------------------------------------------------------- + +// Main size parameter; determines max arena sizes and max arena object sizes etc. +#ifndef MI_ARENA_SLICE_SHIFT + #ifdef MI_SMALL_PAGE_SHIFT // backward compatibility + #define MI_ARENA_SLICE_SHIFT MI_SMALL_PAGE_SHIFT + #else + #define MI_ARENA_SLICE_SHIFT (14 + MI_SIZE_SHIFT) // 64 KiB (32 KiB on 32-bit) + #endif +#endif +#if MI_ARENA_SLICE_SHIFT < 12 +#error Arena slices should be at least 4KiB +#endif + +#ifndef MI_BCHUNK_BITS_SHIFT + #if MI_ARENA_SLICE_SHIFT <= 13 // <= 8KiB + #define MI_BCHUNK_BITS_SHIFT (7) // 128 bits + #elif MI_ARENA_SLICE_SHIFT < 16 // <= 32KiB + #define MI_BCHUNK_BITS_SHIFT (8) // 256 bits + #else + #define MI_BCHUNK_BITS_SHIFT (6 + MI_SIZE_SHIFT) // 512 bits (or 256 on 32-bit) + #endif +#endif + +#define MI_BCHUNK_BITS (1 << MI_BCHUNK_BITS_SHIFT) // sub-bitmaps are "bchunks" of 512 bits +#define MI_ARENA_SLICE_SIZE (MI_ZU(1) << MI_ARENA_SLICE_SHIFT) // arena's allocate in slices of 64 KiB +#define MI_ARENA_SLICE_ALIGN (MI_ARENA_SLICE_SIZE) + +#define MI_ARENA_MIN_OBJ_SLICES (1) +#define MI_ARENA_MAX_OBJ_SLICES (MI_BCHUNK_BITS) // 32 MiB (for now, cannot cross chunk boundaries) + +#define MI_ARENA_MIN_OBJ_SIZE (MI_ARENA_MIN_OBJ_SLICES * MI_ARENA_SLICE_SIZE) +#define MI_ARENA_MAX_OBJ_SIZE (MI_ARENA_MAX_OBJ_SLICES * MI_ARENA_SLICE_SIZE) + +#if MI_ARENA_MAX_OBJ_SIZE < MI_SIZE_SIZE*1024 +#error maximum object size may be too small to hold local thread data +#endif + +#define MI_SMALL_PAGE_SIZE MI_ARENA_MIN_OBJ_SIZE // 64 KiB +#define MI_MEDIUM_PAGE_SIZE (8*MI_SMALL_PAGE_SIZE) // 512 KiB (=byte in the bchunk bitmap) +#define MI_LARGE_PAGE_SIZE (MI_SIZE_SIZE*MI_MEDIUM_PAGE_SIZE) // 4 MiB (=word in the bchunk bitmap) + + +// Maximum number of size classes. (spaced exponentially in 12.5% increments) +#if MI_BIN_HUGE != 73U +#error "mimalloc internal: expecting 73 bins" +#endif +#define MI_BIN_FULL (MI_BIN_HUGE+1) +#define MI_BIN_COUNT (MI_BIN_FULL+1) + +// We never allocate more than PTRDIFF_MAX (see also ) +#define MI_MAX_ALLOC_SIZE PTRDIFF_MAX + +// Minimal commit for a page on-demand commit (should be >= OS page size) +#define MI_PAGE_MIN_COMMIT_SIZE MI_ARENA_SLICE_SIZE // (4*MI_KiB) + + +// ------------------------------------------------------ +// Arena's are large reserved areas of memory allocated from +// the OS that are managed by mimalloc to efficiently +// allocate MI_ARENA_SLICE_SIZE slices of memory for the +// mimalloc pages. +// ------------------------------------------------------ + +// A large memory arena where pages are allocated in. +typedef struct mi_arena_s mi_arena_t; // defined below + + +// --------------------------------------------------------------- +// a memory id tracks the provenance of arena/OS allocated memory +// --------------------------------------------------------------- + +// Memory can reside in arena's, direct OS allocated, meta-data pages, or statically allocated. +// The memid keeps track of this. +typedef enum mi_memkind_e { + MI_MEM_NONE, // not allocated + MI_MEM_EXTERNAL, // not owned by mimalloc but provided externally (via `mi_manage_os_memory` for example) + MI_MEM_STATIC, // allocated in a static area and should not be freed (the initial main heap data for example (`init.c`)) + MI_MEM_META, // allocated with the meta data allocator (`arena-meta.c`) + MI_MEM_OS, // allocated from the OS + MI_MEM_OS_HUGE, // allocated as huge OS pages (usually 1GiB, pinned to physical memory) + MI_MEM_OS_REMAP, // allocated in a remapable area (i.e. using `mremap`) + MI_MEM_ARENA // allocated from an arena (the usual case) (`arena.c`) +} mi_memkind_t; + +static inline bool mi_memkind_is_os(mi_memkind_t memkind) { + return (memkind >= MI_MEM_OS && memkind <= MI_MEM_OS_REMAP); +} + +static inline bool mi_memkind_needs_no_free(mi_memkind_t memkind) { + return (memkind <= MI_MEM_STATIC); +} + + +typedef struct mi_memid_os_info { + void* base; // actual base address of the block (used for offset aligned allocations) + size_t size; // allocated full size + // size_t alignment; // alignment at allocation +} mi_memid_os_info_t; + +typedef struct mi_memid_arena_info { + mi_arena_t* arena; // arena that contains this memory + uint32_t slice_index; // slice index in the arena + uint32_t slice_count; // allocated slices +} mi_memid_arena_info_t; + +typedef struct mi_memid_meta_info { + void* meta_page; // meta-page that contains the block + uint32_t block_index; // block index in the meta-data page + uint32_t block_count; // allocated blocks +} mi_memid_meta_info_t; + +typedef struct mi_memid_s { + union { + mi_memid_os_info_t os; // only used for MI_MEM_OS + mi_memid_arena_info_t arena; // only used for MI_MEM_ARENA + mi_memid_meta_info_t meta; // only used for MI_MEM_META + } mem; + mi_memkind_t memkind; + bool is_pinned; // `true` if we cannot decommit/reset/protect in this memory (e.g. when allocated using large (2Mib) or huge (1GiB) OS pages) + bool initially_committed;// `true` if the memory was originally allocated as committed + bool initially_zero; // `true` if the memory was originally zero initialized +} mi_memid_t; + + +static inline bool mi_memid_is_os(mi_memid_t memid) { + return mi_memkind_is_os(memid.memkind); +} + +static inline bool mi_memid_needs_no_free(mi_memid_t memid) { + return mi_memkind_needs_no_free(memid.memkind); +} + +static inline mi_arena_t* mi_memid_arena(mi_memid_t memid) { + return (memid.memkind == MI_MEM_ARENA ? memid.mem.arena.arena : NULL); +} + + +// ------------------------------------------------------ +// Mimalloc pages contain allocated blocks +// ------------------------------------------------------ + +// The free lists use encoded next fields +// (Only actually encodes when MI_ENCODED_FREELIST is defined.) +typedef uintptr_t mi_encoded_t; + +// thread id's +typedef size_t mi_threadid_t; + +// free lists contain blocks +typedef struct mi_block_s { + mi_encoded_t next; +} mi_block_t; + + +// The page flags are put in the bottom 2 bits of the thread_id (for a fast test in `mi_free`) +// `has_aligned` is true if the page has pointers at an offset in a block (so we unalign before free-ing) +// `in_full_queue` is true if the page is full and resides in the full queue (so we move it to a regular queue on free-ing) +#define MI_PAGE_IN_FULL_QUEUE MI_ZU(0x01) +#define MI_PAGE_HAS_ALIGNED MI_ZU(0x02) +#define MI_PAGE_FLAG_MASK MI_ZU(0x03) +typedef size_t mi_page_flags_t; + +// There are two special threadid's: 0 for abandoned threads, and 4 for abandoned & mapped threads -- +// abandoned-mapped pages are abandoned but also mapped in an arena so can be quickly found for reuse. +#define MI_THREADID_ABANDONED MI_ZU(0) +#define MI_THREADID_ABANDONED_MAPPED (MI_PAGE_FLAG_MASK + 1) + +// Thread free list. +// Points to a list of blocks that are freed by other threads. +// The least-bit is set if the page is owned by the current thread. (`mi_page_is_owned`). +// Ownership is required before we can read any non-atomic fields in the page. +// This way we can push a block on the thread free list and try to claim ownership atomically in `free.c:mi_free_block_mt`. +typedef uintptr_t mi_thread_free_t; + +// A heap can serve only specific objects signified by its heap tag (e.g. various object types in CPython) +typedef uint8_t mi_heaptag_t; + +// A page contains blocks of one specific size (`block_size`). +// Each page has three list of free blocks: +// `free` for blocks that can be allocated, +// `local_free` for freed blocks that are not yet available to `mi_malloc` +// `thread_free` for freed blocks by other threads +// The `local_free` and `thread_free` lists are migrated to the `free` list +// when it is exhausted. The separate `local_free` list is necessary to +// implement a monotonic heartbeat. The `thread_free` list is needed for +// avoiding atomic operations when allocating from the owning thread. +// +// `used - |thread_free|` == actual blocks that are in use (alive) +// `used - |thread_free| + |free| + |local_free| == capacity` +// +// We don't count "freed" (as |free|) but use only the `used` field to reduce +// the number of memory accesses in the `mi_page_all_free` function(s). +// Use `_mi_page_free_collect` to collect the thread_free list and update the `used` count. +// +// Notes: +// - Non-atomic fields can only be accessed if having _ownership_ (low bit of `xthread_free` is 1). +// Combining the `thread_free` list with an ownership bit allows a concurrent `free` to atomically +// free an object and (re)claim ownership if the page was abandoned. +// - If a page is not part of a heap it is called "abandoned" (`heap==NULL`) -- in +// that case the `xthreadid` is 0 or 4 (4 is for abandoned pages that +// are in the abandoned page lists of an arena, these are called "mapped" abandoned pages). +// - page flags are in the bottom 3 bits of `xthread_id` for the fast path in `mi_free`. +// - The layout is optimized for `free.c:mi_free` and `alloc.c:mi_page_alloc` +// - Using `uint16_t` does not seem to slow things down + +typedef struct mi_page_s { + _Atomic(mi_threadid_t) xthread_id; // thread this page belongs to. (= `heap->thread_id (or 0 or 4 if abandoned) | page_flags`) + + mi_block_t* free; // list of available free blocks (`malloc` allocates from this list) + uint16_t used; // number of blocks in use (including blocks in `thread_free`) + uint16_t capacity; // number of blocks committed + uint16_t reserved; // number of blocks reserved in memory + uint8_t block_size_shift; // if not zero, then `(1 << block_size_shift) == block_size` (only used for fast path in `free.c:_mi_page_ptr_unalign`) + uint8_t retire_expire; // expiration count for retired blocks + + mi_block_t* local_free; // list of deferred free blocks by this thread (migrates to `free`) + _Atomic(mi_thread_free_t) xthread_free; // list of deferred free blocks freed by other threads (= `mi_block_t* | (1 if owned)`) + + size_t block_size; // size available in each block (always `>0`) + uint8_t* page_start; // start of the blocks + mi_heaptag_t heap_tag; // tag of the owning heap, used to separate heaps by object type + bool free_is_zero; // `true` if the blocks in the free list are zero initialized + // padding + #if (MI_ENCODE_FREELIST || MI_PADDING) + uintptr_t keys[2]; // two random keys to encode the free lists (see `_mi_block_next`) or padding canary + #endif + + mi_heap_t* heap; // the heap owning this page (or NULL for abandoned pages) + struct mi_page_s* next; // next page owned by the heap with the same `block_size` + struct mi_page_s* prev; // previous page owned by the heap with the same `block_size` + size_t slice_committed; // committed size relative to the first arena slice of the page data (or 0 if the page is fully committed already) + mi_memid_t memid; // provenance of the page memory +} mi_page_t; + + +// ------------------------------------------------------ +// Object sizes +// ------------------------------------------------------ + +#define MI_PAGE_ALIGN MI_ARENA_SLICE_ALIGN // pages must be aligned on this for the page map. +#define MI_PAGE_MIN_START_BLOCK_ALIGN MI_MAX_ALIGN_SIZE // minimal block alignment for the first block in a page (16b) +#define MI_PAGE_MAX_START_BLOCK_ALIGN2 MI_KiB // maximal block alignment for "power of 2"-sized blocks (such that we guarantee natural alignment) +#define MI_PAGE_MAX_OVERALLOC_ALIGN MI_ARENA_SLICE_SIZE // (64 KiB) limit for which we overallocate in arena pages, beyond this use OS allocation + +#if (MI_ENCODE_FREELIST || MI_PADDING) && MI_SIZE_SIZE == 8 +#define MI_PAGE_INFO_SIZE ((MI_INTPTR_SHIFT+2)*32) // 160 >= sizeof(mi_page_t) +#else +#define MI_PAGE_INFO_SIZE ((MI_INTPTR_SHIFT+1)*32) // 128/96 >= sizeof(mi_page_t) +#endif + +// The max object size are checked to not waste more than 12.5% internally over the page sizes. +#define MI_SMALL_MAX_OBJ_SIZE ((MI_SMALL_PAGE_SIZE-MI_PAGE_INFO_SIZE)/8) // < ~8 KiB +#if MI_ENABLE_LARGE_PAGES +#define MI_MEDIUM_MAX_OBJ_SIZE ((MI_MEDIUM_PAGE_SIZE-MI_PAGE_INFO_SIZE)/8) // < ~64 KiB +#define MI_LARGE_MAX_OBJ_SIZE (MI_LARGE_PAGE_SIZE/8) // <= 512KiB // note: this must be a nice power of 2 or we get rounding issues with `_mi_bin` +#else +#define MI_MEDIUM_MAX_OBJ_SIZE (MI_MEDIUM_PAGE_SIZE/8) // <= 64 KiB +#define MI_LARGE_MAX_OBJ_SIZE MI_MEDIUM_MAX_OBJ_SIZE // note: this must be a nice power of 2 or we get rounding issues with `_mi_bin` +#endif +#define MI_LARGE_MAX_OBJ_WSIZE (MI_LARGE_MAX_OBJ_SIZE/MI_SIZE_SIZE) + +#if (MI_LARGE_MAX_OBJ_WSIZE >= 655360) +#error "mimalloc internal: define more bins" +#endif + + +// ------------------------------------------------------ +// Page kinds +// ------------------------------------------------------ + +typedef enum mi_page_kind_e { + MI_PAGE_SMALL, // small blocks go into 64KiB pages + MI_PAGE_MEDIUM, // medium blocks go into 512KiB pages + MI_PAGE_LARGE, // larger blocks go into 4MiB pages (if `MI_ENABLE_LARGE_PAGES==1`) + MI_PAGE_SINGLETON // page containing a single block. + // used for blocks `> MI_LARGE_MAX_OBJ_SIZE` or an aligment `> MI_PAGE_MAX_OVERALLOC_ALIGN`. +} mi_page_kind_t; + + + +// ------------------------------------------------------ +// Heaps +// +// Provide first-class heaps to allocate from. +// A heap just owns a set of pages for allocation and +// can only be allocate/reallocate from the thread that created it. +// Freeing blocks can be done from any thread though. +// +// Per thread, there is always a default heap that is +// used for allocation; it is initialized to statically +// point to an empty heap to avoid initialization checks +// in the fast path. +// ------------------------------------------------------ + +// Thread local data +typedef struct mi_tld_s mi_tld_t; // defined below + +// Pages of a certain block size are held in a queue. +typedef struct mi_page_queue_s { + mi_page_t* first; + mi_page_t* last; + size_t count; + size_t block_size; +} mi_page_queue_t; + +// Random context +typedef struct mi_random_cxt_s { + uint32_t input[16]; + uint32_t output[16]; + int output_available; + bool weak; +} mi_random_ctx_t; + + +// In debug mode there is a padding structure at the end of the blocks to check for buffer overflows +#if MI_PADDING +typedef struct mi_padding_s { + uint32_t canary; // encoded block value to check validity of the padding (in case of overflow) + uint32_t delta; // padding bytes before the block. (mi_usable_size(p) - delta == exact allocated bytes) +} mi_padding_t; +#define MI_PADDING_SIZE (sizeof(mi_padding_t)) +#define MI_PADDING_WSIZE ((MI_PADDING_SIZE + MI_INTPTR_SIZE - 1) / MI_INTPTR_SIZE) +#else +#define MI_PADDING_SIZE 0 +#define MI_PADDING_WSIZE 0 +#endif + +#define MI_PAGES_DIRECT (MI_SMALL_WSIZE_MAX + MI_PADDING_WSIZE + 1) + + +// A heap owns a set of pages. +struct mi_heap_s { + mi_tld_t* tld; // thread-local data + mi_arena_t* exclusive_arena; // if the heap should only allocate from a specific arena (or NULL) + int numa_node; // preferred numa node (or -1 for no preference) + uintptr_t cookie; // random cookie to verify pointers (see `_mi_ptr_cookie`) + mi_random_ctx_t random; // random number context used for secure allocation + size_t page_count; // total number of pages in the `pages` queues. + size_t page_retired_min; // smallest retired index (retired pages are fully free, but still in the page queues) + size_t page_retired_max; // largest retired index into the `pages` array. + long generic_count; // how often is `_mi_malloc_generic` called? + long generic_collect_count; // how often is `_mi_malloc_generic` called without collecting? + mi_heap_t* next; // list of heaps per thread + long page_full_retain; // how many full pages can be retained per queue (before abondoning them) + bool allow_page_reclaim; // `true` if this heap should not reclaim abandoned pages + bool allow_page_abandon; // `true` if this heap can abandon pages to reduce memory footprint + uint8_t tag; // custom tag, can be used for separating heaps based on the object types + #if MI_GUARDED + size_t guarded_size_min; // minimal size for guarded objects + size_t guarded_size_max; // maximal size for guarded objects + size_t guarded_sample_rate; // sample rate (set to 0 to disable guarded pages) + size_t guarded_sample_count; // current sample count (counting down to 0) + #endif + mi_page_t* pages_free_direct[MI_PAGES_DIRECT]; // optimize: array where every entry points a page with possibly free blocks in the corresponding queue for that size. + mi_page_queue_t pages[MI_BIN_COUNT]; // queue of pages for each size class (or "bin") + mi_memid_t memid; // provenance of the heap struct itself (meta or os) +}; + + +// ------------------------------------------------------ +// Sub processes do not reclaim or visit pages from other sub processes. +// These are essentially the static variables of a process, and +// usually there is only one subprocess. This can be used for example +// by CPython to have seperate interpreters within one process. +// Each thread can only belong to one subprocess. +// ------------------------------------------------------ + +#define MI_MAX_ARENAS (160) // Limited for now (and takes up .bss).. but arena's scale up exponentially (see `mi_arena_reserve`) + // 160 arenas is enough for ~2 TiB memory + +typedef struct mi_subproc_s { + _Atomic(size_t) arena_count; // current count of arena's + _Atomic(mi_arena_t*) arenas[MI_MAX_ARENAS]; // arena's of this sub-process + mi_lock_t arena_reserve_lock; // lock to ensure arena's get reserved one at a time + _Atomic(int64_t) purge_expire; // expiration is set if any arenas can be purged + + _Atomic(size_t) abandoned_count[MI_BIN_COUNT]; // total count of abandoned pages for this sub-process + mi_page_t* os_abandoned_pages; // list of pages that OS allocated and not in an arena (only used if `mi_option_visit_abandoned` is on) + mi_lock_t os_abandoned_pages_lock; // lock for the os abandoned pages list (this lock protects list operations) + + mi_memid_t memid; // provenance of this memory block (meta or OS) + mi_stats_t stats; // sub-process statistics (tld stats are merged in on thread termination) +} mi_subproc_t; + + + +// ------------------------------------------------------ +// Thread Local data +// ------------------------------------------------------ + +// Milliseconds as in `int64_t` to avoid overflows +typedef int64_t mi_msecs_t; + +// Thread local data +struct mi_tld_s { + mi_threadid_t thread_id; // thread id of this thread + size_t thread_seq; // thread sequence id (linear count of created threads) + int numa_node; // thread preferred numa node + mi_subproc_t* subproc; // sub-process this thread belongs to. + mi_heap_t* heap_backing; // backing heap of this thread (cannot be deleted) + mi_heap_t* heaps; // list of heaps in this thread (so we can abandon all when the thread terminates) + unsigned long long heartbeat; // monotonic heartbeat count + bool recurse; // true if deferred was called; used to prevent infinite recursion. + bool is_in_threadpool; // true if this thread is part of a threadpool (and can run arbitrary tasks) + mi_stats_t stats; // statistics + mi_memid_t memid; // provenance of the tld memory itself (meta or OS) +}; + + +/* ---------------------------------------------------------------------------- + Arenas are fixed area's of OS memory from which we can allocate + large blocks (>= MI_ARENA_MIN_BLOCK_SIZE). + In contrast to the rest of mimalloc, the arenas are shared between + threads and need to be accessed using atomic operations (using atomic `mi_bitmap_t`'s). + + Arenas are also used to for huge OS page (1GiB) reservations or for reserving + OS memory upfront which can be improve performance or is sometimes needed + on embedded devices. We can also employ this with WASI or `sbrk` systems + to reserve large arenas upfront and be able to reuse the memory more effectively. +-----------------------------------------------------------------------------*/ + +#define MI_ARENA_BIN_COUNT (MI_BIN_COUNT) +#define MI_ARENA_MIN_SIZE (MI_BCHUNK_BITS * MI_ARENA_SLICE_SIZE) // 32 MiB (or 8 MiB on 32-bit) +#define MI_ARENA_MAX_SIZE (MI_BITMAP_MAX_BIT_COUNT * MI_ARENA_SLICE_SIZE) + +typedef struct mi_bitmap_s mi_bitmap_t; // atomic bitmap (defined in `src/bitmap.h`) +typedef struct mi_bbitmap_s mi_bbitmap_t; // atomic binned bitmap (defined in `src/bitmap.h`) + +// A memory arena +typedef struct mi_arena_s { + mi_memid_t memid; // provenance of the memory area + mi_subproc_t* subproc; // subprocess this arena belongs to (`this 'element-of' this->subproc->arenas`) + + size_t slice_count; // total size of the area in arena slices (of `MI_ARENA_SLICE_SIZE`) + size_t info_slices; // initial slices reserved for the arena bitmaps + int numa_node; // associated NUMA node + bool is_exclusive; // only allow allocations if specifically for this arena + _Atomic(mi_msecs_t) purge_expire; // expiration time when slices can be purged from `slices_purge`. + mi_commit_fun_t* commit_fun; // custom commit/decommit memory + void* commit_fun_arg; // user argument for a custom commit function + + mi_bbitmap_t* slices_free; // is the slice free? (a binned bitmap with size classes) + mi_bitmap_t* slices_committed; // is the slice committed? (i.e. accessible) + mi_bitmap_t* slices_dirty; // is the slice potentially non-zero? + mi_bitmap_t* slices_purge; // slices that can be purged + mi_bitmap_t* pages; // all registered pages (abandoned and owned) + mi_bitmap_t* pages_abandoned[MI_ARENA_BIN_COUNT]; // abandoned pages per size bin (a set bit means the start of the page) + // the full queue contains abandoned full pages + // followed by the bitmaps (whose sizes depend on the arena size) + // note: when adding bitmaps revise `mi_arena_info_slices_needed` +} mi_arena_t; + + +/* ----------------------------------------------------------- + Error codes passed to `_mi_fatal_error` + All are recoverable but EFAULT is a serious error and aborts by default in secure mode. + For portability define undefined error codes using common Unix codes: + +----------------------------------------------------------- */ + +#ifndef EAGAIN // double free +#define EAGAIN (11) +#endif +#ifndef ENOMEM // out of memory +#define ENOMEM (12) +#endif +#ifndef EFAULT // corrupted free-list or meta-data +#define EFAULT (14) +#endif +#ifndef EINVAL // trying to free an invalid pointer +#define EINVAL (22) +#endif +#ifndef EOVERFLOW // count*size overflow +#define EOVERFLOW (75) +#endif + +/* ----------------------------------------------------------- + Debug constants +----------------------------------------------------------- */ + +#if !defined(MI_DEBUG_UNINIT) +#define MI_DEBUG_UNINIT (0xD0) +#endif +#if !defined(MI_DEBUG_FREED) +#define MI_DEBUG_FREED (0xDF) +#endif +#if !defined(MI_DEBUG_PADDING) +#define MI_DEBUG_PADDING (0xDE) +#endif + + +#endif // MI_TYPES_H diff --git a/src/dashbls/depends/mimalloc/mimalloc.pc.in b/src/dashbls/depends/mimalloc/mimalloc.pc.in index 36da2038845c..80922256ae0f 100644 --- a/src/dashbls/depends/mimalloc/mimalloc.pc.in +++ b/src/dashbls/depends/mimalloc/mimalloc.pc.in @@ -1,11 +1,11 @@ prefix=@CMAKE_INSTALL_PREFIX@ -libdir=@libdir_for_pc_file@ -includedir=@includedir_for_pc_file@ +libdir=@mi_pc_libdir@ +includedir=@mi_pc_includedir@ Name: @PROJECT_NAME@ Description: A compact general purpose allocator with excellent performance Version: @PACKAGE_VERSION@ URL: https://github.com/microsoft/mimalloc/ -Libs: -L${libdir} -lmimalloc -Libs.private: @pc_libraries@ +Libs: -L${libdir} -l@mi_libname@ +Libs.private: @mi_pc_libraries@ Cflags: -I${includedir} diff --git a/src/dashbls/depends/mimalloc/readme.md b/src/dashbls/depends/mimalloc/readme.md index fe2ead6905b9..71aaf7a24e83 100644 --- a/src/dashbls/depends/mimalloc/readme.md +++ b/src/dashbls/depends/mimalloc/readme.md @@ -9,24 +9,30 @@ mimalloc (pronounced "me-malloc") is a general purpose allocator with excellent [performance](#performance) characteristics. -Initially developed by Daan Leijen for the run-time systems of the +Initially developed by Daan Leijen for the runtime systems of the [Koka](https://koka-lang.github.io) and [Lean](https://github.com/leanprover/lean) languages. -Latest release tag: `v2.0.7` (2022-11-03). -Latest stable tag: `v1.7.7` (2022-11-03). +Latest release : `v3.1.4` (beta) (2025-06-09). +Latest v2 release: `v2.2.4` (2025-06-09). +Latest v1 release: `v1.9.4` (2024-06-09). mimalloc is a drop-in replacement for `malloc` and can be used in other programs without code changes, for example, on dynamically linked ELF-based systems (Linux, BSD, etc.) you can use it as: ``` > LD_PRELOAD=/usr/lib/libmimalloc.so myprogram ``` -It also has an easy way to override the default allocator in [Windows](#override_on_windows). Notable aspects of the design include: +It also includes a way to dynamically override the default allocator in [Windows](#override_on_windows). +Notable aspects of the design include: -- __small and consistent__: the library is about 8k LOC using simple and +- __small and consistent__: the library is about 10k LOC using simple and consistent data structures. This makes it very suitable to integrate and adapt in other projects. For runtime systems it provides hooks for a monotonic _heartbeat_ and deferred freeing (for bounded worst-case times with reference counting). + Partly due to its simplicity, mimalloc has been ported to many systems (Windows, macOS, + Linux, WASM, various BSD's, Haiku, MUSL, etc) and has excellent support for dynamic overriding. + At the same time, it is an industrial strength allocator that runs (very) large scale + distributed services on thousands of machines with excellent worst case latencies. - __free list sharding__: instead of one big free list (per size class) we have many smaller lists per "mimalloc page" which reduces fragmentation and increases locality -- @@ -36,13 +42,13 @@ It also has an easy way to override the default allocator in [Windows](#override per mimalloc page, but for each page we have multiple free lists. In particular, there is one list for thread-local `free` operations, and another one for concurrent `free` operations. Free-ing from another thread can now be a single CAS without needing - sophisticated coordination between threads. Since there will be + sophisticated coordination between threads. Since there will be thousands of separate free lists, contention is naturally distributed over the heap, and the chance of contending on a single location will be low -- this is quite similar to randomized algorithms like skip lists where adding a random oracle removes the need for a more complex algorithm. -- __eager page reset__: when a "page" becomes empty (with increased chance - due to free list sharding) the memory is marked to the OS as unused ("reset" or "purged") +- __eager page purging__: when a "page" becomes empty (with increased chance + due to free list sharding) the memory is marked to the OS as unused (reset or decommitted) reducing (real) memory pressure and fragmentation, especially in long running programs. - __secure__: _mimalloc_ can be built in secure mode, adding guard pages, @@ -50,35 +56,83 @@ It also has an easy way to override the default allocator in [Windows](#override heap vulnerabilities. The performance penalty is usually around 10% on average over our benchmarks. - __first-class heaps__: efficiently create and use multiple heaps to allocate across different regions. - A heap can be destroyed at once instead of deallocating each object separately. + A heap can be destroyed at once instead of deallocating each object separately. - __bounded__: it does not suffer from _blowup_ \[1\], has bounded worst-case allocation - times (_wcat_), bounded space overhead (~0.2% meta-data, with low internal fragmentation), - and has no internal points of contention using only atomic operations. + times (_wcat_) (upto OS primitives), bounded space overhead (~0.2% meta-data, with low + internal fragmentation), and has no internal points of contention using only atomic operations. - __fast__: In our benchmarks (see [below](#performance)), _mimalloc_ outperforms other leading allocators (_jemalloc_, _tcmalloc_, _Hoard_, etc), - and often uses less memory. A nice property - is that it does consistently well over a wide range of benchmarks. There is also good huge OS page - support for larger server programs. + and often uses less memory. A nice property is that it does consistently well over a wide range + of benchmarks. There is also good huge OS page support for larger server programs. The [documentation](https://microsoft.github.io/mimalloc) gives a full overview of the API. -You can read more on the design of _mimalloc_ in the [technical report](https://www.microsoft.com/en-us/research/publication/mimalloc-free-list-sharding-in-action) which also has detailed benchmark results. +You can read more on the design of _mimalloc_ in the [technical report](https://www.microsoft.com/en-us/research/publication/mimalloc-free-list-sharding-in-action) which also has detailed benchmark results. -Enjoy! +Enjoy! ### Branches -* `master`: latest stable release (based on `dev-slice`). -* `dev`: development branch for mimalloc v1. Use this branch for submitting PR's. -* `dev-slice`: development branch for mimalloc v2. This branch is downstream of `dev`. +* `main`: latest stable release (still based on `dev2`). +* `dev`: development branch for mimalloc v1. Use this branch for submitting PR's. +* `dev2`: development branch for mimalloc v2. This branch is downstream of `dev` + (and is essentially equal to `dev` except for `src/segment.c`). Uses larger sliced segments to manage + mimalloc pages that can reduce fragmentation. +* `dev3`: development branch for mimalloc v3 beta. This branch is downstream of `dev`. This version + simplifies the lock-free ownership of previous versions, and improves sharing of memory between + threads. On certain large workloads this version may use (much) less memory. ### Releases -Note: the `v2.x` version has a new algorithm for managing internal mimalloc pages that tends to use reduce memory usage - and fragmentation compared to mimalloc `v1.x` (especially for large workloads). Should otherwise have similar performance - (see [below](#performance)); please report if you observe any significant performance regression. - -* 2022-11-03, `v1.7.7`, `v2.0.7`: Initial support for [Valgrind] for leak testing and heap block overflow detection. Initial - support for attaching heaps to a speficic memory area (only in v2). Fix `realloc` behavior for zero size blocks, remove restriction to integral multiple of the alignment in `alloc_align`, improved aligned allocation performance, reduced contention with many threads on few processors (thank you @dposluns!), vs2022 support, support `pkg-config`, . +* 2025-06-09, `v1.9.4`, `v2.2.4`, `v3.1.4` (beta) : Some important bug fixes, including a case where OS memory + was not always fully released. Improved v3 performance, build on XBox, fix build on Android, support interpose + for older macOS versions, use MADV_FREE_REUSABLE on macOS, always check commit success, better support for Windows + fixed TLS offset, etc. +* 2025-03-28, `v1.9.3`, `v2.2.3`, `v3.0.3` (beta) : Various small bug and build fixes, including: + fix arm32 pre v7 builds, fix mingw build, get runtime statistics, improve statistic commit counts, + fix execution on non BMI1 x64 systems. +* 2025-03-06, `v1.9.2`, `v2.2.2`, `v3.0.2-beta`: Various small bug and build fixes. + Add `mi_options_print`, `mi_arenas_print`, and the experimental `mi_stat_get` and `mi_stat_get_json`. + Add `mi_thread_set_in_threadpool` and `mi_heap_set_numa_affinity` (v3 only). Add vcpkg portfile. + Upgrade mimalloc-redirect to v1.3.2. `MI_OPT_ARCH` is off by default now but still assumes armv8.1-a on arm64 + for fast atomic operations. Add QNX support. +* 2025-01-03, `v1.8.9`, `v2.1.9`, `v3.0.1-alpha`: Interim release. Support Windows arm64. New [guarded](#guarded) build that can place OS + guard pages behind objects to catch buffer overflows as they occur. + Many small fixes: build on Windows arm64, cygwin, riscV, and dragonfly; fix Windows static library initialization to account for + thread local destructors (in Rust/C++); macOS tag change; macOS TLS slot fix; improve stats; + consistent `mimalloc.dll` on Windows (instead of `mimalloc-override.dll`); fix mimalloc-redirect on Win11 H2; + add 0-byte to canary; upstream CPython fixes; reduce .bss size; allow fixed TLS slot on Windows for improved performance. +* 2024-05-21, `v1.8.7`, `v2.1.7`: Fix build issues on less common platforms. Started upstreaming patches + from the CPython [integration](https://github.com/python/cpython/issues/113141#issuecomment-2119255217). Upstream `vcpkg` patches. +* 2024-05-13, `v1.8.6`, `v2.1.6`: Fix build errors on various (older) platforms. Refactored aligned allocation. +* 2024-04-22, `v1.8.4`, `v2.1.4`: Fixes various bugs and build issues. Add `MI_LIBC_MUSL` cmake flag for musl builds. + Free-ing code is refactored into a separate module (`free.c`). Mimalloc page info is simplified with the block size + directly available (and new `block_size_shift` to improve aligned block free-ing). + New approach to collection of abandoned segments: When + a thread terminates the segments it owns are abandoned (containing still live objects) and these can be + reclaimed by other threads. We no longer use a list of abandoned segments but this is now done using bitmaps in arena's + which is more concurrent (and more aggressive). Abandoned memory can now also be reclaimed if a thread frees an object in + an abandoned page (which can be disabled using `mi_option_abandoned_reclaim_on_free`). The option `mi_option_max_segment_reclaim` + gives a maximum percentage of abandoned segments that can be reclaimed per try (=10%). + +* 2023-04-24, `v1.8.2`, `v2.1.2`: Fixes build issues on freeBSD, musl, and C17 (UE 5.1.1). Reduce code size/complexity + by removing regions and segment-cache's and only use arenas with improved memory purging -- this may improve memory + usage as well for larger services. Renamed options for consistency. Improved Valgrind and ASAN checking. + +* 2023-04-03, `v1.8.1`, `v2.1.1`: Fixes build issues on some platforms. + +* 2023-03-29, `v1.8.0`, `v2.1.0`: Improved support dynamic overriding on Windows 11. Improved tracing precision + with [asan](#asan) and [Valgrind](#valgrind), and added Windows event tracing [ETW](#ETW) (contributed by Xinglong He). Created an OS + abstraction layer to make it easier to port and separate platform dependent code (in `src/prim`). Fixed C++ STL compilation on older Microsoft C++ compilers, and various small bug fixes. + +* 2022-12-23, `v1.7.9`, `v2.0.9`: Supports building with [asan](#asan) and improved [Valgrind](#valgrind) support. + Support arbitrary large alignments (in particular for `std::pmr` pools). + Added C++ STL allocators attached to a specific heap (thanks @vmarkovtsev). + Heap walks now visit all object (including huge objects). Support Windows nano server containers (by Johannes Schindelin,@dscho). + Various small bug fixes. + +* 2022-11-03, `v1.7.7`, `v2.0.7`: Initial support for [Valgrind](#valgrind) for leak testing and heap block overflow + detection. Initial + support for attaching heaps to a specific memory area (only in v2). Fix `realloc` behavior for zero size blocks, remove restriction to integral multiple of the alignment in `alloc_align`, improved aligned allocation performance, reduced contention with many threads on few processors (thank you @dposluns!), vs2022 support, support `pkg-config`, . * 2022-04-14, `v1.7.6`, `v2.0.6`: fix fallback path for aligned OS allocation on Windows, improve Windows aligned allocation even when compiling with older SDK's, fix dynamic overriding on macOS Monterey, fix MSVC C++ dynamic overriding, fix @@ -87,24 +141,10 @@ Note: the `v2.x` version has a new algorithm for managing internal mimalloc page * 2022-02-14, `v1.7.5`, `v2.0.5` (alpha): fix malloc override on Windows 11, fix compilation with musl, potentially reduced - committed memory, add `bin/minject` for Windows, + committed memory, add `bin/minject` for Windows, improved wasm support, faster aligned allocation, various small fixes. -* 2021-11-14, `v1.7.3`, `v2.0.3` (beta): improved WASM support, improved macOS support and performance (including - M1), improved performance for v2 for large objects, Python integration improvements, more standard - installation directories, various small fixes. - -* 2021-06-17, `v1.7.2`, `v2.0.2` (beta): support M1, better installation layout on Linux, fix - thread_id on Android, prefer 2-6TiB area for aligned allocation to work better on pre-windows 8, various small fixes. - -* 2021-04-06, `v1.7.1`, `v2.0.1` (beta): fix bug in arena allocation for huge pages, improved aslr on large allocations, initial M1 support (still experimental). - -* 2021-01-31, `v2.0.0`: beta release 2.0: new slice algorithm for managing internal mimalloc pages. - -* 2021-01-31, `v1.7.0`: stable release 1.7: support explicit user provided memory regions, more precise statistics, - improve macOS overriding, initial support for Apple M1, improved DragonFly support, faster memcpy on Windows, various small fixes. - * [Older release notes](#older-release-notes) Special thanks to: @@ -115,9 +155,9 @@ Special thanks to: memory model bugs using the [genMC] model checker. * Weipeng Liu (@pongba), Zhuowei Li, Junhua Wang, and Jakub Szymanski, for their early support of mimalloc and deployment at large scale services, leading to many improvements in the mimalloc algorithms for large workloads. -* Jason Gibson (@jasongibson) for exhaustive testing on large scale workloads and server environments, and finding complex bugs +* Jason Gibson (@jasongibson) for exhaustive testing on large scale workloads and server environments, and finding complex bugs in (early versions of) `mimalloc`. -* Manuel Pöter (@mpoeter) and Sam Gross(@colesbury) for finding an ABA concurrency issue in abandoned segment reclamation. Sam also created the [no GIL](https://github.com/colesbury/nogil) Python fork which +* Manuel Pöter (@mpoeter) and Sam Gross(@colesbury) for finding an ABA concurrency issue in abandoned segment reclamation. Sam also created the [no GIL](https://github.com/colesbury/nogil) Python fork which uses mimalloc internally. @@ -138,14 +178,14 @@ mimalloc is used in various large scale low-latency services and programs, for e ## Windows -Open `ide/vs2019/mimalloc.sln` in Visual Studio 2019 and build. -The `mimalloc` project builds a static library (in `out/msvc-x64`), while the -`mimalloc-override` project builds a DLL for overriding malloc +Open `ide/vs2022/mimalloc.sln` in Visual Studio 2022 and build. +The `mimalloc-lib` project builds a static library (in `out/msvc-x64`), while the +`mimalloc-override-dll` project builds a DLL for overriding malloc in the entire program. -## macOS, Linux, BSD, etc. +## Linux, macOS, BSD, etc. -We use [`cmake`](https://cmake.org)1 as the build system: +We use [`cmake`](https://cmake.org) as the build system: ``` > mkdir -p out/release @@ -168,32 +208,58 @@ maintains detailed statistics as: > cmake -DCMAKE_BUILD_TYPE=Debug ../.. > make ``` + This will name the shared library as `libmimalloc-debug.so`. -Finally, you can build a _secure_ version that uses guard pages, encrypted -free lists, etc., as: +Finally, you can build a _secure_ version that uses guard pages, encrypted free lists, etc., as: + ``` > mkdir -p out/secure > cd out/secure > cmake -DMI_SECURE=ON ../.. > make ``` + This will name the shared library as `libmimalloc-secure.so`. -Use `ccmake`2 instead of `cmake` -to see and customize all the available build options. +Use `cmake ../.. -LH` to see all the available build options. -Notes: -1. Install CMake: `sudo apt-get install cmake` -2. Install CCMake: `sudo apt-get install cmake-curses-gui` +The examples use the default compiler. If you like to use another, use: + +``` +> CC=clang CXX=clang++ cmake ../.. +``` + +## Cmake with Visual Studio + +You can also use cmake on Windows. Open a Visual Studio 2022 development prompt +and invoke `cmake` with the right [generator](https://cmake.org/cmake/help/latest/generator/Visual%20Studio%2017%202022.html) +and architecture, like: + +``` +> cmake ..\.. -G "Visual Studio 17 2022" -A x64 -DMI_OVERRIDE=ON +``` + +The cmake build type is specified when actually building, for example: + +``` +> cmake --build . --config=Release +``` + +You can also install the [LLVM toolset](https://learn.microsoft.com/en-us/cpp/build/clang-support-msbuild?view=msvc-170#install-1) +on Windows to build with the `clang-cl` compiler directly: + +``` +> cmake ../.. -G "Visual Studio 17 2022" -T ClangCl +``` -## Single source +## Single Source You can also directly build the single `src/static.c` file as part of your project without needing `cmake` at all. Make sure to also add the mimalloc `include` directory to the include path. -# Using the library +# Using the Library The preferred usage is including ``, linking with the shared- or static library, and using the `mi_malloc` API exclusively for allocation. For example, @@ -205,7 +271,7 @@ mimalloc uses only safe OS calls (`mmap` and `VirtualAlloc`) and can co-exist with other allocators linked to the same program. If you use `cmake`, you can simply use: ``` -find_package(mimalloc 1.4 REQUIRED) +find_package(mimalloc 1.8 REQUIRED) ``` in your `CMakeLists.txt` to find a locally installed mimalloc. Then use either: ``` @@ -218,8 +284,8 @@ target_link_libraries(myapp PUBLIC mimalloc-static) to link with the static library. See `test\CMakeLists.txt` for an example. For best performance in C++ programs, it is also recommended to override the -global `new` and `delete` operators. For convience, mimalloc provides -[`mimalloc-new-delete.h`](https://github.com/microsoft/mimalloc/blob/master/include/mimalloc-new-delete.h) which does this for you -- just include it in a single(!) source file in your project. +global `new` and `delete` operators. For convenience, mimalloc provides +[`mimalloc-new-delete.h`](include/mimalloc-new-delete.h) which does this for you -- just include it in a single(!) source file in your project. In C++, mimalloc also provides the `mi_stl_allocator` struct which implements the `std::allocator` interface. @@ -266,46 +332,60 @@ completely and redirect all calls to the _mimalloc_ library instead . ## Environment Options -You can set further options either programmatically (using [`mi_option_set`](https://microsoft.github.io/mimalloc/group__options.html)), -or via environment variables: +You can set further options either programmatically (using [`mi_option_set`](https://microsoft.github.io/mimalloc/group__options.html)), or via environment variables: - `MIMALLOC_SHOW_STATS=1`: show statistics when the program terminates. - `MIMALLOC_VERBOSE=1`: show verbose messages. - `MIMALLOC_SHOW_ERRORS=1`: show error and warning messages. -- `MIMALLOC_PAGE_RESET=0`: by default, mimalloc will reset (or purge) OS pages that are not in use, to signal to the OS - that the underlying physical memory can be reused. This can reduce memory fragmentation in long running (server) - programs. By setting it to `0` this will no longer be done which can improve performance for batch-like programs. - As an alternative, the `MIMALLOC_RESET_DELAY=` can be set higher (100ms by default) to make the page - reset occur less frequently instead of turning it off completely. + +Advanced options: + +- `MIMALLOC_ARENA_EAGER_COMMIT=2`: turns on eager commit for the large arenas (usually 1GiB) from which mimalloc + allocates segments and pages. Set this to 2 (default) to + only enable this on overcommit systems (e.g. Linux). Set this to 1 to enable explicitly on other systems + as well (like Windows or macOS) which may improve performance (as the whole arena is committed at once). + Note that eager commit only increases the commit but not the actual the peak resident set + (rss) so it is generally ok to enable this. +- `MIMALLOC_PURGE_DELAY=N`: the delay in `N` milli-seconds (by default `10`) after which mimalloc will purge + OS pages that are not in use. This signals to the OS that the underlying physical memory can be reused which + can reduce memory fragmentation especially in long running (server) programs. Setting `N` to `0` purges immediately when + a page becomes unused which can improve memory usage but also decreases performance. Setting `N` to a higher + value like `100` can improve performance (sometimes by a lot) at the cost of potentially using more memory at times. + Setting it to `-1` disables purging completely. +- `MIMALLOC_PURGE_DECOMMITS=1`: By default "purging" memory means unused memory is decommitted (`MEM_DECOMMIT` on Windows, + `MADV_DONTNEED` (which decresease rss immediately) on `mmap` systems). Set this to 0 to instead "reset" unused + memory on a purge (`MEM_RESET` on Windows, generally `MADV_FREE` (which does not decrease rss immediately) on `mmap` systems). + Mimalloc generally does not "free" OS memory but only "purges" OS memory, in other words, it tries to keep virtual + address ranges and decommits within those ranges (to make the underlying physical memory available to other processes). + +Further options for large workloads and services: + - `MIMALLOC_USE_NUMA_NODES=N`: pretend there are at most `N` NUMA nodes. If not set, the actual NUMA nodes are detected at runtime. Setting `N` to 1 may avoid problems in some virtual environments. Also, setting it to a lower number than the actual NUMA nodes is fine and will only cause threads to potentially allocate more memory across actual NUMA nodes (but this can happen in any case as NUMA local allocation is always a best effort but not guaranteed). -- `MIMALLOC_LARGE_OS_PAGES=1`: use large OS pages (2MiB) when available; for some workloads this can significantly - improve performance. Use `MIMALLOC_VERBOSE` to check if the large OS pages are enabled -- usually one needs - to explicitly allow large OS pages (as on [Windows][windows-huge] and [Linux][linux-huge]). However, sometimes +- `MIMALLOC_ALLOW_LARGE_OS_PAGES=0`: Set to 1 to use large OS pages (2 or 4MiB) when available; for some workloads this can significantly + improve performance. When this option is disabled (default), it also disables transparent huge pages (THP) for the process + (on Linux and Android). On Linux the default setting is 2 -- this enables the use of large pages through THP only. + Use `MIMALLOC_VERBOSE` to check if the large OS pages are enabled -- usually one needs + to explicitly give permissions for large OS pages (as on [Windows][windows-huge] and [Linux][linux-huge]). However, sometimes the OS is very slow to reserve contiguous physical memory for large OS pages so use with care on systems that can have fragmented memory (for that reason, we generally recommend to use `MIMALLOC_RESERVE_HUGE_OS_PAGES` instead whenever possible). - -- `MIMALLOC_RESERVE_HUGE_OS_PAGES=N`: where N is the number of 1GiB _huge_ OS pages. This reserves the huge pages at +- `MIMALLOC_RESERVE_HUGE_OS_PAGES=N`: where `N` is the number of 1GiB _huge_ OS pages. This reserves the huge pages at startup and sometimes this can give a large (latency) performance improvement on big workloads. - Usually it is better to not use - `MIMALLOC_LARGE_OS_PAGES` in combination with this setting. Just like large OS pages, use with care as reserving + Usually it is better to not use `MIMALLOC_ALLOW_LARGE_OS_PAGES=1` in combination with this setting. Just like large + OS pages, use with care as reserving contiguous physical memory can take a long time when memory is fragmented (but reserving the huge pages is done at startup only once). - Note that we usually need to explicitly enable huge OS pages (as on [Windows][windows-huge] and [Linux][linux-huge])). + Note that we usually need to explicitly give permission for huge OS pages (as on [Windows][windows-huge] and [Linux][linux-huge])). With huge OS pages, it may be beneficial to set the setting `MIMALLOC_EAGER_COMMIT_DELAY=N` (`N` is 1 by default) to delay the initial `N` segments (of 4MiB) of a thread to not allocate in the huge OS pages; this prevents threads that are short lived - and allocate just a little to take up space in the huge OS page area (which cannot be reset). + and allocate just a little to take up space in the huge OS page area (which cannot be purged as huge OS pages are pinned + to physical memory). The huge pages are usually allocated evenly among NUMA nodes. - We can use `MIMALLOC_RESERVE_HUGE_OS_PAGES_AT=N` where `N` is the numa node (starting at 0) to allocate all - the huge pages at a specific numa node instead. + We can use `MIMALLOC_RESERVE_HUGE_OS_PAGES_AT=N` where `N` is the numa node (starting at 0) to allocate all + the huge pages at a specific numa node instead. Use caution when using `fork` in combination with either large or huge OS pages: on a fork, the OS uses copy-on-write for all pages in the original process including the huge OS pages. When any memory is now written in that area, the @@ -333,50 +413,38 @@ As always, evaluate with care as part of an overall security strategy as all of ## Debug Mode -When _mimalloc_ is built using debug mode, various checks are done at runtime to catch development errors. +When _mimalloc_ is built using debug mode, (`-DCMAKE_BUILD_TYPE=Debug`), +various checks are done at runtime to catch development errors. - Statistics are maintained in detail for each object size. They can be shown using `MIMALLOC_SHOW_STATS=1` at runtime. - All objects have padding at the end to detect (byte precise) heap block overflows. - Double free's, and freeing invalid heap pointers are detected. - Corrupted free-lists and some forms of use-after-free are detected. -## Valgrind +## Guarded Mode -Generally, we recommend using the standard allocator with the amazing [Valgrind] tool (and -also for other address sanitizers). -However, it is possible to build mimalloc with Valgrind support. This has a small performance -overhead but does allow detecting memory leaks and byte-precise buffer overflows directly on final -executables. To build with valgrind support, use the `MI_VALGRIND=ON` cmake option: +_mimalloc_ can be build in guarded mode using the `-DMI_GUARDED=ON` flags in `cmake`. +This enables placing OS guard pages behind certain object allocations to catch buffer overflows as they occur. +This can be invaluable to catch buffer-overflow bugs in large programs. However, it also means that any object +allocated with a guard page takes at least 8 KiB memory for the guard page and its alignment. As such, allocating +a guard page for every allocation may be too expensive both in terms of memory, and in terms of performance with +many system calls. Therefore, there are various environment variables (and options) to tune this: -``` -> cmake ../.. -DMI_VALGRIND=ON -``` +- `MIMALLOC_GUARDED_SAMPLE_RATE=N`: Set the sample rate to `N` (by default 4000). This mode places a guard page + behind every `N` suitable object allocations (per thread). Since the performance in guarded mode without placing + guard pages is close to release mode, this can be used to enable guard pages even in production to catch latent + buffer overflow bugs. Set the sample rate to `1` to guard every object, and to `0` to place no guard pages at all. -This can also be combined with secure mode or debug mode. -You can then run your programs directly under valgrind: +- `MIMALLOC_GUARDED_SAMPLE_SEED=N`: Start sampling at `N` (by default random). Can be used to reproduce a buffer + overflow if needed. -``` -> valgrind -``` +- `MIMALLOC_GUARDED_MIN=N`, `MIMALLOC_GUARDED_MAX=N`: Minimal and maximal _rounded_ object sizes for which a guard + page is considered (`0` and `1GiB` respectively). If you suspect a buffer overflow occurs with an object of size + 141, set the minimum and maximum to `148` and the sample rate to `1` to have all of those guarded. -If you rely on overriding `malloc`/`free` by mimalloc (instead of using the `mi_malloc`/`mi_free` API directly), -you also need to tell `valgrind` to not intercept those calls itself, and use: - -``` -> MIMALLOC_SHOW_STATS=1 valgrind --soname-synonyms=somalloc=*mimalloc* -- -``` - -By setting the `MIMALLOC_SHOW_STATS` environment variable you can check that mimalloc is indeed -used and not the standard allocator. Even though the [Valgrind option][valgrind-soname] -is called `--soname-synonyms`, this also -works when overriding with a static library or object file. Unfortunately, it is not possible to -dynamically override mimalloc using `LD_PRELOAD` together with `valgrind`. -See also the `test/test-wrong.c` file to test with `valgrind`. - -Valgrind support is in its initial development -- please report any issues. - -[Valgrind]: https://valgrind.org/ -[valgrind-soname]: https://valgrind.org/docs/manual/manual-core.html#opt.soname-synonyms +- `MIMALLOC_GUARDED_PRECISE=1`: If we have an object of size 13, we would usually place it an aligned 16 bytes in + front of the guard page. Using `MIMALLOC_GUARDED_PRECISE` places it exactly 13 bytes before a page so that even + a 1 byte overflow is detected. This violates the C/C++ minimal alignment guarantees though so use with care. # Overriding Standard Malloc @@ -387,7 +455,7 @@ Overriding the standard `malloc` (and `new`) can be done either _dynamically_ or This is the recommended way to override the standard malloc interface. -### Override on Linux, BSD +### Dynamic Override on Linux, BSD On these ELF-based systems we preload the mimalloc shared library so all calls to the standard `malloc` interface are @@ -406,7 +474,7 @@ or run with the debug version to get detailed statistics: > env MIMALLOC_SHOW_STATS=1 LD_PRELOAD=/usr/lib/libmimalloc-debug.so myprogram ``` -### Override on MacOS +### Dynamic Override on MacOS On macOS we can also preload the mimalloc shared library so all calls to the standard `malloc` interface are @@ -419,55 +487,163 @@ Note that certain security restrictions may apply when doing this from the [shell](https://stackoverflow.com/questions/43941322/dyld-insert-libraries-ignored-when-calling-application-through-bash). -### Override on Windows +### Dynamic Override on Windows + +We use a separate redirection DLL to override mimalloc on Windows +such that we redirect all malloc/free calls that go through the (dynamic) C runtime allocator, +including those from other DLL's or libraries. As it intercepts all allocation calls on a low level, +it can be used on large programs that include other 3rd party components. +There are four requirements to make the overriding work well: -Overriding on Windows is robust and has the -particular advantage to be able to redirect all malloc/free calls that go through -the (dynamic) C runtime allocator, including those from other DLL's or libraries. +1. Use the C-runtime library as a DLL (using the `/MD` or `/MDd` switch). -The overriding on Windows requires that you link your program explicitly with -the mimalloc DLL and use the C-runtime library as a DLL (using the `/MD` or `/MDd` switch). -Also, the `mimalloc-redirect.dll` (or `mimalloc-redirect32.dll`) must be put -in the same folder as the main `mimalloc-override.dll` at runtime (as it is a dependency). -The redirection DLL ensures that all calls to the C runtime malloc API get redirected to -mimalloc (in `mimalloc-override.dll`). +2. Link your program explicitly with the `mimalloc.dll.lib` export library for the `mimalloc.dll`. + (which must be compiled with `-DMI_OVERRIDE=ON`, which is the default though). + To ensure the `mimalloc.dll` is actually loaded at run-time it is easiest + to insert some call to the mimalloc API in the `main` function, like `mi_version()` + (or use the `/include:mi_version` switch on the linker command, or + similarly, `#pragma comment(linker, "/include:mi_version")` in some source file). + See the `mimalloc-test-override` project for an example on how to use this. -To ensure the mimalloc DLL is loaded at run-time it is easiest to insert some -call to the mimalloc API in the `main` function, like `mi_version()` -(or use the `/INCLUDE:mi_version` switch on the linker). See the `mimalloc-override-test` project -for an example on how to use this. For best performance on Windows with C++, it -is also recommended to also override the `new`/`delete` operations (by including -[`mimalloc-new-delete.h`](https://github.com/microsoft/mimalloc/blob/master/include/mimalloc-new-delete.h) a single(!) source file in your project). +3. The `mimalloc-redirect.dll` must be put in the same directory as the main + `mimalloc.dll` at runtime (as it is a dependency of that DLL). + The redirection DLL ensures that all calls to the C runtime malloc API get + redirected to mimalloc functions (which reside in `mimalloc.dll`). + +4. Ensure the `mimalloc.dll` comes as early as possible in the import + list of the final executable (so it can intercept all potential allocations). + You can use `minject -l ` to check this if needed. + +For best performance on Windows with C++, it is also recommended to also override +the `new`/`delete` operations (by including [`mimalloc-new-delete.h`](include/mimalloc-new-delete.h) +a single(!) source file in your project). The environment variable `MIMALLOC_DISABLE_REDIRECT=1` can be used to disable dynamic -overriding at run-time. Use `MIMALLOC_VERBOSE=1` to check if mimalloc was successfully redirected. +overriding at run-time. Use `MIMALLOC_VERBOSE=1` to check if mimalloc was successfully +redirected. -(Note: in principle, it is possible to even patch existing executables without any recompilation -if they are linked with the dynamic C runtime (`ucrtbase.dll`) -- just put the `mimalloc-override.dll` -into the import table (and put `mimalloc-redirect.dll` in the same folder) -Such patching can be done for example with [CFF Explorer](https://ntcore.com/?page_id=388)). +For different platforms than x64, you may need a specific [redirection dll](bin). +Furthermore, we cannot always re-link an executable or ensure `mimalloc.dll` comes +first in the import table. In such cases the [`minject`](bin) tool can be used +to patch the executable's import tables. ## Static override On Unix-like systems, you can also statically link with _mimalloc_ to override the standard malloc interface. The recommended way is to link the final program with the -_mimalloc_ single object file (`mimalloc-override.o`). We use +_mimalloc_ single object file (`mimalloc.o`). We use an object file instead of a library file as linkers give preference to that over archives to resolve symbols. To ensure that the standard malloc interface resolves to the _mimalloc_ library, link it as the first object file. For example: + ``` -> gcc -o myprogram mimalloc-override.o myfile1.c ... +> gcc -o myprogram mimalloc.o myfile1.c ... ``` Another way to override statically that works on all platforms, is to link statically to mimalloc (as shown in the introduction) and include a header file in each source file that re-defines `malloc` etc. to `mi_malloc`. -This is provided by [`mimalloc-override.h`](https://github.com/microsoft/mimalloc/blob/master/include/mimalloc-override.h). This only works reliably though if all sources are +This is provided by [`mimalloc-override.h`](include/mimalloc-override.h). This only works +reliably though if all sources are under your control or otherwise mixing of pointers from different heaps may occur! +# Tools + +Generally, we recommend using the standard allocator with memory tracking tools, but mimalloc +can also be build to support the [address sanitizer][asan] or the excellent [Valgrind] tool. +Moreover, it can be build to support Windows event tracing ([ETW]). +This has a small performance overhead but does allow detecting memory leaks and byte-precise +buffer overflows directly on final executables. See also the `test/test-wrong.c` file to test with various tools. + +## Valgrind + +To build with [valgrind] support, use the `MI_TRACK_VALGRIND=ON` cmake option: + +``` +> cmake ../.. -DMI_TRACK_VALGRIND=ON +``` + +This can also be combined with secure mode or debug mode. +You can then run your programs directly under valgrind: + +``` +> valgrind +``` + +If you rely on overriding `malloc`/`free` by mimalloc (instead of using the `mi_malloc`/`mi_free` API directly), +you also need to tell `valgrind` to not intercept those calls itself, and use: + +``` +> MIMALLOC_SHOW_STATS=1 valgrind --soname-synonyms=somalloc=*mimalloc* -- +``` + +By setting the `MIMALLOC_SHOW_STATS` environment variable you can check that mimalloc is indeed +used and not the standard allocator. Even though the [Valgrind option][valgrind-soname] +is called `--soname-synonyms`, this also works when overriding with a static library or object file. +To dynamically override mimalloc using `LD_PRELOAD` together with `valgrind`, use: + +``` +> valgrind --trace-children=yes --soname-synonyms=somalloc=*mimalloc* /usr/bin/env LD_PRELOAD=/usr/lib/libmimalloc.so -- +``` + +See also the `test/test-wrong.c` file to test with `valgrind`. + +Valgrind support is in its initial development -- please report any issues. + +[Valgrind]: https://valgrind.org/ +[valgrind-soname]: https://valgrind.org/docs/manual/manual-core.html#opt.soname-synonyms + +## ASAN + +To build with the address sanitizer, use the `-DMI_TRACK_ASAN=ON` cmake option: + +``` +> cmake ../.. -DMI_TRACK_ASAN=ON +``` + +This can also be combined with secure mode or debug mode. +You can then run your programs as:' + +``` +> ASAN_OPTIONS=verbosity=1 +``` + +When you link a program with an address sanitizer build of mimalloc, you should +generally compile that program too with the address sanitizer enabled. +For example, assuming you build mimalloc in `out/debug`: + +``` +clang -g -o test-wrong -Iinclude test/test-wrong.c out/debug/libmimalloc-asan-debug.a -lpthread -fsanitize=address -fsanitize-recover=address +``` + +Since the address sanitizer redirects the standard allocation functions, on some platforms (macOSX for example) +it is required to compile mimalloc with `-DMI_OVERRIDE=OFF`. +Address sanitizer support is in its initial development -- please report any issues. + +[asan]: https://github.com/google/sanitizers/wiki/AddressSanitizer + +## ETW + +Event tracing for Windows ([ETW]) provides a high performance way to capture all allocations though +mimalloc and analyze them later. To build with ETW support, use the `-DMI_TRACK_ETW=ON` cmake option. + +You can then capture an allocation trace using the Windows performance recorder (WPR), using the +`src/prim/windows/etw-mimalloc.wprp` profile. In an admin prompt, you can use: +``` +> wpr -start src\prim\windows\etw-mimalloc.wprp -filemode +> +> wpr -stop .etl +``` +and then open `.etl` in the Windows Performance Analyzer (WPA), or +use a tool like [TraceControl] that is specialized for analyzing mimalloc traces. + +[ETW]: https://learn.microsoft.com/en-us/windows-hardware/test/wpt/event-tracing-for-windows +[TraceControl]: https://github.com/xinglonghe/TraceControl + + # Performance Last update: 2021-01-30 @@ -573,7 +749,7 @@ The _alloc-test_, by [OLogN Technologies AG](http://ithare.com/testing-memory-allocators-ptmalloc2-tcmalloc-hoard-jemalloc-while-trying-to-simulate-real-world-loads/), is a very allocation intensive benchmark doing millions of allocations in various size classes. The test is scaled such that when an allocator performs almost identically on _alloc-test1_ as _alloc-testN_ it -means that it scales linearly. +means that it scales linearly. The _sh6bench_ and _sh8bench_ benchmarks are developed by [MicroQuill](http://www.microquill.com/) as part of SmartHeap. @@ -728,6 +904,16 @@ provided by the bot. You will only need to do this once across all repos using o # Older Release Notes +* 2021-11-14, `v1.7.3`, `v2.0.3` (beta): improved WASM support, improved macOS support and performance (including + M1), improved performance for v2 for large objects, Python integration improvements, more standard + installation directories, various small fixes. +* 2021-06-17, `v1.7.2`, `v2.0.2` (beta): support M1, better installation layout on Linux, fix + thread_id on Android, prefer 2-6TiB area for aligned allocation to work better on pre-windows 8, various small fixes. +* 2021-04-06, `v1.7.1`, `v2.0.1` (beta): fix bug in arena allocation for huge pages, improved aslr on large allocations, initial M1 support (still experimental). +* 2021-01-31, `v2.0.0`: beta release 2.0: new slice algorithm for managing internal mimalloc pages. +* 2021-01-31, `v1.7.0`: stable release 1.7: support explicit user provided memory regions, more precise statistics, + improve macOS overriding, initial support for Apple M1, improved DragonFly support, faster memcpy on Windows, various small fixes. + * 2020-09-24, `v1.6.7`: stable release 1.6: using standard C atomics, passing tsan testing, improved handling of failing to commit on Windows, add [`mi_process_info`](https://github.com/microsoft/mimalloc/blob/master/include/mimalloc.h#L156) api call. * 2020-08-06, `v1.6.4`: stable release 1.6: improved error recovery in low-memory situations, @@ -749,9 +935,9 @@ provided by the bot. You will only need to do this once across all repos using o more eager concurrent free, addition of STL allocator, fixed potential memory leak. * 2020-01-15, `v1.3.0`: stable release 1.3: bug fixes, improved randomness and [stronger free list encoding](https://github.com/microsoft/mimalloc/blob/783e3377f79ee82af43a0793910a9f2d01ac7863/include/mimalloc-internal.h#L396) in secure mode. + * 2019-12-22, `v1.2.2`: stable release 1.2: minor updates. * 2019-11-22, `v1.2.0`: stable release 1.2: bug fixes, improved secure mode (free list corruption checks, double free mitigation). Improved dynamic overriding on Windows. * 2019-10-07, `v1.1.0`: stable release 1.1. * 2019-09-01, `v1.0.8`: pre-release 8: more robust windows dynamic overriding, initial huge page support. * 2019-08-10, `v1.0.6`: pre-release 6: various performance improvements. - diff --git a/src/dashbls/depends/mimalloc/src/alloc-aligned.c b/src/dashbls/depends/mimalloc/src/alloc-aligned.c index 9614aa092ee0..6b8bc7620f5c 100644 --- a/src/dashbls/depends/mimalloc/src/alloc-aligned.c +++ b/src/dashbls/depends/mimalloc/src/alloc-aligned.c @@ -6,99 +6,204 @@ terms of the MIT license. A copy of the license can be found in the file -----------------------------------------------------------------------------*/ #include "mimalloc.h" -#include "mimalloc-internal.h" +#include "mimalloc/internal.h" +#include "mimalloc/prim.h" // mi_prim_get_default_heap -#include // memset +#include // memset // ------------------------------------------------------ // Aligned Allocation // ------------------------------------------------------ -// Fallback primitive aligned allocation -- split out for better codegen -static mi_decl_noinline void* mi_heap_malloc_zero_aligned_at_fallback(mi_heap_t* const heap, const size_t size, const size_t alignment, const size_t offset, const bool zero) mi_attr_noexcept -{ - mi_assert_internal(size <= PTRDIFF_MAX); - mi_assert_internal(alignment!=0 && _mi_is_power_of_two(alignment) && alignment <= MI_ALIGNMENT_MAX); +static bool mi_malloc_is_naturally_aligned( size_t size, size_t alignment ) { + // objects up to `MI_PAGE_MIN_BLOCK_ALIGN` are always allocated aligned to their size + mi_assert_internal(_mi_is_power_of_two(alignment) && (alignment > 0)); + if (alignment > size) return false; + const size_t bsize = mi_good_size(size); + const bool ok = (bsize <= MI_PAGE_MAX_START_BLOCK_ALIGN2 && _mi_is_power_of_two(bsize)); + if (ok) { mi_assert_internal((bsize & (alignment-1)) == 0); } // since both power of 2 and alignment <= size + return ok; +} - const uintptr_t align_mask = alignment-1; // for any x, `(x & align_mask) == (x % alignment)` - const size_t padsize = size + MI_PADDING_SIZE; +#if MI_GUARDED +static mi_decl_restrict void* mi_heap_malloc_guarded_aligned(mi_heap_t* heap, size_t size, size_t alignment, bool zero) mi_attr_noexcept { + // use over allocation for guarded blocksl + mi_assert_internal(alignment > 0 && alignment < MI_PAGE_MAX_OVERALLOC_ALIGN); + const size_t oversize = size + alignment - 1; + void* base = _mi_heap_malloc_guarded(heap, oversize, zero); + void* p = _mi_align_up_ptr(base, alignment); + mi_track_align(base, p, (uint8_t*)p - (uint8_t*)base, size); + mi_assert_internal(mi_usable_size(p) >= size); + mi_assert_internal(_mi_is_aligned(p, alignment)); + return p; +} - // use regular allocation if it is guaranteed to fit the alignment constraints - if (offset==0 && alignment<=padsize && padsize<=MI_MAX_ALIGN_GUARANTEE && (padsize&align_mask)==0) { - void* p = _mi_heap_malloc_zero(heap, size, zero); - mi_assert_internal(p == NULL || ((uintptr_t)p % alignment) == 0); - return p; - } +static void* mi_heap_malloc_zero_no_guarded(mi_heap_t* heap, size_t size, bool zero) { + const size_t rate = heap->guarded_sample_rate; + // only write if `rate!=0` so we don't write to the constant `_mi_heap_empty` + if (rate != 0) { heap->guarded_sample_rate = 0; } + void* p = _mi_heap_malloc_zero(heap, size, zero); + if (rate != 0) { heap->guarded_sample_rate = rate; } + return p; +} +#else +static void* mi_heap_malloc_zero_no_guarded(mi_heap_t* heap, size_t size, bool zero) { + return _mi_heap_malloc_zero(heap, size, zero); +} +#endif - // otherwise over-allocate - const size_t oversize = size + alignment - 1; - void* p = _mi_heap_malloc_zero(heap, oversize, zero); - if (p == NULL) return NULL; +// Fallback aligned allocation that over-allocates -- split out for better codegen +static mi_decl_noinline void* mi_heap_malloc_zero_aligned_at_overalloc(mi_heap_t* const heap, const size_t size, const size_t alignment, const size_t offset, const bool zero) mi_attr_noexcept +{ + mi_assert_internal(size <= (MI_MAX_ALLOC_SIZE - MI_PADDING_SIZE)); + mi_assert_internal(alignment != 0 && _mi_is_power_of_two(alignment)); + + void* p; + size_t oversize; + if mi_unlikely(alignment > MI_PAGE_MAX_OVERALLOC_ALIGN) { + // use OS allocation for large alignments and allocate inside a singleton page (not in an arena) + // This can support alignments >= MI_PAGE_ALIGN by ensuring the object can be aligned + // in the first (and single) page such that the page info is `MI_PAGE_ALIGN` bytes before it (and can be found in the _mi_page_map). + if mi_unlikely(offset != 0) { + // todo: cannot support offset alignment for very large alignments yet + #if MI_DEBUG > 0 + _mi_error_message(EOVERFLOW, "aligned allocation with a large alignment cannot be used with an alignment offset (size %zu, alignment %zu, offset %zu)\n", size, alignment, offset); + #endif + return NULL; + } + oversize = (size <= MI_SMALL_SIZE_MAX ? MI_SMALL_SIZE_MAX + 1 /* ensure we use generic malloc path */ : size); + // note: no guarded as alignment > 0 + p = _mi_heap_malloc_zero_ex(heap, oversize, zero, alignment); // the page block size should be large enough to align in the single huge page block + if (p == NULL) return NULL; + } + else { + // otherwise over-allocate + oversize = (size < MI_MAX_ALIGN_SIZE ? MI_MAX_ALIGN_SIZE : size) + alignment - 1; // adjust for size <= 16; with size 0 and aligment 64k, we would allocate a 64k block and pointing just beyond that. + p = mi_heap_malloc_zero_no_guarded(heap, oversize, zero); + if (p == NULL) return NULL; + } + mi_page_t* page = _mi_ptr_page(p); // .. and align within the allocation - uintptr_t adjust = alignment - (((uintptr_t)p + offset) & align_mask); - mi_assert_internal(adjust <= alignment); - void* aligned_p = (adjust == alignment ? p : (void*)((uintptr_t)p + adjust)); - if (aligned_p != p) mi_page_set_has_aligned(_mi_ptr_page(p), true); + const uintptr_t align_mask = alignment - 1; // for any x, `(x & align_mask) == (x % alignment)` + const uintptr_t poffset = ((uintptr_t)p + offset) & align_mask; + const uintptr_t adjust = (poffset == 0 ? 0 : alignment - poffset); + mi_assert_internal(adjust < alignment); + void* aligned_p = (void*)((uintptr_t)p + adjust); + if (aligned_p != p) { + mi_page_set_has_aligned(page, true); + #if MI_GUARDED + // set tag to aligned so mi_usable_size works with guard pages + if (adjust >= sizeof(mi_block_t)) { + mi_block_t* const block = (mi_block_t*)p; + block->next = MI_BLOCK_TAG_ALIGNED; + } + #endif + _mi_padding_shrink(page, (mi_block_t*)p, adjust + size); + } + // todo: expand padding if overallocated ? + + mi_assert_internal(mi_page_usable_block_size(page) >= adjust + size); mi_assert_internal(((uintptr_t)aligned_p + offset) % alignment == 0); - mi_assert_internal(p == _mi_page_ptr_unalign(_mi_ptr_segment(aligned_p), _mi_ptr_page(aligned_p), aligned_p)); + mi_assert_internal(mi_usable_size(aligned_p)>=size); + mi_assert_internal(mi_usable_size(p) == mi_usable_size(aligned_p)+adjust); + #if MI_DEBUG > 1 + mi_page_t* const apage = _mi_ptr_page(aligned_p); + void* unalign_p = _mi_page_ptr_unalign(apage, aligned_p); + mi_assert_internal(p == unalign_p); + #endif + + // now zero the block if needed + //if (alignment > MI_PAGE_MAX_OVERALLOC_ALIGN) { + // // for the tracker, on huge aligned allocations only from the start of the large block is defined + // mi_track_mem_undefined(aligned_p, size); + // if (zero) { + // _mi_memzero_aligned(aligned_p, mi_usable_size(aligned_p)); + // } + //} - #if MI_TRACK_ENABLED if (p != aligned_p) { - mi_track_free(p); - mi_track_malloc(aligned_p,size,zero); - } - else { - mi_track_resize(aligned_p,oversize,size); + mi_track_align(p,aligned_p,adjust,mi_usable_size(aligned_p)); + #if MI_GUARDED + mi_track_mem_defined(p, sizeof(mi_block_t)); + #endif } - #endif return aligned_p; } -// Primitive aligned allocation -static void* mi_heap_malloc_zero_aligned_at(mi_heap_t* const heap, const size_t size, const size_t alignment, const size_t offset, const bool zero) mi_attr_noexcept +// Generic primitive aligned allocation -- split out for better codegen +static mi_decl_noinline void* mi_heap_malloc_zero_aligned_at_generic(mi_heap_t* const heap, const size_t size, const size_t alignment, const size_t offset, const bool zero) mi_attr_noexcept { - // note: we don't require `size > offset`, we just guarantee that the address at offset is aligned regardless of the allocated size. - mi_assert(alignment > 0); - if mi_unlikely(alignment==0 || !_mi_is_power_of_two(alignment)) { // require power-of-two (see ) + mi_assert_internal(alignment != 0 && _mi_is_power_of_two(alignment)); + // we don't allocate more than MI_MAX_ALLOC_SIZE (see ) + if mi_unlikely(size > (MI_MAX_ALLOC_SIZE - MI_PADDING_SIZE)) { #if MI_DEBUG > 0 - _mi_error_message(EOVERFLOW, "aligned allocation requires the alignment to be a power-of-two (size %zu, alignment %zu)\n", size, alignment); + _mi_error_message(EOVERFLOW, "aligned allocation request is too large (size %zu, alignment %zu)\n", size, alignment); #endif return NULL; } - if mi_unlikely(alignment > MI_ALIGNMENT_MAX) { // we cannot align at a boundary larger than this (or otherwise we cannot find segment headers) - #if MI_DEBUG > 0 - _mi_error_message(EOVERFLOW, "aligned allocation has a maximum alignment of %zu (size %zu, alignment %zu)\n", MI_ALIGNMENT_MAX, size, alignment); - #endif - return NULL; + + // use regular allocation if it is guaranteed to fit the alignment constraints. + // this is important to try as the fast path in `mi_heap_malloc_zero_aligned` only works when there exist + // a page with the right block size, and if we always use the over-alloc fallback that would never happen. + if (offset == 0 && mi_malloc_is_naturally_aligned(size,alignment)) { + void* p = mi_heap_malloc_zero_no_guarded(heap, size, zero); + mi_assert_internal(p == NULL || ((uintptr_t)p % alignment) == 0); + const bool is_aligned_or_null = (((uintptr_t)p) & (alignment-1))==0; + if mi_likely(is_aligned_or_null) { + return p; + } + else { + // this should never happen if the `mi_malloc_is_naturally_aligned` check is correct.. + mi_assert(false); + mi_free(p); + } } - if mi_unlikely(size > PTRDIFF_MAX) { // we don't allocate more than PTRDIFF_MAX (see ) + + // fall back to over-allocation + return mi_heap_malloc_zero_aligned_at_overalloc(heap,size,alignment,offset,zero); +} + + +// Primitive aligned allocation +static void* mi_heap_malloc_zero_aligned_at(mi_heap_t* const heap, const size_t size, const size_t alignment, const size_t offset, const bool zero) mi_attr_noexcept +{ + // note: we don't require `size > offset`, we just guarantee that the address at offset is aligned regardless of the allocated size. + if mi_unlikely(alignment == 0 || !_mi_is_power_of_two(alignment)) { // require power-of-two (see ) #if MI_DEBUG > 0 - _mi_error_message(EOVERFLOW, "aligned allocation request is too large (size %zu, alignment %zu)\n", size, alignment); + _mi_error_message(EOVERFLOW, "aligned allocation requires the alignment to be a power-of-two (size %zu, alignment %zu)\n", size, alignment); #endif return NULL; } - const uintptr_t align_mask = alignment-1; // for any x, `(x & align_mask) == (x % alignment)` - const size_t padsize = size + MI_PADDING_SIZE; // note: cannot overflow due to earlier size > PTRDIFF_MAX check + + #if MI_GUARDED + if (offset==0 && alignment < MI_PAGE_MAX_OVERALLOC_ALIGN && mi_heap_malloc_use_guarded(heap,size)) { + return mi_heap_malloc_guarded_aligned(heap, size, alignment, zero); + } + #endif // try first if there happens to be a small block available with just the right alignment - if mi_likely(padsize <= MI_SMALL_SIZE_MAX) { + // since most small power-of-2 blocks (under MI_PAGE_MAX_BLOCK_START_ALIGN2) are already + // naturally aligned this can be often the case. + if mi_likely(size <= MI_SMALL_SIZE_MAX && alignment <= size) { + const uintptr_t align_mask = alignment-1; // for any x, `(x & align_mask) == (x % alignment)` + const size_t padsize = size + MI_PADDING_SIZE; mi_page_t* page = _mi_heap_get_free_small_page(heap, padsize); - const bool is_aligned = (((uintptr_t)page->free+offset) & align_mask)==0; - if mi_likely(page->free != NULL && is_aligned) - { - #if MI_STAT>1 - mi_heap_stat_increase(heap, malloc, size); - #endif - void* p = _mi_page_malloc(heap, page, padsize, zero); // TODO: inline _mi_page_malloc - mi_assert_internal(p != NULL); - mi_assert_internal(((uintptr_t)p + offset) % alignment == 0); - mi_track_malloc(p,size,zero); - return p; + if mi_likely(page->free != NULL) { + const bool is_aligned = (((uintptr_t)page->free + offset) & align_mask)==0; + if mi_likely(is_aligned) + { + void* p = (zero ? _mi_page_malloc_zeroed(heap,page,padsize) : _mi_page_malloc(heap,page,padsize)); // call specific page malloc for better codegen + mi_assert_internal(p != NULL); + mi_assert_internal(((uintptr_t)p + offset) % alignment == 0); + mi_track_malloc(p,size,zero); + return p; + } } } - // fallback - return mi_heap_malloc_zero_aligned_at_fallback(heap, size, alignment, offset, zero); + + // fallback to generic aligned allocation + return mi_heap_malloc_zero_aligned_at_generic(heap, size, alignment, offset, zero); } @@ -111,22 +216,7 @@ mi_decl_nodiscard mi_decl_restrict void* mi_heap_malloc_aligned_at(mi_heap_t* he } mi_decl_nodiscard mi_decl_restrict void* mi_heap_malloc_aligned(mi_heap_t* heap, size_t size, size_t alignment) mi_attr_noexcept { - #if !MI_PADDING - // without padding, any small sized allocation is naturally aligned (see also `_mi_segment_page_start`) - if (!_mi_is_power_of_two(alignment)) return NULL; - if mi_likely(_mi_is_power_of_two(size) && size >= alignment && size <= MI_SMALL_SIZE_MAX) - #else - // with padding, we can only guarantee this for fixed alignments - if mi_likely((alignment == sizeof(void*) || (alignment == MI_MAX_ALIGN_SIZE && size > (MI_MAX_ALIGN_SIZE/2))) - && size <= MI_SMALL_SIZE_MAX) - #endif - { - // fast path for common alignment and size - return mi_heap_malloc_small(heap, size); - } - else { - return mi_heap_malloc_aligned_at(heap, size, alignment, 0); - } + return mi_heap_malloc_aligned_at(heap, size, alignment, 0); } // ------------------------------------------------------ @@ -152,27 +242,27 @@ mi_decl_nodiscard mi_decl_restrict void* mi_heap_calloc_aligned(mi_heap_t* heap, } mi_decl_nodiscard mi_decl_restrict void* mi_malloc_aligned_at(size_t size, size_t alignment, size_t offset) mi_attr_noexcept { - return mi_heap_malloc_aligned_at(mi_get_default_heap(), size, alignment, offset); + return mi_heap_malloc_aligned_at(mi_prim_get_default_heap(), size, alignment, offset); } mi_decl_nodiscard mi_decl_restrict void* mi_malloc_aligned(size_t size, size_t alignment) mi_attr_noexcept { - return mi_heap_malloc_aligned(mi_get_default_heap(), size, alignment); + return mi_heap_malloc_aligned(mi_prim_get_default_heap(), size, alignment); } mi_decl_nodiscard mi_decl_restrict void* mi_zalloc_aligned_at(size_t size, size_t alignment, size_t offset) mi_attr_noexcept { - return mi_heap_zalloc_aligned_at(mi_get_default_heap(), size, alignment, offset); + return mi_heap_zalloc_aligned_at(mi_prim_get_default_heap(), size, alignment, offset); } mi_decl_nodiscard mi_decl_restrict void* mi_zalloc_aligned(size_t size, size_t alignment) mi_attr_noexcept { - return mi_heap_zalloc_aligned(mi_get_default_heap(), size, alignment); + return mi_heap_zalloc_aligned(mi_prim_get_default_heap(), size, alignment); } mi_decl_nodiscard mi_decl_restrict void* mi_calloc_aligned_at(size_t count, size_t size, size_t alignment, size_t offset) mi_attr_noexcept { - return mi_heap_calloc_aligned_at(mi_get_default_heap(), count, size, alignment, offset); + return mi_heap_calloc_aligned_at(mi_prim_get_default_heap(), count, size, alignment, offset); } mi_decl_nodiscard mi_decl_restrict void* mi_calloc_aligned(size_t count, size_t size, size_t alignment) mi_attr_noexcept { - return mi_heap_calloc_aligned(mi_get_default_heap(), count, size, alignment); + return mi_heap_calloc_aligned(mi_prim_get_default_heap(), count, size, alignment); } @@ -190,19 +280,13 @@ static void* mi_heap_realloc_zero_aligned_at(mi_heap_t* heap, void* p, size_t ne return p; // reallocation still fits, is aligned and not more than 50% waste } else { + // note: we don't zero allocate upfront so we only zero initialize the expanded part void* newp = mi_heap_malloc_aligned_at(heap,newsize,alignment,offset); if (newp != NULL) { if (zero && newsize > size) { - const mi_page_t* page = _mi_ptr_page(newp); - if (page->is_zero) { - // already zero initialized - mi_assert_expensive(mi_mem_is_zero(newp,newsize)); - } - else { - // also set last word in the previous allocation to zero to ensure any padding is zero-initialized - size_t start = (size >= sizeof(intptr_t) ? size - sizeof(intptr_t) : 0); - memset((uint8_t*)newp + start, 0, newsize - start); - } + // also set last word in the previous allocation to zero to ensure any padding is zero-initialized + size_t start = (size >= sizeof(intptr_t) ? size - sizeof(intptr_t) : 0); + _mi_memzero((uint8_t*)newp + start, newsize - start); } _mi_memcpy_aligned(newp, p, (newsize > size ? size : newsize)); mi_free(p); // only free if successful @@ -247,26 +331,27 @@ mi_decl_nodiscard void* mi_heap_recalloc_aligned(mi_heap_t* heap, void* p, size_ } mi_decl_nodiscard void* mi_realloc_aligned_at(void* p, size_t newsize, size_t alignment, size_t offset) mi_attr_noexcept { - return mi_heap_realloc_aligned_at(mi_get_default_heap(), p, newsize, alignment, offset); + return mi_heap_realloc_aligned_at(mi_prim_get_default_heap(), p, newsize, alignment, offset); } mi_decl_nodiscard void* mi_realloc_aligned(void* p, size_t newsize, size_t alignment) mi_attr_noexcept { - return mi_heap_realloc_aligned(mi_get_default_heap(), p, newsize, alignment); + return mi_heap_realloc_aligned(mi_prim_get_default_heap(), p, newsize, alignment); } mi_decl_nodiscard void* mi_rezalloc_aligned_at(void* p, size_t newsize, size_t alignment, size_t offset) mi_attr_noexcept { - return mi_heap_rezalloc_aligned_at(mi_get_default_heap(), p, newsize, alignment, offset); + return mi_heap_rezalloc_aligned_at(mi_prim_get_default_heap(), p, newsize, alignment, offset); } mi_decl_nodiscard void* mi_rezalloc_aligned(void* p, size_t newsize, size_t alignment) mi_attr_noexcept { - return mi_heap_rezalloc_aligned(mi_get_default_heap(), p, newsize, alignment); + return mi_heap_rezalloc_aligned(mi_prim_get_default_heap(), p, newsize, alignment); } mi_decl_nodiscard void* mi_recalloc_aligned_at(void* p, size_t newcount, size_t size, size_t alignment, size_t offset) mi_attr_noexcept { - return mi_heap_recalloc_aligned_at(mi_get_default_heap(), p, newcount, size, alignment, offset); + return mi_heap_recalloc_aligned_at(mi_prim_get_default_heap(), p, newcount, size, alignment, offset); } mi_decl_nodiscard void* mi_recalloc_aligned(void* p, size_t newcount, size_t size, size_t alignment) mi_attr_noexcept { - return mi_heap_recalloc_aligned(mi_get_default_heap(), p, newcount, size, alignment); + return mi_heap_recalloc_aligned(mi_prim_get_default_heap(), p, newcount, size, alignment); } + diff --git a/src/dashbls/depends/mimalloc/src/alloc-override.c b/src/dashbls/depends/mimalloc/src/alloc-override.c index 9534e9d57b1f..52ab69c5389c 100644 --- a/src/dashbls/depends/mimalloc/src/alloc-override.c +++ b/src/dashbls/depends/mimalloc/src/alloc-override.c @@ -13,7 +13,7 @@ terms of the MIT license. A copy of the license can be found in the file #error "It is only possible to override "malloc" on Windows when building as a DLL (and linking the C runtime as a DLL)" #endif -#if defined(MI_MALLOC_OVERRIDE) && !(defined(_WIN32)) +#if defined(MI_MALLOC_OVERRIDE) && !(defined(_WIN32)) #if defined(__APPLE__) #include @@ -23,7 +23,7 @@ mi_decl_externc size_t malloc_good_size(size_t size); #endif // helper definition for C override of C++ new -typedef struct mi_nothrow_s { int _tag; } mi_nothrow_t; +typedef void* mi_nothrow_t; // ------------------------------------------------------ // Override system malloc @@ -43,19 +43,25 @@ typedef struct mi_nothrow_s { int _tag; } mi_nothrow_t; #define MI_FORWARD0(fun,x) MI_FORWARD(fun) #define MI_FORWARD02(fun,x,y) MI_FORWARD(fun) #else - // otherwise use forwarding by calling our `mi_` function - #define MI_FORWARD1(fun,x) { return fun(x); } + // otherwise use forwarding by calling our `mi_` function + #define MI_FORWARD1(fun,x) { return fun(x); } #define MI_FORWARD2(fun,x,y) { return fun(x,y); } #define MI_FORWARD3(fun,x,y,z) { return fun(x,y,z); } #define MI_FORWARD0(fun,x) { fun(x); } #define MI_FORWARD02(fun,x,y) { fun(x,y); } #endif -#if defined(__APPLE__) && defined(MI_SHARED_LIB_EXPORT) && defined(MI_OSX_INTERPOSE) - // define MI_OSX_IS_INTERPOSED as we should not provide forwarding definitions for + +#if defined(__APPLE__) && defined(MI_SHARED_LIB_EXPORT) && defined(MI_OSX_INTERPOSE) + // define MI_OSX_IS_INTERPOSED as we should not provide forwarding definitions for // functions that are interposed (or the interposing does not work) #define MI_OSX_IS_INTERPOSED + mi_decl_externc size_t mi_malloc_size_checked(void *p) { + if (!mi_is_in_heap_region(p)) return 0; + return mi_usable_size(p); + } + // use interposing so `DYLD_INSERT_LIBRARIES` works without `DYLD_FORCE_FLAT_NAMESPACE=1` // See: struct mi_interpose_s { @@ -64,23 +70,21 @@ typedef struct mi_nothrow_s { int _tag; } mi_nothrow_t; }; #define MI_INTERPOSE_FUN(oldfun,newfun) { (const void*)&newfun, (const void*)&oldfun } #define MI_INTERPOSE_MI(fun) MI_INTERPOSE_FUN(fun,mi_##fun) - - __attribute__((used)) static struct mi_interpose_s _mi_interposes[] __attribute__((section("__DATA, __interpose"))) = + + #define MI_INTERPOSE_DECLS(name) __attribute__((used)) static struct mi_interpose_s name[] __attribute__((section("__DATA, __interpose"))) + + MI_INTERPOSE_DECLS(_mi_interposes) = { MI_INTERPOSE_MI(malloc), MI_INTERPOSE_MI(calloc), MI_INTERPOSE_MI(realloc), MI_INTERPOSE_MI(strdup), - MI_INTERPOSE_MI(strndup), MI_INTERPOSE_MI(realpath), MI_INTERPOSE_MI(posix_memalign), MI_INTERPOSE_MI(reallocf), MI_INTERPOSE_MI(valloc), - MI_INTERPOSE_MI(malloc_size), + MI_INTERPOSE_FUN(malloc_size,mi_malloc_size_checked), MI_INTERPOSE_MI(malloc_good_size), - #if defined(MAC_OS_X_VERSION_10_15) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_15 - MI_INTERPOSE_MI(aligned_alloc), - #endif #ifdef MI_OSX_ZONE // we interpose malloc_default_zone in alloc-override-osx.c so we can use mi_free safely MI_INTERPOSE_MI(free), @@ -91,6 +95,12 @@ typedef struct mi_nothrow_s { int _tag; } mi_nothrow_t; MI_INTERPOSE_FUN(vfree,mi_cfree), #endif }; + MI_INTERPOSE_DECLS(_mi_interposes_10_7) __OSX_AVAILABLE(10.7) = { + MI_INTERPOSE_MI(strndup), + }; + MI_INTERPOSE_DECLS(_mi_interposes_10_15) __OSX_AVAILABLE(10.15) = { + MI_INTERPOSE_MI(aligned_alloc), + }; #ifdef __cplusplus extern "C" { @@ -122,11 +132,19 @@ typedef struct mi_nothrow_s { int _tag; } mi_nothrow_t; // cannot override malloc unless using a dll. // we just override new/delete which does work in a static library. #else - // On all other systems forward to our API + // On all other systems forward allocation primitives to our API mi_decl_export void* malloc(size_t size) MI_FORWARD1(mi_malloc, size) mi_decl_export void* calloc(size_t size, size_t n) MI_FORWARD2(mi_calloc, size, n) mi_decl_export void* realloc(void* p, size_t newsize) MI_FORWARD2(mi_realloc, p, newsize) mi_decl_export void free(void* p) MI_FORWARD0(mi_free, p) + // In principle we do not need to forward `strdup`/`strndup` but on some systems these do not use `malloc` internally (but a more primitive call) + // We only override if `strdup` is not a macro (as on some older libc's, see issue #885) + #if !defined(strdup) + mi_decl_export char* strdup(const char* str) MI_FORWARD1(mi_strdup, str) + #endif + #if !defined(strndup) && (!defined(__APPLE__) || (defined(MAC_OS_X_VERSION_10_7) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7)) + mi_decl_export char* strndup(const char* str, size_t n) MI_FORWARD2(mi_strndup, str, n) + #endif #endif #if (defined(__GNUC__) || defined(__clang__)) && !defined(__APPLE__) @@ -168,34 +186,40 @@ typedef struct mi_nothrow_s { int _tag; } mi_nothrow_t; void operator delete[](void* p, std::size_t n, std::align_val_t al) noexcept { mi_free_size_aligned(p, n, static_cast(al)); }; void operator delete (void* p, std::align_val_t al, const std::nothrow_t&) noexcept { mi_free_aligned(p, static_cast(al)); } void operator delete[](void* p, std::align_val_t al, const std::nothrow_t&) noexcept { mi_free_aligned(p, static_cast(al)); } - + void* operator new( std::size_t n, std::align_val_t al) noexcept(false) { return mi_new_aligned(n, static_cast(al)); } void* operator new[]( std::size_t n, std::align_val_t al) noexcept(false) { return mi_new_aligned(n, static_cast(al)); } void* operator new (std::size_t n, std::align_val_t al, const std::nothrow_t&) noexcept { return mi_new_aligned_nothrow(n, static_cast(al)); } void* operator new[](std::size_t n, std::align_val_t al, const std::nothrow_t&) noexcept { return mi_new_aligned_nothrow(n, static_cast(al)); } #endif -#elif (defined(__GNUC__) || defined(__clang__)) +#elif (defined(__GNUC__) || defined(__clang__)) // ------------------------------------------------------ // Override by defining the mangled C++ names of the operators (as // used by GCC and CLang). // See // ------------------------------------------------------ - + void _ZdlPv(void* p) MI_FORWARD0(mi_free,p) // delete void _ZdaPv(void* p) MI_FORWARD0(mi_free,p) // delete[] void _ZdlPvm(void* p, size_t n) MI_FORWARD02(mi_free_size,p,n) void _ZdaPvm(void* p, size_t n) MI_FORWARD02(mi_free_size,p,n) + void _ZdlPvSt11align_val_t(void* p, size_t al) { mi_free_aligned(p,al); } void _ZdaPvSt11align_val_t(void* p, size_t al) { mi_free_aligned(p,al); } void _ZdlPvmSt11align_val_t(void* p, size_t n, size_t al) { mi_free_size_aligned(p,n,al); } void _ZdaPvmSt11align_val_t(void* p, size_t n, size_t al) { mi_free_size_aligned(p,n,al); } + + void _ZdlPvRKSt9nothrow_t(void* p, mi_nothrow_t tag) { MI_UNUSED(tag); mi_free(p); } // operator delete(void*, std::nothrow_t const&) + void _ZdaPvRKSt9nothrow_t(void* p, mi_nothrow_t tag) { MI_UNUSED(tag); mi_free(p); } // operator delete[](void*, std::nothrow_t const&) + void _ZdlPvSt11align_val_tRKSt9nothrow_t(void* p, size_t al, mi_nothrow_t tag) { MI_UNUSED(tag); mi_free_aligned(p,al); } // operator delete(void*, std::align_val_t, std::nothrow_t const&) + void _ZdaPvSt11align_val_tRKSt9nothrow_t(void* p, size_t al, mi_nothrow_t tag) { MI_UNUSED(tag); mi_free_aligned(p,al); } // operator delete[](void*, std::align_val_t, std::nothrow_t const&) #if (MI_INTPTR_SIZE==8) void* _Znwm(size_t n) MI_FORWARD1(mi_new,n) // new 64-bit void* _Znam(size_t n) MI_FORWARD1(mi_new,n) // new[] 64-bit void* _ZnwmRKSt9nothrow_t(size_t n, mi_nothrow_t tag) { MI_UNUSED(tag); return mi_new_nothrow(n); } - void* _ZnamRKSt9nothrow_t(size_t n, mi_nothrow_t tag) { MI_UNUSED(tag); return mi_new_nothrow(n); } + void* _ZnamRKSt9nothrow_t(size_t n, mi_nothrow_t tag) { MI_UNUSED(tag); return mi_new_nothrow(n); } void* _ZnwmSt11align_val_t(size_t n, size_t al) MI_FORWARD2(mi_new_aligned, n, al) void* _ZnamSt11align_val_t(size_t n, size_t al) MI_FORWARD2(mi_new_aligned, n, al) void* _ZnwmSt11align_val_tRKSt9nothrow_t(size_t n, size_t al, mi_nothrow_t tag) { MI_UNUSED(tag); return mi_new_aligned_nothrow(n,al); } @@ -204,7 +228,7 @@ typedef struct mi_nothrow_s { int _tag; } mi_nothrow_t; void* _Znwj(size_t n) MI_FORWARD1(mi_new,n) // new 64-bit void* _Znaj(size_t n) MI_FORWARD1(mi_new,n) // new[] 64-bit void* _ZnwjRKSt9nothrow_t(size_t n, mi_nothrow_t tag) { MI_UNUSED(tag); return mi_new_nothrow(n); } - void* _ZnajRKSt9nothrow_t(size_t n, mi_nothrow_t tag) { MI_UNUSED(tag); return mi_new_nothrow(n); } + void* _ZnajRKSt9nothrow_t(size_t n, mi_nothrow_t tag) { MI_UNUSED(tag); return mi_new_nothrow(n); } void* _ZnwjSt11align_val_t(size_t n, size_t al) MI_FORWARD2(mi_new_aligned, n, al) void* _ZnajSt11align_val_t(size_t n, size_t al) MI_FORWARD2(mi_new_aligned, n, al) void* _ZnwjSt11align_val_tRKSt9nothrow_t(size_t n, size_t al, mi_nothrow_t tag) { MI_UNUSED(tag); return mi_new_aligned_nothrow(n,al); } @@ -226,7 +250,7 @@ extern "C" { // Forward Posix/Unix calls as well void* reallocf(void* p, size_t newsize) MI_FORWARD2(mi_reallocf,p,newsize) size_t malloc_size(const void* p) MI_FORWARD1(mi_usable_size,p) - #if !defined(__ANDROID__) && !defined(__FreeBSD__) + #if !defined(__ANDROID__) && !defined(__FreeBSD__) && !defined(__DragonFly__) size_t malloc_usable_size(void *p) MI_FORWARD1(mi_usable_size,p) #else size_t malloc_usable_size(const void *p) MI_FORWARD1(mi_usable_size,p) @@ -234,30 +258,41 @@ extern "C" { // No forwarding here due to aliasing/name mangling issues void* valloc(size_t size) { return mi_valloc(size); } - void vfree(void* p) { mi_free(p); } + void vfree(void* p) { mi_free(p); } size_t malloc_good_size(size_t size) { return mi_malloc_good_size(size); } int posix_memalign(void** p, size_t alignment, size_t size) { return mi_posix_memalign(p, alignment, size); } - + // `aligned_alloc` is only available when __USE_ISOC11 is defined. + // Note: it seems __USE_ISOC11 is not defined in musl (and perhaps other libc's) so we only check + // for it if using glibc. // Note: Conda has a custom glibc where `aligned_alloc` is declared `static inline` and we cannot // override it, but both _ISOC11_SOURCE and __USE_ISOC11 are undefined in Conda GCC7 or GCC9. // Fortunately, in the case where `aligned_alloc` is declared as `static inline` it // uses internally `memalign`, `posix_memalign`, or `_aligned_malloc` so we can avoid overriding it ourselves. - #if __USE_ISOC11 + #if !defined(__GLIBC__) || __USE_ISOC11 void* aligned_alloc(size_t alignment, size_t size) { return mi_aligned_alloc(alignment, size); } #endif #endif // no forwarding here due to aliasing/name mangling issues -void cfree(void* p) { mi_free(p); } +void cfree(void* p) { mi_free(p); } void* pvalloc(size_t size) { return mi_pvalloc(size); } -void* reallocarray(void* p, size_t count, size_t size) { return mi_reallocarray(p, count, size); } -int reallocarr(void* p, size_t count, size_t size) { return mi_reallocarr(p, count, size); } void* memalign(size_t alignment, size_t size) { return mi_memalign(alignment, size); } void* _aligned_malloc(size_t alignment, size_t size) { return mi_aligned_alloc(alignment, size); } +void* reallocarray(void* p, size_t count, size_t size) { return mi_reallocarray(p, count, size); } +// some systems define reallocarr so mark it as a weak symbol (#751) +mi_decl_weak int reallocarr(void* p, size_t count, size_t size) { return mi_reallocarr(p, count, size); } + +#if defined(__wasi__) + // forward __libc interface (see PR #667) + void* __libc_malloc(size_t size) MI_FORWARD1(mi_malloc, size) + void* __libc_calloc(size_t count, size_t size) MI_FORWARD2(mi_calloc, count, size) + void* __libc_realloc(void* p, size_t size) MI_FORWARD2(mi_realloc, p, size) + void __libc_free(void* p) MI_FORWARD0(mi_free, p) + void* __libc_memalign(size_t alignment, size_t size) { return mi_memalign(alignment, size); } -#if defined(__GLIBC__) && defined(__linux__) - // forward __libc interface (needed for glibc-based Linux distributions) +#elif defined(__linux__) + // forward __libc interface (needed for glibc-based and musl-based Linux distributions) void* __libc_malloc(size_t size) MI_FORWARD1(mi_malloc,size) void* __libc_calloc(size_t count, size_t size) MI_FORWARD2(mi_calloc,count,size) void* __libc_realloc(void* p, size_t size) MI_FORWARD2(mi_realloc,p,size) diff --git a/src/dashbls/depends/mimalloc/src/alloc-posix.c b/src/dashbls/depends/mimalloc/src/alloc-posix.c index 57e15d05d8db..225752fd8707 100644 --- a/src/dashbls/depends/mimalloc/src/alloc-posix.c +++ b/src/dashbls/depends/mimalloc/src/alloc-posix.c @@ -10,7 +10,7 @@ terms of the MIT license. A copy of the license can be found in the file // for convenience and used when overriding these functions. // ------------------------------------------------------------------------ #include "mimalloc.h" -#include "mimalloc-internal.h" +#include "mimalloc/internal.h" // ------------------------------------------------------ // Posix & Unix functions definitions @@ -33,12 +33,12 @@ terms of the MIT license. A copy of the license can be found in the file mi_decl_nodiscard size_t mi_malloc_size(const void* p) mi_attr_noexcept { - //if (!mi_is_in_heap_region(p)) return 0; + // if (!mi_is_in_heap_region(p)) return 0; return mi_usable_size(p); } mi_decl_nodiscard size_t mi_malloc_usable_size(const void *p) mi_attr_noexcept { - //if (!mi_is_in_heap_region(p)) return 0; + // if (!mi_is_in_heap_region(p)) return 0; return mi_usable_size(p); } @@ -56,7 +56,8 @@ int mi_posix_memalign(void** p, size_t alignment, size_t size) mi_attr_noexcept // Note: The spec dictates we should not modify `*p` on an error. (issue#27) // if (p == NULL) return EINVAL; - if (alignment % sizeof(void*) != 0) return EINVAL; // natural alignment + if ((alignment % sizeof(void*)) != 0) return EINVAL; // natural alignment + // it is also required that alignment is a power of 2 and > 0; this is checked in `mi_malloc_aligned` if (alignment==0 || !_mi_is_power_of_two(alignment)) return EINVAL; // not a power of 2 void* q = mi_malloc_aligned(size, alignment); if (q==NULL && size != 0) return ENOMEM; @@ -91,7 +92,7 @@ mi_decl_nodiscard mi_decl_restrict void* mi_aligned_alloc(size_t alignment, size #endif return NULL; } - */ + */ // C11 also requires alignment to be a power-of-two (and > 0) which is checked in mi_malloc_aligned void* p = mi_malloc_aligned(size, alignment); mi_assert_internal(((uintptr_t)p % alignment) == 0); @@ -110,7 +111,7 @@ mi_decl_nodiscard int mi_reallocarr( void* p, size_t count, size_t size ) mi_att errno = EINVAL; return EINVAL; } - void** op = (void**)p; + void** op = (void**)p; void* newp = mi_reallocarray(*op, count, size); if mi_unlikely(newp == NULL) { return errno; } *op = newp; @@ -149,7 +150,7 @@ int mi_dupenv_s(char** buf, size_t* size, const char* name) mi_attr_noexcept { else { *buf = mi_strdup(p); if (*buf==NULL) return ENOMEM; - if (size != NULL) *size = strlen(p); + if (size != NULL) *size = _mi_strlen(p); } return 0; } diff --git a/src/dashbls/depends/mimalloc/src/alloc.c b/src/dashbls/depends/mimalloc/src/alloc.c index 02d009e2f7d4..3e912726ff46 100644 --- a/src/dashbls/depends/mimalloc/src/alloc.c +++ b/src/dashbls/depends/mimalloc/src/alloc.c @@ -1,5 +1,5 @@ /* ---------------------------------------------------------------------------- -Copyright (c) 2018-2022, Microsoft Research, Daan Leijen +Copyright (c) 2018-2024, Microsoft Research, Daan Leijen This is free software; you can redistribute it and/or modify it under the terms of the MIT license. A copy of the license can be found in the file "LICENSE" at the root of this distribution. @@ -9,15 +9,16 @@ terms of the MIT license. A copy of the license can be found in the file #endif #include "mimalloc.h" -#include "mimalloc-internal.h" -#include "mimalloc-atomic.h" +#include "mimalloc/internal.h" +#include "mimalloc/atomic.h" +#include "mimalloc/prim.h" // _mi_prim_thread_id() - -#include // memset, strlen -#include // malloc, exit +#include // memset, strlen (for mi_strdup) +#include // malloc, abort #define MI_IN_ALLOC_C #include "alloc-override.c" +#include "free.c" #undef MI_IN_ALLOC_C // ------------------------------------------------------ @@ -26,84 +27,135 @@ terms of the MIT license. A copy of the license can be found in the file // Fast allocation in a page: just pop from the free list. // Fall back to generic allocation only if the list is empty. -extern inline void* _mi_page_malloc(mi_heap_t* heap, mi_page_t* page, size_t size, bool zero) mi_attr_noexcept { - mi_assert_internal(page->xblock_size==0||mi_page_block_size(page) >= size); +// Note: in release mode the (inlined) routine is about 7 instructions with a single test. +extern inline void* _mi_page_malloc_zero(mi_heap_t* heap, mi_page_t* page, size_t size, bool zero) mi_attr_noexcept +{ + if (page->block_size != 0) { // not the empty heap + mi_assert_internal(mi_page_block_size(page) >= size); + mi_assert_internal(_mi_is_aligned(page, MI_PAGE_ALIGN)); + mi_assert_internal(_mi_ptr_page(page)==page); + } + + // check the free list mi_block_t* const block = page->free; if mi_unlikely(block == NULL) { - return _mi_malloc_generic(heap, size, zero); + return _mi_malloc_generic(heap, size, zero, 0); } mi_assert_internal(block != NULL && _mi_ptr_page(block) == page); + // pop from the free list - page->used++; page->free = mi_block_next(page, block); + page->used++; mi_assert_internal(page->free == NULL || _mi_ptr_page(page->free) == page); + mi_assert_internal(page->block_size < MI_MAX_ALIGN_SIZE || _mi_is_aligned(block, MI_MAX_ALIGN_SIZE)); + + #if MI_DEBUG>3 + if (page->free_is_zero && size > sizeof(*block)) { + mi_assert_expensive(mi_mem_is_zero(block+1,size - sizeof(*block))); + } + #endif - // allow use of the block internally + // allow use of the block internally // note: when tracking we need to avoid ever touching the MI_PADDING since - // that is tracked by valgrind etc. as non-accessible (through the red-zone, see `mimalloc-track.h`) + // that is tracked by valgrind etc. as non-accessible (through the red-zone, see `mimalloc/track.h`) mi_track_mem_undefined(block, mi_page_usable_block_size(page)); - + // zero the block? note: we need to zero the full block size (issue #63) if mi_unlikely(zero) { - mi_assert_internal(page->xblock_size != 0); // do not call with zero'ing for huge blocks (see _mi_malloc_generic) - const size_t zsize = (page->is_zero ? sizeof(block->next) + MI_PADDING_SIZE : page->xblock_size); - _mi_memzero_aligned(block, zsize - MI_PADDING_SIZE); + mi_assert_internal(page->block_size != 0); // do not call with zero'ing for huge blocks (see _mi_malloc_generic) + mi_assert_internal(!mi_page_is_huge(page)); + #if MI_PADDING + mi_assert_internal(page->block_size >= MI_PADDING_SIZE); + #endif + if (page->free_is_zero) { + block->next = 0; + mi_track_mem_defined(block, page->block_size - MI_PADDING_SIZE); + } + else { + _mi_memzero_aligned(block, page->block_size - MI_PADDING_SIZE); + } } -#if (MI_DEBUG>0) && !MI_TRACK_ENABLED - if (!page->is_zero && !zero) { memset(block, MI_DEBUG_UNINIT, mi_page_usable_block_size(page)); } -#elif (MI_SECURE!=0) + #if (MI_DEBUG>0) && !MI_TRACK_ENABLED && !MI_TSAN + if (!zero && !mi_page_is_huge(page)) { + memset(block, MI_DEBUG_UNINIT, mi_page_usable_block_size(page)); + } + #elif (MI_SECURE!=0) if (!zero) { block->next = 0; } // don't leak internal data -#endif + #endif -#if (MI_STAT>0) + #if (MI_STAT>0) const size_t bsize = mi_page_usable_block_size(page); - if (bsize <= MI_MEDIUM_OBJ_SIZE_MAX) { - mi_heap_stat_increase(heap, normal, bsize); - mi_heap_stat_counter_increase(heap, normal_count, 1); -#if (MI_STAT>1) + if (bsize <= MI_LARGE_MAX_OBJ_SIZE) { + mi_heap_stat_increase(heap, malloc_normal, bsize); + mi_heap_stat_counter_increase(heap, malloc_normal_count, 1); + #if (MI_STAT>1) const size_t bin = _mi_bin(bsize); - mi_heap_stat_increase(heap, normal_bins[bin], 1); -#endif + mi_heap_stat_increase(heap, malloc_bins[bin], 1); + mi_heap_stat_increase(heap, malloc_requested, size - MI_PADDING_SIZE); + #endif } -#endif + #endif -#if (MI_PADDING > 0) && defined(MI_ENCODE_FREELIST) && !MI_TRACK_ENABLED - mi_padding_t* const padding = (mi_padding_t*)((uint8_t*)block + mi_page_usable_block_size(page)); - ptrdiff_t delta = ((uint8_t*)padding - (uint8_t*)block - (size - MI_PADDING_SIZE)); - #if (MI_DEBUG>1) - mi_assert_internal(delta >= 0 && mi_page_usable_block_size(page) >= (size - MI_PADDING_SIZE + delta)); - mi_track_mem_defined(padding,sizeof(mi_padding_t)); // note: re-enable since mi_page_usable_block_size may set noaccess + #if MI_PADDING // && !MI_TRACK_ENABLED + mi_padding_t* const padding = (mi_padding_t*)((uint8_t*)block + mi_page_usable_block_size(page)); + ptrdiff_t delta = ((uint8_t*)padding - (uint8_t*)block - (size - MI_PADDING_SIZE)); + #if (MI_DEBUG>=2) + mi_assert_internal(delta >= 0 && mi_page_usable_block_size(page) >= (size - MI_PADDING_SIZE + delta)); + #endif + mi_track_mem_defined(padding,sizeof(mi_padding_t)); // note: re-enable since mi_page_usable_block_size may set noaccess + padding->canary = mi_ptr_encode_canary(page,block,page->keys); + padding->delta = (uint32_t)(delta); + #if MI_PADDING_CHECK + if (!mi_page_is_huge(page)) { + uint8_t* fill = (uint8_t*)padding - delta; + const size_t maxpad = (delta > MI_MAX_ALIGN_SIZE ? MI_MAX_ALIGN_SIZE : delta); // set at most N initial padding bytes + for (size_t i = 0; i < maxpad; i++) { fill[i] = MI_DEBUG_PADDING; } + } + #endif #endif - padding->canary = (uint32_t)(mi_ptr_encode(page,block,page->keys)); - padding->delta = (uint32_t)(delta); - uint8_t* fill = (uint8_t*)padding - delta; - const size_t maxpad = (delta > MI_MAX_ALIGN_SIZE ? MI_MAX_ALIGN_SIZE : delta); // set at most N initial padding bytes - for (size_t i = 0; i < maxpad; i++) { fill[i] = MI_DEBUG_PADDING; } -#endif return block; } +// extra entries for improved efficiency in `alloc-aligned.c`. +extern void* _mi_page_malloc(mi_heap_t* heap, mi_page_t* page, size_t size) mi_attr_noexcept { + return _mi_page_malloc_zero(heap,page,size,false); +} +extern void* _mi_page_malloc_zeroed(mi_heap_t* heap, mi_page_t* page, size_t size) mi_attr_noexcept { + return _mi_page_malloc_zero(heap,page,size,true); +} + +#if MI_GUARDED +mi_decl_restrict void* _mi_heap_malloc_guarded(mi_heap_t* heap, size_t size, bool zero) mi_attr_noexcept; +#endif + static inline mi_decl_restrict void* mi_heap_malloc_small_zero(mi_heap_t* heap, size_t size, bool zero) mi_attr_noexcept { mi_assert(heap != NULL); - mi_assert(heap->thread_id == 0 || heap->thread_id == _mi_thread_id()); // heaps are thread local mi_assert(size <= MI_SMALL_SIZE_MAX); -#if (MI_PADDING) - if (size == 0) { - size = sizeof(void*); + #if MI_DEBUG + const uintptr_t tid = _mi_thread_id(); + mi_assert(heap->tld->thread_id == 0 || heap->tld->thread_id == tid); // heaps are thread local + #endif + #if (MI_PADDING || MI_GUARDED) + if (size == 0) { size = sizeof(void*); } + #endif + #if MI_GUARDED + if (mi_heap_malloc_use_guarded(heap,size)) { + return _mi_heap_malloc_guarded(heap, size, zero); } -#endif + #endif + + // get page in constant time, and allocate from it mi_page_t* page = _mi_heap_get_free_small_page(heap, size + MI_PADDING_SIZE); - void* p = _mi_page_malloc(heap, page, size + MI_PADDING_SIZE, zero); - mi_assert_internal(p == NULL || mi_usable_size(p) >= size); -#if MI_STAT>1 - if (p != NULL) { - if (!mi_heap_is_initialized(heap)) { heap = mi_get_default_heap(); } - mi_heap_stat_increase(heap, malloc, mi_usable_size(p)); - } -#endif + void* const p = _mi_page_malloc_zero(heap, page, size + MI_PADDING_SIZE, zero); mi_track_malloc(p,size,zero); + + #if MI_DEBUG>3 + if (p != NULL && zero) { + mi_assert_expensive(mi_mem_is_zero(p, size)); + } + #endif return p; } @@ -113,41 +165,52 @@ mi_decl_nodiscard extern inline mi_decl_restrict void* mi_heap_malloc_small(mi_h } mi_decl_nodiscard extern inline mi_decl_restrict void* mi_malloc_small(size_t size) mi_attr_noexcept { - return mi_heap_malloc_small(mi_get_default_heap(), size); + return mi_heap_malloc_small(mi_prim_get_default_heap(), size); } // The main allocation function -extern inline void* _mi_heap_malloc_zero(mi_heap_t* heap, size_t size, bool zero) mi_attr_noexcept { +extern inline void* _mi_heap_malloc_zero_ex(mi_heap_t* heap, size_t size, bool zero, size_t huge_alignment) mi_attr_noexcept { + // fast path for small objects if mi_likely(size <= MI_SMALL_SIZE_MAX) { + mi_assert_internal(huge_alignment == 0); return mi_heap_malloc_small_zero(heap, size, zero); } + #if MI_GUARDED + else if (huge_alignment==0 && mi_heap_malloc_use_guarded(heap,size)) { + return _mi_heap_malloc_guarded(heap, size, zero); + } + #endif else { + // regular allocation mi_assert(heap!=NULL); - mi_assert(heap->thread_id == 0 || heap->thread_id == _mi_thread_id()); // heaps are thread local - void* const p = _mi_malloc_generic(heap, size + MI_PADDING_SIZE, zero); // note: size can overflow but it is detected in malloc_generic - mi_assert_internal(p == NULL || mi_usable_size(p) >= size); - #if MI_STAT>1 - if (p != NULL) { - if (!mi_heap_is_initialized(heap)) { heap = mi_get_default_heap(); } - mi_heap_stat_increase(heap, malloc, mi_usable_size(p)); + mi_assert(heap->tld->thread_id == 0 || heap->tld->thread_id == _mi_thread_id()); // heaps are thread local + void* const p = _mi_malloc_generic(heap, size + MI_PADDING_SIZE, zero, huge_alignment); // note: size can overflow but it is detected in malloc_generic + mi_track_malloc(p,size,zero); + + #if MI_DEBUG>3 + if (p != NULL && zero) { + mi_assert_expensive(mi_mem_is_zero(p, size)); } #endif - mi_track_malloc(p,size,zero); return p; } } +extern inline void* _mi_heap_malloc_zero(mi_heap_t* heap, size_t size, bool zero) mi_attr_noexcept { + return _mi_heap_malloc_zero_ex(heap, size, zero, 0); +} + mi_decl_nodiscard extern inline mi_decl_restrict void* mi_heap_malloc(mi_heap_t* heap, size_t size) mi_attr_noexcept { return _mi_heap_malloc_zero(heap, size, false); } mi_decl_nodiscard extern inline mi_decl_restrict void* mi_malloc(size_t size) mi_attr_noexcept { - return mi_heap_malloc(mi_get_default_heap(), size); + return mi_heap_malloc(mi_prim_get_default_heap(), size); } // zero initialized small block mi_decl_nodiscard mi_decl_restrict void* mi_zalloc_small(size_t size) mi_attr_noexcept { - return mi_heap_malloc_small_zero(mi_get_default_heap(), size, true); + return mi_heap_malloc_small_zero(mi_prim_get_default_heap(), size, true); } mi_decl_nodiscard extern inline mi_decl_restrict void* mi_heap_zalloc(mi_heap_t* heap, size_t size) mi_attr_noexcept { @@ -155,467 +218,9 @@ mi_decl_nodiscard extern inline mi_decl_restrict void* mi_heap_zalloc(mi_heap_t* } mi_decl_nodiscard mi_decl_restrict void* mi_zalloc(size_t size) mi_attr_noexcept { - return mi_heap_zalloc(mi_get_default_heap(),size); -} - - -// ------------------------------------------------------ -// Check for double free in secure and debug mode -// This is somewhat expensive so only enabled for secure mode 4 -// ------------------------------------------------------ - -#if (MI_ENCODE_FREELIST && (MI_SECURE>=4 || MI_DEBUG!=0)) -// linear check if the free list contains a specific element -static bool mi_list_contains(const mi_page_t* page, const mi_block_t* list, const mi_block_t* elem) { - while (list != NULL) { - if (elem==list) return true; - list = mi_block_next(page, list); - } - return false; -} - -static mi_decl_noinline bool mi_check_is_double_freex(const mi_page_t* page, const mi_block_t* block) { - // The decoded value is in the same page (or NULL). - // Walk the free lists to verify positively if it is already freed - if (mi_list_contains(page, page->free, block) || - mi_list_contains(page, page->local_free, block) || - mi_list_contains(page, mi_page_thread_free(page), block)) - { - _mi_error_message(EAGAIN, "double free detected of block %p with size %zu\n", block, mi_page_block_size(page)); - return true; - } - return false; -} - -#define mi_track_page(page,access) { size_t psize; void* pstart = _mi_page_start(_mi_page_segment(page),page,&psize); mi_track_mem_##access( pstart, psize); } - -static inline bool mi_check_is_double_free(const mi_page_t* page, const mi_block_t* block) { - bool is_double_free = false; - mi_block_t* n = mi_block_nextx(page, block, page->keys); // pretend it is freed, and get the decoded first field - if (((uintptr_t)n & (MI_INTPTR_SIZE-1))==0 && // quick check: aligned pointer? - (n==NULL || mi_is_in_same_page(block, n))) // quick check: in same page or NULL? - { - // Suspicous: decoded value a in block is in the same page (or NULL) -- maybe a double free? - // (continue in separate function to improve code generation) - is_double_free = mi_check_is_double_freex(page, block); - } - return is_double_free; -} -#else -static inline bool mi_check_is_double_free(const mi_page_t* page, const mi_block_t* block) { - MI_UNUSED(page); - MI_UNUSED(block); - return false; -} -#endif - -// --------------------------------------------------------------------------- -// Check for heap block overflow by setting up padding at the end of the block -// --------------------------------------------------------------------------- - -#if (MI_PADDING>0) && defined(MI_ENCODE_FREELIST) && !MI_TRACK_ENABLED -static bool mi_page_decode_padding(const mi_page_t* page, const mi_block_t* block, size_t* delta, size_t* bsize) { - *bsize = mi_page_usable_block_size(page); - const mi_padding_t* const padding = (mi_padding_t*)((uint8_t*)block + *bsize); - mi_track_mem_defined(padding,sizeof(mi_padding_t)); - *delta = padding->delta; - uint32_t canary = padding->canary; - uintptr_t keys[2]; - keys[0] = page->keys[0]; - keys[1] = page->keys[1]; - bool ok = ((uint32_t)mi_ptr_encode(page,block,keys) == canary && *delta <= *bsize); - mi_track_mem_noaccess(padding,sizeof(mi_padding_t)); - return ok; -} - -// Return the exact usable size of a block. -static size_t mi_page_usable_size_of(const mi_page_t* page, const mi_block_t* block) { - size_t bsize; - size_t delta; - bool ok = mi_page_decode_padding(page, block, &delta, &bsize); - mi_assert_internal(ok); mi_assert_internal(delta <= bsize); - return (ok ? bsize - delta : 0); -} - -static bool mi_verify_padding(const mi_page_t* page, const mi_block_t* block, size_t* size, size_t* wrong) { - size_t bsize; - size_t delta; - bool ok = mi_page_decode_padding(page, block, &delta, &bsize); - *size = *wrong = bsize; - if (!ok) return false; - mi_assert_internal(bsize >= delta); - *size = bsize - delta; - uint8_t* fill = (uint8_t*)block + bsize - delta; - const size_t maxpad = (delta > MI_MAX_ALIGN_SIZE ? MI_MAX_ALIGN_SIZE : delta); // check at most the first N padding bytes - mi_track_mem_defined(fill,maxpad); - for (size_t i = 0; i < maxpad; i++) { - if (fill[i] != MI_DEBUG_PADDING) { - *wrong = bsize - delta + i; - ok = false; - break; - } - } - mi_track_mem_noaccess(fill,maxpad); - return ok; -} - -static void mi_check_padding(const mi_page_t* page, const mi_block_t* block) { - size_t size; - size_t wrong; - if (!mi_verify_padding(page,block,&size,&wrong)) { - _mi_error_message(EFAULT, "buffer overflow in heap block %p of size %zu: write after %zu bytes\n", block, size, wrong ); - } -} - -// When a non-thread-local block is freed, it becomes part of the thread delayed free -// list that is freed later by the owning heap. If the exact usable size is too small to -// contain the pointer for the delayed list, then shrink the padding (by decreasing delta) -// so it will later not trigger an overflow error in `mi_free_block`. -static void mi_padding_shrink(const mi_page_t* page, const mi_block_t* block, const size_t min_size) { - size_t bsize; - size_t delta; - bool ok = mi_page_decode_padding(page, block, &delta, &bsize); - mi_assert_internal(ok); - if (!ok || (bsize - delta) >= min_size) return; // usually already enough space - mi_assert_internal(bsize >= min_size); - if (bsize < min_size) return; // should never happen - size_t new_delta = (bsize - min_size); - mi_assert_internal(new_delta < bsize); - mi_padding_t* padding = (mi_padding_t*)((uint8_t*)block + bsize); - padding->delta = (uint32_t)new_delta; -} -#else -static void mi_check_padding(const mi_page_t* page, const mi_block_t* block) { - MI_UNUSED(page); - MI_UNUSED(block); -} - -static size_t mi_page_usable_size_of(const mi_page_t* page, const mi_block_t* block) { - MI_UNUSED(block); - return mi_page_usable_block_size(page); -} - -static void mi_padding_shrink(const mi_page_t* page, const mi_block_t* block, const size_t min_size) { - MI_UNUSED(page); - MI_UNUSED(block); - MI_UNUSED(min_size); -} -#endif - -// only maintain stats for smaller objects if requested -#if (MI_STAT>0) -static void mi_stat_free(const mi_page_t* page, const mi_block_t* block) { - #if (MI_STAT < 2) - MI_UNUSED(block); - #endif - mi_heap_t* const heap = mi_heap_get_default(); - const size_t bsize = mi_page_usable_block_size(page); - #if (MI_STAT>1) - const size_t usize = mi_page_usable_size_of(page, block); - mi_heap_stat_decrease(heap, malloc, usize); - #endif - if (bsize <= MI_MEDIUM_OBJ_SIZE_MAX) { - mi_heap_stat_decrease(heap, normal, bsize); - #if (MI_STAT > 1) - mi_heap_stat_decrease(heap, normal_bins[_mi_bin(bsize)], 1); - #endif - } - else if (bsize <= MI_LARGE_OBJ_SIZE_MAX) { - mi_heap_stat_decrease(heap, large, bsize); - } - else { - mi_heap_stat_decrease(heap, huge, bsize); - } -} -#else -static void mi_stat_free(const mi_page_t* page, const mi_block_t* block) { - MI_UNUSED(page); MI_UNUSED(block); -} -#endif - -#if (MI_STAT>0) -// maintain stats for huge objects -static void mi_stat_huge_free(const mi_page_t* page) { - mi_heap_t* const heap = mi_heap_get_default(); - const size_t bsize = mi_page_block_size(page); // to match stats in `page.c:mi_page_huge_alloc` - if (bsize <= MI_LARGE_OBJ_SIZE_MAX) { - mi_heap_stat_decrease(heap, large, bsize); - } - else { - mi_heap_stat_decrease(heap, huge, bsize); - } -} -#else -static void mi_stat_huge_free(const mi_page_t* page) { - MI_UNUSED(page); -} -#endif - -// ------------------------------------------------------ -// Free -// ------------------------------------------------------ - -// multi-threaded free (or free in huge block) -static mi_decl_noinline void _mi_free_block_mt(mi_page_t* page, mi_block_t* block) -{ - // The padding check may access the non-thread-owned page for the key values. - // that is safe as these are constant and the page won't be freed (as the block is not freed yet). - mi_check_padding(page, block); - mi_padding_shrink(page, block, sizeof(mi_block_t)); // for small size, ensure we can fit the delayed thread pointers without triggering overflow detection - #if (MI_DEBUG!=0) && !MI_TRACK_ENABLED // note: when tracking, cannot use mi_usable_size with multi-threading - memset(block, MI_DEBUG_FREED, mi_usable_size(block)); - #endif - - // huge page segments are always abandoned and can be freed immediately - mi_segment_t* segment = _mi_page_segment(page); - if (segment->kind==MI_SEGMENT_HUGE) { - mi_stat_huge_free(page); - _mi_segment_huge_page_free(segment, page, block); - return; - } - - // Try to put the block on either the page-local thread free list, or the heap delayed free list. - mi_thread_free_t tfreex; - bool use_delayed; - mi_thread_free_t tfree = mi_atomic_load_relaxed(&page->xthread_free); - do { - use_delayed = (mi_tf_delayed(tfree) == MI_USE_DELAYED_FREE); - if mi_unlikely(use_delayed) { - // unlikely: this only happens on the first concurrent free in a page that is in the full list - tfreex = mi_tf_set_delayed(tfree,MI_DELAYED_FREEING); - } - else { - // usual: directly add to page thread_free list - mi_block_set_next(page, block, mi_tf_block(tfree)); - tfreex = mi_tf_set_block(tfree,block); - } - } while (!mi_atomic_cas_weak_release(&page->xthread_free, &tfree, tfreex)); - - if mi_unlikely(use_delayed) { - // racy read on `heap`, but ok because MI_DELAYED_FREEING is set (see `mi_heap_delete` and `mi_heap_collect_abandon`) - mi_heap_t* const heap = (mi_heap_t*)(mi_atomic_load_acquire(&page->xheap)); //mi_page_heap(page); - mi_assert_internal(heap != NULL); - if (heap != NULL) { - // add to the delayed free list of this heap. (do this atomically as the lock only protects heap memory validity) - mi_block_t* dfree = mi_atomic_load_ptr_relaxed(mi_block_t, &heap->thread_delayed_free); - do { - mi_block_set_nextx(heap,block,dfree, heap->keys); - } while (!mi_atomic_cas_ptr_weak_release(mi_block_t,&heap->thread_delayed_free, &dfree, block)); - } - - // and reset the MI_DELAYED_FREEING flag - tfree = mi_atomic_load_relaxed(&page->xthread_free); - do { - tfreex = tfree; - mi_assert_internal(mi_tf_delayed(tfree) == MI_DELAYED_FREEING); - tfreex = mi_tf_set_delayed(tfree,MI_NO_DELAYED_FREE); - } while (!mi_atomic_cas_weak_release(&page->xthread_free, &tfree, tfreex)); - } -} - -// regular free -static inline void _mi_free_block(mi_page_t* page, bool local, mi_block_t* block) -{ - // and push it on the free list - //const size_t bsize = mi_page_block_size(page); - if mi_likely(local) { - // owning thread can free a block directly - if mi_unlikely(mi_check_is_double_free(page, block)) return; - mi_check_padding(page, block); - #if (MI_DEBUG!=0) && !MI_TRACK_ENABLED - memset(block, MI_DEBUG_FREED, mi_page_block_size(page)); - #endif - mi_block_set_next(page, block, page->local_free); - page->local_free = block; - page->used--; - if mi_unlikely(mi_page_all_free(page)) { - _mi_page_retire(page); - } - else if mi_unlikely(mi_page_is_in_full(page)) { - _mi_page_unfull(page); - } - } - else { - _mi_free_block_mt(page,block); - } -} - - -// Adjust a block that was allocated aligned, to the actual start of the block in the page. -mi_block_t* _mi_page_ptr_unalign(const mi_segment_t* segment, const mi_page_t* page, const void* p) { - mi_assert_internal(page!=NULL && p!=NULL); - const size_t diff = (uint8_t*)p - _mi_page_start(segment, page, NULL); - const size_t adjust = (diff % mi_page_block_size(page)); - return (mi_block_t*)((uintptr_t)p - adjust); -} - - -static void mi_decl_noinline mi_free_generic(const mi_segment_t* segment, bool local, void* p) mi_attr_noexcept { - mi_page_t* const page = _mi_segment_page_of(segment, p); - mi_block_t* const block = (mi_page_has_aligned(page) ? _mi_page_ptr_unalign(segment, page, p) : (mi_block_t*)p); - mi_stat_free(page, block); // stat_free may access the padding - mi_track_free(p); - _mi_free_block(page, local, block); -} - -// Get the segment data belonging to a pointer -// This is just a single `and` in assembly but does further checks in debug mode -// (and secure mode) if this was a valid pointer. -static inline mi_segment_t* mi_checked_ptr_segment(const void* p, const char* msg) -{ - MI_UNUSED(msg); -#if (MI_DEBUG>0) - if mi_unlikely(((uintptr_t)p & (MI_INTPTR_SIZE - 1)) != 0) { - _mi_error_message(EINVAL, "%s: invalid (unaligned) pointer: %p\n", msg, p); - return NULL; - } -#endif - - mi_segment_t* const segment = _mi_ptr_segment(p); - if mi_unlikely(segment == NULL) return NULL; // checks also for (p==NULL) - -#if (MI_DEBUG>0) - if mi_unlikely(!mi_is_in_heap_region(p)) { - _mi_warning_message("%s: pointer might not point to a valid heap region: %p\n" - "(this may still be a valid very large allocation (over 64MiB))\n", msg, p); - if mi_likely(_mi_ptr_cookie(segment) == segment->cookie) { - _mi_warning_message("(yes, the previous pointer %p was valid after all)\n", p); - } - } -#endif -#if (MI_DEBUG>0 || MI_SECURE>=4) - if mi_unlikely(_mi_ptr_cookie(segment) != segment->cookie) { - _mi_error_message(EINVAL, "%s: pointer does not point to a valid heap space: %p\n", msg, p); - return NULL; - } -#endif - return segment; -} - -// Free a block -void mi_free(void* p) mi_attr_noexcept -{ - mi_segment_t* const segment = mi_checked_ptr_segment(p,"mi_free"); - if mi_unlikely(segment == NULL) return; - - mi_threadid_t tid = _mi_thread_id(); - mi_page_t* const page = _mi_segment_page_of(segment, p); - - if mi_likely(tid == mi_atomic_load_relaxed(&segment->thread_id) && page->flags.full_aligned == 0) { // the thread id matches and it is not a full page, nor has aligned blocks - // local, and not full or aligned - mi_block_t* block = (mi_block_t*)(p); - if mi_unlikely(mi_check_is_double_free(page,block)) return; - mi_check_padding(page, block); - mi_stat_free(page, block); - #if (MI_DEBUG!=0) && !MI_TRACK_ENABLED - memset(block, MI_DEBUG_FREED, mi_page_block_size(page)); - #endif - mi_track_free(p); - mi_block_set_next(page, block, page->local_free); - page->local_free = block; - if mi_unlikely(--page->used == 0) { // using this expression generates better code than: page->used--; if (mi_page_all_free(page)) - _mi_page_retire(page); - } - } - else { - // non-local, aligned blocks, or a full page; use the more generic path - // note: recalc page in generic to improve code generation - mi_free_generic(segment, tid == segment->thread_id, p); - } -} - -// return true if successful -bool _mi_free_delayed_block(mi_block_t* block) { - // get segment and page - const mi_segment_t* const segment = _mi_ptr_segment(block); - mi_assert_internal(_mi_ptr_cookie(segment) == segment->cookie); - mi_assert_internal(_mi_thread_id() == segment->thread_id); - mi_page_t* const page = _mi_segment_page_of(segment, block); - - // Clear the no-delayed flag so delayed freeing is used again for this page. - // This must be done before collecting the free lists on this page -- otherwise - // some blocks may end up in the page `thread_free` list with no blocks in the - // heap `thread_delayed_free` list which may cause the page to be never freed! - // (it would only be freed if we happen to scan it in `mi_page_queue_find_free_ex`) - if (!_mi_page_try_use_delayed_free(page, MI_USE_DELAYED_FREE, false /* dont overwrite never delayed */)) { - return false; - } - - // collect all other non-local frees to ensure up-to-date `used` count - _mi_page_free_collect(page, false); - - // and free the block (possibly freeing the page as well since used is updated) - _mi_free_block(page, true, block); - return true; -} - -// Bytes available in a block -mi_decl_noinline static size_t mi_page_usable_aligned_size_of(const mi_segment_t* segment, const mi_page_t* page, const void* p) mi_attr_noexcept { - const mi_block_t* block = _mi_page_ptr_unalign(segment, page, p); - const size_t size = mi_page_usable_size_of(page, block); - const ptrdiff_t adjust = (uint8_t*)p - (uint8_t*)block; - mi_assert_internal(adjust >= 0 && (size_t)adjust <= size); - return (size - adjust); -} - -static inline size_t _mi_usable_size(const void* p, const char* msg) mi_attr_noexcept { - const mi_segment_t* const segment = mi_checked_ptr_segment(p, msg); - if (segment==NULL) return 0; // also returns 0 if `p == NULL` - const mi_page_t* const page = _mi_segment_page_of(segment, p); - if mi_likely(!mi_page_has_aligned(page)) { - const mi_block_t* block = (const mi_block_t*)p; - return mi_page_usable_size_of(page, block); - } - else { - // split out to separate routine for improved code generation - return mi_page_usable_aligned_size_of(segment, page, p); - } -} - -mi_decl_nodiscard size_t mi_usable_size(const void* p) mi_attr_noexcept { - return _mi_usable_size(p, "mi_usable_size"); -} - - -// ------------------------------------------------------ -// ensure explicit external inline definitions are emitted! -// ------------------------------------------------------ - -#ifdef __cplusplus -void* _mi_externs[] = { - (void*)&_mi_page_malloc, - (void*)&_mi_heap_malloc_zero, - (void*)&mi_malloc, - (void*)&mi_malloc_small, - (void*)&mi_zalloc_small, - (void*)&mi_heap_malloc, - (void*)&mi_heap_zalloc, - (void*)&mi_heap_malloc_small -}; -#endif - - -// ------------------------------------------------------ -// Allocation extensions -// ------------------------------------------------------ - -void mi_free_size(void* p, size_t size) mi_attr_noexcept { - MI_UNUSED_RELEASE(size); - mi_assert(p == NULL || size <= _mi_usable_size(p,"mi_free_size")); - mi_free(p); + return mi_heap_zalloc(mi_prim_get_default_heap(),size); } -void mi_free_size_aligned(void* p, size_t size, size_t alignment) mi_attr_noexcept { - MI_UNUSED_RELEASE(alignment); - mi_assert(((uintptr_t)p % alignment) == 0); - mi_free_size(p,size); -} - -void mi_free_aligned(void* p, size_t alignment) mi_attr_noexcept { - MI_UNUSED_RELEASE(alignment); - mi_assert(((uintptr_t)p % alignment) == 0); - mi_free(p); -} mi_decl_nodiscard extern inline mi_decl_restrict void* mi_heap_calloc(mi_heap_t* heap, size_t count, size_t size) mi_attr_noexcept { size_t total; @@ -624,7 +229,7 @@ mi_decl_nodiscard extern inline mi_decl_restrict void* mi_heap_calloc(mi_heap_t* } mi_decl_nodiscard mi_decl_restrict void* mi_calloc(size_t count, size_t size) mi_attr_noexcept { - return mi_heap_calloc(mi_get_default_heap(),count,size); + return mi_heap_calloc(mi_prim_get_default_heap(),count,size); } // Uninitialized `calloc` @@ -635,13 +240,13 @@ mi_decl_nodiscard extern mi_decl_restrict void* mi_heap_mallocn(mi_heap_t* heap, } mi_decl_nodiscard mi_decl_restrict void* mi_mallocn(size_t count, size_t size) mi_attr_noexcept { - return mi_heap_mallocn(mi_get_default_heap(),count,size); + return mi_heap_mallocn(mi_prim_get_default_heap(),count,size); } // Expand (or shrink) in place (or fail) void* mi_expand(void* p, size_t newsize) mi_attr_noexcept { #if MI_PADDING - // we do not shrink/expand with padding enabled + // we do not shrink/expand with padding enabled MI_UNUSED(p); MI_UNUSED(newsize); return NULL; #else @@ -656,11 +261,12 @@ void* _mi_heap_realloc_zero(mi_heap_t* heap, void* p, size_t newsize, bool zero) // if p == NULL then behave as malloc. // else if size == 0 then reallocate to a zero-sized block (and don't return NULL, just as mi_malloc(0)). // (this means that returning NULL always indicates an error, and `p` will not have been freed in that case.) - const size_t size = _mi_usable_size(p,"mi_realloc"); // also works if p == NULL (with size 0) + const size_t size = (p==NULL ? 0 : _mi_usable_size(p,"mi_realloc")); if mi_unlikely(newsize <= size && newsize >= (size / 2) && newsize > 0) { // note: newsize must be > 0 or otherwise we return NULL for realloc(NULL,0) - // todo: adjust potential padding to reflect the new size? - mi_track_free(p); - mi_track_malloc(p,newsize,true); + mi_assert_internal(p!=NULL); + // todo: do not track as the usable size is still the same in the free; adjust potential padding? + // mi_track_resize(p,size,newsize) + // if (newsize < size) { mi_track_mem_noaccess((uint8_t*)p + newsize, size - newsize); } return p; // reallocation still fits and not more than 50% waste } void* newp = mi_heap_malloc(heap,newsize); @@ -668,14 +274,15 @@ void* _mi_heap_realloc_zero(mi_heap_t* heap, void* p, size_t newsize, bool zero) if (zero && newsize > size) { // also set last word in the previous allocation to zero to ensure any padding is zero-initialized const size_t start = (size >= sizeof(intptr_t) ? size - sizeof(intptr_t) : 0); - memset((uint8_t*)newp + start, 0, newsize - start); + _mi_memzero((uint8_t*)newp + start, newsize - start); + } + else if (newsize == 0) { + ((uint8_t*)newp)[0] = 0; // work around for applications that expect zero-reallocation to be zero initialized (issue #725) } if mi_likely(p != NULL) { - if mi_likely(_mi_is_aligned(p, sizeof(uintptr_t))) { // a client may pass in an arbitrary pointer `p`.. - const size_t copysize = (newsize > size ? size : newsize); - mi_track_mem_defined(p,copysize); // _mi_useable_size may be too large for byte precise memory tracking.. - _mi_memcpy_aligned(newp, p, copysize); - } + const size_t copysize = (newsize > size ? size : newsize); + mi_track_mem_defined(p,copysize); // _mi_useable_size may be too large for byte precise memory tracking.. + _mi_memcpy(newp, p, copysize); mi_free(p); // only free the original pointer if successful } } @@ -683,7 +290,7 @@ void* _mi_heap_realloc_zero(mi_heap_t* heap, void* p, size_t newsize, bool zero) } mi_decl_nodiscard void* mi_heap_realloc(mi_heap_t* heap, void* p, size_t newsize) mi_attr_noexcept { - return _mi_heap_realloc_zero(heap, p, newsize, false); + return _mi_heap_realloc_zero(heap, p, newsize, false); } mi_decl_nodiscard void* mi_heap_reallocn(mi_heap_t* heap, void* p, size_t count, size_t size) mi_attr_noexcept { @@ -712,24 +319,24 @@ mi_decl_nodiscard void* mi_heap_recalloc(mi_heap_t* heap, void* p, size_t count, mi_decl_nodiscard void* mi_realloc(void* p, size_t newsize) mi_attr_noexcept { - return mi_heap_realloc(mi_get_default_heap(),p,newsize); + return mi_heap_realloc(mi_prim_get_default_heap(),p,newsize); } mi_decl_nodiscard void* mi_reallocn(void* p, size_t count, size_t size) mi_attr_noexcept { - return mi_heap_reallocn(mi_get_default_heap(),p,count,size); + return mi_heap_reallocn(mi_prim_get_default_heap(),p,count,size); } // Reallocate but free `p` on errors mi_decl_nodiscard void* mi_reallocf(void* p, size_t newsize) mi_attr_noexcept { - return mi_heap_reallocf(mi_get_default_heap(),p,newsize); + return mi_heap_reallocf(mi_prim_get_default_heap(),p,newsize); } mi_decl_nodiscard void* mi_rezalloc(void* p, size_t newsize) mi_attr_noexcept { - return mi_heap_rezalloc(mi_get_default_heap(), p, newsize); + return mi_heap_rezalloc(mi_prim_get_default_heap(), p, newsize); } mi_decl_nodiscard void* mi_recalloc(void* p, size_t count, size_t size) mi_attr_noexcept { - return mi_heap_recalloc(mi_get_default_heap(), p, count, size); + return mi_heap_recalloc(mi_prim_get_default_heap(), p, count, size); } @@ -741,31 +348,31 @@ mi_decl_nodiscard void* mi_recalloc(void* p, size_t count, size_t size) mi_attr_ // `strdup` using mi_malloc mi_decl_nodiscard mi_decl_restrict char* mi_heap_strdup(mi_heap_t* heap, const char* s) mi_attr_noexcept { if (s == NULL) return NULL; - size_t n = strlen(s); - char* t = (char*)mi_heap_malloc(heap,n+1); - if (t != NULL) _mi_memcpy(t, s, n + 1); + size_t len = _mi_strlen(s); + char* t = (char*)mi_heap_malloc(heap,len+1); + if (t == NULL) return NULL; + _mi_memcpy(t, s, len); + t[len] = 0; return t; } mi_decl_nodiscard mi_decl_restrict char* mi_strdup(const char* s) mi_attr_noexcept { - return mi_heap_strdup(mi_get_default_heap(), s); + return mi_heap_strdup(mi_prim_get_default_heap(), s); } // `strndup` using mi_malloc mi_decl_nodiscard mi_decl_restrict char* mi_heap_strndup(mi_heap_t* heap, const char* s, size_t n) mi_attr_noexcept { if (s == NULL) return NULL; - const char* end = (const char*)memchr(s, 0, n); // find end of string in the first `n` characters (returns NULL if not found) - const size_t m = (end != NULL ? (size_t)(end - s) : n); // `m` is the minimum of `n` or the end-of-string - mi_assert_internal(m <= n); - char* t = (char*)mi_heap_malloc(heap, m+1); + const size_t len = _mi_strnlen(s,n); // len <= n + char* t = (char*)mi_heap_malloc(heap, len+1); if (t == NULL) return NULL; - _mi_memcpy(t, s, m); - t[m] = 0; + _mi_memcpy(t, s, len); + t[len] = 0; return t; } mi_decl_nodiscard mi_decl_restrict char* mi_strndup(const char* s, size_t n) mi_attr_noexcept { - return mi_heap_strndup(mi_get_default_heap(),s,n); + return mi_heap_strndup(mi_prim_get_default_heap(),s,n); } #ifndef __wasi__ @@ -774,7 +381,7 @@ mi_decl_nodiscard mi_decl_restrict char* mi_strndup(const char* s, size_t n) mi_ #ifndef PATH_MAX #define PATH_MAX MAX_PATH #endif -#include + mi_decl_nodiscard mi_decl_restrict char* mi_heap_realpath(mi_heap_t* heap, const char* fname, char* resolved_name) mi_attr_noexcept { // todo: use GetFullPathNameW to allow longer file names char buf[PATH_MAX]; @@ -793,6 +400,7 @@ mi_decl_nodiscard mi_decl_restrict char* mi_heap_realpath(mi_heap_t* heap, const } } #else +/* #include // pathconf static size_t mi_path_max(void) { static size_t path_max = 0; @@ -804,25 +412,37 @@ static size_t mi_path_max(void) { } return path_max; } - +*/ char* mi_heap_realpath(mi_heap_t* heap, const char* fname, char* resolved_name) mi_attr_noexcept { if (resolved_name != NULL) { return realpath(fname,resolved_name); } else { - size_t n = mi_path_max(); + char* rname = realpath(fname, NULL); + if (rname == NULL) return NULL; + char* result = mi_heap_strdup(heap, rname); + mi_cfree(rname); // use checked free (which may be redirected to our free but that's ok) + // note: with ASAN realpath is intercepted and mi_cfree may leak the returned pointer :-( + return result; + } + /* + const size_t n = mi_path_max(); char* buf = (char*)mi_malloc(n+1); - if (buf==NULL) return NULL; + if (buf == NULL) { + errno = ENOMEM; + return NULL; + } char* rname = realpath(fname,buf); char* result = mi_heap_strndup(heap,rname,n); // ok if `rname==NULL` mi_free(buf); return result; } + */ } #endif mi_decl_nodiscard mi_decl_restrict char* mi_realpath(const char* fname, char* resolved_name) mi_attr_noexcept { - return mi_heap_realpath(mi_get_default_heap(),fname,resolved_name); + return mi_heap_realpath(mi_prim_get_default_heap(),fname,resolved_name); } #endif @@ -843,12 +463,16 @@ static bool mi_try_new_handler(bool nothrow) { #else std::new_handler h = std::set_new_handler(); std::set_new_handler(h); - #endif + #endif if (h==NULL) { - _mi_error_message(ENOMEM, "out of memory in 'new'"); + _mi_error_message(ENOMEM, "out of memory in 'new'"); + #if defined(_CPPUNWIND) || defined(__cpp_exceptions) // exceptions are not always enabled if (!nothrow) { throw std::bad_alloc(); } + #else + MI_UNUSED(nothrow); + #endif return false; } else { @@ -876,7 +500,7 @@ static std_new_handler_t mi_get_new_handler() { static bool mi_try_new_handler(bool nothrow) { std_new_handler_t h = mi_get_new_handler(); if (h==NULL) { - _mi_error_message(ENOMEM, "out of memory in 'new'"); + _mi_error_message(ENOMEM, "out of memory in 'new'"); if (!nothrow) { abort(); // cannot throw in plain C, use abort } @@ -889,20 +513,46 @@ static bool mi_try_new_handler(bool nothrow) { } #endif -static mi_decl_noinline void* mi_try_new(size_t size, bool nothrow ) { +mi_decl_export mi_decl_noinline void* mi_heap_try_new(mi_heap_t* heap, size_t size, bool nothrow ) { void* p = NULL; while(p == NULL && mi_try_new_handler(nothrow)) { - p = mi_malloc(size); + p = mi_heap_malloc(heap,size); } return p; } -mi_decl_nodiscard mi_decl_restrict void* mi_new(size_t size) { - void* p = mi_malloc(size); - if mi_unlikely(p == NULL) return mi_try_new(size,false); +static mi_decl_noinline void* mi_try_new(size_t size, bool nothrow) { + return mi_heap_try_new(mi_prim_get_default_heap(), size, nothrow); +} + + +mi_decl_nodiscard mi_decl_restrict void* mi_heap_alloc_new(mi_heap_t* heap, size_t size) { + void* p = mi_heap_malloc(heap,size); + if mi_unlikely(p == NULL) return mi_heap_try_new(heap, size, false); return p; } +mi_decl_nodiscard mi_decl_restrict void* mi_new(size_t size) { + return mi_heap_alloc_new(mi_prim_get_default_heap(), size); +} + + +mi_decl_nodiscard mi_decl_restrict void* mi_heap_alloc_new_n(mi_heap_t* heap, size_t count, size_t size) { + size_t total; + if mi_unlikely(mi_count_size_overflow(count, size, &total)) { + mi_try_new_handler(false); // on overflow we invoke the try_new_handler once to potentially throw std::bad_alloc + return NULL; + } + else { + return mi_heap_alloc_new(heap,total); + } +} + +mi_decl_nodiscard mi_decl_restrict void* mi_new_n(size_t count, size_t size) { + return mi_heap_alloc_new_n(mi_prim_get_default_heap(), count, size); +} + + mi_decl_nodiscard mi_decl_restrict void* mi_new_nothrow(size_t size) mi_attr_noexcept { void* p = mi_malloc(size); if mi_unlikely(p == NULL) return mi_try_new(size, true); @@ -927,17 +577,6 @@ mi_decl_nodiscard mi_decl_restrict void* mi_new_aligned_nothrow(size_t size, siz return p; } -mi_decl_nodiscard mi_decl_restrict void* mi_new_n(size_t count, size_t size) { - size_t total; - if mi_unlikely(mi_count_size_overflow(count, size, &total)) { - mi_try_new_handler(false); // on overflow we invoke the try_new_handler once to potentially throw std::bad_alloc - return NULL; - } - else { - return mi_new(total); - } -} - mi_decl_nodiscard void* mi_new_realloc(void* p, size_t newsize) { void* q; do { @@ -956,3 +595,103 @@ mi_decl_nodiscard void* mi_new_reallocn(void* p, size_t newcount, size_t size) { return mi_new_realloc(p, total); } } + +#if MI_GUARDED +// We always allocate a guarded allocation at an offset (`mi_page_has_aligned` will be true). +// We then set the first word of the block to `0` for regular offset aligned allocations (in `alloc-aligned.c`) +// and the first word to `~0` for guarded allocations to have a correct `mi_usable_size` + +static void* mi_block_ptr_set_guarded(mi_block_t* block, size_t obj_size) { + // TODO: we can still make padding work by moving it out of the guard page area + mi_page_t* const page = _mi_ptr_page(block); + mi_page_set_has_aligned(page, true); + block->next = MI_BLOCK_TAG_GUARDED; + + // set guard page at the end of the block + const size_t block_size = mi_page_block_size(page); // must use `block_size` to match `mi_free_local` + const size_t os_page_size = _mi_os_page_size(); + mi_assert_internal(block_size >= obj_size + os_page_size + sizeof(mi_block_t)); + if (block_size < obj_size + os_page_size + sizeof(mi_block_t)) { + // should never happen + mi_free(block); + return NULL; + } + uint8_t* guard_page = (uint8_t*)block + block_size - os_page_size; + // note: the alignment of the guard page relies on blocks being os_page_size aligned which + // is ensured in `mi_arena_page_alloc_fresh`. + mi_assert_internal(_mi_is_aligned(block, os_page_size)); + mi_assert_internal(_mi_is_aligned(guard_page, os_page_size)); + if (!page->memid.is_pinned && _mi_is_aligned(guard_page, os_page_size)) { + _mi_os_protect(guard_page, os_page_size); + } + else { + _mi_warning_message("unable to set a guard page behind an object due to pinned memory (large OS pages?) (object %p of size %zu)\n", block, block_size); + } + + // align pointer just in front of the guard page + size_t offset = block_size - os_page_size - obj_size; + mi_assert_internal(offset > sizeof(mi_block_t)); + if (offset > MI_PAGE_MAX_OVERALLOC_ALIGN) { + // give up to place it right in front of the guard page if the offset is too large for unalignment + offset = MI_PAGE_MAX_OVERALLOC_ALIGN; + } + void* p = (uint8_t*)block + offset; + mi_track_align(block, p, offset, obj_size); + mi_track_mem_defined(block, sizeof(mi_block_t)); + return p; +} + +mi_decl_restrict void* _mi_heap_malloc_guarded(mi_heap_t* heap, size_t size, bool zero) mi_attr_noexcept +{ + #if defined(MI_PADDING_SIZE) + mi_assert(MI_PADDING_SIZE==0); + #endif + // allocate multiple of page size ending in a guard page + // ensure minimal alignment requirement? + const size_t os_page_size = _mi_os_page_size(); + const size_t obj_size = (mi_option_is_enabled(mi_option_guarded_precise) ? size : _mi_align_up(size, MI_MAX_ALIGN_SIZE)); + const size_t bsize = _mi_align_up(_mi_align_up(obj_size, MI_MAX_ALIGN_SIZE) + sizeof(mi_block_t), MI_MAX_ALIGN_SIZE); + const size_t req_size = _mi_align_up(bsize + os_page_size, os_page_size); + mi_block_t* const block = (mi_block_t*)_mi_malloc_generic(heap, req_size, zero, 0 /* huge_alignment */); + if (block==NULL) return NULL; + void* const p = mi_block_ptr_set_guarded(block, obj_size); + + // stats + mi_track_malloc(p, size, zero); + if (p != NULL) { + if (!mi_heap_is_initialized(heap)) { heap = mi_prim_get_default_heap(); } + #if MI_STAT>1 + mi_heap_stat_adjust_decrease(heap, malloc_requested, req_size); + mi_heap_stat_increase(heap, malloc_requested, size); + #endif + mi_heap_stat_counter_increase(heap, malloc_guarded_count, 1); + } + #if MI_DEBUG>3 + if (p != NULL && zero) { + mi_assert_expensive(mi_mem_is_zero(p, size)); + } + #endif + return p; +} +#endif + +// ------------------------------------------------------ +// ensure explicit external inline definitions are emitted! +// ------------------------------------------------------ + +#ifdef __cplusplus +void* _mi_externs[] = { + (void*)&_mi_page_malloc, + (void*)&_mi_page_malloc_zero, + (void*)&_mi_heap_malloc_zero, + (void*)&_mi_heap_malloc_zero_ex, + (void*)&mi_malloc, + (void*)&mi_malloc_small, + (void*)&mi_zalloc_small, + (void*)&mi_heap_malloc, + (void*)&mi_heap_zalloc, + (void*)&mi_heap_malloc_small + // (void*)&mi_heap_alloc_new, + // (void*)&mi_heap_alloc_new_n +}; +#endif diff --git a/src/dashbls/depends/mimalloc/src/arena-meta.c b/src/dashbls/depends/mimalloc/src/arena-meta.c new file mode 100644 index 000000000000..3b64ab9b6367 --- /dev/null +++ b/src/dashbls/depends/mimalloc/src/arena-meta.c @@ -0,0 +1,179 @@ +/* ---------------------------------------------------------------------------- +Copyright (c) 2019-2024, Microsoft Research, Daan Leijen +This is free software; you can redistribute it and/or modify it under the +terms of the MIT license. A copy of the license can be found in the file +"LICENSE" at the root of this distribution. +-----------------------------------------------------------------------------*/ + +/* ---------------------------------------------------------------------------- + We have a special "mini" allocator just for allocation of meta-data like + the heap (`mi_heap_t`) or thread-local data (`mi_tld_t`). + + We reuse the bitmap of the arena's for allocation of 64b blocks inside + an arena slice (64KiB). + We always ensure that meta data is zero'd (we zero on `free`) +-----------------------------------------------------------------------------*/ + +#include "mimalloc.h" +#include "mimalloc/internal.h" +#include "bitmap.h" + +/* ----------------------------------------------------------- + Meta data allocation +----------------------------------------------------------- */ + +#define MI_META_PAGE_SIZE MI_ARENA_SLICE_SIZE +#define MI_META_PAGE_ALIGN MI_ARENA_SLICE_ALIGN + +// large enough such that META_MAX_SIZE > 4k (even on 32-bit) +#define MI_META_BLOCK_SIZE (1 << (16 - MI_BCHUNK_BITS_SHIFT)) // 128 on 64-bit +#define MI_META_BLOCK_ALIGN MI_META_BLOCK_SIZE +#define MI_META_BLOCKS_PER_PAGE (MI_META_PAGE_SIZE / MI_META_BLOCK_SIZE) // 512 +#define MI_META_MAX_SIZE (MI_BCHUNK_SIZE * MI_META_BLOCK_SIZE) + +#if MI_META_MAX_SIZE <= 4096 +#error "max meta object size should be at least 4KiB" +#endif + +typedef struct mi_meta_page_s { + _Atomic(struct mi_meta_page_s*) next; // a linked list of meta-data pages (never released) + mi_memid_t memid; // provenance of the meta-page memory itself + mi_bbitmap_t blocks_free; // a small bitmap with 1 bit per block. +} mi_meta_page_t; + +static mi_decl_cache_align _Atomic(mi_meta_page_t*) mi_meta_pages = MI_ATOMIC_VAR_INIT(NULL); + + +#if MI_DEBUG > 1 +static mi_meta_page_t* mi_meta_page_of_ptr(void* p, size_t* block_idx) { + mi_meta_page_t* mpage = (mi_meta_page_t*)((uint8_t*)mi_align_down_ptr(p,MI_META_PAGE_ALIGN) + _mi_os_secure_guard_page_size()); + if (block_idx != NULL) { + *block_idx = ((uint8_t*)p - (uint8_t*)mpage) / MI_META_BLOCK_SIZE; + } + return mpage; +} +#endif + +static mi_meta_page_t* mi_meta_page_next( mi_meta_page_t* mpage ) { + return mi_atomic_load_ptr_acquire(mi_meta_page_t, &mpage->next); +} + +static void* mi_meta_block_start( mi_meta_page_t* mpage, size_t block_idx ) { + mi_assert_internal(_mi_is_aligned((uint8_t*)mpage - _mi_os_secure_guard_page_size(), MI_META_PAGE_ALIGN)); + mi_assert_internal(block_idx < MI_META_BLOCKS_PER_PAGE); + void* p = ((uint8_t*)mpage - _mi_os_secure_guard_page_size() + (block_idx * MI_META_BLOCK_SIZE)); + mi_assert_internal(mpage == mi_meta_page_of_ptr(p,NULL)); + return p; +} + +// allocate a fresh meta page and add it to the global list. +static mi_meta_page_t* mi_meta_page_zalloc(void) { + // allocate a fresh arena slice + // note: careful with _mi_subproc as it may recurse into mi_tld and meta_page_zalloc again.. (same with _mi_os_numa_node()...) + mi_memid_t memid; + uint8_t* base = (uint8_t*)_mi_arenas_alloc_aligned(_mi_subproc(), MI_META_PAGE_SIZE, MI_META_PAGE_ALIGN, 0, + true /* commit*/, (MI_SECURE==0) /* allow large? */, + NULL /* req arena */, 0 /* thread_seq */, -1 /* numa node */, &memid); + if (base == NULL) return NULL; + mi_assert_internal(_mi_is_aligned(base,MI_META_PAGE_ALIGN)); + if (!memid.initially_zero) { + _mi_memzero_aligned(base, MI_ARENA_SLICE_SIZE); + } + + // guard pages + #if MI_SECURE >= 1 + _mi_os_secure_guard_page_set_at(base, memid); + _mi_os_secure_guard_page_set_before(base + MI_META_PAGE_SIZE, memid); + #endif + + // initialize the page and free block bitmap + mi_meta_page_t* mpage = (mi_meta_page_t*)(base + _mi_os_secure_guard_page_size()); + mpage->memid = memid; + mi_bbitmap_init(&mpage->blocks_free, MI_META_BLOCKS_PER_PAGE, true /* already_zero */); + const size_t mpage_size = offsetof(mi_meta_page_t,blocks_free) + mi_bbitmap_size(MI_META_BLOCKS_PER_PAGE, NULL); + const size_t info_blocks = _mi_divide_up(mpage_size,MI_META_BLOCK_SIZE); + const size_t guard_blocks = _mi_divide_up(_mi_os_secure_guard_page_size(), MI_META_BLOCK_SIZE); + mi_assert_internal(info_blocks + 2*guard_blocks < MI_META_BLOCKS_PER_PAGE); + mi_bbitmap_unsafe_setN(&mpage->blocks_free, info_blocks + guard_blocks, MI_META_BLOCKS_PER_PAGE - info_blocks - 2*guard_blocks); + + // push atomically in front of the meta page list + // (note: there is no ABA issue since we never free meta-pages) + mi_meta_page_t* old = mi_atomic_load_ptr_acquire(mi_meta_page_t,&mi_meta_pages); + do { + mi_atomic_store_ptr_release(mi_meta_page_t, &mpage->next, old); + } while(!mi_atomic_cas_ptr_weak_acq_rel(mi_meta_page_t,&mi_meta_pages,&old,mpage)); + return mpage; +} + + +// allocate meta-data +mi_decl_noinline void* _mi_meta_zalloc( size_t size, mi_memid_t* pmemid ) +{ + mi_assert_internal(pmemid != NULL); + size = _mi_align_up(size,MI_META_BLOCK_SIZE); + if (size == 0 || size > MI_META_MAX_SIZE) return NULL; + const size_t block_count = _mi_divide_up(size,MI_META_BLOCK_SIZE); + mi_assert_internal(block_count > 0 && block_count < MI_BCHUNK_BITS); + mi_meta_page_t* mpage0 = mi_atomic_load_ptr_acquire(mi_meta_page_t,&mi_meta_pages); + mi_meta_page_t* mpage = mpage0; + while (mpage != NULL) { + size_t block_idx; + if (mi_bbitmap_try_find_and_clearN(&mpage->blocks_free, block_count, 0, &block_idx)) { + // found and claimed `block_count` blocks + *pmemid = _mi_memid_create_meta(mpage, block_idx, block_count); + return mi_meta_block_start(mpage,block_idx); + } + else { + mpage = mi_meta_page_next(mpage); + } + } + // failed to find space in existing pages + if (mi_atomic_load_ptr_acquire(mi_meta_page_t,&mi_meta_pages) != mpage0) { + // the page list was updated by another thread in the meantime, retry + return _mi_meta_zalloc(size,pmemid); + } + // otherwise, allocate a fresh metapage and try once more + mpage = mi_meta_page_zalloc(); + if (mpage != NULL) { + size_t block_idx; + if (mi_bbitmap_try_find_and_clearN(&mpage->blocks_free, block_count, 0, &block_idx)) { + // found and claimed `block_count` blocks + *pmemid = _mi_memid_create_meta(mpage, block_idx, block_count); + return mi_meta_block_start(mpage,block_idx); + } + } + // if all this failed, allocate from the OS + return _mi_os_alloc(size, pmemid); +} + +// free meta-data +mi_decl_noinline void _mi_meta_free(void* p, size_t size, mi_memid_t memid) { + if (p==NULL) return; + if (memid.memkind == MI_MEM_META) { + mi_assert_internal(_mi_divide_up(size, MI_META_BLOCK_SIZE) == memid.mem.meta.block_count); + const size_t block_count = memid.mem.meta.block_count; + const size_t block_idx = memid.mem.meta.block_index; + mi_meta_page_t* mpage = (mi_meta_page_t*)memid.mem.meta.meta_page; + mi_assert_internal(mi_meta_page_of_ptr(p,NULL) == mpage); + mi_assert_internal(block_idx + block_count <= MI_META_BLOCKS_PER_PAGE); + mi_assert_internal(mi_bbitmap_is_clearN(&mpage->blocks_free, block_idx, block_count)); + // we zero on free (and on the initial page allocation) so we don't need a "dirty" map + _mi_memzero_aligned(mi_meta_block_start(mpage, block_idx), block_count*MI_META_BLOCK_SIZE); + mi_bbitmap_setN(&mpage->blocks_free, block_idx, block_count); + } + else { + _mi_arenas_free(p,size,memid); + } +} + +// used for debug output +bool _mi_meta_is_meta_page(void* p) +{ + mi_meta_page_t* mpage0 = mi_atomic_load_ptr_acquire(mi_meta_page_t, &mi_meta_pages); + mi_meta_page_t* mpage = mpage0; + while (mpage != NULL) { + if ((void*)mpage == p) return true; + mpage = mi_meta_page_next(mpage); + } + return false; +} diff --git a/src/dashbls/depends/mimalloc/src/arena.c b/src/dashbls/depends/mimalloc/src/arena.c index 239c56675619..b26f444288f5 100644 --- a/src/dashbls/depends/mimalloc/src/arena.c +++ b/src/dashbls/depends/mimalloc/src/arena.c @@ -1,5 +1,5 @@ /* ---------------------------------------------------------------------------- -Copyright (c) 2019-2022, Microsoft Research, Daan Leijen +Copyright (c) 2019-2024, Microsoft Research, Daan Leijen This is free software; you can redistribute it and/or modify it under the terms of the MIT license. A copy of the license can be found in the file "LICENSE" at the root of this distribution. @@ -11,140 +11,155 @@ large blocks (>= MI_ARENA_MIN_BLOCK_SIZE, 4MiB). In contrast to the rest of mimalloc, the arenas are shared between threads and need to be accessed using atomic operations. -Currently arenas are only used to for huge OS page (1GiB) reservations, -or direct OS memory reservations -- otherwise it delegates to direct allocation from the OS. -In the future, we can expose an API to manually add more kinds of arenas -which is sometimes needed for embedded devices or shared memory for example. -(We can also employ this with WASI or `sbrk` systems to reserve large arenas - on demand and be able to reuse them efficiently). +Arenas are also used to for huge OS page (1GiB) reservations or for reserving +OS memory upfront which can be improve performance or is sometimes needed +on embedded devices. We can also employ this with WASI or `sbrk` systems +to reserve large arenas upfront and be able to reuse the memory more effectively. -The arena allocation needs to be thread safe and we use an atomic bitmap to allocate. +The arena allocation needs to be thread safe and we use an atomic bitmap to allocate. -----------------------------------------------------------------------------*/ -#include "mimalloc.h" -#include "mimalloc-internal.h" -#include "mimalloc-atomic.h" - -#include // memset -#include // ENOMEM -#include "bitmap.h" // atomic bitmap +#include "mimalloc.h" +#include "mimalloc/internal.h" +#include "bitmap.h" -// os.c -void* _mi_os_alloc_aligned(size_t size, size_t alignment, bool commit, bool* large, mi_stats_t* stats); -void _mi_os_free_ex(void* p, size_t size, bool was_committed, mi_stats_t* stats); +/* ----------------------------------------------------------- + Arena id's +----------------------------------------------------------- */ -void* _mi_os_alloc_huge_os_pages(size_t pages, int numa_node, mi_msecs_t max_secs, size_t* pages_reserved, size_t* psize); -void _mi_os_free_huge_pages(void* p, size_t size, mi_stats_t* stats); +mi_arena_id_t _mi_arena_id_none(void) { + return NULL; +} -bool _mi_os_commit(void* p, size_t size, bool* is_zero, mi_stats_t* stats); -bool _mi_os_decommit(void* addr, size_t size, mi_stats_t* stats); +mi_arena_t* _mi_arena_from_id(mi_arena_id_t id) { + return (mi_arena_t*)id; +} -/* ----------------------------------------------------------- - Arena allocation ------------------------------------------------------------ */ +static bool mi_arena_id_is_suitable(mi_arena_t* arena, mi_arena_t* req_arena) { + return ((arena == req_arena) || // they match, + (req_arena == NULL && !arena->is_exclusive)); // or the arena is not exclusive, and we didn't request a specific one +} -// Block info: bit 0 contains the `in_use` bit, the upper bits the -// size in count of arena blocks. -typedef uintptr_t mi_block_info_t; -#define MI_ARENA_BLOCK_SIZE (MI_SEGMENT_SIZE) // 8MiB (must be at least MI_SEGMENT_ALIGN) -#define MI_ARENA_MIN_OBJ_SIZE (MI_ARENA_BLOCK_SIZE/2) // 4MiB -#define MI_MAX_ARENAS (64) // not more than 126 (since we use 7 bits in the memid and an arena index + 1) - -// A memory arena descriptor -typedef struct mi_arena_s { - mi_arena_id_t id; // arena id; 0 for non-specific - bool exclusive; // only allow allocations if specifically for this arena - _Atomic(uint8_t*) start; // the start of the memory area - size_t block_count; // size of the area in arena blocks (of `MI_ARENA_BLOCK_SIZE`) - size_t field_count; // number of bitmap fields (where `field_count * MI_BITMAP_FIELD_BITS >= block_count`) - int numa_node; // associated NUMA node - bool is_zero_init; // is the arena zero initialized? - bool allow_decommit; // is decommit allowed? if true, is_large should be false and blocks_committed != NULL - bool is_large; // large- or huge OS pages (always committed) - _Atomic(size_t) search_idx; // optimization to start the search for free blocks - mi_bitmap_field_t* blocks_dirty; // are the blocks potentially non-zero? - mi_bitmap_field_t* blocks_committed; // are the blocks committed? (can be NULL for memory that cannot be decommitted) - mi_bitmap_field_t blocks_inuse[1]; // in-place bitmap of in-use blocks (of size `field_count`) -} mi_arena_t; - - -// The available arenas -static mi_decl_cache_align _Atomic(mi_arena_t*) mi_arenas[MI_MAX_ARENAS]; -static mi_decl_cache_align _Atomic(size_t) mi_arena_count; // = 0 +bool _mi_arena_memid_is_suitable(mi_memid_t memid, mi_arena_t* request_arena) { + if (memid.memkind == MI_MEM_ARENA) { + return mi_arena_id_is_suitable(memid.mem.arena.arena, request_arena); + } + else { + return mi_arena_id_is_suitable(NULL, request_arena); + } +} +size_t mi_arenas_get_count(mi_subproc_t* subproc) { + return mi_atomic_load_relaxed(&subproc->arena_count); +} -/* ----------------------------------------------------------- - Arena id's - 0 is used for non-arena's (like OS memory) - id = arena_index + 1 ------------------------------------------------------------ */ +mi_arena_t* mi_arena_from_index(mi_subproc_t* subproc, size_t idx) { + mi_assert_internal(idx < mi_arenas_get_count(subproc)); + return mi_atomic_load_ptr_relaxed(mi_arena_t, &subproc->arenas[idx]); +} -static size_t mi_arena_id_index(mi_arena_id_t id) { - return (size_t)(id <= 0 ? MI_MAX_ARENAS : id - 1); +static size_t mi_arena_info_slices(mi_arena_t* arena) { + return arena->info_slices; } -static mi_arena_id_t mi_arena_id_create(size_t arena_index) { - mi_assert_internal(arena_index < MI_MAX_ARENAS); - mi_assert_internal(MI_MAX_ARENAS <= 126); - int id = (int)arena_index + 1; - mi_assert_internal(id >= 1 && id <= 127); - return id; +#if MI_DEBUG > 1 +static bool mi_arena_has_page(mi_arena_t* arena, mi_page_t* page) { + return (page->memid.memkind == MI_MEM_ARENA && + page->memid.mem.arena.arena == arena && + mi_bitmap_is_setN(arena->pages, page->memid.mem.arena.slice_index, 1)); } +#endif -mi_arena_id_t _mi_arena_id_none(void) { - return 0; +size_t mi_arena_min_alignment(void) { + return MI_ARENA_SLICE_ALIGN; } -static bool mi_arena_id_is_suitable(mi_arena_id_t arena_id, bool arena_is_exclusive, mi_arena_id_t req_arena_id) { - return ((!arena_is_exclusive && req_arena_id == _mi_arena_id_none()) || - (arena_id == req_arena_id)); +mi_decl_nodiscard static bool mi_arena_commit(mi_arena_t* arena, void* start, size_t size, bool* is_zero, size_t already_committed) { + if (arena != NULL && arena->commit_fun != NULL) { + return (*arena->commit_fun)(true, start, size, is_zero, arena->commit_fun_arg); + } + else if (already_committed > 0) { + return _mi_os_commit_ex(start, size, is_zero, already_committed); + } + else { + return _mi_os_commit(start, size, is_zero); + } } + /* ----------------------------------------------------------- - Arena allocations get a memory id where the lower 8 bits are - the arena id, and the upper bits the block index. + Util ----------------------------------------------------------- */ -// Use `0` as a special id for direct OS allocated memory. -#define MI_MEMID_OS 0 -static size_t mi_arena_memid_create(mi_arena_id_t id, bool exclusive, mi_bitmap_index_t bitmap_index) { - mi_assert_internal(((bitmap_index << 8) >> 8) == bitmap_index); // no overflow? - mi_assert_internal(id >= 0 && id <= 0x7F); - return ((bitmap_index << 8) | ((uint8_t)id & 0x7F) | (exclusive ? 0x80 : 0)); +// Size of an arena +static size_t mi_arena_size(mi_arena_t* arena) { + return mi_size_of_slices(arena->slice_count); } -static bool mi_arena_memid_indices(size_t arena_memid, size_t* arena_index, mi_bitmap_index_t* bitmap_index) { - *bitmap_index = (arena_memid >> 8); - mi_arena_id_t id = (int)(arena_memid & 0x7F); - *arena_index = mi_arena_id_index(id); - return ((arena_memid & 0x80) != 0); +// Start of the arena memory area +static uint8_t* mi_arena_start(mi_arena_t* arena) { + return ((uint8_t*)arena); } -bool _mi_arena_memid_is_suitable(size_t arena_memid, mi_arena_id_t request_arena_id) { - mi_arena_id_t id = (int)(arena_memid & 0x7F); - bool exclusive = ((arena_memid & 0x80) != 0); - return mi_arena_id_is_suitable(id, exclusive, request_arena_id); +// Start of a slice +uint8_t* mi_arena_slice_start(mi_arena_t* arena, size_t slice_index) { + return (mi_arena_start(arena) + mi_size_of_slices(slice_index)); } -static size_t mi_block_count_of_size(size_t size) { - return _mi_divide_up(size, MI_ARENA_BLOCK_SIZE); +// Arena area +void* mi_arena_area(mi_arena_id_t arena_id, size_t* size) { + if (size != NULL) *size = 0; + mi_arena_t* arena = _mi_arena_from_id(arena_id); + if (arena == NULL) return NULL; + if (size != NULL) { *size = mi_size_of_slices(arena->slice_count); } + return mi_arena_start(arena); } -/* ----------------------------------------------------------- - Thread safe allocation in an arena ------------------------------------------------------------ */ -static bool mi_arena_alloc(mi_arena_t* arena, size_t blocks, mi_bitmap_index_t* bitmap_idx) -{ - size_t idx = 0; // mi_atomic_load_relaxed(&arena->search_idx); // start from last search; ok to be relaxed as the exact start does not matter - if (_mi_bitmap_try_find_from_claim_across(arena->blocks_inuse, arena->field_count, idx, blocks, bitmap_idx)) { - mi_atomic_store_relaxed(&arena->search_idx, mi_bitmap_index_field(*bitmap_idx)); // start search from found location next time around - return true; - }; - return false; + +// Create an arena memid +static mi_memid_t mi_memid_create_arena(mi_arena_t* arena, size_t slice_index, size_t slice_count) { + mi_assert_internal(slice_index < UINT32_MAX); + mi_assert_internal(slice_count < UINT32_MAX); + mi_assert_internal(slice_count > 0); + mi_assert_internal(slice_index < arena->slice_count); + mi_memid_t memid = _mi_memid_create(MI_MEM_ARENA); + memid.mem.arena.arena = arena; + memid.mem.arena.slice_index = (uint32_t)slice_index; + memid.mem.arena.slice_count = (uint32_t)slice_count; + return memid; +} + +// get the arena and slice span +static mi_arena_t* mi_arena_from_memid(mi_memid_t memid, size_t* slice_index, size_t* slice_count) { + mi_assert_internal(memid.memkind == MI_MEM_ARENA); + mi_arena_t* arena = memid.mem.arena.arena; + if (slice_index) *slice_index = memid.mem.arena.slice_index; + if (slice_count) *slice_count = memid.mem.arena.slice_count; + return arena; +} + +static mi_arena_t* mi_page_arena(mi_page_t* page, size_t* slice_index, size_t* slice_count) { + // todo: maybe store the arena* directly in the page? + return mi_arena_from_memid(page->memid, slice_index, slice_count); +} + +static size_t mi_page_full_size(mi_page_t* page) { + if (page->memid.memkind == MI_MEM_ARENA) { + return page->memid.mem.arena.slice_count * MI_ARENA_SLICE_SIZE; + } + else if (mi_memid_is_os(page->memid) || page->memid.memkind == MI_MEM_EXTERNAL) { + mi_assert_internal((uint8_t*)page->memid.mem.os.base <= (uint8_t*)page); + const ptrdiff_t presize = (uint8_t*)page - (uint8_t*)page->memid.mem.os.base; + mi_assert_internal((ptrdiff_t)page->memid.mem.os.size >= presize); + return (presize > (ptrdiff_t)page->memid.mem.os.size ? 0 : page->memid.mem.os.size - presize); + } + else { + return 0; + } } @@ -152,284 +167,1175 @@ static bool mi_arena_alloc(mi_arena_t* arena, size_t blocks, mi_bitmap_index_t* Arena Allocation ----------------------------------------------------------- */ -static mi_decl_noinline void* mi_arena_alloc_from(mi_arena_t* arena, size_t arena_index, size_t needed_bcount, - bool* commit, bool* large, bool* is_pinned, bool* is_zero, - mi_arena_id_t req_arena_id, size_t* memid, mi_os_tld_t* tld) +static mi_decl_noinline void* mi_arena_try_alloc_at( + mi_arena_t* arena, size_t slice_count, bool commit, size_t tseq, mi_memid_t* memid) { - MI_UNUSED(arena_index); - mi_assert_internal(mi_arena_id_index(arena->id) == arena_index); - if (!mi_arena_id_is_suitable(arena->id, arena->exclusive, req_arena_id)) return NULL; - - mi_bitmap_index_t bitmap_index; - if (!mi_arena_alloc(arena, needed_bcount, &bitmap_index)) return NULL; - - // claimed it! set the dirty bits (todo: no need for an atomic op here?) - void* p = arena->start + (mi_bitmap_index_bit(bitmap_index)*MI_ARENA_BLOCK_SIZE); - *memid = mi_arena_memid_create(arena->id, arena->exclusive, bitmap_index); - *is_zero = _mi_bitmap_claim_across(arena->blocks_dirty, arena->field_count, needed_bcount, bitmap_index, NULL); - *large = arena->is_large; - *is_pinned = (arena->is_large || !arena->allow_decommit); - if (arena->blocks_committed == NULL) { - // always committed - *commit = true; - } - else if (*commit) { - // arena not committed as a whole, but commit requested: ensure commit now - bool any_uncommitted; - _mi_bitmap_claim_across(arena->blocks_committed, arena->field_count, needed_bcount, bitmap_index, &any_uncommitted); - if (any_uncommitted) { - bool commit_zero; - _mi_os_commit(p, needed_bcount * MI_ARENA_BLOCK_SIZE, &commit_zero, tld->stats); - if (commit_zero) *is_zero = true; + size_t slice_index; + if (!mi_bbitmap_try_find_and_clearN(arena->slices_free, slice_count, tseq, &slice_index)) return NULL; + + // claimed it! + void* p = mi_arena_slice_start(arena, slice_index); + *memid = mi_memid_create_arena(arena, slice_index, slice_count); + memid->is_pinned = arena->memid.is_pinned; + + // set the dirty bits and track which slices become accessible + size_t touched_slices = slice_count; + if (arena->memid.initially_zero) { + size_t already_dirty = 0; + memid->initially_zero = mi_bitmap_setN(arena->slices_dirty, slice_index, slice_count, &already_dirty); + mi_assert_internal(already_dirty <= touched_slices); + touched_slices -= already_dirty; + } + + // set commit state + if (commit) { + // commit requested, but the range may not be committed as a whole: ensure it is committed now + const size_t already_committed = mi_bitmap_popcountN(arena->slices_committed, slice_index, slice_count); + if (already_committed < slice_count) { + // not all committed, try to commit now + bool commit_zero = false; + if (!_mi_os_commit_ex(p, mi_size_of_slices(slice_count), &commit_zero, mi_size_of_slices(slice_count - already_committed))) { + // if the commit fails, release ownership, and return NULL; + // note: this does not roll back dirty bits but that is ok. + mi_bbitmap_setN(arena->slices_free, slice_index, slice_count); + return NULL; + } + if (commit_zero) { + memid->initially_zero = true; + } + + // set the commit bits + mi_bitmap_setN(arena->slices_committed, slice_index, slice_count, NULL); + + // committed + #if MI_DEBUG > 1 + if (memid->initially_zero) { + if (!mi_mem_is_zero(p, mi_size_of_slices(slice_count))) { + _mi_error_message(EFAULT, "interal error: arena allocation was not zero-initialized!\n"); + memid->initially_zero = false; + } + } + #endif + } + else { + // already fully committed. + _mi_os_reuse(p, mi_size_of_slices(slice_count)); + // if the OS has overcommit, and this is the first time we access these pages, then + // count the commit now (as at arena reserve we didn't count those commits as these are on-demand) + if (_mi_os_has_overcommit() && touched_slices > 0) { + mi_subproc_stat_increase( arena->subproc, committed, mi_size_of_slices(touched_slices)); + } + } + + mi_assert_internal(mi_bitmap_is_setN(arena->slices_committed, slice_index, slice_count)); + memid->initially_committed = true; + + // tool support + if (memid->initially_zero) { + mi_track_mem_defined(p, slice_count * MI_ARENA_SLICE_SIZE); + } + else { + mi_track_mem_undefined(p, slice_count * MI_ARENA_SLICE_SIZE); } } else { - // no need to commit, but check if already fully committed - *commit = _mi_bitmap_is_claimed_across(arena->blocks_committed, arena->field_count, needed_bcount, bitmap_index); + // no need to commit, but check if it is already fully committed + memid->initially_committed = mi_bitmap_is_setN(arena->slices_committed, slice_index, slice_count); + if (!memid->initially_committed) { + // partly committed.. adjust stats + size_t already_committed_count = 0; + mi_bitmap_setN(arena->slices_committed, slice_index, slice_count, &already_committed_count); + mi_bitmap_clearN(arena->slices_committed, slice_index, slice_count); + mi_os_stat_decrease(committed, mi_size_of_slices(already_committed_count)); + } } + + mi_assert_internal(mi_bbitmap_is_clearN(arena->slices_free, slice_index, slice_count)); + if (commit) { mi_assert_internal(mi_bitmap_is_setN(arena->slices_committed, slice_index, slice_count)); } + if (commit) { mi_assert_internal(memid->initially_committed); } + mi_assert_internal(mi_bitmap_is_setN(arena->slices_dirty, slice_index, slice_count)); + return p; } -static mi_decl_noinline void* mi_arena_allocate(int numa_node, size_t size, size_t alignment, bool* commit, bool* large, - bool* is_pinned, bool* is_zero, - mi_arena_id_t req_arena_id, size_t* memid, mi_os_tld_t* tld) -{ - MI_UNUSED_RELEASE(alignment); - mi_assert_internal(alignment <= MI_SEGMENT_ALIGN); - const size_t max_arena = mi_atomic_load_relaxed(&mi_arena_count); - const size_t bcount = mi_block_count_of_size(size); - if mi_likely(max_arena == 0) return NULL; - mi_assert_internal(size <= bcount*MI_ARENA_BLOCK_SIZE); - - size_t arena_index = mi_arena_id_index(req_arena_id); - if (arena_index < MI_MAX_ARENAS) { - // try a specific arena if requested - mi_arena_t* arena = mi_atomic_load_ptr_relaxed(mi_arena_t, &mi_arenas[arena_index]); - if (arena != NULL && - (arena->numa_node < 0 || arena->numa_node == numa_node) && // numa local? - (*large || !arena->is_large)) // large OS pages allowed, or arena is not large OS pages - { - void* p = mi_arena_alloc_from(arena, arena_index, bcount, commit, large, is_pinned, is_zero, req_arena_id, memid, tld); - mi_assert_internal((uintptr_t)p % alignment == 0); - if (p != NULL) return p; + +static int mi_reserve_os_memory_ex2(mi_subproc_t* subproc, size_t size, bool commit, bool allow_large, bool exclusive, mi_arena_id_t* arena_id); + +// try to reserve a fresh arena space +static bool mi_arena_reserve(mi_subproc_t* subproc, size_t req_size, bool allow_large, mi_arena_id_t* arena_id) +{ + const size_t arena_count = mi_arenas_get_count(subproc); + if (arena_count > (MI_MAX_ARENAS - 4)) return false; + + // calc reserve + size_t arena_reserve = mi_option_get_size(mi_option_arena_reserve); + if (arena_reserve == 0) return false; + + if (!_mi_os_has_virtual_reserve()) { + arena_reserve = arena_reserve/4; // be conservative if virtual reserve is not supported (for WASM for example) + } + arena_reserve = _mi_align_up(arena_reserve, MI_ARENA_SLICE_SIZE); + + if (arena_count >= 1 && arena_count <= 128) { + // scale up the arena sizes exponentially every 4 entries + const size_t multiplier = (size_t)1 << _mi_clamp(arena_count/4, 0, 16); + size_t reserve = 0; + if (!mi_mul_overflow(multiplier, arena_reserve, &reserve)) { + arena_reserve = reserve; } } - else { - // try numa affine allocation - for (size_t i = 0; i < max_arena; i++) { - mi_arena_t* arena = mi_atomic_load_ptr_relaxed(mi_arena_t, &mi_arenas[i]); - if (arena == NULL) break; // end reached - if ((arena->numa_node < 0 || arena->numa_node == numa_node) && // numa local? - (*large || !arena->is_large)) // large OS pages allowed, or arena is not large OS pages - { - void* p = mi_arena_alloc_from(arena, i, bcount, commit, large, is_pinned, is_zero, req_arena_id, memid, tld); - mi_assert_internal((uintptr_t)p % alignment == 0); - if (p != NULL) return p; - } + + // check arena bounds + const size_t min_reserve = MI_ARENA_MIN_SIZE; + const size_t max_reserve = MI_ARENA_MAX_SIZE; // 16 GiB + if (arena_reserve < min_reserve) { + arena_reserve = min_reserve; + } + else if (arena_reserve > max_reserve) { + arena_reserve = max_reserve; + } + + if (arena_reserve < req_size) return false; // should be able to at least handle the current allocation size + + // commit eagerly? + bool arena_commit = false; + const bool overcommit = _mi_os_has_overcommit(); + if (mi_option_get(mi_option_arena_eager_commit) == 2) { arena_commit = overcommit; } + else if (mi_option_get(mi_option_arena_eager_commit) == 1) { arena_commit = true; } + + // on an OS with overcommit (Linux) we don't count the commit yet as it is on-demand. Once a slice + // is actually allocated for the first time it will be counted. + const bool adjust = (overcommit && arena_commit); + if (adjust) { mi_subproc_stat_adjust_decrease( subproc, committed, arena_reserve); } + // and try to reserve the arena + int err = mi_reserve_os_memory_ex2(subproc, arena_reserve, arena_commit, allow_large, false /* exclusive? */, arena_id); + if (err != 0) { + if (adjust) { mi_subproc_stat_adjust_increase( subproc, committed, arena_reserve); } // roll back + // failed, try a smaller size? + const size_t small_arena_reserve = (MI_SIZE_BITS == 32 ? 128*MI_MiB : 1*MI_GiB); + if (adjust) { mi_subproc_stat_adjust_decrease( subproc, committed, arena_reserve); } + if (arena_reserve > small_arena_reserve) { + // try again + err = mi_reserve_os_memory_ex(small_arena_reserve, arena_commit, allow_large, false /* exclusive? */, arena_id); + if (err != 0 && adjust) { mi_subproc_stat_adjust_increase( subproc, committed, arena_reserve); } // roll back } + } + return (err==0); +} - // try from another numa node instead.. - for (size_t i = 0; i < max_arena; i++) { - mi_arena_t* arena = mi_atomic_load_ptr_relaxed(mi_arena_t, &mi_arenas[i]); - if (arena == NULL) break; // end reached - if ((arena->numa_node >= 0 && arena->numa_node != numa_node) && // not numa local! - (*large || !arena->is_large)) // large OS pages allowed, or arena is not large OS pages - { - void* p = mi_arena_alloc_from(arena, i, bcount, commit, large, is_pinned, is_zero, req_arena_id, memid, tld); - mi_assert_internal((uintptr_t)p % alignment == 0); - if (p != NULL) return p; - } + + + +/* ----------------------------------------------------------- + Arena iteration +----------------------------------------------------------- */ + +static inline bool mi_arena_is_suitable(mi_arena_t* arena, mi_arena_t* req_arena, bool match_numa, int numa_node, bool allow_pinned) { + if (!allow_pinned && arena->memid.is_pinned) return false; + if (!mi_arena_id_is_suitable(arena, req_arena)) return false; + if (req_arena == NULL) { // if not specific, check numa affinity + const bool numa_suitable = (numa_node < 0 || arena->numa_node < 0 || arena->numa_node == numa_node); + if (match_numa) { if (!numa_suitable) return false; } + else { if (numa_suitable) return false; } + } + return true; +} + +#define mi_forall_arenas(subproc, req_arena, tseq, name_arena) { \ + const size_t _arena_count = mi_arenas_get_count(subproc); \ + const size_t _arena_cycle = (_arena_count == 0 ? 0 : _arena_count - 1); /* first search the arenas below the last one */ \ + /* always start searching in the arena's below the max */ \ + size_t _start = (_arena_cycle <= 1 ? 0 : (tseq % _arena_cycle)); \ + for (size_t _i = 0; _i < _arena_count; _i++) { \ + mi_arena_t* name_arena; \ + if (req_arena != NULL) { \ + name_arena = req_arena; /* if there is a specific req_arena, only search that one */\ + if (_i > 0) break; /* only once */ \ + } \ + else { \ + size_t _idx; \ + if (_i < _arena_cycle) { \ + _idx = _i + _start; \ + if (_idx >= _arena_cycle) { _idx -= _arena_cycle; } /* adjust so we rotate through the cycle */ \ + } \ + else { \ + _idx = _i; /* remaining arena's */ \ + } \ + name_arena = mi_arena_from_index(subproc,_idx); \ + } \ + if (name_arena != NULL) \ + { + +#define mi_forall_arenas_end() \ + } \ + } \ + } + +#define mi_forall_suitable_arenas(subproc, req_arena, tseq, match_numa, numa_node, allow_large, name_arena) \ + mi_forall_arenas(subproc, req_arena,tseq,name_arena) { \ + if (mi_arena_is_suitable(name_arena, req_arena, match_numa, numa_node, allow_large)) { \ + +#define mi_forall_suitable_arenas_end() \ + }} \ + mi_forall_arenas_end() + +/* ----------------------------------------------------------- + Arena allocation +----------------------------------------------------------- */ + +// allocate slices from the arenas +static mi_decl_noinline void* mi_arenas_try_find_free( + mi_subproc_t* subproc, size_t slice_count, size_t alignment, + bool commit, bool allow_large, mi_arena_t* req_arena, size_t tseq, int numa_node, mi_memid_t* memid) +{ + mi_assert_internal(slice_count <= mi_slice_count_of_size(MI_ARENA_MAX_OBJ_SIZE)); + mi_assert(alignment <= MI_ARENA_SLICE_ALIGN); + if (alignment > MI_ARENA_SLICE_ALIGN) return NULL; + + // search arena's + mi_forall_suitable_arenas(subproc, req_arena, tseq, true /* only numa matching */, numa_node, allow_large, arena) + { + void* p = mi_arena_try_alloc_at(arena, slice_count, commit, tseq, memid); + if (p != NULL) return p; + } + mi_forall_suitable_arenas_end(); + if (numa_node < 0) return NULL; + + // search again but now regardless of preferred numa affinity + mi_forall_suitable_arenas(subproc, req_arena, tseq, false /* numa non-matching now */, numa_node, allow_large, arena) + { + void* p = mi_arena_try_alloc_at(arena, slice_count, commit, tseq, memid); + if (p != NULL) return p; + } + mi_forall_suitable_arenas_end(); + return NULL; +} + +// Allocate slices from the arena's -- potentially allocating a fresh arena +static mi_decl_noinline void* mi_arenas_try_alloc( + mi_subproc_t* subproc, + size_t slice_count, size_t alignment, + bool commit, bool allow_large, + mi_arena_t* req_arena, size_t tseq, int numa_node, mi_memid_t* memid) +{ + mi_assert(slice_count <= MI_ARENA_MAX_OBJ_SLICES); + mi_assert(alignment <= MI_ARENA_SLICE_ALIGN); + void* p; + + // try to find free slices in the arena's + p = mi_arenas_try_find_free(subproc, slice_count, alignment, commit, allow_large, req_arena, tseq, numa_node, memid); + if (p != NULL) return p; + + // did we need a specific arena? + if (req_arena != NULL) return NULL; + + // don't create arena's while preloading (todo: or should we?) + if (_mi_preloading()) return NULL; + + // otherwise, try to reserve a new arena -- but one thread at a time.. (todo: allow 2 or 4 to reduce contention?) + const size_t arena_count = mi_arenas_get_count(subproc); + mi_lock(&subproc->arena_reserve_lock) { + if (arena_count == mi_arenas_get_count(subproc)) { + // we are the first to enter the lock, reserve a fresh arena + mi_arena_id_t arena_id = 0; + mi_arena_reserve(subproc, mi_size_of_slices(slice_count), allow_large, &arena_id); + } + else { + // another thread already reserved a new arena } } + // try once more to allocate in the new arena + mi_assert_internal(req_arena == NULL); + p = mi_arenas_try_find_free(subproc, slice_count, alignment, commit, allow_large, req_arena, tseq, numa_node, memid); + if (p != NULL) return p; + return NULL; } +// Allocate from the OS (if allowed) +static void* mi_arena_os_alloc_aligned( + size_t size, size_t alignment, size_t align_offset, + bool commit, bool allow_large, + mi_arena_id_t req_arena_id, mi_memid_t* memid) +{ + // if we cannot use OS allocation, return NULL + if (mi_option_is_enabled(mi_option_disallow_os_alloc) || req_arena_id != _mi_arena_id_none()) { + errno = ENOMEM; + return NULL; + } + + if (align_offset > 0) { + return _mi_os_alloc_aligned_at_offset(size, alignment, align_offset, commit, allow_large, memid); + } + else { + return _mi_os_alloc_aligned(size, alignment, commit, allow_large, memid); + } +} + -void* _mi_arena_alloc_aligned(size_t size, size_t alignment, bool* commit, bool* large, bool* is_pinned, bool* is_zero, - mi_arena_id_t req_arena_id, size_t* memid, mi_os_tld_t* tld) +// Allocate large sized memory +void* _mi_arenas_alloc_aligned( mi_subproc_t* subproc, + size_t size, size_t alignment, size_t align_offset, + bool commit, bool allow_large, + mi_arena_t* req_arena, size_t tseq, int numa_node, mi_memid_t* memid) { - mi_assert_internal(commit != NULL && is_pinned != NULL && is_zero != NULL && memid != NULL && tld != NULL); + mi_assert_internal(memid != NULL); mi_assert_internal(size > 0); - *memid = MI_MEMID_OS; - *is_zero = false; - *is_pinned = false; - - bool default_large = false; - if (large==NULL) large = &default_large; // ensure `large != NULL` - const int numa_node = _mi_os_numa_node(tld); // current numa node // try to allocate in an arena if the alignment is small enough and the object is not too small (as for heap meta data) - if (size >= MI_ARENA_MIN_OBJ_SIZE && alignment <= MI_SEGMENT_ALIGN) { - void* p = mi_arena_allocate(numa_node, size, alignment, commit, large, is_pinned, is_zero, req_arena_id, memid, tld); + if (!mi_option_is_enabled(mi_option_disallow_arena_alloc) && // is arena allocation allowed? + size >= MI_ARENA_MIN_OBJ_SIZE && size <= MI_ARENA_MAX_OBJ_SIZE && // and not too small/large + alignment <= MI_ARENA_SLICE_ALIGN && align_offset == 0) // and good alignment + { + const size_t slice_count = mi_slice_count_of_size(size); + void* p = mi_arenas_try_alloc(subproc,slice_count, alignment, commit, allow_large, req_arena, tseq, numa_node, memid); if (p != NULL) return p; } - // finally, fall back to the OS - if (mi_option_is_enabled(mi_option_limit_os_alloc) || req_arena_id != _mi_arena_id_none()) { - errno = ENOMEM; + // fall back to the OS + void* p = mi_arena_os_alloc_aligned(size, alignment, align_offset, commit, allow_large, req_arena, memid); + return p; +} + +void* _mi_arenas_alloc(mi_subproc_t* subproc, size_t size, bool commit, bool allow_large, mi_arena_t* req_arena, size_t tseq, int numa_node, mi_memid_t* memid) +{ + return _mi_arenas_alloc_aligned(subproc, size, MI_ARENA_SLICE_SIZE, 0, commit, allow_large, req_arena, tseq, numa_node, memid); +} + + + +/* ----------------------------------------------------------- + Arena page allocation +----------------------------------------------------------- */ + +static bool mi_arena_try_claim_abandoned(size_t slice_index, mi_arena_t* arena, mi_heaptag_t heap_tag, bool* keep_abandoned) { + // found an abandoned page of the right size + mi_page_t* const page = (mi_page_t*)mi_arena_slice_start(arena, slice_index); + // can we claim ownership? + if (!mi_page_try_claim_ownership(page)) { + // there was a concurrent free .. + // we need to keep it in the abandoned map as the free will call `mi_arena_page_unabandon`, + // and wait for readers (us!) to finish. This is why it is very important to set the abandoned + // bit again (or otherwise the unabandon will never stop waiting). + *keep_abandoned = true; + return false; + } + if (heap_tag != page->heap_tag) { + // wrong heap_tag.. we need to unown again + // note: this normally never happens unless heaptags are actually used. + // (an unown might free the page, and depending on that we can keep it in the abandoned map or not) + // note: a minor wrinkle: the page will still be mapped but the abandoned map entry is (temporarily) clear at this point. + // so we cannot check in `mi_arenas_free` for this invariant to hold. + const bool freed = _mi_page_unown(page); + *keep_abandoned = !freed; + return false; + } + // yes, we can reclaim it, keep the abandoned map entry clear + *keep_abandoned = false; + return true; +} + +static mi_page_t* mi_arenas_page_try_find_abandoned(mi_subproc_t* subproc, size_t slice_count, size_t block_size, mi_arena_t* req_arena, mi_heaptag_t heaptag, size_t tseq) +{ + MI_UNUSED(slice_count); + const size_t bin = _mi_bin(block_size); + mi_assert_internal(bin < MI_BIN_COUNT); + + // any abandoned in our size class? + mi_assert_internal(subproc != NULL); + if (mi_atomic_load_relaxed(&subproc->abandoned_count[bin]) == 0) { return NULL; } - *is_zero = true; - *memid = MI_MEMID_OS; - void* p = _mi_os_alloc_aligned(size, alignment, *commit, large, tld->stats); - if (p != NULL) *is_pinned = *large; - return p; + + // search arena's + const bool allow_large = true; + const int any_numa = -1; + const bool match_numa = true; + mi_forall_suitable_arenas(subproc, req_arena, tseq, match_numa, any_numa, allow_large, arena) + { + size_t slice_index; + mi_bitmap_t* const bitmap = arena->pages_abandoned[bin]; + + if (mi_bitmap_try_find_and_claim(bitmap, tseq, &slice_index, &mi_arena_try_claim_abandoned, arena, heaptag)) { + // found an abandoned page of the right size + // and claimed ownership. + mi_page_t* page = (mi_page_t*)mi_arena_slice_start(arena, slice_index); + mi_assert_internal(mi_page_is_owned(page)); + mi_assert_internal(mi_page_is_abandoned(page)); + mi_assert_internal(mi_arena_has_page(arena,page)); + mi_atomic_decrement_relaxed(&subproc->abandoned_count[bin]); + mi_tld_t* tld = _mi_thread_tld(); + mi_tld_stat_decrease( tld, pages_abandoned, 1); + mi_tld_stat_counter_increase( tld, pages_reclaim_on_alloc, 1); + + _mi_page_free_collect(page, false); // update `used` count + mi_assert_internal(mi_bbitmap_is_clearN(arena->slices_free, slice_index, slice_count)); + mi_assert_internal(page->slice_committed > 0 || mi_bitmap_is_setN(arena->slices_committed, slice_index, slice_count)); + mi_assert_internal(mi_bitmap_is_setN(arena->slices_dirty, slice_index, slice_count)); + mi_assert_internal(_mi_is_aligned(page, MI_PAGE_ALIGN)); + mi_assert_internal(_mi_ptr_page(page)==page); + mi_assert_internal(_mi_ptr_page(mi_page_start(page))==page); + mi_assert_internal(mi_page_block_size(page) == block_size); + mi_assert_internal(!mi_page_is_full(page)); + return page; + } + } + mi_forall_suitable_arenas_end(); + return NULL; } -void* _mi_arena_alloc(size_t size, bool* commit, bool* large, bool* is_pinned, bool* is_zero, mi_arena_id_t req_arena_id, size_t* memid, mi_os_tld_t* tld) +// Allocate a fresh page +static mi_page_t* mi_arenas_page_alloc_fresh(size_t slice_count, size_t block_size, size_t block_alignment, + mi_arena_t* req_arena, int numa_node, bool commit, mi_tld_t* tld) { - return _mi_arena_alloc_aligned(size, MI_ARENA_BLOCK_SIZE, commit, large, is_pinned, is_zero, req_arena_id, memid, tld); + const bool allow_large = (MI_SECURE < 2); // 2 = guard page at end of each arena page + const bool os_align = (block_alignment > MI_PAGE_MAX_OVERALLOC_ALIGN); + const size_t page_alignment = MI_ARENA_SLICE_ALIGN; + + // try to allocate from free space in arena's + mi_memid_t memid = _mi_memid_none(); + mi_page_t* page = NULL; + const size_t alloc_size = mi_size_of_slices(slice_count); + if (!mi_option_is_enabled(mi_option_disallow_arena_alloc) && // allowed to allocate from arena's? + !os_align && // not large alignment + slice_count <= MI_ARENA_MAX_OBJ_SLICES) // and not too large + { + page = (mi_page_t*)mi_arenas_try_alloc(tld->subproc, slice_count, page_alignment, commit, allow_large, req_arena, tld->thread_seq, numa_node, &memid); + if (page != NULL) { + mi_assert_internal(mi_bitmap_is_clearN(memid.mem.arena.arena->pages, memid.mem.arena.slice_index, memid.mem.arena.slice_count)); + mi_bitmap_set(memid.mem.arena.arena->pages, memid.mem.arena.slice_index); + } + } + + // otherwise fall back to the OS + if (page == NULL) { + if (os_align) { + // note: slice_count already includes the page + mi_assert_internal(slice_count >= mi_slice_count_of_size(block_size) + mi_slice_count_of_size(page_alignment)); + page = (mi_page_t*)mi_arena_os_alloc_aligned(alloc_size, block_alignment, page_alignment /* align offset */, commit, allow_large, req_arena, &memid); + } + else { + page = (mi_page_t*)mi_arena_os_alloc_aligned(alloc_size, page_alignment, 0 /* align offset */, commit, allow_large, req_arena, &memid); + } + } + + if (page == NULL) return NULL; + mi_assert_internal(_mi_is_aligned(page, MI_PAGE_ALIGN)); + mi_assert_internal(!os_align || _mi_is_aligned((uint8_t*)page + page_alignment, block_alignment)); + + // guard page at the end of mimalloc page? + #if MI_SECURE < 2 + const size_t page_noguard_size = alloc_size; + #else + mi_assert(alloc_size > _mi_os_secure_guard_page_size()); + const size_t page_noguard_size = alloc_size - _mi_os_secure_guard_page_size(); + if (memid.initially_committed) { + _mi_os_secure_guard_page_set_at((uint8_t*)page + page_noguard_size, memid); + } + #endif + + // claimed free slices: initialize the page partly + if (!memid.initially_zero && memid.initially_committed) { + mi_track_mem_undefined(page, slice_count * MI_ARENA_SLICE_SIZE); + _mi_memzero_aligned(page, sizeof(*page)); + } + else if (memid.initially_committed) { + mi_track_mem_defined(page, slice_count * MI_ARENA_SLICE_SIZE); + } + #if MI_DEBUG > 1 + if (memid.initially_zero && memid.initially_committed) { + if (!mi_mem_is_zero(page, page_noguard_size)) { + _mi_error_message(EFAULT, "internal error: page memory was not zero initialized.\n"); + memid.initially_zero = false; + _mi_memzero_aligned(page, sizeof(*page)); + } + } + #endif + mi_assert(MI_PAGE_INFO_SIZE >= mi_page_info_size()); + + size_t block_start; + #if MI_GUARDED + // in a guarded build, we align pages with blocks a multiple of an OS page size, to the OS page size + // this ensures that all blocks in such pages are OS page size aligned (which is needed for the guard pages) + const size_t os_page_size = _mi_os_page_size(); + mi_assert_internal(MI_PAGE_ALIGN >= os_page_size); + if (!os_align && block_size % os_page_size == 0 && block_size > os_page_size /* at least 2 or more */ ) { + block_start = _mi_align_up(mi_page_info_size(), os_page_size); + } + else + #endif + if (os_align) { + block_start = MI_PAGE_ALIGN; + } + else if (_mi_is_power_of_two(block_size) && block_size <= MI_PAGE_MAX_START_BLOCK_ALIGN2) { + // naturally align all power-of-2 blocks + block_start = _mi_align_up(mi_page_info_size(), block_size); + } + else { + // otherwise start after the info + block_start = mi_page_info_size(); + } + const size_t reserved = (os_align ? 1 : (page_noguard_size - block_start) / block_size); + mi_assert_internal(reserved > 0 && reserved <= UINT16_MAX); + + // commit first block? + size_t commit_size = 0; + if (!memid.initially_committed) { + commit_size = _mi_align_up(block_start + block_size, MI_PAGE_MIN_COMMIT_SIZE); + if (commit_size > page_noguard_size) { commit_size = page_noguard_size; } + bool is_zero; + if (!mi_arena_commit( mi_memid_arena(memid), page, commit_size, &is_zero, 0)) { + _mi_arenas_free(page, alloc_size, memid); + return NULL; + } + if (!memid.initially_zero && !is_zero) { + _mi_memzero_aligned(page, commit_size); + } + } + + // initialize + page->reserved = (uint16_t)reserved; + page->page_start = (uint8_t*)page + block_start; + page->block_size = block_size; + page->slice_committed = commit_size; + page->memid = memid; + page->free_is_zero = memid.initially_zero; + if (block_size > 0 && _mi_is_power_of_two(block_size)) { + page->block_size_shift = (uint8_t)mi_ctz(block_size); + } + else { + page->block_size_shift = 0; + } + // and own it + mi_page_try_claim_ownership(page); + + // register in the page map + _mi_page_map_register(page); + + // stats + mi_tld_stat_increase(tld, pages, 1); + mi_tld_stat_increase(tld, page_bins[_mi_page_bin(page)], 1); + + mi_assert_internal(_mi_ptr_page(page)==page); + mi_assert_internal(_mi_ptr_page(mi_page_start(page))==page); + mi_assert_internal(mi_page_block_size(page) == block_size); + mi_assert_internal(mi_page_is_abandoned(page)); + mi_assert_internal(mi_page_is_owned(page)); + + return page; } -void* mi_arena_area(mi_arena_id_t arena_id, size_t* size) { - if (size != NULL) *size = 0; - size_t arena_index = mi_arena_id_index(arena_id); - if (arena_index >= MI_MAX_ARENAS) return NULL; - mi_arena_t* arena = mi_atomic_load_ptr_relaxed(mi_arena_t, &mi_arenas[arena_index]); - if (arena == NULL) return NULL; - if (size != NULL) *size = arena->block_count * MI_ARENA_BLOCK_SIZE; - return arena->start; +// Allocate a regular small/medium/large page. +static mi_page_t* mi_arenas_page_regular_alloc(mi_heap_t* heap, size_t slice_count, size_t block_size) { + mi_arena_t* req_arena = heap->exclusive_arena; + mi_tld_t* const tld = heap->tld; + + // 1. look for an abandoned page + mi_page_t* page = mi_arenas_page_try_find_abandoned(tld->subproc, slice_count, block_size, req_arena, heap->tag, tld->thread_seq); + if (page != NULL) { + return page; // return as abandoned + } + + // 2. find a free block, potentially allocating a new arena + const long commit_on_demand = mi_option_get(mi_option_page_commit_on_demand); + const bool commit = (slice_count <= mi_slice_count_of_size(MI_PAGE_MIN_COMMIT_SIZE) || // always commit small pages + (commit_on_demand == 2 && _mi_os_has_overcommit()) || (commit_on_demand == 0)); + page = mi_arenas_page_alloc_fresh(slice_count, block_size, 1, req_arena, heap->numa_node, commit, tld); + if (page == NULL) return NULL; + + mi_assert_internal(page->memid.memkind != MI_MEM_ARENA || page->memid.mem.arena.slice_count == slice_count); + if (!_mi_page_init(heap, page)) { + _mi_arenas_free( page, mi_page_full_size(page), page->memid); + return NULL; + } + + return page; +} + +// Allocate a page containing one block (very large, or with large alignment) +static mi_page_t* mi_arenas_page_singleton_alloc(mi_heap_t* heap, size_t block_size, size_t block_alignment) { + mi_arena_t* req_arena = heap->exclusive_arena; + mi_tld_t* const tld = heap->tld; + const bool os_align = (block_alignment > MI_PAGE_MAX_OVERALLOC_ALIGN); + const size_t info_size = (os_align ? MI_PAGE_ALIGN : mi_page_info_size()); + #if MI_SECURE < 2 + const size_t slice_count = mi_slice_count_of_size(info_size + block_size); + #else + const size_t slice_count = mi_slice_count_of_size(_mi_align_up(info_size + block_size, _mi_os_secure_guard_page_size()) + _mi_os_secure_guard_page_size()); + #endif + + mi_page_t* page = mi_arenas_page_alloc_fresh(slice_count, block_size, block_alignment, req_arena, heap->numa_node, true /* commit singletons always */, tld); + if (page == NULL) return NULL; + + mi_assert(page->reserved == 1); + if (!_mi_page_init(heap, page)) { + _mi_arenas_free( page, mi_page_full_size(page), page->memid); + return NULL; + } + + return page; +} + + +mi_page_t* _mi_arenas_page_alloc(mi_heap_t* heap, size_t block_size, size_t block_alignment) { + mi_page_t* page; + if mi_unlikely(block_alignment > MI_PAGE_MAX_OVERALLOC_ALIGN) { + mi_assert_internal(_mi_is_power_of_two(block_alignment)); + page = mi_arenas_page_singleton_alloc(heap, block_size, block_alignment); + } + else if (block_size <= MI_SMALL_MAX_OBJ_SIZE) { + page = mi_arenas_page_regular_alloc(heap, mi_slice_count_of_size(MI_SMALL_PAGE_SIZE), block_size); + } + else if (block_size <= MI_MEDIUM_MAX_OBJ_SIZE) { + page = mi_arenas_page_regular_alloc(heap, mi_slice_count_of_size(MI_MEDIUM_PAGE_SIZE), block_size); + } + #if MI_ENABLE_LARGE_PAGES + else if (block_size <= MI_LARGE_MAX_OBJ_SIZE) { + page = mi_arenas_page_regular_alloc(heap, mi_slice_count_of_size(MI_LARGE_PAGE_SIZE), block_size); + } + #endif + else { + page = mi_arenas_page_singleton_alloc(heap, block_size, block_alignment); + } + // mi_assert_internal(page == NULL || _mi_page_segment(page)->subproc == tld->subproc); + mi_assert_internal(_mi_is_aligned(page, MI_PAGE_ALIGN)); + mi_assert_internal(_mi_ptr_page(page)==page); + mi_assert_internal(_mi_ptr_page(mi_page_start(page))==page); + mi_assert_internal(block_alignment <= MI_PAGE_MAX_OVERALLOC_ALIGN || _mi_is_aligned(mi_page_start(page), block_alignment)); + + return page; +} + +void _mi_arenas_page_free(mi_page_t* page, mi_tld_t* stats_tld /* can be NULL */) { + mi_assert_internal(_mi_is_aligned(page, MI_PAGE_ALIGN)); + mi_assert_internal(_mi_ptr_page(page)==page); + mi_assert_internal(mi_page_is_owned(page)); + mi_assert_internal(mi_page_all_free(page)); + mi_assert_internal(mi_page_is_abandoned(page)); + mi_assert_internal(page->next==NULL && page->prev==NULL); + + if (stats_tld != NULL) { + mi_tld_stat_decrease(stats_tld, page_bins[_mi_page_bin(page)], 1); + mi_tld_stat_decrease(stats_tld, pages, 1); + } + else { + mi_os_stat_decrease(page_bins[_mi_page_bin(page)], 1); + mi_os_stat_decrease(pages, 1); + } + + #if MI_DEBUG>1 + if (page->memid.memkind==MI_MEM_ARENA && !mi_page_is_full(page)) { + size_t bin = _mi_bin(mi_page_block_size(page)); + size_t slice_index; + size_t slice_count; + mi_arena_t* const arena = mi_page_arena(page, &slice_index, &slice_count); + mi_assert_internal(mi_bbitmap_is_clearN(arena->slices_free, slice_index, slice_count)); + mi_assert_internal(page->slice_committed > 0 || mi_bitmap_is_setN(arena->slices_committed, slice_index, slice_count)); + mi_assert_internal(mi_bitmap_is_clearN(arena->pages_abandoned[bin], slice_index, 1)); + mi_assert_internal(mi_bitmap_is_setN(page->memid.mem.arena.arena->pages, page->memid.mem.arena.slice_index, 1)); + // note: we cannot check for `!mi_page_is_abandoned_and_mapped` since that may + // be (temporarily) not true if the free happens while trying to reclaim + // see `mi_arana_try_claim_abandoned` + } + #endif + + // recommit guard page at the end? + // we must do this since we may later allocate large spans over this page and cannot have a guard page in between + #if MI_SECURE >= 2 + if (!page->memid.is_pinned) { + _mi_os_secure_guard_page_reset_before((uint8_t*)page + mi_page_full_size(page), page->memid); + } + #endif + + // unregister page + _mi_page_map_unregister(page); + if (page->memid.memkind == MI_MEM_ARENA) { + mi_arena_t* const arena = page->memid.mem.arena.arena; + mi_bitmap_clear(arena->pages, page->memid.mem.arena.slice_index); + if (page->slice_committed > 0) { + // if committed on-demand, set the commit bits to account commit properly + mi_assert_internal(mi_page_full_size(page) >= page->slice_committed); + const size_t total_slices = page->slice_committed / MI_ARENA_SLICE_SIZE; // conservative + //mi_assert_internal(mi_bitmap_is_clearN(arena->slices_committed, page->memid.mem.arena.slice_index, total_slices)); + mi_assert_internal(page->memid.mem.arena.slice_count >= total_slices); + if (total_slices > 0) { + mi_bitmap_setN(arena->slices_committed, page->memid.mem.arena.slice_index, total_slices, NULL); + } + // any left over? + const size_t extra = page->slice_committed % MI_ARENA_SLICE_SIZE; + if (extra > 0) { + // pretend it was decommitted already + mi_os_stat_decrease(committed, extra); + } + } + else { + mi_assert_internal(mi_bitmap_is_setN(arena->slices_committed, page->memid.mem.arena.slice_index, page->memid.mem.arena.slice_count)); + } + } + _mi_arenas_free(page, mi_page_full_size(page), page->memid); } +/* ----------------------------------------------------------- + Arena abandon +----------------------------------------------------------- */ + +void _mi_arenas_page_abandon(mi_page_t* page, mi_tld_t* tld) { + mi_assert_internal(_mi_is_aligned(page, MI_PAGE_ALIGN)); + mi_assert_internal(_mi_ptr_page(page)==page); + mi_assert_internal(mi_page_is_owned(page)); + mi_assert_internal(mi_page_is_abandoned(page)); + mi_assert_internal(!mi_page_all_free(page)); + mi_assert_internal(page->next==NULL && page->prev == NULL); + + if (page->memid.memkind==MI_MEM_ARENA && !mi_page_is_full(page)) { + // make available for allocations + size_t bin = _mi_bin(mi_page_block_size(page)); + size_t slice_index; + size_t slice_count; + mi_arena_t* arena = mi_page_arena(page, &slice_index, &slice_count); + mi_assert_internal(!mi_page_is_singleton(page)); + mi_assert_internal(mi_bbitmap_is_clearN(arena->slices_free, slice_index, slice_count)); + mi_assert_internal(page->slice_committed > 0 || mi_bitmap_is_setN(arena->slices_committed, slice_index, slice_count)); + mi_assert_internal(mi_bitmap_is_setN(arena->slices_dirty, slice_index, slice_count)); + + mi_page_set_abandoned_mapped(page); + const bool wasclear = mi_bitmap_set(arena->pages_abandoned[bin], slice_index); + MI_UNUSED(wasclear); mi_assert_internal(wasclear); + mi_atomic_increment_relaxed(&arena->subproc->abandoned_count[bin]); + mi_tld_stat_increase(tld, pages_abandoned, 1); + } + else { + // page is full (or a singleton), or the page is OS/externally allocated + // leave as is; it will be reclaimed when an object is free'd in the page + mi_subproc_t* subproc = _mi_subproc(); + // but for non-arena pages, add to the subproc list so these can be visited + if (page->memid.memkind != MI_MEM_ARENA && mi_option_is_enabled(mi_option_visit_abandoned)) { + mi_lock(&subproc->os_abandoned_pages_lock) { + // push in front + page->prev = NULL; + page->next = subproc->os_abandoned_pages; + if (page->next != NULL) { page->next->prev = page; } + subproc->os_abandoned_pages = page; + } + } + mi_tld_stat_increase(tld, pages_abandoned, 1); + } + _mi_page_unown(page); +} + +bool _mi_arenas_page_try_reabandon_to_mapped(mi_page_t* page) { + mi_assert_internal(_mi_is_aligned(page, MI_PAGE_ALIGN)); + mi_assert_internal(_mi_ptr_page(page)==page); + mi_assert_internal(mi_page_is_owned(page)); + mi_assert_internal(mi_page_is_abandoned(page)); + mi_assert_internal(!mi_page_is_abandoned_mapped(page)); + mi_assert_internal(!mi_page_is_full(page)); + mi_assert_internal(!mi_page_all_free(page)); + mi_assert_internal(!mi_page_is_singleton(page)); + if (mi_page_is_full(page) || mi_page_is_abandoned_mapped(page) || page->memid.memkind != MI_MEM_ARENA) { + return false; + } + else { + mi_tld_t* tld = _mi_thread_tld(); + mi_tld_stat_counter_increase( tld, pages_reabandon_full, 1); + mi_tld_stat_adjust_decrease( tld, pages_abandoned, 1); // adjust as we are not abandoning fresh + _mi_arenas_page_abandon(page,tld); + return true; + } +} + +// called from `mi_free` if trying to unabandon an abandoned page +void _mi_arenas_page_unabandon(mi_page_t* page) { + mi_assert_internal(_mi_is_aligned(page, MI_PAGE_ALIGN)); + mi_assert_internal(_mi_ptr_page(page)==page); + mi_assert_internal(mi_page_is_owned(page)); + mi_assert_internal(mi_page_is_abandoned(page)); + + if (mi_page_is_abandoned_mapped(page)) { + mi_assert_internal(page->memid.memkind==MI_MEM_ARENA); + // remove from the abandoned map + size_t bin = _mi_bin(mi_page_block_size(page)); + size_t slice_index; + size_t slice_count; + mi_arena_t* arena = mi_page_arena(page, &slice_index, &slice_count); + + mi_assert_internal(mi_bbitmap_is_clearN(arena->slices_free, slice_index, slice_count)); + mi_assert_internal(page->slice_committed > 0 || mi_bitmap_is_setN(arena->slices_committed, slice_index, slice_count)); + + // this busy waits until a concurrent reader (from alloc_abandoned) is done + mi_bitmap_clear_once_set(arena->pages_abandoned[bin], slice_index); + mi_page_clear_abandoned_mapped(page); + mi_atomic_decrement_relaxed(&arena->subproc->abandoned_count[bin]); + mi_tld_stat_decrease(_mi_thread_tld(), pages_abandoned, 1); + } + else { + // page is full (or a singleton), page is OS allocated + mi_tld_stat_decrease(_mi_thread_tld(), pages_abandoned, 1); + // if not an arena page, remove from the subproc os pages list + if (page->memid.memkind != MI_MEM_ARENA && mi_option_is_enabled(mi_option_visit_abandoned)) { + mi_subproc_t* subproc = _mi_subproc(); + mi_lock(&subproc->os_abandoned_pages_lock) { + if (page->prev != NULL) { page->prev->next = page->next; } + if (page->next != NULL) { page->next->prev = page->prev; } + if (subproc->os_abandoned_pages == page) { subproc->os_abandoned_pages = page->next; } + page->next = NULL; + page->prev = NULL; + } + } + } +} + + /* ----------------------------------------------------------- Arena free ----------------------------------------------------------- */ +static void mi_arena_schedule_purge(mi_arena_t* arena, size_t slice_index, size_t slices); +static void mi_arenas_try_purge(bool force, bool visit_all, mi_tld_t* tld); -void _mi_arena_free(void* p, size_t size, size_t memid, bool all_committed, mi_os_tld_t* tld) { - mi_assert_internal(size > 0 && tld->stats != NULL); +void _mi_arenas_free(void* p, size_t size, mi_memid_t memid) { if (p==NULL) return; if (size==0) return; - if (memid == MI_MEMID_OS) { + // need to set all memory to undefined as some parts may still be marked as no_access (like padding etc.) + mi_track_mem_undefined(p, size); + + if (mi_memkind_is_os(memid.memkind)) { // was a direct OS allocation, pass through - _mi_os_free_ex(p, size, all_committed, tld->stats); + _mi_os_free(p, size, memid); } - else { + else if (memid.memkind == MI_MEM_ARENA) { // allocated in an arena - size_t arena_idx; - size_t bitmap_idx; - mi_arena_memid_indices(memid, &arena_idx, &bitmap_idx); - mi_assert_internal(arena_idx < MI_MAX_ARENAS); - mi_arena_t* arena = mi_atomic_load_ptr_relaxed(mi_arena_t,&mi_arenas[arena_idx]); - mi_assert_internal(arena != NULL); - const size_t blocks = mi_block_count_of_size(size); + size_t slice_count; + size_t slice_index; + mi_arena_t* arena = mi_arena_from_memid(memid, &slice_index, &slice_count); + mi_assert_internal((size%MI_ARENA_SLICE_SIZE)==0); + mi_assert_internal((slice_count*MI_ARENA_SLICE_SIZE)==size); + mi_assert_internal(mi_arena_slice_start(arena,slice_index) <= (uint8_t*)p); + mi_assert_internal(mi_arena_slice_start(arena,slice_index) + mi_size_of_slices(slice_count) > (uint8_t*)p); // checks if (arena == NULL) { - _mi_error_message(EINVAL, "trying to free from non-existent arena: %p, size %zu, memid: 0x%zx\n", p, size, memid); + _mi_error_message(EINVAL, "trying to free from an invalid arena: %p, size %zu, memid: 0x%zx\n", p, size, memid); return; } - mi_assert_internal(arena->field_count > mi_bitmap_index_field(bitmap_idx)); - if (arena->field_count <= mi_bitmap_index_field(bitmap_idx)) { - _mi_error_message(EINVAL, "trying to free from non-existent arena block: %p, size %zu, memid: 0x%zx\n", p, size, memid); + mi_assert_internal(slice_index < arena->slice_count); + mi_assert_internal(slice_index >= mi_arena_info_slices(arena)); + if (slice_index < mi_arena_info_slices(arena) || slice_index > arena->slice_count) { + _mi_error_message(EINVAL, "trying to free from an invalid arena block: %p, size %zu, memid: 0x%zx\n", p, size, memid); return; } + // potentially decommit - if (!arena->allow_decommit || arena->blocks_committed == NULL) { - mi_assert_internal(all_committed); // note: may be not true as we may "pretend" to be not committed (in segment.c) - } - else { - mi_assert_internal(arena->blocks_committed != NULL); - _mi_os_decommit(p, blocks * MI_ARENA_BLOCK_SIZE, tld->stats); // ok if this fails - _mi_bitmap_unclaim_across(arena->blocks_committed, arena->field_count, blocks, bitmap_idx); + if (!arena->memid.is_pinned /* && !arena->memid.initially_committed */) { // todo: allow decommit even if initially committed? + // (delay) purge the page + mi_arena_schedule_purge(arena, slice_index, slice_count); } - // and make it available to others again - bool all_inuse = _mi_bitmap_unclaim_across(arena->blocks_inuse, arena->field_count, blocks, bitmap_idx); + + // and make it available to others again + bool all_inuse = mi_bbitmap_setN(arena->slices_free, slice_index, slice_count); if (!all_inuse) { - _mi_error_message(EAGAIN, "trying to free an already freed block: %p, size %zu\n", p, size); + _mi_error_message(EAGAIN, "trying to free an already freed arena block: %p, size %zu\n", mi_arena_slice_start(arena,slice_index), mi_size_of_slices(slice_count)); return; }; } + else if (memid.memkind == MI_MEM_META) { + _mi_meta_free(p, size, memid); + } + else { + // arena was none, external, or static; nothing to do + mi_assert_internal(mi_memid_needs_no_free(memid)); + } + + // try to purge expired decommits + // mi_arenas_try_purge(false, false, NULL); +} + +// Purge the arenas; if `force_purge` is true, amenable parts are purged even if not yet expired +void _mi_arenas_collect(bool force_purge, bool visit_all, mi_tld_t* tld) { + mi_arenas_try_purge(force_purge, visit_all, tld); +} + + +// Is a pointer contained in the given arena area? +bool mi_arena_contains(mi_arena_id_t arena_id, const void* p) { + mi_arena_t* arena = _mi_arena_from_id(arena_id); + return (mi_arena_start(arena) <= (const uint8_t*)p && + mi_arena_start(arena) + mi_size_of_slices(arena->slice_count) >(const uint8_t*)p); +} + +// Is a pointer inside any of our arenas? +bool _mi_arenas_contain(const void* p) { + mi_subproc_t* subproc = _mi_subproc(); + const size_t max_arena = mi_arenas_get_count(subproc); + for (size_t i = 0; i < max_arena; i++) { + mi_arena_t* arena = mi_atomic_load_ptr_acquire(mi_arena_t, &subproc->arenas[i]); + if (arena != NULL && mi_arena_contains(arena,p)) { + return true; + } + } + return false; +} + + + +/* ----------------------------------------------------------- + Remove an arena. +----------------------------------------------------------- */ + +// destroy owned arenas; this is unsafe and should only be done using `mi_option_destroy_on_exit` +// for dynamic libraries that are unloaded and need to release all their allocated memory. +static void mi_arenas_unsafe_destroy(mi_subproc_t* subproc) { + mi_assert_internal(subproc != NULL); + const size_t max_arena = mi_arenas_get_count(subproc); + size_t new_max_arena = 0; + for (size_t i = 0; i < max_arena; i++) { + mi_arena_t* arena = mi_atomic_load_ptr_acquire(mi_arena_t, &subproc->arenas[i]); + if (arena != NULL) { + // mi_lock_done(&arena->abandoned_visit_lock); + mi_atomic_store_ptr_release(mi_arena_t, &subproc->arenas[i], NULL); + if (mi_memkind_is_os(arena->memid.memkind)) { + _mi_os_free_ex(mi_arena_start(arena), mi_arena_size(arena), true, arena->memid, subproc); // pass `subproc` to avoid accessing the heap pointer (in `_mi_subproc()`) + } + } + } + + // try to lower the max arena. + size_t expected = max_arena; + mi_atomic_cas_strong_acq_rel(&subproc->arena_count, &expected, new_max_arena); } + +// destroy owned arenas; this is unsafe and should only be done using `mi_option_destroy_on_exit` +// for dynamic libraries that are unloaded and need to release all their allocated memory. +void _mi_arenas_unsafe_destroy_all(mi_tld_t* tld) { + mi_arenas_unsafe_destroy(tld->subproc); + _mi_arenas_collect(true /* force purge */, true /* visit all*/, tld); // purge non-owned arenas +} + + /* ----------------------------------------------------------- Add an arena. ----------------------------------------------------------- */ -static bool mi_arena_add(mi_arena_t* arena, mi_arena_id_t* arena_id) { +static bool mi_arenas_add(mi_subproc_t* subproc, mi_arena_t* arena, mi_arena_id_t* arena_id) { mi_assert_internal(arena != NULL); - mi_assert_internal((uintptr_t)mi_atomic_load_ptr_relaxed(uint8_t,&arena->start) % MI_SEGMENT_ALIGN == 0); - mi_assert_internal(arena->block_count > 0); - if (arena_id != NULL) *arena_id = -1; + mi_assert_internal(arena->slice_count > 0); + if (arena_id != NULL) { *arena_id = NULL; } + + // first try to find a NULL entry + const size_t count = mi_arenas_get_count(subproc); + size_t i; + for (i = 0; i < count; i++) { + if (mi_arena_from_index(subproc,i) == NULL) { + mi_arena_t* expected = NULL; + if (mi_atomic_cas_ptr_strong_release(mi_arena_t, &subproc->arenas[i], &expected, arena)) { + // success + if (arena_id != NULL) { *arena_id = arena; } + return true; + } + } + } - size_t i = mi_atomic_increment_acq_rel(&mi_arena_count); + // otherwise increase the max + i = mi_atomic_increment_acq_rel(&subproc->arena_count); if (i >= MI_MAX_ARENAS) { - mi_atomic_decrement_acq_rel(&mi_arena_count); + mi_atomic_decrement_acq_rel(&subproc->arena_count); + arena->subproc = NULL; return false; } - mi_atomic_store_ptr_release(mi_arena_t,&mi_arenas[i], arena); - arena->id = mi_arena_id_create(i); - if (arena_id != NULL) *arena_id = arena->id; + + mi_subproc_stat_counter_increase(arena->subproc, arena_count, 1); + mi_atomic_store_ptr_release(mi_arena_t,&subproc->arenas[i], arena); + if (arena_id != NULL) { *arena_id = arena; } return true; } -bool mi_manage_os_memory_ex(void* start, size_t size, bool is_committed, bool is_large, bool is_zero, int numa_node, bool exclusive, mi_arena_id_t* arena_id) mi_attr_noexcept +static size_t mi_arena_info_slices_needed(size_t slice_count, size_t* bitmap_base) { + if (slice_count == 0) slice_count = MI_BCHUNK_BITS; + mi_assert_internal((slice_count % MI_BCHUNK_BITS) == 0); + const size_t base_size = _mi_align_up(sizeof(mi_arena_t), MI_BCHUNK_SIZE); + const size_t bitmaps_count = 4 + MI_BIN_COUNT; // commit, dirty, purge, pages, and abandonded + const size_t bitmaps_size = bitmaps_count * mi_bitmap_size(slice_count, NULL) + mi_bbitmap_size(slice_count, NULL); // + free + const size_t size = base_size + bitmaps_size; + + const size_t os_page_size = _mi_os_page_size(); + const size_t info_size = _mi_align_up(size, os_page_size) + _mi_os_secure_guard_page_size(); + const size_t info_slices = mi_slice_count_of_size(info_size); + + if (bitmap_base != NULL) *bitmap_base = base_size; + return info_slices; +} + +static mi_bitmap_t* mi_arena_bitmap_init(size_t slice_count, uint8_t** base) { + mi_bitmap_t* bitmap = (mi_bitmap_t*)(*base); + *base = (*base) + mi_bitmap_init(bitmap, slice_count, true /* already zero */); + return bitmap; +} + +static mi_bbitmap_t* mi_arena_bbitmap_init(size_t slice_count, uint8_t** base) { + mi_bbitmap_t* bbitmap = (mi_bbitmap_t*)(*base); + *base = (*base) + mi_bbitmap_init(bbitmap, slice_count, true /* already zero */); + return bbitmap; +} + + +static bool mi_manage_os_memory_ex2(mi_subproc_t* subproc, void* start, size_t size, int numa_node, bool exclusive, + mi_memid_t memid, mi_commit_fun_t* commit_fun, void* commit_fun_arg, mi_arena_id_t* arena_id) mi_attr_noexcept { - if (arena_id != NULL) *arena_id = _mi_arena_id_none(); - if (size < MI_ARENA_BLOCK_SIZE) return false; + mi_assert(_mi_is_aligned(start,MI_ARENA_SLICE_SIZE)); + mi_assert(start!=NULL); + if (arena_id != NULL) { *arena_id = _mi_arena_id_none(); } + if (start==NULL) return false; + if (!_mi_is_aligned(start,MI_ARENA_SLICE_SIZE)) { + // we can align the start since the memid tracks the real base of the memory. + void* const aligned_start = _mi_align_up_ptr(start, MI_ARENA_SLICE_SIZE); + const size_t diff = (uint8_t*)aligned_start - (uint8_t*)start; + if (diff >= size || (size - diff) < MI_ARENA_SLICE_SIZE) { + _mi_warning_message("after alignment, the size of the arena becomes too small (memory at %p with size %zu)\n", start, size); + return false; + } + start = aligned_start; + size = size - diff; + } - if (is_large) { - mi_assert_internal(is_committed); - is_committed = true; + const size_t slice_count = _mi_align_down(size / MI_ARENA_SLICE_SIZE, MI_BCHUNK_BITS); + if (slice_count > MI_BITMAP_MAX_BIT_COUNT) { // 16 GiB for now + // todo: allow larger areas (either by splitting it up in arena's or having larger arena's) + _mi_warning_message("cannot use OS memory since it is too large (size %zu MiB, maximum is %zu MiB)", size/MI_MiB, mi_size_of_slices(MI_BITMAP_MAX_BIT_COUNT)/MI_MiB); + return false; } - - const size_t bcount = size / MI_ARENA_BLOCK_SIZE; - const size_t fields = _mi_divide_up(bcount, MI_BITMAP_FIELD_BITS); - const size_t bitmaps = (is_committed ? 2 : 3); - const size_t asize = sizeof(mi_arena_t) + (bitmaps*fields*sizeof(mi_bitmap_field_t)); - mi_arena_t* arena = (mi_arena_t*)_mi_os_alloc(asize, &_mi_stats_main); // TODO: can we avoid allocating from the OS? - if (arena == NULL) return false; - - arena->id = _mi_arena_id_none(); - arena->exclusive = exclusive; - arena->block_count = bcount; - arena->field_count = fields; - arena->start = (uint8_t*)start; + size_t bitmap_base; + const size_t info_slices = mi_arena_info_slices_needed(slice_count, &bitmap_base); + if (slice_count < info_slices+1) { + _mi_warning_message("cannot use OS memory since it is not large enough (size %zu KiB, minimum required is %zu KiB)", size/MI_KiB, mi_size_of_slices(info_slices+1)/MI_KiB); + return false; + } + else if (info_slices >= MI_ARENA_MAX_OBJ_SLICES) { + _mi_warning_message("cannot use OS memory since it is too large with respect to the maximum object size (size %zu MiB, meta-info slices %zu, maximum object slices are %zu)", size/MI_MiB, info_slices, MI_ARENA_MAX_OBJ_SLICES); + return false; + } + + mi_arena_t* arena = (mi_arena_t*)start; + + // commit & zero if needed + if (!memid.initially_committed) { + size_t commit_size = mi_size_of_slices(info_slices); + // leave a guard OS page decommitted at the end? + if (!memid.is_pinned) { commit_size -= _mi_os_secure_guard_page_size(); } + bool ok = false; + if (commit_fun != NULL) { + ok = (*commit_fun)(true /* commit */, arena, commit_size, NULL, commit_fun_arg); + } + else { + ok = _mi_os_commit(arena, commit_size, NULL); + } + if (!ok) { + _mi_warning_message("unable to commit meta-data for OS memory"); + return false; + } + } + else if (!memid.is_pinned) { + // if MI_SECURE, set a guard page at the end + // todo: this does not respect the commit_fun as the memid is of external memory + _mi_os_secure_guard_page_set_before((uint8_t*)arena + mi_size_of_slices(info_slices), memid); + } + if (!memid.initially_zero) { + _mi_memzero(arena, mi_size_of_slices(info_slices) - _mi_os_secure_guard_page_size()); + } + + // init + arena->subproc = subproc; + arena->memid = memid; + arena->is_exclusive = exclusive; + arena->slice_count = slice_count; + arena->info_slices = info_slices; arena->numa_node = numa_node; // TODO: or get the current numa node if -1? (now it allows anyone to allocate on -1) - arena->is_large = is_large; - arena->is_zero_init = is_zero; - arena->allow_decommit = !is_large && !is_committed; // only allow decommit for initially uncommitted memory - arena->search_idx = 0; - arena->blocks_dirty = &arena->blocks_inuse[fields]; // just after inuse bitmap - arena->blocks_committed = (!arena->allow_decommit ? NULL : &arena->blocks_inuse[2*fields]); // just after dirty bitmap - // the bitmaps are already zero initialized due to os_alloc - // initialize committed bitmap? - if (arena->blocks_committed != NULL && is_committed) { - memset((void*)arena->blocks_committed, 0xFF, fields*sizeof(mi_bitmap_field_t)); // cast to void* to avoid atomic warning + arena->purge_expire = 0; + arena->commit_fun = commit_fun; + arena->commit_fun_arg = commit_fun_arg; + // mi_lock_init(&arena->abandoned_visit_lock); + + // init bitmaps + uint8_t* base = mi_arena_start(arena) + bitmap_base; + arena->slices_free = mi_arena_bbitmap_init(slice_count,&base); + arena->slices_committed = mi_arena_bitmap_init(slice_count,&base); + arena->slices_dirty = mi_arena_bitmap_init(slice_count,&base); + arena->slices_purge = mi_arena_bitmap_init(slice_count, &base); + arena->pages = mi_arena_bitmap_init(slice_count, &base); + for( size_t i = 0; i < MI_ARENA_BIN_COUNT; i++) { + arena->pages_abandoned[i] = mi_arena_bitmap_init(slice_count,&base); + } + mi_assert_internal(mi_size_of_slices(info_slices) >= (size_t)(base - mi_arena_start(arena))); + + // reserve our meta info (and reserve slices outside the memory area) + mi_bbitmap_unsafe_setN(arena->slices_free, info_slices /* start */, arena->slice_count - info_slices); + if (memid.initially_committed) { + mi_bitmap_unsafe_setN(arena->slices_committed, 0, arena->slice_count); + } + else { + mi_bitmap_setN(arena->slices_committed, 0, info_slices, NULL); + } + if (!memid.initially_zero) { + mi_bitmap_unsafe_setN(arena->slices_dirty, 0, arena->slice_count); } - // and claim leftover blocks if needed (so we never allocate there) - ptrdiff_t post = (fields * MI_BITMAP_FIELD_BITS) - bcount; - mi_assert_internal(post >= 0); - if (post > 0) { - // don't use leftover bits at the end - mi_bitmap_index_t postidx = mi_bitmap_index_create(fields - 1, MI_BITMAP_FIELD_BITS - post); - _mi_bitmap_claim(arena->blocks_inuse, fields, post, postidx, NULL); + else { + mi_bitmap_setN(arena->slices_dirty, 0, info_slices, NULL); } - return mi_arena_add(arena, arena_id); + return mi_arenas_add(subproc, arena, arena_id); +} + +bool mi_manage_os_memory_ex(void* start, size_t size, bool is_committed, bool is_pinned, bool is_zero, int numa_node, bool exclusive, mi_arena_id_t* arena_id) mi_attr_noexcept { + mi_memid_t memid = _mi_memid_create(MI_MEM_EXTERNAL); + memid.mem.os.base = start; + memid.mem.os.size = size; + memid.initially_committed = is_committed; + memid.initially_zero = is_zero; + memid.is_pinned = is_pinned; + return mi_manage_os_memory_ex2(_mi_subproc(), start, size, numa_node, exclusive, memid, NULL, NULL, arena_id); } -// Reserve a range of regular OS memory -int mi_reserve_os_memory_ex(size_t size, bool commit, bool allow_large, bool exclusive, mi_arena_id_t* arena_id) mi_attr_noexcept +bool mi_manage_memory(void* start, size_t size, bool is_committed, bool is_zero, bool is_pinned, int numa_node, bool exclusive, mi_commit_fun_t* commit_fun, void* commit_fun_arg, mi_arena_id_t* arena_id) mi_attr_noexcept { + mi_memid_t memid = _mi_memid_create(MI_MEM_EXTERNAL); + memid.mem.os.base = start; + memid.mem.os.size = size; + memid.initially_committed = is_committed; + memid.initially_zero = is_zero; + memid.is_pinned = is_pinned; + return mi_manage_os_memory_ex2(_mi_subproc(), start, size, numa_node, exclusive, memid, commit_fun, commit_fun_arg, arena_id); +} + + +// Reserve a range of regular OS memory +static int mi_reserve_os_memory_ex2(mi_subproc_t* subproc, size_t size, bool commit, bool allow_large, bool exclusive, mi_arena_id_t* arena_id) { if (arena_id != NULL) *arena_id = _mi_arena_id_none(); - size = _mi_align_up(size, MI_ARENA_BLOCK_SIZE); // at least one block - bool large = allow_large; - void* start = _mi_os_alloc_aligned(size, MI_SEGMENT_ALIGN, commit, &large, &_mi_stats_main); - if (start==NULL) return ENOMEM; - if (!mi_manage_os_memory_ex(start, size, (large || commit), large, true, -1, exclusive, arena_id)) { - _mi_os_free_ex(start, size, commit, &_mi_stats_main); - _mi_verbose_message("failed to reserve %zu k memory\n", _mi_divide_up(size,1024)); + size = _mi_align_up(size, MI_ARENA_SLICE_SIZE); // at least one slice + mi_memid_t memid; + void* start = _mi_os_alloc_aligned(size, MI_ARENA_SLICE_ALIGN, commit, allow_large, &memid); + if (start == NULL) return ENOMEM; + if (!mi_manage_os_memory_ex2(subproc, start, size, -1 /* numa node */, exclusive, memid, NULL, NULL, arena_id)) { + _mi_os_free_ex(start, size, commit, memid, NULL); + _mi_verbose_message("failed to reserve %zu KiB memory\n", _mi_divide_up(size, 1024)); return ENOMEM; } - _mi_verbose_message("reserved %zu KiB memory%s\n", _mi_divide_up(size,1024), large ? " (in large os pages)" : ""); + _mi_verbose_message("reserved %zu KiB memory%s\n", _mi_divide_up(size, 1024), memid.is_pinned ? " (in large os pages)" : ""); + // mi_debug_show_arenas(true, true, false); + return 0; } +// Reserve a range of regular OS memory +int mi_reserve_os_memory_ex(size_t size, bool commit, bool allow_large, bool exclusive, mi_arena_id_t* arena_id) mi_attr_noexcept { + return mi_reserve_os_memory_ex2(_mi_subproc(), size, commit, allow_large, exclusive, arena_id); +} + +// Manage a range of regular OS memory bool mi_manage_os_memory(void* start, size_t size, bool is_committed, bool is_large, bool is_zero, int numa_node) mi_attr_noexcept { - return mi_manage_os_memory_ex(start, size, is_committed, is_large, is_zero, numa_node, false, NULL); + return mi_manage_os_memory_ex(start, size, is_committed, is_large, is_zero, numa_node, false /* exclusive? */, NULL); } +// Reserve a range of regular OS memory int mi_reserve_os_memory(size_t size, bool commit, bool allow_large) mi_attr_noexcept { return mi_reserve_os_memory_ex(size, commit, allow_large, false, NULL); } @@ -439,32 +1345,223 @@ int mi_reserve_os_memory(size_t size, bool commit, bool allow_large) mi_attr_noe Debugging ----------------------------------------------------------- */ -static size_t mi_debug_show_bitmap(const char* prefix, mi_bitmap_field_t* fields, size_t field_count ) { - size_t inuse_count = 0; - for (size_t i = 0; i < field_count; i++) { - char buf[MI_BITMAP_FIELD_BITS + 1]; - uintptr_t field = mi_atomic_load_relaxed(&fields[i]); - for (size_t bit = 0; bit < MI_BITMAP_FIELD_BITS; bit++) { - bool inuse = ((((uintptr_t)1 << bit) & field) != 0); - if (inuse) inuse_count++; - buf[MI_BITMAP_FIELD_BITS - 1 - bit] = (inuse ? 'x' : '.'); +// Return idx of the slice past the last used slice +static size_t mi_arena_used_slices(mi_arena_t* arena) { + size_t idx; + if (mi_bitmap_bsr(arena->pages, &idx)) { + mi_page_t* page = (mi_page_t*)mi_arena_slice_start(arena, idx); + const size_t page_slice_count = page->memid.mem.arena.slice_count; + return (idx + page_slice_count); + } + else { + return mi_arena_info_slices(arena); + } +} + +static size_t mi_debug_show_bfield(mi_bfield_t field, char* buf, size_t* k) { + size_t bit_set_count = 0; + for (int bit = 0; bit < MI_BFIELD_BITS; bit++) { + bool is_set = ((((mi_bfield_t)1 << bit) & field) != 0); + if (is_set) bit_set_count++; + buf[*k++] = (is_set ? 'x' : '.'); + } + return bit_set_count; +} + +typedef enum mi_ansi_color_e { + MI_BLACK = 30, + MI_MAROON, + MI_DARKGREEN, + MI_ORANGE, + MI_NAVY, + MI_PURPLE, + MI_TEAL, + MI_GRAY, + MI_DARKGRAY = 90, + MI_RED, + MI_GREEN, + MI_YELLOW, + MI_BLUE, + MI_MAGENTA, + MI_CYAN, + MI_WHITE +} mi_ansi_color_t; + +static void mi_debug_color(char* buf, size_t* k, mi_ansi_color_t color) { + *k += _mi_snprintf(buf + *k, 32, "\x1B[%dm", (int)color); +} + +static int mi_page_commit_usage(mi_page_t* page) { + // if (mi_page_size(page) <= MI_PAGE_MIN_COMMIT_SIZE) return 100; + const size_t committed_size = mi_page_committed(page); + const size_t used_size = page->used * mi_page_block_size(page); + return (int)(used_size * 100 / committed_size); +} + +static size_t mi_debug_show_page_bfield(mi_bfield_t field, char* buf, size_t* k, mi_arena_t* arena, size_t slice_index, long* pbit_of_page, mi_ansi_color_t* pcolor_of_page ) { + size_t bit_set_count = 0; + long bit_of_page = *pbit_of_page; + mi_ansi_color_t color = *pcolor_of_page; + mi_ansi_color_t prev_color = MI_GRAY; + for (int bit = 0; bit < MI_BFIELD_BITS; bit++, bit_of_page--) { + bool is_set = ((((mi_bfield_t)1 << bit) & field) != 0); + void* start = mi_arena_slice_start(arena, slice_index + bit); + char c = ' '; + if (is_set) { + mi_assert_internal(bit_of_page <= 0); + bit_set_count++; + c = 'p'; + color = MI_GRAY; + mi_page_t* page = (mi_page_t*)start; + if (mi_page_is_singleton(page)) { c = 's'; } + else if (mi_page_is_full(page)) { c = 'f'; } + if (!mi_page_is_abandoned(page)) { c = _mi_toupper(c); } + int commit_usage = mi_page_commit_usage(page); + if (commit_usage < 25) { color = MI_MAROON; } + else if (commit_usage < 50) { color = MI_ORANGE; } + else if (commit_usage < 75) { color = MI_TEAL; } + else color = MI_DARKGREEN; + bit_of_page = (long)page->memid.mem.arena.slice_count; } - buf[MI_BITMAP_FIELD_BITS] = 0; - _mi_verbose_message("%s%s\n", prefix, buf); + else { + c = '?'; + if (bit_of_page > 0) { c = '-'; } + else if (_mi_meta_is_meta_page(start)) { c = 'm'; color = MI_GRAY; } + else if (slice_index + bit < arena->info_slices) { c = 'i'; color = MI_GRAY; } + // else if (mi_bitmap_is_setN(arena->pages_purge, slice_index + bit, NULL)) { c = '*'; } + else if (mi_bbitmap_is_setN(arena->slices_free, slice_index+bit,1)) { + if (mi_bitmap_is_set(arena->slices_purge, slice_index + bit)) { c = '~'; color = MI_ORANGE; } + else if (mi_bitmap_is_setN(arena->slices_committed, slice_index + bit, 1)) { c = '_'; color = MI_GRAY; } + else { c = '.'; color = MI_GRAY; } + } + if (bit==MI_BFIELD_BITS-1 && bit_of_page > 1) { c = '>'; } + } + if (color != prev_color) { + mi_debug_color(buf, k, color); + prev_color = color; + } + buf[*k] = c; *k += 1; } - return inuse_count; + mi_debug_color(buf, k, MI_GRAY); + *pbit_of_page = bit_of_page; + *pcolor_of_page = color; + return bit_set_count; } -void mi_debug_show_arenas(void) mi_attr_noexcept { - size_t max_arenas = mi_atomic_load_relaxed(&mi_arena_count); +static size_t mi_debug_show_chunks(const char* header1, const char* header2, const char* header3, + size_t slice_count, size_t chunk_count, + mi_bchunk_t* chunks, mi_bchunkmap_t* chunk_bins, bool invert, mi_arena_t* arena, bool narrow) +{ + _mi_raw_message("\x1B[37m%s%s%s (use/commit: \x1B[31m0 - 25%%\x1B[33m - 50%%\x1B[36m - 75%%\x1B[32m - 100%%\x1B[0m)\n", header1, header2, header3); + const size_t fields_per_line = (narrow ? 2 : 4); + const size_t used_slice_count = mi_arena_used_slices(arena); + size_t bit_count = 0; + size_t bit_set_count = 0; + for (size_t i = 0; i < chunk_count && bit_count < slice_count; i++) { + char buf[5*MI_BCHUNK_BITS + 64]; _mi_memzero(buf, sizeof(buf)); + if (bit_count > used_slice_count && i+2 < chunk_count) { + const size_t diff = chunk_count - 1 - i; + bit_count += diff*MI_BCHUNK_BITS; + _mi_raw_message(" |\n"); + i = chunk_count-1; + } + + size_t k = 0; + mi_bchunk_t* chunk = &chunks[i]; + + if (i<10) { buf[k++] = ('0' + (char)i); buf[k++] = ' '; buf[k++] = ' '; } + else if (i<100) { buf[k++] = ('0' + (char)(i/10)); buf[k++] = ('0' + (char)(i%10)); buf[k++] = ' '; } + else if (i<1000) { buf[k++] = ('0' + (char)(i/100)); buf[k++] = ('0' + (char)((i%100)/10)); buf[k++] = ('0' + (char)(i%10)); } + + char chunk_kind = ' '; + if (chunk_bins != NULL) { + switch (mi_bbitmap_debug_get_bin(chunk_bins,i)) { + case MI_CBIN_SMALL: chunk_kind = 'S'; break; + case MI_CBIN_MEDIUM: chunk_kind = 'M'; break; + case MI_CBIN_LARGE: chunk_kind = 'L'; break; + case MI_CBIN_OTHER: chunk_kind = 'X'; break; + default: chunk_kind = ' '; break; // suppress warning + // case MI_CBIN_NONE: chunk_kind = 'N'; break; + } + } + buf[k++] = chunk_kind; + buf[k++] = ' '; + + long bit_of_page = 0; + mi_ansi_color_t color_of_page = MI_GRAY; + for (size_t j = 0; j < MI_BCHUNK_FIELDS; j++) { + if (j > 0 && (j % fields_per_line) == 0) { + // buf[k++] = '\n'; _mi_memset(buf+k,' ',7); k += 7; + _mi_raw_message(" %s\n\x1B[37m", buf); + _mi_memzero(buf, sizeof(buf)); + _mi_memset(buf, ' ', 5); k = 5; + } + if (bit_count < slice_count) { + mi_bfield_t bfield = chunk->bfields[j]; + if (invert) bfield = ~bfield; + size_t xcount = (arena!=NULL ? mi_debug_show_page_bfield(bfield, buf, &k, arena, bit_count, &bit_of_page, &color_of_page) + : mi_debug_show_bfield(bfield, buf, &k)); + if (invert) xcount = MI_BFIELD_BITS - xcount; + bit_set_count += xcount; + buf[k++] = ' '; + } + else { + _mi_memset(buf + k, 'o', MI_BFIELD_BITS); + k += MI_BFIELD_BITS; + } + bit_count += MI_BFIELD_BITS; + } + _mi_raw_message(" %s\n\x1B[37m", buf); + } + _mi_raw_message("\x1B[0m total ('x'): %zu\n", bit_set_count); + return bit_set_count; +} + +static size_t mi_debug_show_bitmap_binned(const char* header1, const char* header2, const char* header3, size_t slice_count, mi_bitmap_t* bitmap, mi_bchunkmap_t* chunk_bins, bool invert, mi_arena_t* arena, bool narrow) { + return mi_debug_show_chunks(header1, header2, header3, slice_count, mi_bitmap_chunk_count(bitmap), &bitmap->chunks[0], chunk_bins, invert, arena, narrow); +} + +static void mi_debug_show_arenas_ex(bool show_pages, bool narrow) mi_attr_noexcept { + mi_subproc_t* subproc = _mi_subproc(); + size_t max_arenas = mi_arenas_get_count(subproc); + //size_t free_total = 0; + //size_t slice_total = 0; + //size_t abandoned_total = 0; + size_t page_total = 0; for (size_t i = 0; i < max_arenas; i++) { - mi_arena_t* arena = mi_atomic_load_ptr_relaxed(mi_arena_t, &mi_arenas[i]); + mi_arena_t* arena = mi_atomic_load_ptr_acquire(mi_arena_t, &subproc->arenas[i]); if (arena == NULL) break; - size_t inuse_count = 0; - _mi_verbose_message("arena %zu: %zu blocks with %zu fields\n", i, arena->block_count, arena->field_count); - inuse_count += mi_debug_show_bitmap(" ", arena->blocks_inuse, arena->field_count); - _mi_verbose_message(" blocks in use ('x'): %zu\n", inuse_count); + mi_assert(arena->subproc == subproc); + // slice_total += arena->slice_count; + _mi_raw_message("arena %zu at %p: %zu slices (%zu MiB)%s, subproc: %p\n", i, arena, arena->slice_count, (size_t)(mi_size_of_slices(arena->slice_count)/MI_MiB), (arena->memid.is_pinned ? ", pinned" : ""), arena->subproc); + //if (show_inuse) { + // free_total += mi_debug_show_bbitmap("in-use slices", arena->slice_count, arena->slices_free, true, NULL); + //} + //if (show_committed) { + // mi_debug_show_bitmap("committed slices", arena->slice_count, arena->slices_committed, false, NULL); + //} + // todo: abandoned slices + //if (show_purge) { + // purge_total += mi_debug_show_bitmap("purgeable slices", arena->slice_count, arena->slices_purge, false, NULL); + //} + if (show_pages) { + const char* header1 = "pages (p:page, f:full, s:singleton, P,F,S:not abandoned, i:arena-info, m:meta-data, ~:free-purgable, _:free-committed, .:free-reserved)"; + const char* header2 = (narrow ? "\n " : " "); + const char* header3 = "(chunk bin: S:small, M : medium, L : large, X : other)"; + page_total += mi_debug_show_bitmap_binned(header1, header2, header3, arena->slice_count, arena->pages, arena->slices_free->chunkmap_bins, false, arena, narrow); + } } + // if (show_inuse) _mi_raw_message("total inuse slices : %zu\n", slice_total - free_total); + // if (show_abandoned) _mi_raw_message("total abandoned slices: %zu\n", abandoned_total); + if (show_pages) _mi_raw_message("total pages in arenas: %zu\n", page_total); +} + +void mi_debug_show_arenas(void) mi_attr_noexcept { + mi_debug_show_arenas_ex(true /* show pages */, false /* narrow? */); +} + +void mi_arenas_print(void) mi_attr_noexcept { + mi_debug_show_arenas(); } @@ -473,21 +1570,22 @@ void mi_debug_show_arenas(void) mi_attr_noexcept { ----------------------------------------------------------- */ // reserve at a specific numa node int mi_reserve_huge_os_pages_at_ex(size_t pages, int numa_node, size_t timeout_msecs, bool exclusive, mi_arena_id_t* arena_id) mi_attr_noexcept { - if (arena_id != NULL) *arena_id = -1; + if (arena_id != NULL) *arena_id = NULL; if (pages==0) return 0; if (numa_node < -1) numa_node = -1; if (numa_node >= 0) numa_node = numa_node % _mi_os_numa_node_count(); size_t hsize = 0; size_t pages_reserved = 0; - void* p = _mi_os_alloc_huge_os_pages(pages, numa_node, timeout_msecs, &pages_reserved, &hsize); + mi_memid_t memid; + void* p = _mi_os_alloc_huge_os_pages(pages, numa_node, timeout_msecs, &pages_reserved, &hsize, &memid); if (p==NULL || pages_reserved==0) { _mi_warning_message("failed to reserve %zu GiB huge pages\n", pages); return ENOMEM; } _mi_verbose_message("numa node %i: reserved %zu GiB huge pages (of the %zu GiB requested)\n", numa_node, pages_reserved, pages); - if (!mi_manage_os_memory_ex(p, hsize, true, true, true, numa_node, exclusive, arena_id)) { - _mi_os_free_huge_pages(p, hsize, &_mi_stats_main); + if (!mi_manage_os_memory_ex2(_mi_subproc(), p, hsize, numa_node, exclusive, memid, NULL, NULL, arena_id)) { + _mi_os_free(p, hsize, memid); return ENOMEM; } return 0; @@ -502,17 +1600,17 @@ int mi_reserve_huge_os_pages_interleave(size_t pages, size_t numa_nodes, size_t if (pages == 0) return 0; // pages per numa node - size_t numa_count = (numa_nodes > 0 ? numa_nodes : _mi_os_numa_node_count()); - if (numa_count <= 0) numa_count = 1; + int numa_count = (numa_nodes > 0 && numa_nodes <= INT_MAX ? (int)numa_nodes : _mi_os_numa_node_count()); + if (numa_count <= 0) { numa_count = 1; } const size_t pages_per = pages / numa_count; const size_t pages_mod = pages % numa_count; const size_t timeout_per = (timeout_msecs==0 ? 0 : (timeout_msecs / numa_count) + 50); // reserve evenly among numa nodes - for (size_t numa_node = 0; numa_node < numa_count && pages > 0; numa_node++) { + for (int numa_node = 0; numa_node < numa_count && pages > 0; numa_node++) { size_t node_pages = pages_per; // can be 0 - if (numa_node < pages_mod) node_pages++; - int err = mi_reserve_huge_os_pages_at(node_pages, (int)numa_node, timeout_per); + if ((size_t)numa_node < pages_mod) { node_pages++; } + int err = mi_reserve_huge_os_pages_at(node_pages, numa_node, timeout_per); if (err) return err; if (pages < node_pages) { pages = 0; @@ -533,3 +1631,363 @@ int mi_reserve_huge_os_pages(size_t pages, double max_secs, size_t* pages_reserv if (err==0 && pages_reserved!=NULL) *pages_reserved = pages; return err; } + + + + + +/* ----------------------------------------------------------- + Arena purge +----------------------------------------------------------- */ + +static long mi_arena_purge_delay(void) { + // <0 = no purging allowed, 0=immediate purging, >0=milli-second delay + return (mi_option_get(mi_option_purge_delay) * mi_option_get(mi_option_arena_purge_mult)); +} + +// reset or decommit in an arena and update the commit bitmap +// assumes we own the area (i.e. slices_free is claimed by us) +// returns if the memory is no longer committed (versus reset which keeps the commit) +static bool mi_arena_purge(mi_arena_t* arena, size_t slice_index, size_t slice_count) { + mi_assert_internal(!arena->memid.is_pinned); + mi_assert_internal(mi_bbitmap_is_clearN(arena->slices_free, slice_index, slice_count)); + + const size_t size = mi_size_of_slices(slice_count); + void* const p = mi_arena_slice_start(arena, slice_index); + //const bool all_committed = mi_bitmap_is_setN(arena->slices_committed, slice_index, slice_count); + size_t already_committed; + mi_bitmap_setN(arena->slices_committed, slice_index, slice_count, &already_committed); // pretend all committed.. (as we lack a clearN call that counts the already set bits..) + const bool all_committed = (already_committed == slice_count); + const bool needs_recommit = _mi_os_purge_ex(p, size, all_committed /* allow reset? */, mi_size_of_slices(already_committed), arena->commit_fun, arena->commit_fun_arg); + + if (needs_recommit) { + // no longer committed + mi_bitmap_clearN(arena->slices_committed, slice_index, slice_count); + // we just counted in the purge to decommit all, but the some part was not committed so adjust that here + // mi_os_stat_decrease(committed, mi_size_of_slices(slice_count - already_committed)); + } + else if (!all_committed) { + // we cannot assume any of these are committed any longer (even with reset since we did setN and may have marked uncommitted slices as committed) + mi_bitmap_clearN(arena->slices_committed, slice_index, slice_count); + // we adjust the commit count as parts will be re-committed + // mi_os_stat_decrease(committed, mi_size_of_slices(already_committed)); + } + + return needs_recommit; +} + + +// Schedule a purge. This is usually delayed to avoid repeated decommit/commit calls. +// Note: assumes we (still) own the area as we may purge immediately +static void mi_arena_schedule_purge(mi_arena_t* arena, size_t slice_index, size_t slice_count) { + const long delay = mi_arena_purge_delay(); + if (arena->memid.is_pinned || delay < 0 || _mi_preloading()) return; // is purging allowed at all? + + mi_assert_internal(mi_bbitmap_is_clearN(arena->slices_free, slice_index, slice_count)); + if (delay == 0) { + // purge directly + mi_arena_purge(arena, slice_index, slice_count); + } + else { + // schedule purge + const mi_msecs_t expire = _mi_clock_now() + delay; + mi_msecs_t expire0 = 0; + if (mi_atomic_casi64_strong_acq_rel(&arena->purge_expire, &expire0, expire)) { + // expiration was not yet set + // maybe set the global arenas expire as well (if it wasn't set already) + mi_assert_internal(expire0==0); + mi_atomic_casi64_strong_acq_rel(&arena->subproc->purge_expire, &expire0, expire); + } + else { + // already an expiration was set + } + mi_bitmap_setN(arena->slices_purge, slice_index, slice_count, NULL); + } +} + +typedef struct mi_purge_visit_info_s { + mi_msecs_t now; + mi_msecs_t delay; + bool all_purged; + bool any_purged; +} mi_purge_visit_info_t; + +static bool mi_arena_try_purge_range(mi_arena_t* arena, size_t slice_index, size_t slice_count) { + if (mi_bbitmap_try_clearN(arena->slices_free, slice_index, slice_count)) { + // purge + bool decommitted = mi_arena_purge(arena, slice_index, slice_count); MI_UNUSED(decommitted); + mi_assert_internal(!decommitted || mi_bitmap_is_clearN(arena->slices_committed, slice_index, slice_count)); + // and reset the free range + mi_bbitmap_setN(arena->slices_free, slice_index, slice_count); + return true; + } + else { + // was allocated again already + return false; + } +} + +static bool mi_arena_try_purge_visitor(size_t slice_index, size_t slice_count, mi_arena_t* arena, void* arg) { + mi_purge_visit_info_t* vinfo = (mi_purge_visit_info_t*)arg; + // try to purge: first claim the free blocks + if (mi_arena_try_purge_range(arena, slice_index, slice_count)) { + vinfo->any_purged = true; + vinfo->all_purged = true; + } + else if (slice_count > 1) + { + // failed to claim the full range, try per slice instead + for (size_t i = 0; i < slice_count; i++) { + const bool purged = mi_arena_try_purge_range(arena, slice_index + i, 1); + vinfo->any_purged = vinfo->any_purged || purged; + vinfo->all_purged = vinfo->all_purged && purged; + } + } + // don't clear the purge bits as that is done atomically be the _bitmap_forall_set_ranges + // mi_bitmap_clearN(arena->slices_purge, slice_index, slice_count); + return true; // continue +} + +// returns true if anything was purged +static bool mi_arena_try_purge(mi_arena_t* arena, mi_msecs_t now, bool force) +{ + // check pre-conditions + if (arena->memid.is_pinned) return false; + + // expired yet? + mi_msecs_t expire = mi_atomic_loadi64_relaxed(&arena->purge_expire); + if (!force && (expire == 0 || expire > now)) return false; + + // reset expire + mi_atomic_storei64_release(&arena->purge_expire, (mi_msecs_t)0); + mi_subproc_stat_counter_increase(arena->subproc, arena_purges, 1); + + // go through all purge info's (with max MI_BFIELD_BITS ranges at a time) + // this also clears those ranges atomically (so any newly freed blocks will get purged next + // time around) + mi_purge_visit_info_t vinfo = { now, mi_arena_purge_delay(), true /*all?*/, false /*any?*/}; + _mi_bitmap_forall_setc_ranges(arena->slices_purge, &mi_arena_try_purge_visitor, arena, &vinfo); + + return vinfo.any_purged; +} + + +static void mi_arenas_try_purge(bool force, bool visit_all, mi_tld_t* tld) +{ + // try purge can be called often so try to only run when needed + const long delay = mi_arena_purge_delay(); + if (_mi_preloading() || delay <= 0) return; // nothing will be scheduled + + // check if any arena needs purging? + mi_subproc_t* subproc = tld->subproc; + const mi_msecs_t now = _mi_clock_now(); + const mi_msecs_t arenas_expire = mi_atomic_loadi64_acquire(&subproc->purge_expire); + if (!visit_all && !force && (arenas_expire == 0 || arenas_expire > now)) return; + + const size_t max_arena = mi_arenas_get_count(subproc); + if (max_arena == 0) return; + + // allow only one thread to purge at a time (todo: allow concurrent purging?) + static mi_atomic_guard_t purge_guard; + mi_atomic_guard(&purge_guard) + { + // increase global expire: at most one purge per delay cycle + if (arenas_expire > now) { mi_atomic_storei64_release(&subproc->purge_expire, now + (delay/10)); } + const size_t arena_start = tld->thread_seq % max_arena; + size_t max_purge_count = (visit_all ? max_arena : (max_arena/4)+1); + bool all_visited = true; + bool any_purged = false; + for (size_t _i = 0; _i < max_arena; _i++) { + size_t i = _i + arena_start; + if (i >= max_arena) { i -= max_arena; } + mi_arena_t* arena = mi_arena_from_index(subproc,i); + if (arena != NULL) { + if (mi_arena_try_purge(arena, now, force)) { + any_purged = true; + if (max_purge_count <= 1) { + all_visited = false; + break; + } + max_purge_count--; + } + } + } + if (all_visited && !any_purged) { + mi_atomic_storei64_release(&subproc->purge_expire, 0); + } + } +} + +/* ----------------------------------------------------------- + Visit abandoned pages +----------------------------------------------------------- */ + +typedef struct mi_abandoned_page_visit_info_s { + int heap_tag; + mi_block_visit_fun* visitor; + void* arg; + bool visit_blocks; +} mi_abandoned_page_visit_info_t; + +static bool abandoned_page_visit(mi_page_t* page, mi_abandoned_page_visit_info_t* vinfo) { + if (page->heap_tag != vinfo->heap_tag) { return true; } // continue + mi_heap_area_t area; + _mi_heap_area_init(&area, page); + if (!vinfo->visitor(NULL, &area, NULL, area.block_size, vinfo->arg)) { + return false; + } + if (vinfo->visit_blocks) { + return _mi_heap_area_visit_blocks(&area, page, vinfo->visitor, vinfo->arg); + } + else { + return true; + } +} + +static bool abandoned_page_visit_at(size_t slice_index, size_t slice_count, mi_arena_t* arena, void* arg) { + MI_UNUSED(slice_count); + mi_abandoned_page_visit_info_t* vinfo = (mi_abandoned_page_visit_info_t*)arg; + mi_page_t* page = (mi_page_t*)mi_arena_slice_start(arena, slice_index); + mi_assert_internal(mi_page_is_abandoned_mapped(page)); + return abandoned_page_visit(page, vinfo); +} + +// Visit all abandoned pages in this subproc. +bool mi_abandoned_visit_blocks(mi_subproc_id_t subproc_id, int heap_tag, bool visit_blocks, mi_block_visit_fun* visitor, void* arg) { + mi_abandoned_page_visit_info_t visit_info = { heap_tag, visitor, arg, visit_blocks }; + MI_UNUSED(subproc_id); MI_UNUSED(heap_tag); MI_UNUSED(visit_blocks); MI_UNUSED(visitor); MI_UNUSED(arg); + + // visit abandoned pages in the arenas + // we don't have to claim because we assume we are the only thread running (in this subproc). + // (but we could atomically claim as well by first doing abandoned_reclaim and afterwards reabandoning). + bool ok = true; + mi_subproc_t* subproc = _mi_subproc_from_id(subproc_id); + mi_forall_arenas(subproc, NULL, 0, arena) { + mi_assert_internal(arena->subproc == subproc); + for (size_t bin = 0; ok && bin < MI_BIN_COUNT; bin++) { + // todo: if we had a single abandoned page map as well, this can be faster. + if (mi_atomic_load_relaxed(&subproc->abandoned_count[bin]) > 0) { + ok = _mi_bitmap_forall_set(arena->pages_abandoned[bin], &abandoned_page_visit_at, arena, &visit_info); + } + } + } + mi_forall_arenas_end(); + if (!ok) return false; + + // visit abandoned pages in OS allocated memory + // (technically we don't need the lock as we assume we are the only thread running in this subproc) + mi_lock(&subproc->os_abandoned_pages_lock) { + for (mi_page_t* page = subproc->os_abandoned_pages; ok && page != NULL; page = page->next) { + ok = abandoned_page_visit(page, &visit_info); + } + } + + return ok; +} + + +/* ----------------------------------------------------------- + Unloading and reloading an arena. +----------------------------------------------------------- */ +static bool mi_arena_page_register(size_t slice_index, size_t slice_count, mi_arena_t* arena, void* arg) { + MI_UNUSED(arg); MI_UNUSED(slice_count); + mi_assert_internal(slice_count == 1); + mi_page_t* page = (mi_page_t*)mi_arena_slice_start(arena, slice_index); + mi_assert_internal(mi_bitmap_is_setN(page->memid.mem.arena.arena->pages, page->memid.mem.arena.slice_index, 1)); + _mi_page_map_register(page); + mi_assert_internal(_mi_ptr_page(page)==page); + return true; +} + +static bool mi_arena_pages_reregister(mi_arena_t* arena) { + return _mi_bitmap_forall_set(arena->pages, &mi_arena_page_register, arena, NULL); +} + +mi_decl_export bool mi_arena_unload(mi_arena_id_t arena_id, void** base, size_t* accessed_size, size_t* full_size) { + mi_arena_t* arena = _mi_arena_from_id(arena_id); + if (arena==NULL) { + return false; + } + else if (!arena->is_exclusive) { + _mi_warning_message("cannot unload a non-exclusive arena (id %zu at %p)\n", arena_id, arena); + return false; + } + else if (arena->memid.memkind != MI_MEM_EXTERNAL) { + _mi_warning_message("can only unload managed arena's for external memory (id %zu at %p)\n", arena_id, arena); + return false; + } + + // find accessed size + const size_t asize = mi_size_of_slices(mi_arena_used_slices(arena)); + if (base != NULL) { *base = (void*)arena; } + if (full_size != NULL) { *full_size = arena->memid.mem.os.size; } + if (accessed_size != NULL) { *accessed_size = asize; } + + // adjust abandoned page count + mi_subproc_t* const subproc = arena->subproc; + for (size_t bin = 0; bin < MI_BIN_COUNT; bin++) { + const size_t count = mi_bitmap_popcount(arena->pages_abandoned[bin]); + if (count > 0) { mi_atomic_decrement_acq_rel(&subproc->abandoned_count[bin]); } + } + + // unregister the pages + _mi_page_map_unregister_range(arena, asize); + + // set arena entry to NULL + const size_t count = mi_arenas_get_count(subproc); + for(size_t i = 0; i < count; i++) { + if (mi_arena_from_index(subproc, i) == arena) { + mi_atomic_store_ptr_release(mi_arena_t, &subproc->arenas[i], NULL); + if (i + 1 == count) { // try adjust the count? + size_t expected = count; + mi_atomic_cas_strong_acq_rel(&subproc->arena_count, &expected, count-1); + } + break; + } + } + return true; +} + +mi_decl_export bool mi_arena_reload(void* start, size_t size, mi_commit_fun_t* commit_fun, void* commit_fun_arg, mi_arena_id_t* arena_id) { + // assume the memory area is already containing the arena + if (arena_id != NULL) { *arena_id = _mi_arena_id_none(); } + if (start == NULL || size == 0) return false; + mi_arena_t* arena = (mi_arena_t*)start; + mi_memid_t memid = arena->memid; + if (memid.memkind != MI_MEM_EXTERNAL) { + _mi_warning_message("can only reload arena's from external memory (%p)\n", arena); + return false; + } + if (memid.mem.os.base != start) { + _mi_warning_message("the reloaded arena base address differs from the external memory (arena: %p, external: %p)\n", arena, start); + return false; + } + if (memid.mem.os.size != size) { + _mi_warning_message("the reloaded arena size differs from the external memory (arena size: %zu, external size: %zu)\n", arena->memid.mem.os.size, size); + return false; + } + if (!arena->is_exclusive) { + _mi_warning_message("the reloaded arena is not exclusive\n"); + return false; + } + + // re-initialize + arena->is_exclusive = true; + arena->commit_fun = commit_fun; + arena->commit_fun_arg = commit_fun_arg; + arena->subproc = _mi_subproc(); + if (!mi_arenas_add(arena->subproc, arena, arena_id)) { + return false; + } + mi_arena_pages_reregister(arena); + + // adjust abandoned page count + for (size_t bin = 0; bin < MI_BIN_COUNT; bin++) { + const size_t count = mi_bitmap_popcount(arena->pages_abandoned[bin]); + if (count > 0) { mi_atomic_decrement_acq_rel(&arena->subproc->abandoned_count[bin]); } + } + + return true; +} + + diff --git a/src/dashbls/depends/mimalloc/src/bitmap.c b/src/dashbls/depends/mimalloc/src/bitmap.c index 4fc7a1f3d140..66ebc157b04c 100644 --- a/src/dashbls/depends/mimalloc/src/bitmap.c +++ b/src/dashbls/depends/mimalloc/src/bitmap.c @@ -1,414 +1,1730 @@ /* ---------------------------------------------------------------------------- -Copyright (c) 2019-2021 Microsoft Research, Daan Leijen +Copyright (c) 2019-2024 Microsoft Research, Daan Leijen This is free software; you can redistribute it and/or modify it under the terms of the MIT license. A copy of the license can be found in the file "LICENSE" at the root of this distribution. -----------------------------------------------------------------------------*/ /* ---------------------------------------------------------------------------- -Concurrent bitmap that can set/reset sequences of bits atomically, -represeted as an array of fields where each field is a machine word (`size_t`) - -There are two api's; the standard one cannot have sequences that cross -between the bitmap fields (and a sequence must be <= MI_BITMAP_FIELD_BITS). -(this is used in region allocation) - -The `_across` postfixed functions do allow sequences that can cross over -between the fields. (This is used in arena allocation) +Concurrent bitmap that can set/reset sequences of bits atomically ---------------------------------------------------------------------------- */ #include "mimalloc.h" -#include "mimalloc-internal.h" +#include "mimalloc/internal.h" +#include "mimalloc/bits.h" #include "bitmap.h" -/* ----------------------------------------------------------- - Bitmap definition ------------------------------------------------------------ */ +#ifndef MI_OPT_SIMD +#define MI_OPT_SIMD 0 +#endif + +/* -------------------------------------------------------------------------------- + bfields +-------------------------------------------------------------------------------- */ -// The bit mask for a given number of blocks at a specified bit index. -static inline size_t mi_bitmap_mask_(size_t count, size_t bitidx) { - mi_assert_internal(count + bitidx <= MI_BITMAP_FIELD_BITS); - mi_assert_internal(count > 0); - if (count >= MI_BITMAP_FIELD_BITS) return MI_BITMAP_FIELD_FULL; - if (count == 0) return 0; - return ((((size_t)1 << count) - 1) << bitidx); +static inline size_t mi_bfield_ctz(mi_bfield_t x) { + return mi_ctz(x); } +static inline size_t mi_bfield_clz(mi_bfield_t x) { + return mi_clz(x); +} -/* ----------------------------------------------------------- - Claim a bit sequence atomically ------------------------------------------------------------ */ +static inline size_t mi_bfield_popcount(mi_bfield_t x) { + return mi_popcount(x); +} -// Try to atomically claim a sequence of `count` bits in a single -// field at `idx` in `bitmap`. Returns `true` on success. -inline bool _mi_bitmap_try_find_claim_field(mi_bitmap_t bitmap, size_t idx, const size_t count, mi_bitmap_index_t* bitmap_idx) -{ - mi_assert_internal(bitmap_idx != NULL); - mi_assert_internal(count <= MI_BITMAP_FIELD_BITS); - mi_assert_internal(count > 0); - mi_bitmap_field_t* field = &bitmap[idx]; - size_t map = mi_atomic_load_relaxed(field); - if (map==MI_BITMAP_FIELD_FULL) return false; // short cut - - // search for 0-bit sequence of length count - const size_t mask = mi_bitmap_mask_(count, 0); - const size_t bitidx_max = MI_BITMAP_FIELD_BITS - count; - -#ifdef MI_HAVE_FAST_BITSCAN - size_t bitidx = mi_ctz(~map); // quickly find the first zero bit if possible +static inline mi_bfield_t mi_bfield_clear_least_bit(mi_bfield_t x) { + return (x & (x-1)); +} + +// find the least significant bit that is set (i.e. count trailing zero's) +// return false if `x==0` (with `*idx` undefined) and true otherwise, +// with the `idx` is set to the bit index (`0 <= *idx < MI_BFIELD_BITS`). +static inline bool mi_bfield_find_least_bit(mi_bfield_t x, size_t* idx) { + return mi_bsf(x,idx); +} + +// find the most significant bit that is set. +// return false if `x==0` (with `*idx` undefined) and true otherwise, +// with the `idx` is set to the bit index (`0 <= *idx < MI_BFIELD_BITS`). +static inline bool mi_bfield_find_highest_bit(mi_bfield_t x, size_t* idx) { + return mi_bsr(x, idx); +} + + + +// find each set bit in a bit field `x` and clear it, until it becomes zero. +static inline bool mi_bfield_foreach_bit(mi_bfield_t* x, size_t* idx) { + const bool found = mi_bfield_find_least_bit(*x, idx); + *x = mi_bfield_clear_least_bit(*x); + return found; +} + +static inline mi_bfield_t mi_bfield_zero(void) { + return 0; +} + +static inline mi_bfield_t mi_bfield_one(void) { + return 1; +} + +static inline mi_bfield_t mi_bfield_all_set(void) { + return ~((mi_bfield_t)0); +} + +// mask of `bit_count` bits set shifted to the left by `shiftl` +static inline mi_bfield_t mi_bfield_mask(size_t bit_count, size_t shiftl) { + mi_assert_internal(bit_count > 0); + mi_assert_internal(bit_count + shiftl <= MI_BFIELD_BITS); + const mi_bfield_t mask0 = (bit_count < MI_BFIELD_BITS ? (mi_bfield_one() << bit_count)-1 : mi_bfield_all_set()); + return (mask0 << shiftl); +} + + +// ------- mi_bfield_atomic_set --------------------------------------- +// the `_set` functions return also the count of bits that were already set (for commit statistics) +// the `_clear` functions return also whether the new bfield is all clear or not (for the chunk_map) + +// Set a bit atomically. Returns `true` if the bit transitioned from 0 to 1 +static inline bool mi_bfield_atomic_set(_Atomic(mi_bfield_t)*b, size_t idx) { + mi_assert_internal(idx < MI_BFIELD_BITS); + const mi_bfield_t mask = mi_bfield_mask(1, idx);; + const mi_bfield_t old = mi_atomic_or_acq_rel(b, mask); + return ((old&mask) == 0); +} + +// Clear a bit atomically. Returns `true` if the bit transitioned from 1 to 0. +// `all_clear` is set if the new bfield is zero. +static inline bool mi_bfield_atomic_clear(_Atomic(mi_bfield_t)*b, size_t idx, bool* all_clear) { + mi_assert_internal(idx < MI_BFIELD_BITS); + const mi_bfield_t mask = mi_bfield_mask(1, idx);; + mi_bfield_t old = mi_atomic_and_acq_rel(b, ~mask); + if (all_clear != NULL) { *all_clear = ((old&~mask)==0); } + return ((old&mask) == mask); +} + +// Clear a bit but only when/once it is set. This is used by concurrent free's while +// the page is abandoned and mapped. This can incure a busy wait :-( but it should +// happen almost never (and is accounted for in the stats) +static inline void mi_bfield_atomic_clear_once_set(_Atomic(mi_bfield_t)*b, size_t idx) { + mi_assert_internal(idx < MI_BFIELD_BITS); + const mi_bfield_t mask = mi_bfield_mask(1, idx);; + mi_bfield_t old = mi_atomic_load_relaxed(b); + do { + if mi_unlikely((old&mask) == 0) { + old = mi_atomic_load_acquire(b); + if ((old&mask)==0) { + mi_subproc_stat_counter_increase(_mi_subproc(), pages_unabandon_busy_wait, 1); + } + while ((old&mask)==0) { // busy wait + mi_atomic_yield(); + old = mi_atomic_load_acquire(b); + } + } + } while (!mi_atomic_cas_weak_acq_rel(b,&old, (old&~mask))); + mi_assert_internal((old&mask)==mask); // we should only clear when it was set +} + +// Set a mask set of bits atomically, and return true of the mask bits transitioned from all 0's to 1's. +// `already_set` contains the count of bits that were already set (used when committing ranges to account +// statistics correctly). +static inline bool mi_bfield_atomic_set_mask(_Atomic(mi_bfield_t)*b, mi_bfield_t mask, size_t* already_set) { + mi_assert_internal(mask != 0); + mi_bfield_t old = mi_atomic_load_relaxed(b); + while (!mi_atomic_cas_weak_acq_rel(b, &old, old|mask)) {}; // try to atomically set the mask bits until success + if (already_set!=NULL) { *already_set = mi_bfield_popcount(old&mask); } + return ((old&mask) == 0); +} + +// Clear a mask set of bits atomically, and return true of the mask bits transitioned from all 1's to 0's +// `all_clear` is set to `true` if the new bfield became zero. +static inline bool mi_bfield_atomic_clear_mask(_Atomic(mi_bfield_t)*b, mi_bfield_t mask, bool* all_clear) { + mi_assert_internal(mask != 0); + mi_bfield_t old = mi_atomic_load_relaxed(b); + while (!mi_atomic_cas_weak_acq_rel(b, &old, old&~mask)) {}; // try to atomically clear the mask bits until success + if (all_clear != NULL) { *all_clear = ((old&~mask)==0); } + return ((old&mask) == mask); +} + +static inline bool mi_bfield_atomic_setX(_Atomic(mi_bfield_t)*b, size_t* already_set) { + const mi_bfield_t old = mi_atomic_exchange_release(b, mi_bfield_all_set()); + if (already_set!=NULL) { *already_set = mi_bfield_popcount(old); } + return (old==0); +} + +// static inline bool mi_bfield_atomic_clearX(_Atomic(mi_bfield_t)*b, bool* all_clear) { +// const mi_bfield_t old = mi_atomic_exchange_release(b, mi_bfield_zero()); +// if (all_clear!=NULL) { *all_clear = true; } +// return (~old==0); +// } + +// ------- mi_bfield_atomic_try_clear --------------------------------------- + + +// Tries to clear a mask atomically, and returns true if the mask bits atomically transitioned from mask to 0 +// and false otherwise (leaving the bit field as is). +// `all_clear` is set to `true` if the new bfield became zero. +static inline bool mi_bfield_atomic_try_clear_mask_of(_Atomic(mi_bfield_t)*b, mi_bfield_t mask, mi_bfield_t expect, bool* all_clear) { + mi_assert_internal(mask != 0); + // try to atomically clear the mask bits + do { + if ((expect & mask) != mask) { // are all bits still set? + if (all_clear != NULL) { *all_clear = (expect == 0); } + return false; + } + } while (!mi_atomic_cas_weak_acq_rel(b, &expect, expect & ~mask)); + if (all_clear != NULL) { *all_clear = ((expect & ~mask) == 0); } + return true; +} + +static inline bool mi_bfield_atomic_try_clear_mask(_Atomic(mi_bfield_t)* b, mi_bfield_t mask, bool* all_clear) { + mi_assert_internal(mask != 0); + const mi_bfield_t expect = mi_atomic_load_relaxed(b); + return mi_bfield_atomic_try_clear_mask_of(b, mask, expect, all_clear); +} + +// Tries to clear a bit atomically. Returns `true` if the bit transitioned from 1 to 0 +// and `false` otherwise leaving the bfield `b` as-is. +// `all_clear` is set to true if the new bfield became zero (and false otherwise) +mi_decl_maybe_unused static inline bool mi_bfield_atomic_try_clear(_Atomic(mi_bfield_t)* b, size_t idx, bool* all_clear) { + mi_assert_internal(idx < MI_BFIELD_BITS); + const mi_bfield_t mask = mi_bfield_one()<bfields[i], idx); + if (already_set != NULL) { *already_set = (was_clear ? 0 : 1); } + return was_clear; +} + +// Set `0 < n <= MI_BFIELD_BITS`, and return true of the mask bits transitioned from all 0's to 1's. +// `already_set` contains the count of bits that were already set (used when committing ranges to account +// statistics correctly). +// Can cross over two bfields. +static inline bool mi_bchunk_setNX(mi_bchunk_t* chunk, size_t cidx, size_t n, size_t* already_set) { + mi_assert_internal(cidx < MI_BCHUNK_BITS); + mi_assert_internal(n > 0 && n <= MI_BFIELD_BITS); + const size_t i = cidx / MI_BFIELD_BITS; + const size_t idx = cidx % MI_BFIELD_BITS; + if mi_likely(idx + n <= MI_BFIELD_BITS) { + // within one field + return mi_bfield_atomic_set_mask(&chunk->bfields[i], mi_bfield_mask(n,idx), already_set); + } + else { + // spanning two fields + const size_t m = MI_BFIELD_BITS - idx; // bits to clear in the first field + mi_assert_internal(m < n); + mi_assert_internal(i < MI_BCHUNK_FIELDS - 1); + mi_assert_internal(idx + m <= MI_BFIELD_BITS); + size_t already_set1; + const bool all_set1 = mi_bfield_atomic_set_mask(&chunk->bfields[i], mi_bfield_mask(m, idx), &already_set1); + mi_assert_internal(n - m > 0); + mi_assert_internal(n - m < MI_BFIELD_BITS); + size_t already_set2; + const bool all_set2 = mi_bfield_atomic_set_mask(&chunk->bfields[i+1], mi_bfield_mask(n - m, 0), &already_set2); + if (already_set != NULL) { *already_set = already_set1 + already_set2; } + return (all_set1 && all_set2); + } +} + +// Set a sequence of `n` bits within a chunk. +// Returns true if all bits transitioned from 0 to 1 (or 1 to 0). +mi_decl_noinline static bool mi_bchunk_xsetN_(mi_xset_t set, mi_bchunk_t* chunk, size_t cidx, size_t n, size_t* palready_set, bool* pmaybe_all_clear) { + mi_assert_internal(cidx + n <= MI_BCHUNK_BITS); + mi_assert_internal(n>0); + bool all_transition = true; + bool maybe_all_clear = true; + size_t total_already_set = 0; + size_t idx = cidx % MI_BFIELD_BITS; + size_t field = cidx / MI_BFIELD_BITS; + while (n > 0) { + size_t m = MI_BFIELD_BITS - idx; // m is the bits to xset in this field + if (m > n) { m = n; } + mi_assert_internal(idx + m <= MI_BFIELD_BITS); + mi_assert_internal(field < MI_BCHUNK_FIELDS); + const mi_bfield_t mask = mi_bfield_mask(m, idx); + size_t already_set = 0; + bool all_clear = false; + const bool transition = (set ? mi_bfield_atomic_set_mask(&chunk->bfields[field], mask, &already_set) + : mi_bfield_atomic_clear_mask(&chunk->bfields[field], mask, &all_clear)); + mi_assert_internal((transition && already_set == 0) || (!transition && already_set > 0)); + all_transition = all_transition && transition; + total_already_set += already_set; + maybe_all_clear = maybe_all_clear && all_clear; + // next field + field++; + idx = 0; + mi_assert_internal(m <= n); + n -= m; + } + if (palready_set!=NULL) { *palready_set = total_already_set; } + if (pmaybe_all_clear!=NULL) { *pmaybe_all_clear = maybe_all_clear; } + return all_transition; +} + +static inline bool mi_bchunk_setN(mi_bchunk_t* chunk, size_t cidx, size_t n, size_t* already_set) { + mi_assert_internal(n>0 && n <= MI_BCHUNK_BITS); + if (n==1) return mi_bchunk_set(chunk, cidx, already_set); + // if (n==8 && (cidx%8) == 0) return mi_bchunk_set8(chunk, cidx, already_set); + // if (n==MI_BFIELD_BITS) return mi_bchunk_setX(chunk, cidx, already_set); + if (n<=MI_BFIELD_BITS) return mi_bchunk_setNX(chunk, cidx, n, already_set); + return mi_bchunk_xsetN_(MI_BIT_SET, chunk, cidx, n, already_set, NULL); +} + +// ------- mi_bchunk_clear --------------------------------------- + +static inline bool mi_bchunk_clear(mi_bchunk_t* chunk, size_t cidx, bool* all_clear) { + mi_assert_internal(cidx < MI_BCHUNK_BITS); + const size_t i = cidx / MI_BFIELD_BITS; + const size_t idx = cidx % MI_BFIELD_BITS; + return mi_bfield_atomic_clear(&chunk->bfields[i], idx, all_clear); +} + +static inline bool mi_bchunk_clearN(mi_bchunk_t* chunk, size_t cidx, size_t n, bool* maybe_all_clear) { + mi_assert_internal(n>0 && n <= MI_BCHUNK_BITS); + if (n==1) return mi_bchunk_clear(chunk, cidx, maybe_all_clear); + // if (n==8) return mi_bchunk_clear8(chunk, cidx, maybe_all_clear); + // if (n==MI_BFIELD_BITS) return mi_bchunk_clearX(chunk, cidx, maybe_all_clear); + // TODO: implement mi_bchunk_xsetNX instead of setNX + return mi_bchunk_xsetN_(MI_BIT_CLEAR, chunk, cidx, n, NULL, maybe_all_clear); +} + +// Check if a sequence of `n` bits within a chunk are all set/cleared. +// This can cross bfield's +mi_decl_noinline static size_t mi_bchunk_popcountN_(mi_bchunk_t* chunk, size_t field_idx, size_t idx, size_t n) { + mi_assert_internal((field_idx*MI_BFIELD_BITS) + idx + n <= MI_BCHUNK_BITS); + size_t count = 0; + while (n > 0) { + size_t m = MI_BFIELD_BITS - idx; // m is the bits to xset in this field + if (m > n) { m = n; } + mi_assert_internal(idx + m <= MI_BFIELD_BITS); + mi_assert_internal(field_idx < MI_BCHUNK_FIELDS); + const size_t mask = mi_bfield_mask(m, idx); + count += mi_bfield_atomic_popcount_mask(&chunk->bfields[field_idx], mask); + // next field + field_idx++; + idx = 0; + n -= m; + } + return count; +} + +// Count set bits a sequence of `n` bits. +static inline size_t mi_bchunk_popcountN(mi_bchunk_t* chunk, size_t cidx, size_t n) { + mi_assert_internal(cidx + n <= MI_BCHUNK_BITS); + mi_assert_internal(n>0); + if (n==0) return 0; + const size_t i = cidx / MI_BFIELD_BITS; + const size_t idx = cidx % MI_BFIELD_BITS; + if (n==1) { return (mi_bfield_atomic_is_set(&chunk->bfields[i], idx) ? 1 : 0); } + if (idx + n <= MI_BFIELD_BITS) { return mi_bfield_atomic_popcount_mask(&chunk->bfields[i], mi_bfield_mask(n, idx)); } + return mi_bchunk_popcountN_(chunk, i, idx, n); +} + + +// ------- mi_bchunk_is_xset --------------------------------------- + +// Check if a sequence of `n` bits within a chunk are all set/cleared. +// This can cross bfield's +mi_decl_noinline static bool mi_bchunk_is_xsetN_(mi_xset_t set, const mi_bchunk_t* chunk, size_t field_idx, size_t idx, size_t n) { + mi_assert_internal((field_idx*MI_BFIELD_BITS) + idx + n <= MI_BCHUNK_BITS); + while (n > 0) { + size_t m = MI_BFIELD_BITS - idx; // m is the bits to xset in this field + if (m > n) { m = n; } + mi_assert_internal(idx + m <= MI_BFIELD_BITS); + mi_assert_internal(field_idx < MI_BCHUNK_FIELDS); + const size_t mask = mi_bfield_mask(m, idx); + if (!mi_bfield_atomic_is_xset_mask(set, &chunk->bfields[field_idx], mask)) { + return false; + } + // next field + field_idx++; + idx = 0; + n -= m; + } + return true; +} + +// Check if a sequence of `n` bits within a chunk are all set/cleared. +static inline bool mi_bchunk_is_xsetN(mi_xset_t set, const mi_bchunk_t* chunk, size_t cidx, size_t n) { + mi_assert_internal(cidx + n <= MI_BCHUNK_BITS); + mi_assert_internal(n>0); + if (n==0) return true; + const size_t i = cidx / MI_BFIELD_BITS; + const size_t idx = cidx % MI_BFIELD_BITS; + if (n==1) { return mi_bfield_atomic_is_xset(set, &chunk->bfields[i], idx); } + if (idx + n <= MI_BFIELD_BITS) { return mi_bfield_atomic_is_xset_mask(set, &chunk->bfields[i], mi_bfield_mask(n, idx)); } + return mi_bchunk_is_xsetN_(set, chunk, i, idx, n); +} + + +// ------- mi_bchunk_try_clear --------------------------------------- + +// Clear `0 < n <= MI_BITFIELD_BITS`. Can cross over a bfield boundary. +static inline bool mi_bchunk_try_clearNX(mi_bchunk_t* chunk, size_t cidx, size_t n, bool* pmaybe_all_clear) { + mi_assert_internal(cidx < MI_BCHUNK_BITS); + mi_assert_internal(n <= MI_BFIELD_BITS); + const size_t i = cidx / MI_BFIELD_BITS; + const size_t idx = cidx % MI_BFIELD_BITS; + if mi_likely(idx + n <= MI_BFIELD_BITS) { + // within one field + return mi_bfield_atomic_try_clear_mask(&chunk->bfields[i], mi_bfield_mask(n, idx), pmaybe_all_clear); + } + else { + // spanning two fields (todo: use double-word atomic ops?) + const size_t m = MI_BFIELD_BITS - idx; // bits to clear in the first field + mi_assert_internal(m < n); + mi_assert_internal(i < MI_BCHUNK_FIELDS - 1); + bool field1_is_clear; + if (!mi_bfield_atomic_try_clear_mask(&chunk->bfields[i], mi_bfield_mask(m, idx), &field1_is_clear)) return false; + // try the second field as well + mi_assert_internal(n - m > 0); + mi_assert_internal(n - m < MI_BFIELD_BITS); + bool field2_is_clear; + if (!mi_bfield_atomic_try_clear_mask(&chunk->bfields[i+1], mi_bfield_mask(n - m, 0), &field2_is_clear)) { + // we failed to clear the second field, restore the first one + mi_bfield_atomic_set_mask(&chunk->bfields[i], mi_bfield_mask(m, idx), NULL); + return false; + } + if (pmaybe_all_clear != NULL) { *pmaybe_all_clear = field1_is_clear && field2_is_clear; } + return true; + } +} + +// Clear a full aligned bfield. +// static inline bool mi_bchunk_try_clearX(mi_bchunk_t* chunk, size_t cidx, bool* pmaybe_all_clear) { +// mi_assert_internal(cidx < MI_BCHUNK_BITS); +// mi_assert_internal((cidx%MI_BFIELD_BITS) == 0); +// const size_t i = cidx / MI_BFIELD_BITS; +// return mi_bfield_atomic_try_clearX(&chunk->bfields[i], pmaybe_all_clear); +// } + +// Try to atomically clear a sequence of `n` bits within a chunk. +// Returns true if all bits transitioned from 1 to 0, +// and false otherwise leaving all bit fields as is. +// Note: this is the complex one as we need to unwind partial atomic operations if we fail halfway.. +// `maybe_all_clear` is set to `true` if all the bfields involved become zero. +mi_decl_noinline static bool mi_bchunk_try_clearN_(mi_bchunk_t* chunk, size_t cidx, size_t n, bool* pmaybe_all_clear) { + mi_assert_internal(cidx + n <= MI_BCHUNK_BITS); + mi_assert_internal(n>0); + if (pmaybe_all_clear != NULL) { *pmaybe_all_clear = true; } + if (n==0) return true; + + // first field + const size_t start_idx = cidx % MI_BFIELD_BITS; + const size_t start_field = cidx / MI_BFIELD_BITS; + size_t field = start_field; + size_t m = MI_BFIELD_BITS - start_idx; // m are the bits to clear in this field + if (m > n) { m = n; } + mi_assert_internal(start_idx + m <= MI_BFIELD_BITS); + mi_assert_internal(start_field < MI_BCHUNK_FIELDS); + const mi_bfield_t mask_start = mi_bfield_mask(m, start_idx); + bool maybe_all_clear; + if (!mi_bfield_atomic_try_clear_mask(&chunk->bfields[field], mask_start, &maybe_all_clear)) return false; + + // done? + mi_assert_internal(m <= n); + n -= m; + + // continue with mid fields and last field: if these fail we need to recover by unsetting previous fields + // mid fields? + while (n >= MI_BFIELD_BITS) { + field++; + mi_assert_internal(field < MI_BCHUNK_FIELDS); + bool field_is_clear; + if (!mi_bfield_atomic_try_clearX(&chunk->bfields[field], &field_is_clear)) goto restore; + maybe_all_clear = maybe_all_clear && field_is_clear; + n -= MI_BFIELD_BITS; + } + + // last field? + if (n > 0) { + mi_assert_internal(n < MI_BFIELD_BITS); + field++; + mi_assert_internal(field < MI_BCHUNK_FIELDS); + const mi_bfield_t mask_end = mi_bfield_mask(n, 0); + bool field_is_clear; + if (!mi_bfield_atomic_try_clear_mask(&chunk->bfields[field], mask_end, &field_is_clear)) goto restore; + maybe_all_clear = maybe_all_clear && field_is_clear; + } + + if (pmaybe_all_clear != NULL) { *pmaybe_all_clear = maybe_all_clear; } + return true; + +restore: + // `field` is the index of the field that failed to set atomically; we need to restore all previous fields + mi_assert_internal(field > start_field); + while( field > start_field) { + field--; + if (field == start_field) { + mi_bfield_atomic_set_mask(&chunk->bfields[field], mask_start, NULL); + } + else { + mi_bfield_atomic_setX(&chunk->bfields[field], NULL); // mid-field: set all bits again + } + } + return false; +} + + +static inline bool mi_bchunk_try_clearN(mi_bchunk_t* chunk, size_t cidx, size_t n, bool* maybe_all_clear) { + mi_assert_internal(n>0); + // if (n==MI_BFIELD_BITS) return mi_bchunk_try_clearX(chunk, cidx, maybe_all_clear); + if (n<=MI_BFIELD_BITS) return mi_bchunk_try_clearNX(chunk, cidx, n, maybe_all_clear); + return mi_bchunk_try_clearN_(chunk, cidx, n, maybe_all_clear); +} + + +// ------- mi_bchunk_try_find_and_clear --------------------------------------- + +#if MI_OPT_SIMD && defined(__AVX2__) +mi_decl_maybe_unused static inline __m256i mi_mm256_zero(void) { + return _mm256_setzero_si256(); +} +mi_decl_maybe_unused static inline __m256i mi_mm256_ones(void) { + return _mm256_set1_epi64x(~0); +} +mi_decl_maybe_unused static inline bool mi_mm256_is_ones(__m256i vec) { + return _mm256_testc_si256(vec, _mm256_cmpeq_epi32(vec, vec)); +} +mi_decl_maybe_unused static inline bool mi_mm256_is_zero( __m256i vec) { + return _mm256_testz_si256(vec,vec); +} +#endif + +static inline bool mi_bchunk_try_find_and_clear_at(mi_bchunk_t* chunk, size_t chunk_idx, size_t* pidx) { + mi_assert_internal(chunk_idx < MI_BCHUNK_FIELDS); + // note: this must be acquire (and not relaxed), or otherwise the AVX code below can loop forever + // as the compiler won't reload the registers vec1 and vec2 from memory again. + const mi_bfield_t b = mi_atomic_load_acquire(&chunk->bfields[chunk_idx]); + size_t idx; + if (mi_bfield_find_least_bit(b, &idx)) { // find the least bit + if mi_likely(mi_bfield_atomic_try_clear_mask_of(&chunk->bfields[chunk_idx], mi_bfield_mask(1,idx), b, NULL)) { // clear it atomically + *pidx = (chunk_idx*MI_BFIELD_BITS) + idx; + mi_assert_internal(*pidx < MI_BCHUNK_BITS); + return true; + } + } + return false; +} + +// Find least 1-bit in a chunk and try to clear it atomically +// set `*pidx` to the bit index (0 <= *pidx < MI_BCHUNK_BITS) on success. +// This is used to find free slices and abandoned pages and should be efficient. +// todo: try neon version +static inline bool mi_bchunk_try_find_and_clear(mi_bchunk_t* chunk, size_t* pidx) { + #if MI_OPT_SIMD && defined(__AVX2__) && (MI_BCHUNK_BITS==256) + while (true) { + const __m256i vec = _mm256_load_si256((const __m256i*)chunk->bfields); + const __m256i vcmp = _mm256_cmpeq_epi64(vec, mi_mm256_zero()); // (elem64 == 0 ? 0xFF : 0) + const uint32_t mask = ~_mm256_movemask_epi8(vcmp); // mask of most significant bit of each byte (so each 8 bits are all set or clear) + // mask is inverted, so each 8-bits is 0xFF iff the corresponding elem64 has a bit set (and thus can be cleared) + if (mask==0) return false; + mi_assert_internal((_tzcnt_u32(mask)%8) == 0); // tzcnt == 0, 8, 16, or 24 + const size_t chunk_idx = _tzcnt_u32(mask) / 8; + if (mi_bchunk_try_find_and_clear_at(chunk, chunk_idx, pidx)) return true; + // try again + // note: there must be an atomic release/acquire in between or otherwise the registers may not be reloaded + } + #elif MI_OPT_SIMD && defined(__AVX2__) && (MI_BCHUNK_BITS==512) + while (true) { + size_t chunk_idx = 0; + #if 0 + // one vector at a time + __m256i vec = _mm256_load_si256((const __m256i*)chunk->bfields); + if (mi_mm256_is_zero(vec)) { + chunk_idx += 4; + vec = _mm256_load_si256(((const __m256i*)chunk->bfields) + 1); + } + const __m256i vcmp = _mm256_cmpeq_epi64(vec, mi_mm256_zero()); // (elem64 == 0 ? 0xFF : 0) + const uint32_t mask = ~_mm256_movemask_epi8(vcmp); // mask of most significant bit of each byte (so each 8 bits are all set or clear) + // mask is inverted, so each 8-bits is 0xFF iff the corresponding elem64 has a bit set (and thus can be cleared) + if (mask==0) return false; + mi_assert_internal((_tzcnt_u32(mask)%8) == 0); // tzcnt == 0, 8, 16, or 24 + chunk_idx += _tzcnt_u32(mask) / 8; + #else + // a cache line is 64b so we can just as well load all at the same time + const __m256i vec1 = _mm256_load_si256((const __m256i*)chunk->bfields); + const __m256i vec2 = _mm256_load_si256(((const __m256i*)chunk->bfields)+1); + const __m256i cmpv = mi_mm256_zero(); + const __m256i vcmp1 = _mm256_cmpeq_epi64(vec1, cmpv); // (elem64 == 0 ? 0xFF : 0) + const __m256i vcmp2 = _mm256_cmpeq_epi64(vec2, cmpv); // (elem64 == 0 ? 0xFF : 0) + const uint32_t mask1 = ~_mm256_movemask_epi8(vcmp1); // mask of most significant bit of each byte (so each 8 bits are all set or clear) + const uint32_t mask2 = ~_mm256_movemask_epi8(vcmp2); // mask of most significant bit of each byte (so each 8 bits are all set or clear) + const uint64_t mask = ((uint64_t)mask2 << 32) | mask1; + // mask is inverted, so each 8-bits is 0xFF iff the corresponding elem64 has a bit set (and thus can be cleared) + if (mask==0) return false; + mi_assert_internal((_tzcnt_u64(mask)%8) == 0); // tzcnt == 0, 8, 16, 24 , .. + chunk_idx = mi_ctz(mask) / 8; + #endif + if (mi_bchunk_try_find_and_clear_at(chunk, chunk_idx, pidx)) return true; + // try again + // note: there must be an atomic release/acquire in between or otherwise the registers may not be reloaded + } + #elif MI_OPT_SIMD && (MI_BCHUNK_BITS==512) && MI_ARCH_ARM64 + while(true) { + // a cache line is 64b so we can just as well load all at the same time (?) + const uint64x2_t vzero1_lo = vceqzq_u64(vld1q_u64((uint64_t*)chunk->bfields)); // 2x64 bit is_zero + const uint64x2_t vzero1_hi = vceqzq_u64(vld1q_u64((uint64_t*)chunk->bfields + 2)); // 2x64 bit is_zero + const uint64x2_t vzero2_lo = vceqzq_u64(vld1q_u64((uint64_t*)chunk->bfields + 4)); // 2x64 bit is_zero + const uint64x2_t vzero2_hi = vceqzq_u64(vld1q_u64((uint64_t*)chunk->bfields + 6)); // 2x64 bit is_zero + const uint32x4_t vzero1 = vuzp1q_u32(vreinterpretq_u32_u64(vzero1_lo),vreinterpretq_u32_u64(vzero1_hi)); // unzip even elements: narrow to 4x32 bit is_zero () + const uint32x4_t vzero2 = vuzp1q_u32(vreinterpretq_u32_u64(vzero2_lo),vreinterpretq_u32_u64(vzero2_hi)); // unzip even elements: narrow to 4x32 bit is_zero () + const uint32x4_t vzero1x = vreinterpretq_u32_u64(vshrq_n_u64(vreinterpretq_u64_u32(vzero1), 24)); // shift-right 2x32bit elem by 24: lo 16 bits contain the 2 lo bytes + const uint32x4_t vzero2x = vreinterpretq_u32_u64(vshrq_n_u64(vreinterpretq_u64_u32(vzero2), 24)); + const uint16x8_t vzero12 = vreinterpretq_u16_u32(vuzp1q_u32(vzero1x,vzero2x)); // unzip even 32-bit elements into one vector + const uint8x8_t vzero = vmovn_u32(vzero12); // narrow the bottom 16-bits + const uint64_t mask = ~vget_lane_u64(vreinterpret_u64_u8(vzero), 0); // 1 byte for each bfield (0xFF => bfield has a bit set) + if (mask==0) return false; + mi_assert_internal((mi_ctz(mask)%8) == 0); // tzcnt == 0, 8, 16, 24 , .. + const size_t chunk_idx = mi_ctz(mask) / 8; + if (mi_bchunk_try_find_and_clear_at(chunk, chunk_idx, pidx)) return true; + // try again + // note: there must be an atomic release/acquire in between or otherwise the registers may not be reloaded + } + #else + for (int i = 0; i < MI_BCHUNK_FIELDS; i++) { + if (mi_bchunk_try_find_and_clear_at(chunk, i, pidx)) return true; + } + return false; + #endif +} + +static inline bool mi_bchunk_try_find_and_clear_1(mi_bchunk_t* chunk, size_t n, size_t* pidx) { + mi_assert_internal(n==1); MI_UNUSED(n); + return mi_bchunk_try_find_and_clear(chunk, pidx); +} + +mi_decl_maybe_unused static inline bool mi_bchunk_try_find_and_clear8_at(mi_bchunk_t* chunk, size_t chunk_idx, size_t* pidx) { + const mi_bfield_t b = mi_atomic_load_relaxed(&chunk->bfields[chunk_idx]); + // has_set8 has low bit in each byte set if the byte in x == 0xFF + const mi_bfield_t has_set8 = + ((~b - MI_BFIELD_LO_BIT8) & // high bit set if byte in x is 0xFF or < 0x7F + (b & MI_BFIELD_HI_BIT8)) // high bit set if byte in x is >= 0x80 + >> 7; // shift high bit to low bit + size_t idx; + if (mi_bfield_find_least_bit(has_set8, &idx)) { // find least 1-bit + mi_assert_internal(idx <= (MI_BFIELD_BITS - 8)); + mi_assert_internal((idx%8)==0); + if mi_likely(mi_bfield_atomic_try_clear_mask_of(&chunk->bfields[chunk_idx], (mi_bfield_t)0xFF << idx, b, NULL)) { // unset the byte atomically + *pidx = (chunk_idx*MI_BFIELD_BITS) + idx; + mi_assert_internal(*pidx + 8 <= MI_BCHUNK_BITS); + return true; + } + } + return false; +} + +// find least aligned byte in a chunk with all bits set, and try unset it atomically +// set `*pidx` to its bit index (0 <= *pidx < MI_BCHUNK_BITS) on success. +// Used to find medium size pages in the free blocks. +// todo: try neon version +static mi_decl_noinline bool mi_bchunk_try_find_and_clear8(mi_bchunk_t* chunk, size_t* pidx) { + #if MI_OPT_SIMD && defined(__AVX2__) && (MI_BCHUNK_BITS==512) + while (true) { + // since a cache-line is 64b, load all at once + const __m256i vec1 = _mm256_load_si256((const __m256i*)chunk->bfields); + const __m256i vec2 = _mm256_load_si256((const __m256i*)chunk->bfields+1); + const __m256i cmpv = mi_mm256_ones(); + const __m256i vcmp1 = _mm256_cmpeq_epi8(vec1, cmpv); // (byte == ~0 ? 0xFF : 0) + const __m256i vcmp2 = _mm256_cmpeq_epi8(vec2, cmpv); // (byte == ~0 ? 0xFF : 0) + const uint32_t mask1 = _mm256_movemask_epi8(vcmp1); // mask of most significant bit of each byte + const uint32_t mask2 = _mm256_movemask_epi8(vcmp2); // mask of most significant bit of each byte + const uint64_t mask = ((uint64_t)mask2 << 32) | mask1; + // mask is inverted, so each bit is 0xFF iff the corresponding byte has a bit set (and thus can be cleared) + if (mask==0) return false; + const size_t bidx = _tzcnt_u64(mask); // byte-idx of the byte in the chunk + const size_t chunk_idx = bidx / 8; + const size_t idx = (bidx % 8)*8; + mi_assert_internal(chunk_idx < MI_BCHUNK_FIELDS); + if mi_likely(mi_bfield_atomic_try_clear8(&chunk->bfields[chunk_idx], idx, NULL)) { // clear it atomically + *pidx = (chunk_idx*MI_BFIELD_BITS) + idx; + mi_assert_internal(*pidx + 8 <= MI_BCHUNK_BITS); + return true; + } + // try again + // note: there must be an atomic release/acquire in between or otherwise the registers may not be reloaded } + } + #else + for (int i = 0; i < MI_BCHUNK_FIELDS; i++) { + if (mi_bchunk_try_find_and_clear8_at(chunk, i, pidx)) return true; + } + return false; + #endif +} + +static inline bool mi_bchunk_try_find_and_clear_8(mi_bchunk_t* chunk, size_t n, size_t* pidx) { + mi_assert_internal(n==8); MI_UNUSED(n); + return mi_bchunk_try_find_and_clear8(chunk, pidx); +} + + +// find least aligned bfield in a chunk with all bits set, and try unset it atomically +// set `*pidx` to its bit index (0 <= *pidx < MI_BCHUNK_BITS) on success. +// Used to find large size pages in the free blocks. +// todo: try neon version +/* +static mi_decl_noinline bool mi_bchunk_try_find_and_clearX(mi_bchunk_t* chunk, size_t* pidx) { + #if MI_OPT_SIMD && defined(__AVX2__) && (MI_BCHUNK_BITS==512) + while (true) { + // since a cache-line is 64b, load all at once + const __m256i vec1 = _mm256_load_si256((const __m256i*)chunk->bfields); + const __m256i vec2 = _mm256_load_si256((const __m256i*)chunk->bfields+1); + const __m256i cmpv = mi_mm256_ones(); + const __m256i vcmp1 = _mm256_cmpeq_epi64(vec1, cmpv); // (bfield == ~0 ? -1 : 0) + const __m256i vcmp2 = _mm256_cmpeq_epi64(vec2, cmpv); // (bfield == ~0 ? -1 : 0) + const uint32_t mask1 = _mm256_movemask_epi8(vcmp1); // mask of most significant bit of each byte + const uint32_t mask2 = _mm256_movemask_epi8(vcmp2); // mask of most significant bit of each byte + const uint64_t mask = ((uint64_t)mask2 << 32) | mask1; + // mask is inverted, so each 8-bits are set iff the corresponding elem64 has all bits set (and thus can be cleared) + if (mask==0) return false; + mi_assert_internal((_tzcnt_u64(mask)%8) == 0); // tzcnt == 0, 8, 16, 24 , .. + const size_t chunk_idx = _tzcnt_u64(mask) / 8; + mi_assert_internal(chunk_idx < MI_BCHUNK_FIELDS); + if mi_likely(mi_bfield_atomic_try_clearX(&chunk->bfields[chunk_idx],NULL)) { + *pidx = chunk_idx*MI_BFIELD_BITS; + mi_assert_internal(*pidx + MI_BFIELD_BITS <= MI_BCHUNK_BITS); + return true; + } + // try again + // note: there must be an atomic release/acquire in between or otherwise the registers may not be reloaded + } #else - size_t bitidx = 0; // otherwise start at 0 + for (int i = 0; i < MI_BCHUNK_FIELDS; i++) { + const mi_bfield_t b = mi_atomic_load_relaxed(&chunk->bfields[i]); + if (~b==0 && mi_bfield_atomic_try_clearX(&chunk->bfields[i], NULL)) { + *pidx = i*MI_BFIELD_BITS; + mi_assert_internal(*pidx + MI_BFIELD_BITS <= MI_BCHUNK_BITS); + return true; + } + } + return false; #endif - size_t m = (mask << bitidx); // invariant: m == mask shifted by bitidx - - // scan linearly for a free range of zero bits - while (bitidx <= bitidx_max) { - const size_t mapm = map & m; - if (mapm == 0) { // are the mask bits free at bitidx? - mi_assert_internal((m >> bitidx) == mask); // no overflow? - const size_t newmap = map | m; - mi_assert_internal((newmap^map) >> bitidx == mask); - if (!mi_atomic_cas_weak_acq_rel(field, &map, newmap)) { // TODO: use strong cas here? - // no success, another thread claimed concurrently.. keep going (with updated `map`) - continue; +} + +static inline bool mi_bchunk_try_find_and_clear_X(mi_bchunk_t* chunk, size_t n, size_t* pidx) { + mi_assert_internal(n==MI_BFIELD_BITS); MI_UNUSED(n); + return mi_bchunk_try_find_and_clearX(chunk, pidx); +} +*/ + +// find a sequence of `n` bits in a chunk with `0 < n <= MI_BFIELD_BITS` with all bits set, +// and try to clear them atomically. +// set `*pidx` to its bit index (0 <= *pidx <= MI_BCHUNK_BITS - n) on success. +// will cross bfield boundaries. +mi_decl_noinline static bool mi_bchunk_try_find_and_clearNX(mi_bchunk_t* chunk, size_t n, size_t* pidx) { + if (n == 0 || n > MI_BFIELD_BITS) return false; + const mi_bfield_t mask = mi_bfield_mask(n, 0); + // for all fields in the chunk + for (int i = 0; i < MI_BCHUNK_FIELDS; i++) { + mi_bfield_t b0 = mi_atomic_load_relaxed(&chunk->bfields[i]); + mi_bfield_t b = b0; + size_t idx; + + // is there a range inside the field? + while (mi_bfield_find_least_bit(b, &idx)) { // find least 1-bit + if (idx + n > MI_BFIELD_BITS) break; // too short: maybe cross over, or continue with the next field + + const size_t bmask = mask<>idx == mask); + if ((b&bmask) == bmask) { // found a match with all bits set, try clearing atomically + if mi_likely(mi_bfield_atomic_try_clear_mask_of(&chunk->bfields[i], bmask, b0, NULL)) { + *pidx = (i*MI_BFIELD_BITS) + idx; + mi_assert_internal(*pidx < MI_BCHUNK_BITS); + mi_assert_internal(*pidx + n <= MI_BCHUNK_BITS); + return true; + } + else { + // if we failed to atomically commit, reload b and try again from the start + b = b0 = mi_atomic_load_acquire(&chunk->bfields[i]); + } } else { - // success, we claimed the bits! - *bitmap_idx = mi_bitmap_index_create(idx, bitidx); - return true; + // advance by clearing the least run of ones, for example, with n>=4, idx=2: + // b = 1111 1101 1010 1100 + // .. + (1< 0) { + const size_t pre = mi_bfield_ctz(~mi_atomic_load_relaxed(&chunk->bfields[i+1])); + if (post + pre >= n) { + // it fits -- try to claim it atomically + const size_t cidx = (i*MI_BFIELD_BITS) + (MI_BFIELD_BITS - post); + if (mi_bchunk_try_clearNX(chunk, cidx, n, NULL)) { + // we cleared all atomically + *pidx = cidx; + mi_assert_internal(*pidx < MI_BCHUNK_BITS); + mi_assert_internal(*pidx + n <= MI_BCHUNK_BITS); + return true; + } + } } } + } + return false; +} + +// find a sequence of `n` bits in a chunk with `n < MI_BCHUNK_BITS` with all bits set, +// and try to clear them atomically. +// set `*pidx` to its bit index (0 <= *pidx <= MI_BCHUNK_BITS - n) on success. +// This can cross bfield boundaries. +static mi_decl_noinline bool mi_bchunk_try_find_and_clearN_(mi_bchunk_t* chunk, size_t n, size_t* pidx) { + if (n == 0 || n > MI_BCHUNK_BITS) return false; // cannot be more than a chunk + + // we first scan ahead to see if there is a range of `n` set bits, and only then try to clear atomically + mi_assert_internal(n>0); + const size_t skip_count = (n-1)/MI_BFIELD_BITS; + size_t cidx; + for (size_t i = 0; i < MI_BCHUNK_FIELDS - skip_count; i++) + { + size_t m = n; // bits to go + + // first field + mi_bfield_t b = mi_atomic_load_relaxed(&chunk->bfields[i]); + size_t ones = mi_bfield_clz(~b); + cidx = (i*MI_BFIELD_BITS) + (MI_BFIELD_BITS - ones); // start index + if (ones >= m) { + // we found enough bits! + m = 0; + } else { - // on to the next bit range -#ifdef MI_HAVE_FAST_BITSCAN - const size_t shift = (count == 1 ? 1 : mi_bsr(mapm) - bitidx + 1); - mi_assert_internal(shift > 0 && shift <= count); + m -= ones; + + // keep scanning further fields? + size_t j = 1; // field count from i + while (i+j < MI_BCHUNK_FIELDS) { + mi_assert_internal(m > 0); + b = mi_atomic_load_relaxed(&chunk->bfields[i+j]); + ones = mi_bfield_ctz(~b); + if (ones >= m) { + // we found enough bits + m = 0; + break; + } + else if (ones == MI_BFIELD_BITS) { + // not enough yet, proceed to the next field + j++; + m -= MI_BFIELD_BITS; + } + else { + // the range was not enough, start from scratch + i = i + j - 1; // no need to re-scan previous fields, except the last one (with clz this time) + mi_assert_internal(m>0); + break; + } + } + } + + // did we find a range? + if (m==0) { + if (mi_bchunk_try_clearN(chunk, cidx, n, NULL)) { + // we cleared all atomically + *pidx = cidx; + mi_assert_internal(*pidx < MI_BCHUNK_BITS); + mi_assert_internal(*pidx + n <= MI_BCHUNK_BITS); + return true; + } + // note: if we fail for a small `n` on the first field, we don't rescan that field (as `i` is incremented) + } + // otherwise continue searching + } + return false; +} + + + +// ------- mi_bchunk_clear_once_set --------------------------------------- + +static inline void mi_bchunk_clear_once_set(mi_bchunk_t* chunk, size_t cidx) { + mi_assert_internal(cidx < MI_BCHUNK_BITS); + const size_t i = cidx / MI_BFIELD_BITS; + const size_t idx = cidx % MI_BFIELD_BITS; + mi_bfield_atomic_clear_once_set(&chunk->bfields[i], idx); +} + + +// ------- mi_bitmap_all_are_clear --------------------------------------- + + +// are all bits in a bitmap chunk clear? +static inline bool mi_bchunk_all_are_clear_relaxed(mi_bchunk_t* chunk) { + #if MI_OPT_SIMD && defined(__AVX2__) && (MI_BCHUNK_BITS==256) + const __m256i vec = _mm256_load_si256((const __m256i*)chunk->bfields); + return mi_mm256_is_zero(vec); + #elif MI_OPT_SIMD && defined(__AVX2__) && (MI_BCHUNK_BITS==512) + // a 64b cache-line contains the entire chunk anyway so load both at once + const __m256i vec1 = _mm256_load_si256((const __m256i*)chunk->bfields); + const __m256i vec2 = _mm256_load_si256(((const __m256i*)chunk->bfields)+1); + return (mi_mm256_is_zero(_mm256_or_si256(vec1,vec2))); + #elif MI_OPT_SIMD && (MI_BCHUNK_BITS==512) && MI_ARCH_ARM64 + const uint64x2_t v0 = vld1q_u64((uint64_t*)chunk->bfields); + const uint64x2_t v1 = vld1q_u64((uint64_t*)chunk->bfields + 2); + const uint64x2_t v2 = vld1q_u64((uint64_t*)chunk->bfields + 4); + const uint64x2_t v3 = vld1q_u64((uint64_t*)chunk->bfields + 6); + const uint64x2_t v = vorrq_u64(vorrq_u64(v0,v1),vorrq_u64(v2,v3)); + return (vmaxvq_u32(vreinterpretq_u32_u64(v)) == 0); + #else + for (int i = 0; i < MI_BCHUNK_FIELDS; i++) { + if (mi_atomic_load_relaxed(&chunk->bfields[i]) != 0) return false; + } + return true; + #endif +} + +// are all bits in a bitmap chunk set? +static inline bool mi_bchunk_all_are_set_relaxed(mi_bchunk_t* chunk) { +#if MI_OPT_SIMD && defined(__AVX2__) && (MI_BCHUNK_BITS==256) + const __m256i vec = _mm256_load_si256((const __m256i*)chunk->bfields); + return mi_mm256_is_ones(vec); +#elif MI_OPT_SIMD && defined(__AVX2__) && (MI_BCHUNK_BITS==512) + // a 64b cache-line contains the entire chunk anyway so load both at once + const __m256i vec1 = _mm256_load_si256((const __m256i*)chunk->bfields); + const __m256i vec2 = _mm256_load_si256(((const __m256i*)chunk->bfields)+1); + return (mi_mm256_is_ones(_mm256_and_si256(vec1, vec2))); +#elif MI_OPT_SIMD && (MI_BCHUNK_BITS==512) && MI_ARCH_ARM64 + const uint64x2_t v0 = vld1q_u64((uint64_t*)chunk->bfields); + const uint64x2_t v1 = vld1q_u64((uint64_t*)chunk->bfields + 2); + const uint64x2_t v2 = vld1q_u64((uint64_t*)chunk->bfields + 4); + const uint64x2_t v3 = vld1q_u64((uint64_t*)chunk->bfields + 6); + const uint64x2_t v = vandq_u64(vandq_u64(v0,v1),vandq_u64(v2,v3)); + return (vminvq_u32(vreinterpretq_u32_u64(v)) == 0xFFFFFFFFUL); #else - const size_t shift = 1; + for (int i = 0; i < MI_BCHUNK_FIELDS; i++) { + if (~mi_atomic_load_relaxed(&chunk->bfields[i]) != 0) return false; + } + return true; #endif - bitidx += shift; - m <<= shift; +} + + +static bool mi_bchunk_bsr(mi_bchunk_t* chunk, size_t* pidx) { + for (size_t i = MI_BCHUNK_FIELDS; i > 0; ) { + i--; + mi_bfield_t b = mi_atomic_load_relaxed(&chunk->bfields[i]); + size_t idx; + if (mi_bsr(b, &idx)) { + *pidx = (i*MI_BFIELD_BITS) + idx; + return true; + } + } + return false; +} + +static size_t mi_bchunk_popcount(mi_bchunk_t* chunk) { + size_t popcount = 0; + for (size_t i = 0; i < MI_BCHUNK_FIELDS; i++) { + const mi_bfield_t b = mi_atomic_load_relaxed(&chunk->bfields[i]); + popcount += mi_bfield_popcount(b); + } + return popcount; +} + + +/* -------------------------------------------------------------------------------- + bitmap chunkmap +-------------------------------------------------------------------------------- */ + +static void mi_bitmap_chunkmap_set(mi_bitmap_t* bitmap, size_t chunk_idx) { + mi_assert(chunk_idx < mi_bitmap_chunk_count(bitmap)); + mi_bchunk_set(&bitmap->chunkmap, chunk_idx, NULL); +} + +static bool mi_bitmap_chunkmap_try_clear(mi_bitmap_t* bitmap, size_t chunk_idx) { + mi_assert(chunk_idx < mi_bitmap_chunk_count(bitmap)); + // check if the corresponding chunk is all clear + if (!mi_bchunk_all_are_clear_relaxed(&bitmap->chunks[chunk_idx])) return false; + // clear the chunkmap bit + mi_bchunk_clear(&bitmap->chunkmap, chunk_idx, NULL); + // .. but a concurrent set may have happened in between our all-clear test and the clearing of the + // bit in the mask. We check again to catch this situation. + if (!mi_bchunk_all_are_clear_relaxed(&bitmap->chunks[chunk_idx])) { + mi_bchunk_set(&bitmap->chunkmap, chunk_idx, NULL); + return false; + } + return true; +} + + +/* -------------------------------------------------------------------------------- + bitmap +-------------------------------------------------------------------------------- */ + +size_t mi_bitmap_size(size_t bit_count, size_t* pchunk_count) { + mi_assert_internal((bit_count % MI_BCHUNK_BITS) == 0); + bit_count = _mi_align_up(bit_count, MI_BCHUNK_BITS); + mi_assert_internal(bit_count <= MI_BITMAP_MAX_BIT_COUNT); + mi_assert_internal(bit_count > 0); + const size_t chunk_count = bit_count / MI_BCHUNK_BITS; + mi_assert_internal(chunk_count >= 1); + const size_t size = offsetof(mi_bitmap_t,chunks) + (chunk_count * MI_BCHUNK_SIZE); + mi_assert_internal( (size%MI_BCHUNK_SIZE) == 0 ); + if (pchunk_count != NULL) { *pchunk_count = chunk_count; } + return size; +} + + +// initialize a bitmap to all unset; avoid a mem_zero if `already_zero` is true +// returns the size of the bitmap +size_t mi_bitmap_init(mi_bitmap_t* bitmap, size_t bit_count, bool already_zero) { + size_t chunk_count; + const size_t size = mi_bitmap_size(bit_count, &chunk_count); + if (!already_zero) { + _mi_memzero_aligned(bitmap, size); + } + mi_atomic_store_release(&bitmap->chunk_count, chunk_count); + mi_assert_internal(mi_atomic_load_relaxed(&bitmap->chunk_count) <= MI_BITMAP_MAX_CHUNK_COUNT); + return size; +} + + +// Set a sequence of `n` bits in the bitmap (and can cross chunks). Not atomic so only use if local to a thread. +static void mi_bchunks_unsafe_setN(mi_bchunk_t* chunks, mi_bchunkmap_t* cmap, size_t idx, size_t n) { + mi_assert_internal(n>0); + + // start chunk and index + size_t chunk_idx = idx / MI_BCHUNK_BITS; + const size_t cidx = idx % MI_BCHUNK_BITS; + const size_t ccount = _mi_divide_up(n, MI_BCHUNK_BITS); + + // first update the chunkmap + mi_bchunk_setN(cmap, chunk_idx, ccount, NULL); + + // first chunk + size_t m = MI_BCHUNK_BITS - cidx; + if (m > n) { m = n; } + mi_bchunk_setN(&chunks[chunk_idx], cidx, m, NULL); + + // n can be large so use memset for efficiency for all in-between chunks + chunk_idx++; + n -= m; + const size_t mid_chunks = n / MI_BCHUNK_BITS; + if (mid_chunks > 0) { + _mi_memset(&chunks[chunk_idx], ~0, mid_chunks * MI_BCHUNK_SIZE); + chunk_idx += mid_chunks; + n -= (mid_chunks * MI_BCHUNK_BITS); + } + + // last chunk + if (n > 0) { + mi_assert_internal(n < MI_BCHUNK_BITS); + mi_assert_internal(chunk_idx < MI_BCHUNK_FIELDS); + mi_bchunk_setN(&chunks[chunk_idx], 0, n, NULL); + } +} + +// Set a sequence of `n` bits in the bitmap (and can cross chunks). Not atomic so only use if local to a thread. +void mi_bitmap_unsafe_setN(mi_bitmap_t* bitmap, size_t idx, size_t n) { + mi_assert_internal(n>0); + mi_assert_internal(idx + n <= mi_bitmap_max_bits(bitmap)); + mi_bchunks_unsafe_setN(&bitmap->chunks[0], &bitmap->chunkmap, idx, n); +} + + + + +// ------- mi_bitmap_xset --------------------------------------- + +// Set a sequence of `n` bits in the bitmap; returns `true` if atomically transitioned from 0's to 1's (or 1's to 0's). +// `n` cannot cross chunk boundaries (and `n <= MI_BCHUNK_BITS`)! +bool mi_bitmap_setN(mi_bitmap_t* bitmap, size_t idx, size_t n, size_t* already_set) { + mi_assert_internal(n>0); + mi_assert_internal(n<=MI_BCHUNK_BITS); + + const size_t chunk_idx = idx / MI_BCHUNK_BITS; + const size_t cidx = idx % MI_BCHUNK_BITS; + mi_assert_internal(cidx + n <= MI_BCHUNK_BITS); // don't cross chunks (for now) + mi_assert_internal(chunk_idx < mi_bitmap_chunk_count(bitmap)); + if (cidx + n > MI_BCHUNK_BITS) { n = MI_BCHUNK_BITS - cidx; } // paranoia + + const bool were_allclear = mi_bchunk_setN(&bitmap->chunks[chunk_idx], cidx, n, already_set); + mi_bitmap_chunkmap_set(bitmap, chunk_idx); // set afterwards + return were_allclear; +} + +// Clear a sequence of `n` bits in the bitmap; returns `true` if atomically transitioned from 1's to 0's. +// `n` cannot cross chunk boundaries (and `n <= MI_BCHUNK_BITS`)! +bool mi_bitmap_clearN(mi_bitmap_t* bitmap, size_t idx, size_t n) { + mi_assert_internal(n>0); + mi_assert_internal(n<=MI_BCHUNK_BITS); + + const size_t chunk_idx = idx / MI_BCHUNK_BITS; + const size_t cidx = idx % MI_BCHUNK_BITS; + mi_assert_internal(cidx + n <= MI_BCHUNK_BITS); // don't cross chunks (for now) + mi_assert_internal(chunk_idx < mi_bitmap_chunk_count(bitmap)); + if (cidx + n > MI_BCHUNK_BITS) { n = MI_BCHUNK_BITS - cidx; } // paranoia + + bool maybe_all_clear; + const bool were_allset = mi_bchunk_clearN(&bitmap->chunks[chunk_idx], cidx, n, &maybe_all_clear); + if (maybe_all_clear) { mi_bitmap_chunkmap_try_clear(bitmap, chunk_idx); } + return were_allset; +} + +// Count bits set in a range of `n` bits. +// `n` cannot cross chunk boundaries (and `n <= MI_BCHUNK_BITS`)! +size_t mi_bitmap_popcountN( mi_bitmap_t* bitmap, size_t idx, size_t n) { + mi_assert_internal(n>0); + mi_assert_internal(n<=MI_BCHUNK_BITS); + + const size_t chunk_idx = idx / MI_BCHUNK_BITS; + const size_t cidx = idx % MI_BCHUNK_BITS; + mi_assert_internal(cidx + n <= MI_BCHUNK_BITS); // don't cross chunks (for now) + mi_assert_internal(chunk_idx < mi_bitmap_chunk_count(bitmap)); + if (cidx + n > MI_BCHUNK_BITS) { n = MI_BCHUNK_BITS - cidx; } // paranoia + return mi_bchunk_popcountN(&bitmap->chunks[chunk_idx], cidx, n); +} + + +// Set/clear a bit in the bitmap; returns `true` if atomically transitioned from 0 to 1 (or 1 to 0) +bool mi_bitmap_set(mi_bitmap_t* bitmap, size_t idx) { + return mi_bitmap_setN(bitmap, idx, 1, NULL); +} + +bool mi_bitmap_clear(mi_bitmap_t* bitmap, size_t idx) { + return mi_bitmap_clearN(bitmap, idx, 1); +} + + + +// ------- mi_bitmap_is_xset --------------------------------------- + +// Is a sequence of n bits already all set/cleared? +bool mi_bitmap_is_xsetN(mi_xset_t set, mi_bitmap_t* bitmap, size_t idx, size_t n) { + mi_assert_internal(n>0); + mi_assert_internal(n<=MI_BCHUNK_BITS); + mi_assert_internal(idx + n <= mi_bitmap_max_bits(bitmap)); + + const size_t chunk_idx = idx / MI_BCHUNK_BITS; + const size_t cidx = idx % MI_BCHUNK_BITS; + mi_assert_internal(cidx + n <= MI_BCHUNK_BITS); // don't cross chunks (for now) + mi_assert_internal(chunk_idx < mi_bitmap_chunk_count(bitmap)); + if (cidx + n > MI_BCHUNK_BITS) { n = MI_BCHUNK_BITS - cidx; } // paranoia + + return mi_bchunk_is_xsetN(set, &bitmap->chunks[chunk_idx], cidx, n); +} + + + + +/* -------------------------------------------------------------------------------- + Iterate through a bfield +-------------------------------------------------------------------------------- */ + +// Cycle iteration through a bitfield. This is used to space out threads +// so there is less chance of contention. When searching for a free page we +// like to first search only the accessed part (so we reuse better). This +// high point is called the `cycle`. +// +// We then iterate through the bitfield as: +// first: [start, cycle> +// then : [0, start> +// then : [cycle, MI_BFIELD_BITS> +// +// The start is determined usually as `tseq % cycle` to have each thread +// start at a different spot. +// - We use `popcount` to improve branch prediction (maybe not needed? can we simplify?) +// - The `cycle_mask` is the part `[start, cycle>`. +#define mi_bfield_iterate(bfield,start,cycle,name_idx,SUF) { \ + mi_assert_internal(start <= cycle); \ + mi_assert_internal(start < MI_BFIELD_BITS); \ + mi_assert_internal(cycle <= MI_BFIELD_BITS); \ + mi_bfield_t _cycle_mask##SUF = mi_bfield_mask(cycle - start, start); \ + size_t _bcount##SUF = mi_bfield_popcount(bfield); \ + mi_bfield_t _b##SUF = bfield & _cycle_mask##SUF; /* process [start, cycle> first*/\ + while(_bcount##SUF > 0) { \ + _bcount##SUF--;\ + if (_b##SUF==0) { _b##SUF = bfield & ~_cycle_mask##SUF; } /* process [0,start> + [cycle, MI_BFIELD_BITS> next */ \ + /* size_t name_idx; */ \ + bool _found##SUF = mi_bfield_find_least_bit(_b##SUF,&name_idx); \ + mi_assert_internal(_found##SUF); MI_UNUSED(_found##SUF); \ + { \ + +#define mi_bfield_iterate_end(SUF) \ + } \ + _b##SUF = mi_bfield_clear_least_bit(_b##SUF); \ + } \ +} + +#define mi_bfield_cycle_iterate(bfield,tseq,cycle,name_idx,SUF) { \ + const size_t _start##SUF = (uint32_t)(tseq) % (uint32_t)(cycle); /* or: 0 to always search from the start? */\ + mi_bfield_iterate(bfield,_start##SUF,cycle,name_idx,SUF) + +#define mi_bfield_cycle_iterate_end(SUF) \ + mi_bfield_iterate_end(SUF); } + + +/* -------------------------------------------------------------------------------- + mi_bitmap_find + (used to find free pages) +-------------------------------------------------------------------------------- */ + +typedef bool (mi_bitmap_visit_fun_t)(mi_bitmap_t* bitmap, size_t chunk_idx, size_t n, size_t* idx, void* arg1, void* arg2); + +// Go through the bitmap and for every sequence of `n` set bits, call the visitor function. +// If it returns `true` stop the search. +static inline bool mi_bitmap_find(mi_bitmap_t* bitmap, size_t tseq, size_t n, size_t* pidx, mi_bitmap_visit_fun_t* on_find, void* arg1, void* arg2) +{ + const size_t chunkmap_max = _mi_divide_up(mi_bitmap_chunk_count(bitmap), MI_BFIELD_BITS); + for (size_t i = 0; i < chunkmap_max; i++) { + // and for each chunkmap entry we iterate over its bits to find the chunks + const mi_bfield_t cmap_entry = mi_atomic_load_relaxed(&bitmap->chunkmap.bfields[i]); + size_t hi; + if (mi_bfield_find_highest_bit(cmap_entry, &hi)) { + size_t eidx = 0; + mi_bfield_cycle_iterate(cmap_entry, tseq%8, hi+1, eidx, Y) // reduce the tseq to 8 bins to reduce using extra memory (see `mstress`) + { + mi_assert_internal(eidx <= MI_BFIELD_BITS); + const size_t chunk_idx = i*MI_BFIELD_BITS + eidx; + mi_assert_internal(chunk_idx < mi_bitmap_chunk_count(bitmap)); + if ((*on_find)(bitmap, chunk_idx, n, pidx, arg1, arg2)) { + return true; + } + } + mi_bfield_cycle_iterate_end(Y); } } - // no bits found return false; } -// Find `count` bits of 0 and set them to 1 atomically; returns `true` on success. -// Starts at idx, and wraps around to search in all `bitmap_fields` fields. -// `count` can be at most MI_BITMAP_FIELD_BITS and will never cross fields. -bool _mi_bitmap_try_find_from_claim(mi_bitmap_t bitmap, const size_t bitmap_fields, const size_t start_field_idx, const size_t count, mi_bitmap_index_t* bitmap_idx) { - size_t idx = start_field_idx; - for (size_t visited = 0; visited < bitmap_fields; visited++, idx++) { - if (idx >= bitmap_fields) idx = 0; // wrap - if (_mi_bitmap_try_find_claim_field(bitmap, idx, count, bitmap_idx)) { + +/* -------------------------------------------------------------------------------- + Bitmap: try_find_and_claim -- used to allocate abandoned pages + note: the compiler will fully inline the indirect function call +-------------------------------------------------------------------------------- */ + +typedef struct mi_claim_fun_data_s { + mi_arena_t* arena; + mi_heaptag_t heap_tag; +} mi_claim_fun_data_t; + +static bool mi_bitmap_try_find_and_claim_visit(mi_bitmap_t* bitmap, size_t chunk_idx, size_t n, size_t* pidx, void* arg1, void* arg2) +{ + mi_assert_internal(n==1); MI_UNUSED(n); + mi_claim_fun_t* claim_fun = (mi_claim_fun_t*)arg1; + mi_claim_fun_data_t* claim_data = (mi_claim_fun_data_t*)arg2; + size_t cidx; + if mi_likely(mi_bchunk_try_find_and_clear(&bitmap->chunks[chunk_idx], &cidx)) { + const size_t slice_index = (chunk_idx * MI_BCHUNK_BITS) + cidx; + mi_assert_internal(slice_index < mi_bitmap_max_bits(bitmap)); + bool keep_set = true; + if ((*claim_fun)(slice_index, claim_data->arena, claim_data->heap_tag, &keep_set)) { + // success! + mi_assert_internal(!keep_set); + *pidx = slice_index; return true; } + else { + // failed to claim it, set abandoned mapping again (unless the page was freed) + if (keep_set) { + const bool wasclear = mi_bchunk_set(&bitmap->chunks[chunk_idx], cidx, NULL); + mi_assert_internal(wasclear); MI_UNUSED(wasclear); + } + } + } + else { + // we may find that all are cleared only on a second iteration but that is ok as + // the chunkmap is a conservative approximation. + mi_bitmap_chunkmap_try_clear(bitmap, chunk_idx); } return false; } -// Like _mi_bitmap_try_find_from_claim but with an extra predicate that must be fullfilled -bool _mi_bitmap_try_find_from_claim_pred(mi_bitmap_t bitmap, const size_t bitmap_fields, - const size_t start_field_idx, const size_t count, - mi_bitmap_pred_fun_t pred_fun, void* pred_arg, - mi_bitmap_index_t* bitmap_idx) { - size_t idx = start_field_idx; - for (size_t visited = 0; visited < bitmap_fields; visited++, idx++) { - if (idx >= bitmap_fields) idx = 0; // wrap - if (_mi_bitmap_try_find_claim_field(bitmap, idx, count, bitmap_idx)) { - if (pred_fun == NULL || pred_fun(*bitmap_idx, pred_arg)) { +// Find a set bit in the bitmap and try to atomically clear it and claim it. +// (Used to find pages in the pages_abandoned bitmaps.) +mi_decl_nodiscard bool mi_bitmap_try_find_and_claim(mi_bitmap_t* bitmap, size_t tseq, size_t* pidx, + mi_claim_fun_t* claim, mi_arena_t* arena, mi_heaptag_t heap_tag) +{ + mi_claim_fun_data_t claim_data = { arena, heap_tag }; + return mi_bitmap_find(bitmap, tseq, 1, pidx, &mi_bitmap_try_find_and_claim_visit, (void*)claim, &claim_data); +} + + +bool mi_bitmap_bsr(mi_bitmap_t* bitmap, size_t* idx) { + const size_t chunkmap_max = _mi_divide_up(mi_bitmap_chunk_count(bitmap), MI_BFIELD_BITS); + for (size_t i = chunkmap_max; i > 0; ) { + i--; + mi_bfield_t cmap = mi_atomic_load_relaxed(&bitmap->chunkmap.bfields[i]); + size_t cmap_idx; + if (mi_bsr(cmap,&cmap_idx)) { + // highest chunk + const size_t chunk_idx = i*MI_BFIELD_BITS + cmap_idx; + size_t cidx; + if (mi_bchunk_bsr(&bitmap->chunks[chunk_idx], &cidx)) { + *idx = (chunk_idx * MI_BCHUNK_BITS) + cidx; return true; } - // predicate returned false, unclaim and look further - _mi_bitmap_unclaim(bitmap, bitmap_fields, count, *bitmap_idx); } } return false; } -/* -// Find `count` bits of 0 and set them to 1 atomically; returns `true` on success. -// For now, `count` can be at most MI_BITMAP_FIELD_BITS and will never span fields. -bool _mi_bitmap_try_find_claim(mi_bitmap_t bitmap, const size_t bitmap_fields, const size_t count, mi_bitmap_index_t* bitmap_idx) { - return _mi_bitmap_try_find_from_claim(bitmap, bitmap_fields, 0, count, bitmap_idx); +// Return count of all set bits in a bitmap. +size_t mi_bitmap_popcount(mi_bitmap_t* bitmap) { + // for all chunkmap entries + size_t popcount = 0; + const size_t chunkmap_max = _mi_divide_up(mi_bitmap_chunk_count(bitmap), MI_BFIELD_BITS); + for (size_t i = 0; i < chunkmap_max; i++) { + mi_bfield_t cmap_entry = mi_atomic_load_relaxed(&bitmap->chunkmap.bfields[i]); + size_t cmap_idx; + // for each chunk (corresponding to a set bit in a chunkmap entry) + while (mi_bfield_foreach_bit(&cmap_entry, &cmap_idx)) { + const size_t chunk_idx = i*MI_BFIELD_BITS + cmap_idx; + // count bits in a chunk + popcount += mi_bchunk_popcount(&bitmap->chunks[chunk_idx]); + } + } + return popcount; } -*/ -// Set `count` bits at `bitmap_idx` to 0 atomically -// Returns `true` if all `count` bits were 1 previously. -bool _mi_bitmap_unclaim(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx) { - const size_t idx = mi_bitmap_index_field(bitmap_idx); - const size_t bitidx = mi_bitmap_index_bit_in_field(bitmap_idx); - const size_t mask = mi_bitmap_mask_(count, bitidx); - mi_assert_internal(bitmap_fields > idx); MI_UNUSED(bitmap_fields); - // mi_assert_internal((bitmap[idx] & mask) == mask); - size_t prev = mi_atomic_and_acq_rel(&bitmap[idx], ~mask); - return ((prev & mask) == mask); + + +// Clear a bit once it is set. +void mi_bitmap_clear_once_set(mi_bitmap_t* bitmap, size_t idx) { + mi_assert_internal(idx < mi_bitmap_max_bits(bitmap)); + const size_t chunk_idx = idx / MI_BCHUNK_BITS; + const size_t cidx = idx % MI_BCHUNK_BITS; + mi_assert_internal(chunk_idx < mi_bitmap_chunk_count(bitmap)); + mi_bchunk_clear_once_set(&bitmap->chunks[chunk_idx], cidx); } -// Set `count` bits at `bitmap_idx` to 1 atomically -// Returns `true` if all `count` bits were 0 previously. `any_zero` is `true` if there was at least one zero bit. -bool _mi_bitmap_claim(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx, bool* any_zero) { - const size_t idx = mi_bitmap_index_field(bitmap_idx); - const size_t bitidx = mi_bitmap_index_bit_in_field(bitmap_idx); - const size_t mask = mi_bitmap_mask_(count, bitidx); - mi_assert_internal(bitmap_fields > idx); MI_UNUSED(bitmap_fields); - //mi_assert_internal(any_zero != NULL || (bitmap[idx] & mask) == 0); - size_t prev = mi_atomic_or_acq_rel(&bitmap[idx], mask); - if (any_zero != NULL) *any_zero = ((prev & mask) != mask); - return ((prev & mask) == 0); +// Visit all set bits in a bitmap. +// todo: optimize further? maybe use avx512 to directly get all indices using a mask_compressstore? +bool _mi_bitmap_forall_set(mi_bitmap_t* bitmap, mi_forall_set_fun_t* visit, mi_arena_t* arena, void* arg) { + // for all chunkmap entries + const size_t chunkmap_max = _mi_divide_up(mi_bitmap_chunk_count(bitmap), MI_BFIELD_BITS); + for(size_t i = 0; i < chunkmap_max; i++) { + mi_bfield_t cmap_entry = mi_atomic_load_relaxed(&bitmap->chunkmap.bfields[i]); + size_t cmap_idx; + // for each chunk (corresponding to a set bit in a chunkmap entry) + while (mi_bfield_foreach_bit(&cmap_entry, &cmap_idx)) { + const size_t chunk_idx = i*MI_BFIELD_BITS + cmap_idx; + // for each chunk field + mi_bchunk_t* const chunk = &bitmap->chunks[chunk_idx]; + for (size_t j = 0; j < MI_BCHUNK_FIELDS; j++) { + const size_t base_idx = (chunk_idx*MI_BCHUNK_BITS) + (j*MI_BFIELD_BITS); + mi_bfield_t b = mi_atomic_load_relaxed(&chunk->bfields[j]); + size_t bidx; + while (mi_bfield_foreach_bit(&b, &bidx)) { + const size_t idx = base_idx + bidx; + if (!visit(idx, 1, arena, arg)) return false; + } + } + } + } + return true; } -// Returns `true` if all `count` bits were 1. `any_ones` is `true` if there was at least one bit set to one. -static bool mi_bitmap_is_claimedx(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx, bool* any_ones) { - const size_t idx = mi_bitmap_index_field(bitmap_idx); - const size_t bitidx = mi_bitmap_index_bit_in_field(bitmap_idx); - const size_t mask = mi_bitmap_mask_(count, bitidx); - mi_assert_internal(bitmap_fields > idx); MI_UNUSED(bitmap_fields); - size_t field = mi_atomic_load_relaxed(&bitmap[idx]); - if (any_ones != NULL) *any_ones = ((field & mask) != 0); - return ((field & mask) == mask); +// Visit all set bits in a bitmap but try to return ranges (within bfields) if possible. +// Also clear those ranges atomically. +// Used by purging to purge larger ranges when possible +// todo: optimize further? maybe use avx512 to directly get all indices using a mask_compressstore? +bool _mi_bitmap_forall_setc_ranges(mi_bitmap_t* bitmap, mi_forall_set_fun_t* visit, mi_arena_t* arena, void* arg) { + // for all chunkmap entries + const size_t chunkmap_max = _mi_divide_up(mi_bitmap_chunk_count(bitmap), MI_BFIELD_BITS); + for (size_t i = 0; i < chunkmap_max; i++) { + mi_bfield_t cmap_entry = mi_atomic_load_relaxed(&bitmap->chunkmap.bfields[i]); + size_t cmap_idx; + // for each chunk (corresponding to a set bit in a chunkmap entry) + while (mi_bfield_foreach_bit(&cmap_entry, &cmap_idx)) { + const size_t chunk_idx = i*MI_BFIELD_BITS + cmap_idx; + // for each chunk field + mi_bchunk_t* const chunk = &bitmap->chunks[chunk_idx]; + for (size_t j = 0; j < MI_BCHUNK_FIELDS; j++) { + const size_t base_idx = (chunk_idx*MI_BCHUNK_BITS) + (j*MI_BFIELD_BITS); + mi_bfield_t b = mi_atomic_exchange_acq_rel(&chunk->bfields[j], 0); // can be relaxed? + #if MI_DEBUG > 1 + const size_t bpopcount = mi_popcount(b); + size_t rngcount = 0; + #endif + size_t bidx; + while (mi_bfield_find_least_bit(b, &bidx)) { + const size_t rng = mi_ctz(~(b>>bidx)); // all the set bits from bidx + #if MI_DEBUG > 1 + rngcount += rng; + #endif + mi_assert_internal(rng>=1 && rng<=MI_BFIELD_BITS); + const size_t idx = base_idx + bidx; + mi_assert_internal((idx % MI_BFIELD_BITS) + rng <= MI_BFIELD_BITS); + mi_assert_internal((idx / MI_BCHUNK_BITS) < mi_bitmap_chunk_count(bitmap)); + if (!visit(idx, rng, arena, arg)) return false; + // clear rng bits in b + b = b & ~mi_bfield_mask(rng, bidx); + } + mi_assert_internal(rngcount == bpopcount); + } + } + } + return true; } -bool _mi_bitmap_is_claimed(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx) { - return mi_bitmap_is_claimedx(bitmap, bitmap_fields, count, bitmap_idx, NULL); + + +/* -------------------------------------------------------------------------------- + binned bitmap's +-------------------------------------------------------------------------------- */ + + +size_t mi_bbitmap_size(size_t bit_count, size_t* pchunk_count) { + // mi_assert_internal((bit_count % MI_BCHUNK_BITS) == 0); + bit_count = _mi_align_up(bit_count, MI_BCHUNK_BITS); + mi_assert_internal(bit_count <= MI_BITMAP_MAX_BIT_COUNT); + mi_assert_internal(bit_count > 0); + const size_t chunk_count = bit_count / MI_BCHUNK_BITS; + mi_assert_internal(chunk_count >= 1); + const size_t size = offsetof(mi_bbitmap_t,chunks) + (chunk_count * MI_BCHUNK_SIZE); + mi_assert_internal( (size%MI_BCHUNK_SIZE) == 0 ); + if (pchunk_count != NULL) { *pchunk_count = chunk_count; } + return size; } -bool _mi_bitmap_is_any_claimed(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx) { - bool any_ones; - mi_bitmap_is_claimedx(bitmap, bitmap_fields, count, bitmap_idx, &any_ones); - return any_ones; +// initialize a bitmap to all unset; avoid a mem_zero if `already_zero` is true +// returns the size of the bitmap +size_t mi_bbitmap_init(mi_bbitmap_t* bbitmap, size_t bit_count, bool already_zero) { + size_t chunk_count; + const size_t size = mi_bbitmap_size(bit_count, &chunk_count); + if (!already_zero) { + _mi_memzero_aligned(bbitmap, size); + } + mi_atomic_store_release(&bbitmap->chunk_count, chunk_count); + mi_assert_internal(mi_atomic_load_relaxed(&bbitmap->chunk_count) <= MI_BITMAP_MAX_CHUNK_COUNT); + return size; } +void mi_bbitmap_unsafe_setN(mi_bbitmap_t* bbitmap, size_t idx, size_t n) { + mi_assert_internal(n>0); + mi_assert_internal(idx + n <= mi_bbitmap_max_bits(bbitmap)); + mi_bchunks_unsafe_setN(&bbitmap->chunks[0], &bbitmap->chunkmap, idx, n); +} -//-------------------------------------------------------------------------- -// the `_across` functions work on bitmaps where sequences can cross over -// between the fields. This is used in arena allocation -//-------------------------------------------------------------------------- -// Try to atomically claim a sequence of `count` bits starting from the field -// at `idx` in `bitmap` and crossing into subsequent fields. Returns `true` on success. -static bool mi_bitmap_try_find_claim_field_across(mi_bitmap_t bitmap, size_t bitmap_fields, size_t idx, const size_t count, const size_t retries, mi_bitmap_index_t* bitmap_idx) -{ - mi_assert_internal(bitmap_idx != NULL); - - // check initial trailing zeros - mi_bitmap_field_t* field = &bitmap[idx]; - size_t map = mi_atomic_load_relaxed(field); - const size_t initial = mi_clz(map); // count of initial zeros starting at idx - mi_assert_internal(initial <= MI_BITMAP_FIELD_BITS); - if (initial == 0) return false; - if (initial >= count) return _mi_bitmap_try_find_claim_field(bitmap, idx, count, bitmap_idx); // no need to cross fields - if (_mi_divide_up(count - initial, MI_BITMAP_FIELD_BITS) >= (bitmap_fields - idx)) return false; // not enough entries - - // scan ahead - size_t found = initial; - size_t mask = 0; // mask bits for the final field - while(found < count) { - field++; - map = mi_atomic_load_relaxed(field); - const size_t mask_bits = (found + MI_BITMAP_FIELD_BITS <= count ? MI_BITMAP_FIELD_BITS : (count - found)); - mask = mi_bitmap_mask_(mask_bits, 0); - if ((map & mask) != 0) return false; - found += mask_bits; - } - mi_assert_internal(field < &bitmap[bitmap_fields]); - - // found range of zeros up to the final field; mask contains mask in the final field - // now claim it atomically - mi_bitmap_field_t* const final_field = field; - const size_t final_mask = mask; - mi_bitmap_field_t* const initial_field = &bitmap[idx]; - const size_t initial_mask = mi_bitmap_mask_(initial, MI_BITMAP_FIELD_BITS - initial); - - // initial field - size_t newmap; - field = initial_field; - map = mi_atomic_load_relaxed(field); - do { - newmap = map | initial_mask; - if ((map & initial_mask) != 0) { goto rollback; }; - } while (!mi_atomic_cas_strong_acq_rel(field, &map, newmap)); - - // intermediate fields - while (++field < final_field) { - newmap = MI_BITMAP_FIELD_FULL; - map = 0; - if (!mi_atomic_cas_strong_acq_rel(field, &map, newmap)) { goto rollback; } - } - - // final field - mi_assert_internal(field == final_field); - map = mi_atomic_load_relaxed(field); - do { - newmap = map | final_mask; - if ((map & final_mask) != 0) { goto rollback; } - } while (!mi_atomic_cas_strong_acq_rel(field, &map, newmap)); - // claimed! - *bitmap_idx = mi_bitmap_index_create(idx, MI_BITMAP_FIELD_BITS - initial); - return true; +/* -------------------------------------------------------------------------------- + binned bitmap used to track free slices +-------------------------------------------------------------------------------- */ -rollback: - // roll back intermediate fields - while (--field > initial_field) { - newmap = 0; - map = MI_BITMAP_FIELD_FULL; - mi_assert_internal(mi_atomic_load_relaxed(field) == map); - mi_atomic_store_release(field, newmap); - } - if (field == initial_field) { - map = mi_atomic_load_relaxed(field); - do { - mi_assert_internal((map & initial_mask) == initial_mask); - newmap = map & ~initial_mask; - } while (!mi_atomic_cas_strong_acq_rel(field, &map, newmap)); +// Assign a specific size bin to a chunk +static void mi_bbitmap_set_chunk_bin(mi_bbitmap_t* bbitmap, size_t chunk_idx, mi_chunkbin_t bin) { + mi_assert_internal(chunk_idx < mi_bbitmap_chunk_count(bbitmap)); + for (mi_chunkbin_t ibin = MI_CBIN_SMALL; ibin < MI_CBIN_NONE; ibin = mi_chunkbin_inc(ibin)) { + if (ibin == bin) { + const bool was_clear = mi_bchunk_set(& bbitmap->chunkmap_bins[ibin], chunk_idx, NULL); + if (was_clear) { mi_os_stat_increase(chunk_bins[ibin],1); } + } + else { + const bool was_set = mi_bchunk_clear(&bbitmap->chunkmap_bins[ibin], chunk_idx, NULL); + if (was_set) { mi_os_stat_decrease(chunk_bins[ibin],1); } + } } - // retry? (we make a recursive call instead of goto to be able to use const declarations) - if (retries < 4) { - return mi_bitmap_try_find_claim_field_across(bitmap, bitmap_fields, idx, count, retries+1, bitmap_idx); +} + +mi_chunkbin_t mi_bbitmap_debug_get_bin(const mi_bchunkmap_t* chunkmap_bins, size_t chunk_idx) { + for (mi_chunkbin_t ibin = MI_CBIN_SMALL; ibin < MI_CBIN_NONE; ibin = mi_chunkbin_inc(ibin)) { + if (mi_bchunk_is_xsetN(MI_BIT_SET, &chunkmap_bins[ibin], chunk_idx, 1)) { + return ibin; + } } - else { + return MI_CBIN_NONE; +} + +// Track the index of the highest chunk that is accessed. +static void mi_bbitmap_chunkmap_set_max(mi_bbitmap_t* bbitmap, size_t chunk_idx) { + size_t oldmax = mi_atomic_load_relaxed(&bbitmap->chunk_max_accessed); + if mi_unlikely(chunk_idx > oldmax) { + mi_atomic_cas_strong_relaxed(&bbitmap->chunk_max_accessed, &oldmax, chunk_idx); + } +} + +// Set a bit in the chunkmap +static void mi_bbitmap_chunkmap_set(mi_bbitmap_t* bbitmap, size_t chunk_idx, bool check_all_set) { + mi_assert(chunk_idx < mi_bbitmap_chunk_count(bbitmap)); + if (check_all_set) { + if (mi_bchunk_all_are_set_relaxed(&bbitmap->chunks[chunk_idx])) { + // all slices are free in this chunk: return back to the NONE bin + mi_bbitmap_set_chunk_bin(bbitmap, chunk_idx, MI_CBIN_NONE); + } + } + mi_bchunk_set(&bbitmap->chunkmap, chunk_idx, NULL); + mi_bbitmap_chunkmap_set_max(bbitmap, chunk_idx); +} + +static bool mi_bbitmap_chunkmap_try_clear(mi_bbitmap_t* bbitmap, size_t chunk_idx) { + mi_assert(chunk_idx < mi_bbitmap_chunk_count(bbitmap)); + // check if the corresponding chunk is all clear + if (!mi_bchunk_all_are_clear_relaxed(&bbitmap->chunks[chunk_idx])) return false; + // clear the chunkmap bit + mi_bchunk_clear(&bbitmap->chunkmap, chunk_idx, NULL); + // .. but a concurrent set may have happened in between our all-clear test and the clearing of the + // bit in the mask. We check again to catch this situation. (note: mi_bchunk_clear must be acq-rel) + if (!mi_bchunk_all_are_clear_relaxed(&bbitmap->chunks[chunk_idx])) { + mi_bchunk_set(&bbitmap->chunkmap, chunk_idx, NULL); return false; } + mi_bbitmap_chunkmap_set_max(bbitmap, chunk_idx); + return true; } -// Find `count` bits of zeros and set them to 1 atomically; returns `true` on success. -// Starts at idx, and wraps around to search in all `bitmap_fields` fields. -bool _mi_bitmap_try_find_from_claim_across(mi_bitmap_t bitmap, const size_t bitmap_fields, const size_t start_field_idx, const size_t count, mi_bitmap_index_t* bitmap_idx) { - mi_assert_internal(count > 0); - if (count==1) return _mi_bitmap_try_find_from_claim(bitmap, bitmap_fields, start_field_idx, count, bitmap_idx); - size_t idx = start_field_idx; - for (size_t visited = 0; visited < bitmap_fields; visited++, idx++) { - if (idx >= bitmap_fields) idx = 0; // wrap - // try to claim inside the field - if (count <= MI_BITMAP_FIELD_BITS) { - if (_mi_bitmap_try_find_claim_field(bitmap, idx, count, bitmap_idx)) { - return true; - } +/* -------------------------------------------------------------------------------- + mi_bbitmap_setN, try_clearN, and is_xsetN + (used to find free pages) +-------------------------------------------------------------------------------- */ + +// Set a sequence of `n` bits in the bitmap; returns `true` if atomically transitioned from 0's to 1's (or 1's to 0's). +// `n` cannot cross chunk boundaries (and `n <= MI_BCHUNK_BITS`)! +bool mi_bbitmap_setN(mi_bbitmap_t* bbitmap, size_t idx, size_t n) { + mi_assert_internal(n>0); + mi_assert_internal(n<=MI_BCHUNK_BITS); + + const size_t chunk_idx = idx / MI_BCHUNK_BITS; + const size_t cidx = idx % MI_BCHUNK_BITS; + mi_assert_internal(cidx + n <= MI_BCHUNK_BITS); // don't cross chunks (for now) + mi_assert_internal(chunk_idx < mi_bbitmap_chunk_count(bbitmap)); + if (cidx + n > MI_BCHUNK_BITS) { n = MI_BCHUNK_BITS - cidx; } // paranoia + + const bool were_allclear = mi_bchunk_setN(&bbitmap->chunks[chunk_idx], cidx, n, NULL); + mi_bbitmap_chunkmap_set(bbitmap, chunk_idx, true); // set after + return were_allclear; +} + + +// ------- mi_bbitmap_try_clearN --------------------------------------- + +bool mi_bbitmap_try_clearN(mi_bbitmap_t* bbitmap, size_t idx, size_t n) { + mi_assert_internal(n>0); + mi_assert_internal(n<=MI_BCHUNK_BITS); + mi_assert_internal(idx + n <= mi_bbitmap_max_bits(bbitmap)); + + const size_t chunk_idx = idx / MI_BCHUNK_BITS; + const size_t cidx = idx % MI_BCHUNK_BITS; + mi_assert_internal(cidx + n <= MI_BCHUNK_BITS); // don't cross chunks (for now) + mi_assert_internal(chunk_idx < mi_bbitmap_chunk_count(bbitmap)); + if (cidx + n > MI_BCHUNK_BITS) return false; + bool maybe_all_clear; + const bool cleared = mi_bchunk_try_clearN(&bbitmap->chunks[chunk_idx], cidx, n, &maybe_all_clear); + if (cleared && maybe_all_clear) { mi_bbitmap_chunkmap_try_clear(bbitmap, chunk_idx); } + // note: we don't set the size class for an explicit try_clearN (only used by purging) + return cleared; +} + + +// ------- mi_bbitmap_is_xset --------------------------------------- + +// Is a sequence of n bits already all set/cleared? +bool mi_bbitmap_is_xsetN(mi_xset_t set, mi_bbitmap_t* bbitmap, size_t idx, size_t n) { + mi_assert_internal(n>0); + mi_assert_internal(n<=MI_BCHUNK_BITS); + mi_assert_internal(idx + n <= mi_bbitmap_max_bits(bbitmap)); + + const size_t chunk_idx = idx / MI_BCHUNK_BITS; + const size_t cidx = idx % MI_BCHUNK_BITS; + mi_assert_internal(cidx + n <= MI_BCHUNK_BITS); // don't cross chunks (for now) + mi_assert_internal(chunk_idx < mi_bbitmap_chunk_count(bbitmap)); + if (cidx + n > MI_BCHUNK_BITS) { n = MI_BCHUNK_BITS - cidx; } // paranoia + + return mi_bchunk_is_xsetN(set, &bbitmap->chunks[chunk_idx], cidx, n); +} + + + + +/* -------------------------------------------------------------------------------- + mi_bbitmap_find + (used to find free pages) +-------------------------------------------------------------------------------- */ + +typedef bool (mi_bchunk_try_find_and_clear_fun_t)(mi_bchunk_t* chunk, size_t n, size_t* idx); + +// Go through the bbitmap and for every sequence of `n` set bits, call the visitor function. +// If it returns `true` stop the search. +// +// This is used for finding free blocks and it is important to be efficient (with 2-level bitscan) +// but also reduce fragmentation (through size bins). +static inline bool mi_bbitmap_try_find_and_clear_generic(mi_bbitmap_t* bbitmap, size_t tseq, size_t n, size_t* pidx, mi_bchunk_try_find_and_clear_fun_t* on_find) +{ + // we space out threads to reduce contention + const size_t cmap_max_count = _mi_divide_up(mi_bbitmap_chunk_count(bbitmap),MI_BFIELD_BITS); + const size_t chunk_acc = mi_atomic_load_relaxed(&bbitmap->chunk_max_accessed); + const size_t cmap_acc = chunk_acc / MI_BFIELD_BITS; + const size_t cmap_acc_bits = 1 + (chunk_acc % MI_BFIELD_BITS); + + // create a mask over the chunkmap entries to iterate over them efficiently + mi_assert_internal(MI_BFIELD_BITS >= MI_BCHUNK_FIELDS); + const mi_bfield_t cmap_mask = mi_bfield_mask(cmap_max_count,0); + const size_t cmap_cycle = cmap_acc+1; + const mi_chunkbin_t bbin = mi_chunkbin_of(n); + // visit each cmap entry + size_t cmap_idx = 0; + mi_bfield_cycle_iterate(cmap_mask, tseq, cmap_cycle, cmap_idx, X) + { + // and for each chunkmap entry we iterate over its bits to find the chunks + const mi_bfield_t cmap_entry = mi_atomic_load_relaxed(&bbitmap->chunkmap.bfields[cmap_idx]); + const size_t cmap_entry_cycle = (cmap_idx != cmap_acc ? MI_BFIELD_BITS : cmap_acc_bits); + if (cmap_entry == 0) continue; + + // get size bin masks + mi_bfield_t cmap_bins[MI_CBIN_COUNT] = { 0 }; + cmap_bins[MI_CBIN_NONE] = cmap_entry; + for (mi_chunkbin_t ibin = MI_CBIN_SMALL; ibin < MI_CBIN_NONE; ibin = mi_chunkbin_inc(ibin)) { + const mi_bfield_t cmap_bin = mi_atomic_load_relaxed(&bbitmap->chunkmap_bins[ibin].bfields[cmap_idx]); + cmap_bins[ibin] = cmap_bin & cmap_entry; + cmap_bins[MI_CBIN_NONE] &= ~cmap_bin; // clear bits that are in an assigned size bin } - // try to claim across fields - if (mi_bitmap_try_find_claim_field_across(bitmap, bitmap_fields, idx, count, 0, bitmap_idx)) { - return true; + + // consider only chunks for a particular size bin at a time + // this picks the best bin only within a cmap entry (~ 1GiB address space), but avoids multiple + // iterations through all entries. + mi_assert_internal(bbin < MI_CBIN_NONE); + for (mi_chunkbin_t ibin = MI_CBIN_SMALL; ibin <= MI_CBIN_NONE; + // skip from bbin to NONE (so, say, a SMALL will never be placed in a OTHER, MEDIUM, or LARGE chunk to reduce fragmentation) + ibin = (ibin == bbin ? MI_CBIN_NONE : mi_chunkbin_inc(ibin))) + { + mi_assert_internal(ibin < MI_CBIN_COUNT); + const mi_bfield_t cmap_bin = cmap_bins[ibin]; + size_t eidx = 0; + mi_bfield_cycle_iterate(cmap_bin, tseq, cmap_entry_cycle, eidx, Y) + { + // assertion doesn't quite hold as the max_accessed may be out-of-date + // mi_assert_internal(cmap_entry_cycle > eidx || ibin == MI_CBIN_NONE); + + // get the chunk + const size_t chunk_idx = cmap_idx*MI_BFIELD_BITS + eidx; + mi_bchunk_t* chunk = &bbitmap->chunks[chunk_idx]; + + size_t cidx; + if ((*on_find)(chunk, n, &cidx)) { + if (cidx==0 && ibin == MI_CBIN_NONE) { // only the first block determines the size bin + // this chunk is now reserved for the `bbin` size class + mi_bbitmap_set_chunk_bin(bbitmap, chunk_idx, bbin); + } + *pidx = (chunk_idx * MI_BCHUNK_BITS) + cidx; + mi_assert_internal(*pidx + n <= mi_bbitmap_max_bits(bbitmap)); + return true; + } + else { + // todo: should _on_find_ return a boolen if there is a chance all are clear to avoid calling `try_clear?` + // we may find that all are cleared only on a second iteration but that is ok as the chunkmap is a conservative approximation. + mi_bbitmap_chunkmap_try_clear(bbitmap, chunk_idx); + } + } + mi_bfield_cycle_iterate_end(Y); } } + mi_bfield_cycle_iterate_end(X); return false; } -// Helper for masks across fields; returns the mid count, post_mask may be 0 -static size_t mi_bitmap_mask_across(mi_bitmap_index_t bitmap_idx, size_t bitmap_fields, size_t count, size_t* pre_mask, size_t* mid_mask, size_t* post_mask) { - MI_UNUSED_RELEASE(bitmap_fields); - const size_t bitidx = mi_bitmap_index_bit_in_field(bitmap_idx); - if mi_likely(bitidx + count <= MI_BITMAP_FIELD_BITS) { - *pre_mask = mi_bitmap_mask_(count, bitidx); - *mid_mask = 0; - *post_mask = 0; - mi_assert_internal(mi_bitmap_index_field(bitmap_idx) < bitmap_fields); - return 0; - } - else { - const size_t pre_bits = MI_BITMAP_FIELD_BITS - bitidx; - mi_assert_internal(pre_bits < count); - *pre_mask = mi_bitmap_mask_(pre_bits, bitidx); - count -= pre_bits; - const size_t mid_count = (count / MI_BITMAP_FIELD_BITS); - *mid_mask = MI_BITMAP_FIELD_FULL; - count %= MI_BITMAP_FIELD_BITS; - *post_mask = (count==0 ? 0 : mi_bitmap_mask_(count, 0)); - mi_assert_internal(mi_bitmap_index_field(bitmap_idx) + mid_count + (count==0 ? 0 : 1) < bitmap_fields); - return mid_count; - } -} - -// Set `count` bits at `bitmap_idx` to 0 atomically -// Returns `true` if all `count` bits were 1 previously. -bool _mi_bitmap_unclaim_across(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx) { - size_t idx = mi_bitmap_index_field(bitmap_idx); - size_t pre_mask; - size_t mid_mask; - size_t post_mask; - size_t mid_count = mi_bitmap_mask_across(bitmap_idx, bitmap_fields, count, &pre_mask, &mid_mask, &post_mask); - bool all_one = true; - mi_bitmap_field_t* field = &bitmap[idx]; - size_t prev = mi_atomic_and_acq_rel(field++, ~pre_mask); - if ((prev & pre_mask) != pre_mask) all_one = false; - while(mid_count-- > 0) { - prev = mi_atomic_and_acq_rel(field++, ~mid_mask); - if ((prev & mid_mask) != mid_mask) all_one = false; - } - if (post_mask!=0) { - prev = mi_atomic_and_acq_rel(field, ~post_mask); - if ((prev & post_mask) != post_mask) all_one = false; - } - return all_one; -} - -// Set `count` bits at `bitmap_idx` to 1 atomically -// Returns `true` if all `count` bits were 0 previously. `any_zero` is `true` if there was at least one zero bit. -bool _mi_bitmap_claim_across(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx, bool* pany_zero) { - size_t idx = mi_bitmap_index_field(bitmap_idx); - size_t pre_mask; - size_t mid_mask; - size_t post_mask; - size_t mid_count = mi_bitmap_mask_across(bitmap_idx, bitmap_fields, count, &pre_mask, &mid_mask, &post_mask); - bool all_zero = true; - bool any_zero = false; - _Atomic(size_t)*field = &bitmap[idx]; - size_t prev = mi_atomic_or_acq_rel(field++, pre_mask); - if ((prev & pre_mask) != 0) all_zero = false; - if ((prev & pre_mask) != pre_mask) any_zero = true; - while (mid_count-- > 0) { - prev = mi_atomic_or_acq_rel(field++, mid_mask); - if ((prev & mid_mask) != 0) all_zero = false; - if ((prev & mid_mask) != mid_mask) any_zero = true; - } - if (post_mask!=0) { - prev = mi_atomic_or_acq_rel(field, post_mask); - if ((prev & post_mask) != 0) all_zero = false; - if ((prev & post_mask) != post_mask) any_zero = true; - } - if (pany_zero != NULL) *pany_zero = any_zero; - return all_zero; -} - - -// Returns `true` if all `count` bits were 1. -// `any_ones` is `true` if there was at least one bit set to one. -static bool mi_bitmap_is_claimedx_across(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx, bool* pany_ones) { - size_t idx = mi_bitmap_index_field(bitmap_idx); - size_t pre_mask; - size_t mid_mask; - size_t post_mask; - size_t mid_count = mi_bitmap_mask_across(bitmap_idx, bitmap_fields, count, &pre_mask, &mid_mask, &post_mask); - bool all_ones = true; - bool any_ones = false; - mi_bitmap_field_t* field = &bitmap[idx]; - size_t prev = mi_atomic_load_relaxed(field++); - if ((prev & pre_mask) != pre_mask) all_ones = false; - if ((prev & pre_mask) != 0) any_ones = true; - while (mid_count-- > 0) { - prev = mi_atomic_load_relaxed(field++); - if ((prev & mid_mask) != mid_mask) all_ones = false; - if ((prev & mid_mask) != 0) any_ones = true; - } - if (post_mask!=0) { - prev = mi_atomic_load_relaxed(field); - if ((prev & post_mask) != post_mask) all_ones = false; - if ((prev & post_mask) != 0) any_ones = true; - } - if (pany_ones != NULL) *pany_ones = any_ones; - return all_ones; + +/* -------------------------------------------------------------------------------- + mi_bbitmap_try_find_and_clear -- used to find free pages + note: the compiler will fully inline the indirect function calls +-------------------------------------------------------------------------------- */ + +bool mi_bbitmap_try_find_and_clear(mi_bbitmap_t* bbitmap, size_t tseq, size_t* pidx) { + return mi_bbitmap_try_find_and_clear_generic(bbitmap, tseq, 1, pidx, &mi_bchunk_try_find_and_clear_1); } -bool _mi_bitmap_is_claimed_across(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx) { - return mi_bitmap_is_claimedx_across(bitmap, bitmap_fields, count, bitmap_idx, NULL); +bool mi_bbitmap_try_find_and_clear8(mi_bbitmap_t* bbitmap, size_t tseq, size_t* pidx) { + return mi_bbitmap_try_find_and_clear_generic(bbitmap, tseq, 8, pidx, &mi_bchunk_try_find_and_clear_8); +} + +// bool mi_bbitmap_try_find_and_clearX(mi_bbitmap_t* bbitmap, size_t tseq, size_t* pidx) { +// return mi_bbitmap_try_find_and_clear_generic(bbitmap, tseq, MI_BFIELD_BITS, pidx, &mi_bchunk_try_find_and_clear_X); +// } + +bool mi_bbitmap_try_find_and_clearNX(mi_bbitmap_t* bbitmap, size_t tseq, size_t n, size_t* pidx) { + mi_assert_internal(n<=MI_BFIELD_BITS); + return mi_bbitmap_try_find_and_clear_generic(bbitmap, tseq, n, pidx, &mi_bchunk_try_find_and_clearNX); } -bool _mi_bitmap_is_any_claimed_across(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx) { - bool any_ones; - mi_bitmap_is_claimedx_across(bitmap, bitmap_fields, count, bitmap_idx, &any_ones); - return any_ones; +bool mi_bbitmap_try_find_and_clearN_(mi_bbitmap_t* bbitmap, size_t tseq, size_t n, size_t* pidx) { + mi_assert_internal(n<=MI_BCHUNK_BITS); + return mi_bbitmap_try_find_and_clear_generic(bbitmap, tseq, n, pidx, &mi_bchunk_try_find_and_clearN_); } diff --git a/src/dashbls/depends/mimalloc/src/bitmap.h b/src/dashbls/depends/mimalloc/src/bitmap.h index 0c501ec1feac..b9c9dfb41b06 100644 --- a/src/dashbls/depends/mimalloc/src/bitmap.h +++ b/src/dashbls/depends/mimalloc/src/bitmap.h @@ -1,111 +1,330 @@ /* ---------------------------------------------------------------------------- -Copyright (c) 2019-2020 Microsoft Research, Daan Leijen +Copyright (c) 2019-2024 Microsoft Research, Daan Leijen This is free software; you can redistribute it and/or modify it under the terms of the MIT license. A copy of the license can be found in the file "LICENSE" at the root of this distribution. -----------------------------------------------------------------------------*/ /* ---------------------------------------------------------------------------- -Concurrent bitmap that can set/reset sequences of bits atomically, -represeted as an array of fields where each field is a machine word (`size_t`) - -There are two api's; the standard one cannot have sequences that cross -between the bitmap fields (and a sequence must be <= MI_BITMAP_FIELD_BITS). -(this is used in region allocation) - -The `_across` postfixed functions do allow sequences that can cross over -between the fields. (This is used in arena allocation) +Concurrent bitmap that can set/reset sequences of bits atomically ---------------------------------------------------------------------------- */ #pragma once #ifndef MI_BITMAP_H #define MI_BITMAP_H -/* ----------------------------------------------------------- - Bitmap definition ------------------------------------------------------------ */ +/* -------------------------------------------------------------------------------- + Atomic bitmaps with release/acquire guarantees: + + `mi_bfield_t`: is a single machine word that can efficiently be bit counted (usually `size_t`) + each bit usually represents a single MI_ARENA_SLICE_SIZE in an arena (64 KiB). + We need 16K bits to represent a 1GiB arena. + + `mi_bchunk_t`: a chunk of bfield's of a total of MI_BCHUNK_BITS (= 512 on 64-bit, 256 on 32-bit) + allocations never span across chunks -- so MI_ARENA_MAX_OBJ_SIZE is the number + of bits in a chunk times the MI_ARENA_SLICE_SIZE (512 * 64KiB = 32 MiB). + These chunks are cache-aligned and we can use AVX2/AVX512/NEON/SVE/SVE2/etc. instructions + to scan for bits (perhaps) more efficiently. + + We allocate byte-sized ranges aligned to bytes in the bfield, and bfield-sized + ranges aligned to a bfield. + + Searching linearly through the chunks would be too slow (16K bits per GiB). + Instead we add a "chunkmap" to do a two-level search (more or less a btree of depth 2). + + `mi_bchunkmap_t` (== `mi_bchunk_t`): for each chunk we track if it has (potentially) any bit set. + The chunkmap has 1 bit per chunk that is set if the chunk potentially has a bit set. + This is used to avoid scanning every chunk. (and thus strictly an optimization) + It is conservative: it is fine to set a bit in the chunk map even if the chunk turns out + to have no bits set. It is also allowed to briefly have a clear bit even if the + chunk has bits set -- as long as we guarantee that the bit will be set later on; + (this allows us to set the chunkmap bit right after we set a bit in the corresponding chunk). + + However, when we clear a bit in a chunk, and the chunk is indeed all clear, we + cannot safely clear the bit corresponding to the chunk in the chunkmap since it + may race with another thread setting a bit in the same chunk. Therefore, when + clearing, we first test if a chunk is clear, then clear the chunkmap bit, and + then test again to catch any set bits that we may have missed. + + Since the chunkmap may thus be briefly out-of-sync, this means that we may sometimes + not find a free page even though it's there (but we accept this as we avoid taking + full locks). (Another way to do this is to use an epoch but we like to avoid that complexity + for now). + + `mi_bitmap_t`: a bitmap with N chunks. A bitmap has a chunkmap of MI_BCHUNK_BITS (512) + and thus has at most 512 chunks (=2^18 bits x 64 KiB slices = 16 GiB max arena size). + The minimum is 1 chunk which is a 32 MiB arena. + + For now, the implementation assumes MI_HAS_FAST_BITSCAN and uses trailing-zero-count + and pop-count (but we think it can be adapted work reasonably well on older hardware too) +--------------------------------------------------------------------------------------------- */ + +// A word-size bit field. +typedef size_t mi_bfield_t; + +#define MI_BFIELD_BITS_SHIFT (MI_SIZE_SHIFT+3) +#define MI_BFIELD_BITS (1 << MI_BFIELD_BITS_SHIFT) +#define MI_BFIELD_SIZE (MI_BFIELD_BITS/8) +#define MI_BFIELD_LO_BIT8 (((~(mi_bfield_t)0))/0xFF) // 0x01010101 .. +#define MI_BFIELD_HI_BIT8 (MI_BFIELD_LO_BIT8 << 7) // 0x80808080 .. + +#define MI_BCHUNK_SIZE (MI_BCHUNK_BITS / 8) +#define MI_BCHUNK_FIELDS (MI_BCHUNK_BITS / MI_BFIELD_BITS) // 8 on both 64- and 32-bit + + +// some compiler (msvc in C mode) cannot have expressions in the alignment attribute +#if MI_BCHUNK_SIZE==64 +#define mi_decl_bchunk_align mi_decl_align(64) +#elif MI_BCHUNK_SIZE==32 +#define mi_decl_bchunk_align mi_decl_align(32) +#else +#define mi_decl_bchunk_align mi_decl_align(MI_BCHUNK_SIZE) +#endif + + +// A bitmap chunk contains 512 bits on 64-bit (256 on 32-bit) +typedef mi_decl_bchunk_align struct mi_bchunk_s { + _Atomic(mi_bfield_t) bfields[MI_BCHUNK_FIELDS]; +} mi_bchunk_t; + + +// The chunkmap has one bit per corresponding chunk that is set if the chunk potentially has bits set. +// The chunkmap is itself a chunk. +typedef mi_bchunk_t mi_bchunkmap_t; + +#define MI_BCHUNKMAP_BITS MI_BCHUNK_BITS + +#define MI_BITMAP_MAX_CHUNK_COUNT (MI_BCHUNKMAP_BITS) +#define MI_BITMAP_MIN_CHUNK_COUNT (1) +#if MI_SIZE_BITS > 32 +#define MI_BITMAP_DEFAULT_CHUNK_COUNT (64) // 2 GiB on 64-bit -- this is for the page map +#else +#define MI_BITMAP_DEFAULT_CHUNK_COUNT (1) +#endif +#define MI_BITMAP_MAX_BIT_COUNT (MI_BITMAP_MAX_CHUNK_COUNT * MI_BCHUNK_BITS) // 16 GiB arena +#define MI_BITMAP_MIN_BIT_COUNT (MI_BITMAP_MIN_CHUNK_COUNT * MI_BCHUNK_BITS) // 32 MiB arena +#define MI_BITMAP_DEFAULT_BIT_COUNT (MI_BITMAP_DEFAULT_CHUNK_COUNT * MI_BCHUNK_BITS) // 2 GiB arena + + +// An atomic bitmap +typedef mi_decl_bchunk_align struct mi_bitmap_s { + _Atomic(size_t) chunk_count; // total count of chunks (0 < N <= MI_BCHUNKMAP_BITS) + size_t _padding[MI_BCHUNK_SIZE/MI_SIZE_SIZE - 1]; // suppress warning on msvc + mi_bchunkmap_t chunkmap; + mi_bchunk_t chunks[MI_BITMAP_DEFAULT_CHUNK_COUNT]; // usually dynamic MI_BITMAP_MAX_CHUNK_COUNT +} mi_bitmap_t; + + +static inline size_t mi_bitmap_chunk_count(const mi_bitmap_t* bitmap) { + return mi_atomic_load_relaxed(&((mi_bitmap_t*)bitmap)->chunk_count); +} + +static inline size_t mi_bitmap_max_bits(const mi_bitmap_t* bitmap) { + return (mi_bitmap_chunk_count(bitmap) * MI_BCHUNK_BITS); +} + + + +/* -------------------------------------------------------------------------------- + Atomic bitmap operations +-------------------------------------------------------------------------------- */ + +// Many operations are generic over setting or clearing the bit sequence: we use `mi_xset_t` for this (true if setting, false if clearing) +typedef bool mi_xset_t; +#define MI_BIT_SET (true) +#define MI_BIT_CLEAR (false) + + +// Required size of a bitmap to represent `bit_count` bits. +size_t mi_bitmap_size(size_t bit_count, size_t* chunk_count); + +// Initialize a bitmap to all clear; avoid a mem_zero if `already_zero` is true +// returns the size of the bitmap. +size_t mi_bitmap_init(mi_bitmap_t* bitmap, size_t bit_count, bool already_zero); + +// Set/clear a sequence of `n` bits in the bitmap (and can cross chunks). +// Not atomic so only use if still local to a thread. +void mi_bitmap_unsafe_setN(mi_bitmap_t* bitmap, size_t idx, size_t n); -#define MI_BITMAP_FIELD_BITS (8*MI_SIZE_SIZE) -#define MI_BITMAP_FIELD_FULL (~((size_t)0)) // all bits set -// An atomic bitmap of `size_t` fields -typedef _Atomic(size_t) mi_bitmap_field_t; -typedef mi_bitmap_field_t* mi_bitmap_t; +// Set a bit in the bitmap; returns `true` if it atomically transitioned from 0 to 1 +bool mi_bitmap_set(mi_bitmap_t* bitmap, size_t idx); -// A bitmap index is the index of the bit in a bitmap. -typedef size_t mi_bitmap_index_t; +// Clear a bit in the bitmap; returns `true` if it atomically transitioned from 1 to 0 +bool mi_bitmap_clear(mi_bitmap_t* bitmap, size_t idx); -// Create a bit index. -static inline mi_bitmap_index_t mi_bitmap_index_create(size_t idx, size_t bitidx) { - mi_assert_internal(bitidx < MI_BITMAP_FIELD_BITS); - return (idx*MI_BITMAP_FIELD_BITS) + bitidx; +// Set a sequence of `n` bits in the bitmap; returns `true` if atomically transitioned from all 0's to 1's +// `n` cannot cross chunk boundaries (and `n <= MI_BCHUNK_BITS`)! +// If `already_set` is not NULL, it is set to count of bits were already all set. +// (this is used for correct statistics if commiting over a partially committed area) +bool mi_bitmap_setN(mi_bitmap_t* bitmap, size_t idx, size_t n, size_t* already_set); + +// Clear a sequence of `n` bits in the bitmap; returns `true` if atomically transitioned from all 1's to 0's +// `n` cannot cross chunk boundaries (and `n <= MI_BCHUNK_BITS`)! +bool mi_bitmap_clearN(mi_bitmap_t* bitmap, size_t idx, size_t n); + + +// Is a sequence of n bits already all set/cleared? +bool mi_bitmap_is_xsetN(mi_xset_t set, mi_bitmap_t* bitmap, size_t idx, size_t n); + +// Is a sequence of n bits already set? +// (Used to check if a memory range is already committed) +static inline bool mi_bitmap_is_setN(mi_bitmap_t* bitmap, size_t idx, size_t n) { + return mi_bitmap_is_xsetN(MI_BIT_SET, bitmap, idx, n); +} + +// Is a sequence of n bits already clear? +static inline bool mi_bitmap_is_clearN(mi_bitmap_t* bitmap, size_t idx, size_t n) { + return mi_bitmap_is_xsetN(MI_BIT_CLEAR, bitmap, idx, n); +} + +static inline bool mi_bitmap_is_set(mi_bitmap_t* bitmap, size_t idx) { + return mi_bitmap_is_setN(bitmap, idx, 1); +} + +static inline bool mi_bitmap_is_clear(mi_bitmap_t* bitmap, size_t idx) { + return mi_bitmap_is_clearN(bitmap, idx, 1); +} + +// Called once a bit is cleared to see if the memory slice can be claimed. +typedef bool (mi_claim_fun_t)(size_t slice_index, mi_arena_t* arena, mi_heaptag_t heap_tag, bool* keep_set); + +// Find a set bits in the bitmap, atomically clear it, and check if `claim` returns true. +// If not claimed, continue on (potentially setting the bit again depending on `keep_set`). +// Returns true on success, and in that case sets the index: `0 <= *pidx <= MI_BITMAP_MAX_BITS-n`. +mi_decl_nodiscard bool mi_bitmap_try_find_and_claim(mi_bitmap_t* bitmap, size_t tseq, size_t* pidx, + mi_claim_fun_t* claim, mi_arena_t* arena, mi_heaptag_t heap_tag ); + + +// Atomically clear a bit but only if it is set. Will block otherwise until the bit is set. +// This is used to delay free-ing a page that it at the same time being considered to be +// allocated from `mi_arena_try_abandoned` (and is in the `claim` function of `mi_bitmap_try_find_and_claim`). +void mi_bitmap_clear_once_set(mi_bitmap_t* bitmap, size_t idx); + + +// If a bit is set in the bitmap, return `true` and set `idx` to the index of the highest bit. +// Otherwise return `false` (and `*idx` is undefined). +// Used for unloading arena's +bool mi_bitmap_bsr(mi_bitmap_t* bitmap, size_t* idx); + +// Return count of all set bits in a bitmap. +size_t mi_bitmap_popcount(mi_bitmap_t* bitmap); + + +typedef bool (mi_forall_set_fun_t)(size_t slice_index, size_t slice_count, mi_arena_t* arena, void* arg2); + +// Visit all set bits in a bitmap (`slice_count == 1`) +bool _mi_bitmap_forall_set(mi_bitmap_t* bitmap, mi_forall_set_fun_t* visit, mi_arena_t* arena, void* arg); + +// Visit all set bits in a bitmap with larger ranges if possible (`slice_count >= 1`) +bool _mi_bitmap_forall_setc_ranges(mi_bitmap_t* bitmap, mi_forall_set_fun_t* visit, mi_arena_t* arena, void* arg); + + +// Count all set bits in given range in the bitmap. (cannot cross chunks) +size_t mi_bitmap_popcountN( mi_bitmap_t* bitmap, size_t idx, size_t n); + +/* ---------------------------------------------------------------------------- + Binned concurrent bitmap + Assigns a size class to each chunk such that small blocks don't cause too + much fragmentation since we keep chunks for larger blocks separate. +---------------------------------------------------------------------------- */ + +// mi_chunkbin_t is defined in mimalloc-stats.h + +static inline mi_chunkbin_t mi_chunkbin_inc(mi_chunkbin_t bbin) { + mi_assert_internal(bbin < MI_CBIN_COUNT); + return (mi_chunkbin_t)((int)bbin + 1); } -// Create a bit index. -static inline mi_bitmap_index_t mi_bitmap_index_create_from_bit(size_t full_bitidx) { - return mi_bitmap_index_create(full_bitidx / MI_BITMAP_FIELD_BITS, full_bitidx % MI_BITMAP_FIELD_BITS); +static inline mi_chunkbin_t mi_chunkbin_dec(mi_chunkbin_t bbin) { + mi_assert_internal(bbin > MI_CBIN_NONE); + return (mi_chunkbin_t)((int)bbin - 1); } -// Get the field index from a bit index. -static inline size_t mi_bitmap_index_field(mi_bitmap_index_t bitmap_idx) { - return (bitmap_idx / MI_BITMAP_FIELD_BITS); +static inline mi_chunkbin_t mi_chunkbin_of(size_t slice_count) { + if (slice_count==1) return MI_CBIN_SMALL; + if (slice_count==8) return MI_CBIN_MEDIUM; + #if MI_ENABLE_LARGE_PAGES + if (slice_count==MI_BFIELD_BITS) return MI_CBIN_LARGE; + #endif + return MI_CBIN_OTHER; } -// Get the bit index in a bitmap field -static inline size_t mi_bitmap_index_bit_in_field(mi_bitmap_index_t bitmap_idx) { - return (bitmap_idx % MI_BITMAP_FIELD_BITS); +// An atomic "binned" bitmap for the free slices where we keep chunks reserved for particalar size classes +typedef mi_decl_bchunk_align struct mi_bbitmap_s { + _Atomic(size_t) chunk_count; // total count of chunks (0 < N <= MI_BCHUNKMAP_BITS) + _Atomic(size_t) chunk_max_accessed; // max chunk index that was once cleared or set + #if (MI_BCHUNK_SIZE / MI_SIZE_SIZE) > 2 + size_t _padding[MI_BCHUNK_SIZE/MI_SIZE_SIZE - 2]; // suppress warning on msvc by aligning manually + #endif + mi_bchunkmap_t chunkmap; + mi_bchunkmap_t chunkmap_bins[MI_CBIN_COUNT - 1]; // chunkmaps with bit set if the chunk is in that size class (excluding MI_CBIN_NONE) + mi_bchunk_t chunks[MI_BITMAP_DEFAULT_CHUNK_COUNT]; // usually dynamic MI_BITMAP_MAX_CHUNK_COUNT +} mi_bbitmap_t; + + +static inline size_t mi_bbitmap_chunk_count(const mi_bbitmap_t* bbitmap) { + return mi_atomic_load_relaxed(&((mi_bbitmap_t*)bbitmap)->chunk_count); } -// Get the full bit index -static inline size_t mi_bitmap_index_bit(mi_bitmap_index_t bitmap_idx) { - return bitmap_idx; +static inline size_t mi_bbitmap_max_bits(const mi_bbitmap_t* bbitmap) { + return (mi_bbitmap_chunk_count(bbitmap) * MI_BCHUNK_BITS); } -/* ----------------------------------------------------------- - Claim a bit sequence atomically ------------------------------------------------------------ */ +mi_chunkbin_t mi_bbitmap_debug_get_bin(const mi_bchunk_t* chunkmap_bins, size_t chunk_idx); -// Try to atomically claim a sequence of `count` bits in a single -// field at `idx` in `bitmap`. Returns `true` on success. -bool _mi_bitmap_try_find_claim_field(mi_bitmap_t bitmap, size_t idx, const size_t count, mi_bitmap_index_t* bitmap_idx); +size_t mi_bbitmap_size(size_t bit_count, size_t* chunk_count); -// Starts at idx, and wraps around to search in all `bitmap_fields` fields. -// For now, `count` can be at most MI_BITMAP_FIELD_BITS and will never cross fields. -bool _mi_bitmap_try_find_from_claim(mi_bitmap_t bitmap, const size_t bitmap_fields, const size_t start_field_idx, const size_t count, mi_bitmap_index_t* bitmap_idx); -// Like _mi_bitmap_try_find_from_claim but with an extra predicate that must be fullfilled -typedef bool (mi_cdecl *mi_bitmap_pred_fun_t)(mi_bitmap_index_t bitmap_idx, void* pred_arg); -bool _mi_bitmap_try_find_from_claim_pred(mi_bitmap_t bitmap, const size_t bitmap_fields, const size_t start_field_idx, const size_t count, mi_bitmap_pred_fun_t pred_fun, void* pred_arg, mi_bitmap_index_t* bitmap_idx); +// Initialize a bitmap to all clear; avoid a mem_zero if `already_zero` is true +// returns the size of the bitmap. +size_t mi_bbitmap_init(mi_bbitmap_t* bbitmap, size_t bit_count, bool already_zero); -// Set `count` bits at `bitmap_idx` to 0 atomically -// Returns `true` if all `count` bits were 1 previously. -bool _mi_bitmap_unclaim(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx); +// Set/clear a sequence of `n` bits in the bitmap (and can cross chunks). +// Not atomic so only use if still local to a thread. +void mi_bbitmap_unsafe_setN(mi_bbitmap_t* bbitmap, size_t idx, size_t n); -// Set `count` bits at `bitmap_idx` to 1 atomically -// Returns `true` if all `count` bits were 0 previously. `any_zero` is `true` if there was at least one zero bit. -bool _mi_bitmap_claim(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx, bool* any_zero); -bool _mi_bitmap_is_claimed(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx); -bool _mi_bitmap_is_any_claimed(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx); +// Set a sequence of `n` bits in the bbitmap; returns `true` if atomically transitioned from all 0's to 1's +// `n` cannot cross chunk boundaries (and `n <= MI_BCHUNK_BITS`)! +bool mi_bbitmap_setN(mi_bbitmap_t* bbitmap, size_t idx, size_t n); -//-------------------------------------------------------------------------- -// the `_across` functions work on bitmaps where sequences can cross over -// between the fields. This is used in arena allocation -//-------------------------------------------------------------------------- +// Is a sequence of n bits already all set/cleared? +bool mi_bbitmap_is_xsetN(mi_xset_t set, mi_bbitmap_t* bbitmap, size_t idx, size_t n); -// Find `count` bits of zeros and set them to 1 atomically; returns `true` on success. -// Starts at idx, and wraps around to search in all `bitmap_fields` fields. -bool _mi_bitmap_try_find_from_claim_across(mi_bitmap_t bitmap, const size_t bitmap_fields, const size_t start_field_idx, const size_t count, mi_bitmap_index_t* bitmap_idx); +// Is a sequence of n bits already set? +// (Used to check if a memory range is already committed) +static inline bool mi_bbitmap_is_setN(mi_bbitmap_t* bbitmap, size_t idx, size_t n) { + return mi_bbitmap_is_xsetN(MI_BIT_SET, bbitmap, idx, n); +} -// Set `count` bits at `bitmap_idx` to 0 atomically -// Returns `true` if all `count` bits were 1 previously. -bool _mi_bitmap_unclaim_across(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx); +// Is a sequence of n bits already clear? +static inline bool mi_bbitmap_is_clearN(mi_bbitmap_t* bbitmap, size_t idx, size_t n) { + return mi_bbitmap_is_xsetN(MI_BIT_CLEAR, bbitmap, idx, n); +} -// Set `count` bits at `bitmap_idx` to 1 atomically -// Returns `true` if all `count` bits were 0 previously. `any_zero` is `true` if there was at least one zero bit. -bool _mi_bitmap_claim_across(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx, bool* pany_zero); -bool _mi_bitmap_is_claimed_across(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx); -bool _mi_bitmap_is_any_claimed_across(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx); +// Try to atomically transition `n` bits from all set to all clear. Returns `true` on succes. +// `n` cannot cross chunk boundaries, where `n <= MI_CHUNK_BITS`. +bool mi_bbitmap_try_clearN(mi_bbitmap_t* bbitmap, size_t idx, size_t n); -#endif +// Specialized versions for common bit sequence sizes +bool mi_bbitmap_try_find_and_clear(mi_bbitmap_t* bbitmap, size_t tseq, size_t* pidx); // 1-bit +bool mi_bbitmap_try_find_and_clear8(mi_bbitmap_t* bbitmap, size_t tseq, size_t* pidx); // 8-bits +// bool mi_bbitmap_try_find_and_clearX(mi_bbitmap_t* bbitmap, size_t tseq, size_t* pidx); // MI_BFIELD_BITS +bool mi_bbitmap_try_find_and_clearNX(mi_bbitmap_t* bbitmap, size_t n, size_t tseq, size_t* pidx); // < MI_BFIELD_BITS +bool mi_bbitmap_try_find_and_clearN_(mi_bbitmap_t* bbitmap, size_t n, size_t tseq, size_t* pidx); // > MI_BFIELD_BITS <= MI_BCHUNK_BITS + +// Find a sequence of `n` bits in the bbitmap with all bits set, and try to atomically clear all. +// Returns true on success, and in that case sets the index: `0 <= *pidx <= MI_BITMAP_MAX_BITS-n`. +mi_decl_nodiscard static inline bool mi_bbitmap_try_find_and_clearN(mi_bbitmap_t* bbitmap, size_t n, size_t tseq, size_t* pidx) { + if (n==1) return mi_bbitmap_try_find_and_clear(bbitmap, tseq, pidx); // small pages + if (n==8) return mi_bbitmap_try_find_and_clear8(bbitmap, tseq, pidx); // medium pages + // if (n==MI_BFIELD_BITS) return mi_bbitmap_try_find_and_clearX(bbitmap, tseq, pidx); // large pages + if (n==0 || n>MI_BCHUNK_BITS) return false; // cannot be more than a chunk + if (n<=MI_BFIELD_BITS) return mi_bbitmap_try_find_and_clearNX(bbitmap, tseq, n, pidx); + return mi_bbitmap_try_find_and_clearN_(bbitmap, tseq, n, pidx); +} + + +#endif // MI_BITMAP_H diff --git a/src/dashbls/depends/mimalloc/src/free.c b/src/dashbls/depends/mimalloc/src/free.c new file mode 100644 index 000000000000..40e813809336 --- /dev/null +++ b/src/dashbls/depends/mimalloc/src/free.c @@ -0,0 +1,577 @@ +/* ---------------------------------------------------------------------------- +Copyright (c) 2018-2024, Microsoft Research, Daan Leijen +This is free software; you can redistribute it and/or modify it under the +terms of the MIT license. A copy of the license can be found in the file +"LICENSE" at the root of this distribution. +-----------------------------------------------------------------------------*/ +#if !defined(MI_IN_ALLOC_C) +#error "this file should be included from 'alloc.c' (so aliases can work from alloc-override)" +// add includes help an IDE +#include "mimalloc.h" +#include "mimalloc/internal.h" +#include "mimalloc/prim.h" // _mi_prim_thread_id() +#endif + +// forward declarations +static void mi_check_padding(const mi_page_t* page, const mi_block_t* block); +static bool mi_check_is_double_free(const mi_page_t* page, const mi_block_t* block); +static size_t mi_page_usable_size_of(const mi_page_t* page, const mi_block_t* block); +static void mi_stat_free(const mi_page_t* page, const mi_block_t* block); + + +// ------------------------------------------------------ +// Free +// ------------------------------------------------------ + +// regular free of a (thread local) block pointer +// fast path written carefully to prevent spilling on the stack +static inline void mi_free_block_local(mi_page_t* page, mi_block_t* block, bool track_stats, bool check_full) +{ + // checks + if mi_unlikely(mi_check_is_double_free(page, block)) return; + mi_check_padding(page, block); + if (track_stats) { mi_stat_free(page, block); } + #if (MI_DEBUG>0) && !MI_TRACK_ENABLED && !MI_TSAN && !MI_GUARDED + memset(block, MI_DEBUG_FREED, mi_page_block_size(page)); + #endif + if (track_stats) { mi_track_free_size(block, mi_page_usable_size_of(page, block)); } // faster then mi_usable_size as we already know the page and that p is unaligned + + // actual free: push on the local free list + mi_block_set_next(page, block, page->local_free); + page->local_free = block; + if mi_unlikely(--page->used == 0) { + _mi_page_retire(page); + } + else if mi_unlikely(check_full && mi_page_is_in_full(page)) { + _mi_page_unfull(page); + } +} + +// Forward declaration for multi-threaded collect +static void mi_decl_noinline mi_free_try_collect_mt(mi_page_t* page, mi_block_t* mt_free) mi_attr_noexcept; + +// Free a block multi-threaded +static inline void mi_free_block_mt(mi_page_t* page, mi_block_t* block) mi_attr_noexcept +{ + // adjust stats (after padding check and potentially recursive `mi_free` above) + mi_stat_free(page, block); // stat_free may access the padding + mi_track_free_size(block, mi_page_usable_size_of(page, block)); + + // _mi_padding_shrink(page, block, sizeof(mi_block_t)); +#if (MI_DEBUG>0) && !MI_TRACK_ENABLED && !MI_TSAN // note: when tracking, cannot use mi_usable_size with multi-threading + size_t dbgsize = mi_usable_size(block); + if (dbgsize > MI_MiB) { dbgsize = MI_MiB; } + _mi_memset_aligned(block, MI_DEBUG_FREED, dbgsize); +#endif + + // push atomically on the page thread free list + mi_thread_free_t tf_new; + mi_thread_free_t tf_old = mi_atomic_load_relaxed(&page->xthread_free); + do { + mi_block_set_next(page, block, mi_tf_block(tf_old)); + tf_new = mi_tf_create(block, true /* always use owned: try to claim it if the page is abandoned */); + } while (!mi_atomic_cas_weak_acq_rel(&page->xthread_free, &tf_old, tf_new)); // todo: release is enough? + + // and atomically try to collect the page if it was abandoned + const bool is_owned_now = !mi_tf_is_owned(tf_old); + if (is_owned_now) { + mi_assert_internal(mi_page_is_abandoned(page)); + mi_free_try_collect_mt(page,block); + } +} + + +// Adjust a block that was allocated aligned, to the actual start of the block in the page. +// note: this can be called from `mi_free_generic_mt` where a non-owning thread accesses the +// `page_start` and `block_size` fields; however these are constant and the page won't be +// deallocated (as the block we are freeing keeps it alive) and thus safe to read concurrently. +mi_block_t* _mi_page_ptr_unalign(const mi_page_t* page, const void* p) { + mi_assert_internal(page!=NULL && p!=NULL); + + size_t diff = (uint8_t*)p - mi_page_start(page); + size_t adjust; + if mi_likely(page->block_size_shift != 0) { + adjust = diff & (((size_t)1 << page->block_size_shift) - 1); + } + else { + adjust = diff % mi_page_block_size(page); + } + + return (mi_block_t*)((uintptr_t)p - adjust); +} + +// forward declaration for a MI_GUARDED build +#if MI_GUARDED +static void mi_block_unguard(mi_page_t* page, mi_block_t* block, void* p); // forward declaration +static inline void mi_block_check_unguard(mi_page_t* page, mi_block_t* block, void* p) { + if (mi_block_ptr_is_guarded(block, p)) { mi_block_unguard(page, block, p); } +} +#else +static inline void mi_block_check_unguard(mi_page_t* page, mi_block_t* block, void* p) { + MI_UNUSED(page); MI_UNUSED(block); MI_UNUSED(p); +} +#endif + + +// free a local pointer (page parameter comes first for better codegen) +static void mi_decl_noinline mi_free_generic_local(mi_page_t* page, void* p) mi_attr_noexcept { + mi_assert_internal(p!=NULL && page != NULL); + mi_block_t* const block = (mi_page_has_aligned(page) ? _mi_page_ptr_unalign(page, p) : (mi_block_t*)p); + mi_block_check_unguard(page, block, p); + mi_free_block_local(page, block, true /* track stats */, true /* check for a full page */); +} + +// free a pointer owned by another thread (page parameter comes first for better codegen) +static void mi_decl_noinline mi_free_generic_mt(mi_page_t* page, void* p) mi_attr_noexcept { + mi_assert_internal(p!=NULL && page != NULL); + mi_block_t* const block = _mi_page_ptr_unalign(page, p); // don't check `has_aligned` flag to avoid a race (issue #865) + mi_block_check_unguard(page, block, p); + mi_free_block_mt(page, block); +} + +// generic free (for runtime integration) +void mi_decl_noinline _mi_free_generic(mi_page_t* page, bool is_local, void* p) mi_attr_noexcept { + if (is_local) mi_free_generic_local(page,p); + else mi_free_generic_mt(page,p); +} + + +// Get the page belonging to a pointer +// Does further checks in debug mode to see if this was a valid pointer. +static inline mi_page_t* mi_validate_ptr_page(const void* p, const char* msg) +{ + MI_UNUSED_RELEASE(msg); + #if MI_DEBUG + if mi_unlikely(((uintptr_t)p & (MI_INTPTR_SIZE - 1)) != 0 && !mi_option_is_enabled(mi_option_guarded_precise)) { + _mi_error_message(EINVAL, "%s: invalid (unaligned) pointer: %p\n", msg, p); + return NULL; + } + mi_page_t* page = _mi_safe_ptr_page(p); + if (p != NULL && page == NULL) { + _mi_error_message(EINVAL, "%s: invalid pointer: %p\n", msg, p); + } + return page; + #else + return _mi_ptr_page(p); + #endif +} + +// Free a block +// Fast path written carefully to prevent register spilling on the stack +void mi_free(void* p) mi_attr_noexcept +{ + mi_page_t* const page = mi_validate_ptr_page(p,"mi_free"); + if mi_unlikely(page==NULL) return; // page will be NULL if p==NULL + mi_assert_internal(p!=NULL && page!=NULL); + + const mi_threadid_t xtid = (_mi_prim_thread_id() ^ mi_page_xthread_id(page)); + if mi_likely(xtid == 0) { // `tid == mi_page_thread_id(page) && mi_page_flags(page) == 0` + // thread-local, aligned, and not a full page + mi_block_t* const block = (mi_block_t*)p; + mi_free_block_local(page, block, true /* track stats */, false /* no need to check if the page is full */); + } + else if (xtid <= MI_PAGE_FLAG_MASK) { // `tid == mi_page_thread_id(page) && mi_page_flags(page) != 0` + // page is local, but is full or contains (inner) aligned blocks; use generic path + mi_free_generic_local(page, p); + } + // free-ing in a page owned by a heap in another thread, or an abandoned page (not belonging to a heap) + else if ((xtid & MI_PAGE_FLAG_MASK) == 0) { // `tid != mi_page_thread_id(page) && mi_page_flags(page) == 0` + // blocks are aligned (and not a full page); push on the thread_free list + mi_block_t* const block = (mi_block_t*)p; + mi_free_block_mt(page,block); + } + else { + // page is full or contains (inner) aligned blocks; use generic multi-thread path + mi_free_generic_mt(page, p); + } +} + + +// ------------------------------------------------------ +// Multi-threaded Free (`_mt`) +// ------------------------------------------------------ +static bool mi_page_unown_from_free(mi_page_t* page, mi_block_t* mt_free); + +static inline bool mi_page_queue_len_is_atmost( mi_heap_t* heap, size_t block_size, long atmost) { + mi_page_queue_t* const pq = mi_page_queue(heap,block_size); + mi_assert_internal(pq!=NULL); + return (pq->count <= (size_t)atmost); +} + +static void mi_decl_noinline mi_free_try_collect_mt(mi_page_t* page, mi_block_t* mt_free) mi_attr_noexcept { + mi_assert_internal(mi_page_is_owned(page)); + mi_assert_internal(mi_page_is_abandoned(page)); + + // we own the page now.. + // safe to collect the thread atomic free list + // use the `_partly` version to avoid atomic operations since we already have the `mt_free` pointing into the thread free list + _mi_page_free_collect_partly(page, mt_free); + + #if MI_DEBUG > 1 + if (mi_page_is_singleton(page)) { mi_assert_internal(mi_page_all_free(page)); } + #endif + + // 1. free if the page is free now (this is updated by `_mi_page_free_collect_partly`) + if (mi_page_all_free(page)) + { + // first remove it from the abandoned pages in the arena (if mapped, this might wait for any readers to finish) + _mi_arenas_page_unabandon(page); + // we can free the page directly + _mi_arenas_page_free(page,NULL); + return; + } + + // 2. we can try to reclaim the page for ourselves + // note: reclaiming can improve benchmarks like `larson` or `rbtree-ck` a lot even in the single-threaded case, + // since free-ing from an owned page avoids atomic operations. However, if we reclaim too eagerly in + // a multi-threaded scenario we may start to hold on to too much memory and reduce reuse among threads. + // If the current heap is where the page originally came from, we reclaim much more eagerly while + // 'cross-thread' reclaiming on free is by default off (and we only 'reclaim' these by finding the abandoned + // pages when we allocate a fresh page). + if (page->block_size <= MI_SMALL_MAX_OBJ_SIZE) // only for small sized blocks + { + const long reclaim_on_free = _mi_option_get_fast(mi_option_page_reclaim_on_free); + if (reclaim_on_free >= 0) { // and reclaiming is allowed + // get our heap (with the right tag) + // note: don't use `mi_heap_get_default()` as we may just have terminated this thread and we should + // not reinitialize the heap for this thread. (can happen due to thread-local destructors for example -- issue #944) + mi_heap_t* heap = mi_prim_get_default_heap(); + if (heap != page->heap) { + if (mi_heap_is_initialized(heap)) { + heap = _mi_heap_by_tag(heap, page->heap_tag); + } + } + // can we reclaim into this heap? + if (heap != NULL && heap->allow_page_reclaim) + { + long max_reclaim = 0; + if mi_likely(heap == page->heap) { // did this page originate from the current heap? + // originating heap + max_reclaim = _mi_option_get_fast(heap->tld->is_in_threadpool ? mi_option_page_cross_thread_max_reclaim : mi_option_page_max_reclaim); + } + else if (reclaim_on_free == 1 && // if cross-thread is allowed + !heap->tld->is_in_threadpool && // and we are not part of a threadpool + !mi_page_is_used_at_frac(page,8) && // and the page is not too full + _mi_arena_memid_is_suitable(page->memid, heap->exclusive_arena)) { // and it fits our memory + // across threads + max_reclaim = _mi_option_get_fast(mi_option_page_cross_thread_max_reclaim); + } + + if (max_reclaim < 0 || mi_page_queue_len_is_atmost(heap, page->block_size, max_reclaim)) { // are we within the reclaim limit? + // reclaim the page into this heap + // first remove it from the abandoned pages in the arena -- this might wait for any readers to finish + _mi_arenas_page_unabandon(page); + _mi_heap_page_reclaim(heap, page); + mi_heap_stat_counter_increase(heap, pages_reclaim_on_free, 1); + return; + } + } + } + } + + // 3. if the page is unmapped, try to reabandon so it can possibly be mapped and found for allocations + if (!mi_page_is_used_at_frac(page, 8) && // only reabandon if a full page starts to have enough blocks available to prevent immediate re-abandon of a full page + !mi_page_is_abandoned_mapped(page) && page->memid.memkind == MI_MEM_ARENA && + _mi_arenas_page_try_reabandon_to_mapped(page)) + { + return; + } + + + // not reclaimed or free'd, unown again + // _mi_page_unown(page); + mi_page_unown_from_free(page, mt_free); +} + + +// release ownership of a page. This may free the page if all (other) blocks were concurrently +// freed in the meantime. Returns true if the page was freed. +// This is a specialized version of `mi_page_unown` to (try to) avoid calling `mi_page_free_collect` again. +static bool mi_page_unown_from_free(mi_page_t* page, mi_block_t* mt_free) { + mi_assert_internal(mi_page_is_owned(page)); + mi_assert_internal(mi_page_is_abandoned(page)); + mi_assert_internal(mt_free != NULL); + mi_assert_internal(page->used > 1); + mi_thread_free_t tf_expect = mi_tf_create(mt_free, true); + mi_thread_free_t tf_new = mi_tf_create(mt_free, false); + while mi_unlikely(!mi_atomic_cas_weak_acq_rel(&page->xthread_free, &tf_expect, tf_new)) { + mi_assert_internal(mi_tf_is_owned(tf_expect)); + while (mi_tf_block(tf_expect) != NULL) { + _mi_page_free_collect(page,false); // update used + if (mi_page_all_free(page)) { // it may become free just before unowning it + _mi_arenas_page_unabandon(page); + _mi_arenas_page_free(page,NULL); + return true; + } + tf_expect = mi_atomic_load_relaxed(&page->xthread_free); + } + mi_assert_internal(mi_tf_block(tf_expect)==NULL); + tf_new = mi_tf_create(NULL, false); + } + return false; +} + + +// ------------------------------------------------------ +// Usable size +// ------------------------------------------------------ + +// Bytes available in a block +static size_t mi_decl_noinline mi_page_usable_aligned_size_of(const mi_page_t* page, const void* p) mi_attr_noexcept { + const mi_block_t* block = _mi_page_ptr_unalign(page, p); + const size_t size = mi_page_usable_size_of(page, block); + const ptrdiff_t adjust = (uint8_t*)p - (uint8_t*)block; + mi_assert_internal(adjust >= 0 && (size_t)adjust <= size); + const size_t aligned_size = (size - adjust); + #if MI_GUARDED + if (mi_block_ptr_is_guarded(block, p)) { + return aligned_size - _mi_os_page_size(); + } + #endif + return aligned_size; +} + +static inline size_t _mi_usable_size(const void* p, const char* msg) mi_attr_noexcept { + const mi_page_t* const page = mi_validate_ptr_page(p,msg); + if mi_unlikely(page==NULL) return 0; + if mi_likely(!mi_page_has_aligned(page)) { + const mi_block_t* block = (const mi_block_t*)p; + return mi_page_usable_size_of(page, block); + } + else { + // split out to separate routine for improved code generation + return mi_page_usable_aligned_size_of(page, p); + } +} + +mi_decl_nodiscard size_t mi_usable_size(const void* p) mi_attr_noexcept { + return _mi_usable_size(p, "mi_usable_size"); +} + + +// ------------------------------------------------------ +// Free variants +// ------------------------------------------------------ + +void mi_free_size(void* p, size_t size) mi_attr_noexcept { + MI_UNUSED_RELEASE(size); + #if MI_DEBUG + const size_t available = _mi_usable_size(p,"mi_free_size"); + mi_assert(p == NULL || size <= available || available == 0 /* invalid pointer */ ); + #endif + mi_free(p); +} + +void mi_free_size_aligned(void* p, size_t size, size_t alignment) mi_attr_noexcept { + MI_UNUSED_RELEASE(alignment); + mi_assert(((uintptr_t)p % alignment) == 0); + mi_free_size(p,size); +} + +void mi_free_aligned(void* p, size_t alignment) mi_attr_noexcept { + MI_UNUSED_RELEASE(alignment); + mi_assert(((uintptr_t)p % alignment) == 0); + mi_free(p); +} + + +// ------------------------------------------------------ +// Check for double free in secure and debug mode +// This is somewhat expensive so only enabled for secure mode 4 +// ------------------------------------------------------ + +#if (MI_ENCODE_FREELIST && (MI_SECURE>=4 || MI_DEBUG!=0)) +// linear check if the free list contains a specific element +static bool mi_list_contains(const mi_page_t* page, const mi_block_t* list, const mi_block_t* elem) { + while (list != NULL) { + if (elem==list) return true; + list = mi_block_next(page, list); + } + return false; +} + +static mi_decl_noinline bool mi_check_is_double_freex(const mi_page_t* page, const mi_block_t* block) { + // The decoded value is in the same page (or NULL). + // Walk the free lists to verify positively if it is already freed + if (mi_list_contains(page, page->free, block) || + mi_list_contains(page, page->local_free, block) || + mi_list_contains(page, mi_page_thread_free(page), block)) + { + _mi_error_message(EAGAIN, "double free detected of block %p with size %zu\n", block, mi_page_block_size(page)); + return true; + } + return false; +} + +#define mi_track_page(page,access) { size_t psize; void* pstart = _mi_page_start(_mi_page_segment(page),page,&psize); mi_track_mem_##access( pstart, psize); } + +static inline bool mi_check_is_double_free(const mi_page_t* page, const mi_block_t* block) { + bool is_double_free = false; + mi_block_t* n = mi_block_nextx(page, block, page->keys); // pretend it is freed, and get the decoded first field + if (((uintptr_t)n & (MI_INTPTR_SIZE-1))==0 && // quick check: aligned pointer? + (n==NULL || mi_is_in_same_page(block, n))) // quick check: in same page or NULL? + { + // Suspicious: decoded value a in block is in the same page (or NULL) -- maybe a double free? + // (continue in separate function to improve code generation) + is_double_free = mi_check_is_double_freex(page, block); + } + return is_double_free; +} +#else +static inline bool mi_check_is_double_free(const mi_page_t* page, const mi_block_t* block) { + MI_UNUSED(page); + MI_UNUSED(block); + return false; +} +#endif + + +// --------------------------------------------------------------------------- +// Check for heap block overflow by setting up padding at the end of the block +// --------------------------------------------------------------------------- + +#if MI_PADDING // && !MI_TRACK_ENABLED +static bool mi_page_decode_padding(const mi_page_t* page, const mi_block_t* block, size_t* delta, size_t* bsize) { + *bsize = mi_page_usable_block_size(page); + const mi_padding_t* const padding = (mi_padding_t*)((uint8_t*)block + *bsize); + mi_track_mem_defined(padding,sizeof(mi_padding_t)); + *delta = padding->delta; + uint32_t canary = padding->canary; + uintptr_t keys[2]; + keys[0] = page->keys[0]; + keys[1] = page->keys[1]; + bool ok = (mi_ptr_encode_canary(page,block,keys) == canary && *delta <= *bsize); + mi_track_mem_noaccess(padding,sizeof(mi_padding_t)); + return ok; +} + +// Return the exact usable size of a block. +static size_t mi_page_usable_size_of(const mi_page_t* page, const mi_block_t* block) { + size_t bsize; + size_t delta; + bool ok = mi_page_decode_padding(page, block, &delta, &bsize); + mi_assert_internal(ok); mi_assert_internal(delta <= bsize); + return (ok ? bsize - delta : 0); +} + +// When a non-thread-local block is freed, it becomes part of the thread delayed free +// list that is freed later by the owning heap. If the exact usable size is too small to +// contain the pointer for the delayed list, then shrink the padding (by decreasing delta) +// so it will later not trigger an overflow error in `mi_free_block`. +void _mi_padding_shrink(const mi_page_t* page, const mi_block_t* block, const size_t min_size) { + size_t bsize; + size_t delta; + bool ok = mi_page_decode_padding(page, block, &delta, &bsize); + mi_assert_internal(ok); + if (!ok || (bsize - delta) >= min_size) return; // usually already enough space + mi_assert_internal(bsize >= min_size); + if (bsize < min_size) return; // should never happen + size_t new_delta = (bsize - min_size); + mi_assert_internal(new_delta < bsize); + mi_padding_t* padding = (mi_padding_t*)((uint8_t*)block + bsize); + mi_track_mem_defined(padding,sizeof(mi_padding_t)); + padding->delta = (uint32_t)new_delta; + mi_track_mem_noaccess(padding,sizeof(mi_padding_t)); +} +#else +static size_t mi_page_usable_size_of(const mi_page_t* page, const mi_block_t* block) { + MI_UNUSED(block); + return mi_page_usable_block_size(page); +} + +void _mi_padding_shrink(const mi_page_t* page, const mi_block_t* block, const size_t min_size) { + MI_UNUSED(page); + MI_UNUSED(block); + MI_UNUSED(min_size); +} +#endif + +#if MI_PADDING && MI_PADDING_CHECK + +static bool mi_verify_padding(const mi_page_t* page, const mi_block_t* block, size_t* size, size_t* wrong) { + size_t bsize; + size_t delta; + bool ok = mi_page_decode_padding(page, block, &delta, &bsize); + *size = *wrong = bsize; + if (!ok) return false; + mi_assert_internal(bsize >= delta); + *size = bsize - delta; + if (!mi_page_is_huge(page)) { + uint8_t* fill = (uint8_t*)block + bsize - delta; + const size_t maxpad = (delta > MI_MAX_ALIGN_SIZE ? MI_MAX_ALIGN_SIZE : delta); // check at most the first N padding bytes + mi_track_mem_defined(fill, maxpad); + for (size_t i = 0; i < maxpad; i++) { + if (fill[i] != MI_DEBUG_PADDING) { + *wrong = bsize - delta + i; + ok = false; + break; + } + } + mi_track_mem_noaccess(fill, maxpad); + } + return ok; +} + +static void mi_check_padding(const mi_page_t* page, const mi_block_t* block) { + size_t size; + size_t wrong; + if (!mi_verify_padding(page,block,&size,&wrong)) { + _mi_error_message(EFAULT, "buffer overflow in heap block %p of size %zu: write after %zu bytes\n", block, size, wrong ); + } +} + +#else + +static void mi_check_padding(const mi_page_t* page, const mi_block_t* block) { + MI_UNUSED(page); + MI_UNUSED(block); +} + +#endif + +// only maintain stats for smaller objects if requested +#if (MI_STAT>0) +static void mi_stat_free(const mi_page_t* page, const mi_block_t* block) { + MI_UNUSED(block); + mi_heap_t* const heap = mi_heap_get_default(); + const size_t bsize = mi_page_usable_block_size(page); + // #if (MI_STAT>1) + // const size_t usize = mi_page_usable_size_of(page, block); + // mi_heap_stat_decrease(heap, malloc_requested, usize); + // #endif + if (bsize <= MI_LARGE_MAX_OBJ_SIZE) { + mi_heap_stat_decrease(heap, malloc_normal, bsize); + #if (MI_STAT > 1) + mi_heap_stat_decrease(heap, malloc_bins[_mi_bin(bsize)], 1); + #endif + } + else { + const size_t bpsize = mi_page_block_size(page); // match stat in page.c:mi_huge_page_alloc + mi_heap_stat_decrease(heap, malloc_huge, bpsize); + } +} +#else +void mi_stat_free(const mi_page_t* page, const mi_block_t* block) { + MI_UNUSED(page); MI_UNUSED(block); +} +#endif + + +// Remove guard page when building with MI_GUARDED +#if MI_GUARDED +static void mi_block_unguard(mi_page_t* page, mi_block_t* block, void* p) { + MI_UNUSED(p); + mi_assert_internal(mi_block_ptr_is_guarded(block, p)); + mi_assert_internal(mi_page_has_aligned(page)); + mi_assert_internal((uint8_t*)p - (uint8_t*)block >= (ptrdiff_t)sizeof(mi_block_t)); + mi_assert_internal(block->next == MI_BLOCK_TAG_GUARDED); + + const size_t bsize = mi_page_block_size(page); + const size_t psize = _mi_os_page_size(); + mi_assert_internal(bsize > psize); + mi_assert_internal(!page->memid.is_pinned); + void* gpage = (uint8_t*)block + bsize - psize; + mi_assert_internal(_mi_is_aligned(gpage, psize)); + _mi_os_unprotect(gpage, psize); +} +#endif diff --git a/src/dashbls/depends/mimalloc/src/heap.c b/src/dashbls/depends/mimalloc/src/heap.c index 15ca360312f1..fb0a6c9d379f 100644 --- a/src/dashbls/depends/mimalloc/src/heap.c +++ b/src/dashbls/depends/mimalloc/src/heap.c @@ -6,10 +6,8 @@ terms of the MIT license. A copy of the license can be found in the file -----------------------------------------------------------------------------*/ #include "mimalloc.h" -#include "mimalloc-internal.h" -#include "mimalloc-atomic.h" - -#include // memset, memcpy +#include "mimalloc/internal.h" +#include "mimalloc/prim.h" // mi_prim_get_default_heap #if defined(_MSC_VER) && (_MSC_VER < 1920) #pragma warning(disable:4204) // non-constant aggregate initializer @@ -30,15 +28,18 @@ static bool mi_heap_visit_pages(mi_heap_t* heap, heap_page_visitor_fun* fn, void // visit all pages #if MI_DEBUG>1 size_t total = heap->page_count; - #endif size_t count = 0; + #endif + for (size_t i = 0; i <= MI_BIN_FULL; i++) { mi_page_queue_t* pq = &heap->pages[i]; mi_page_t* page = pq->first; while(page != NULL) { mi_page_t* next = page->next; // save next in case the page gets removed from the queue mi_assert_internal(mi_page_heap(page) == heap); + #if MI_DEBUG>1 count++; + #endif if (!fn(heap, pq, page, arg1, arg2)) return false; page = next; // and continue } @@ -54,8 +55,6 @@ static bool mi_heap_page_is_valid(mi_heap_t* heap, mi_page_queue_t* pq, mi_page_ MI_UNUSED(arg2); MI_UNUSED(pq); mi_assert_internal(mi_page_heap(page) == heap); - mi_segment_t* segment = _mi_page_segment(page); - mi_assert_internal(segment->thread_id == heap->thread_id); mi_assert_expensive(_mi_page_is_valid(page)); return true; } @@ -64,6 +63,9 @@ static bool mi_heap_page_is_valid(mi_heap_t* heap, mi_page_queue_t* pq, mi_page_ static bool mi_heap_is_valid(mi_heap_t* heap) { mi_assert_internal(heap!=NULL); mi_heap_visit_pages(heap, &mi_heap_page_is_valid, NULL, NULL); + for (size_t bin = 0; bin < MI_BIN_COUNT; bin++) { + mi_assert_internal(_mi_page_queue_is_valid(heap, &heap->pages[bin])); + } return true; } #endif @@ -92,9 +94,9 @@ static bool mi_heap_page_collect(mi_heap_t* heap, mi_page_queue_t* pq, mi_page_t mi_collect_t collect = *((mi_collect_t*)arg_collect); _mi_page_free_collect(page, collect >= MI_FORCE); if (mi_page_all_free(page)) { - // no more used blocks, free the page. + // no more used blocks, free the page. // note: this will free retired pages as well. - _mi_page_free(page, pq, collect >= MI_FORCE); + _mi_page_free(page, pq); } else if (collect == MI_ABANDON) { // still used blocks but the thread is done; abandon the page @@ -103,70 +105,32 @@ static bool mi_heap_page_collect(mi_heap_t* heap, mi_page_queue_t* pq, mi_page_t return true; // don't break } -static bool mi_heap_page_never_delayed_free(mi_heap_t* heap, mi_page_queue_t* pq, mi_page_t* page, void* arg1, void* arg2) { - MI_UNUSED(arg1); - MI_UNUSED(arg2); - MI_UNUSED(heap); - MI_UNUSED(pq); - _mi_page_use_delayed_free(page, MI_NEVER_DELAYED_FREE, false); - return true; // don't break -} static void mi_heap_collect_ex(mi_heap_t* heap, mi_collect_t collect) { if (heap==NULL || !mi_heap_is_initialized(heap)) return; + mi_assert_expensive(mi_heap_is_valid(heap)); - const bool force = collect >= MI_FORCE; + const bool force = (collect >= MI_FORCE); _mi_deferred_free(heap, force); - // note: never reclaim on collect but leave it to threads that need storage to reclaim - const bool force_main = - #ifdef NDEBUG - collect == MI_FORCE - #else - collect >= MI_FORCE - #endif - && _mi_is_main_thread() && mi_heap_is_backing(heap) && !heap->no_reclaim; + // python/cpython#112532: we may be called from a thread that is not the owner of the heap + // const bool is_main_thread = (_mi_is_main_thread() && heap->thread_id == _mi_thread_id()); - if (force_main) { - // the main thread is abandoned (end-of-program), try to reclaim all abandoned segments. - // if all memory is freed by now, all segments should be freed. - _mi_abandoned_reclaim_all(heap, &heap->tld->segments); - } - - // if abandoning, mark all pages to no longer add to delayed_free - if (collect == MI_ABANDON) { - mi_heap_visit_pages(heap, &mi_heap_page_never_delayed_free, NULL, NULL); - } - - // free all current thread delayed blocks. - // (if abandoning, after this there are no more thread-delayed references into the pages.) - _mi_heap_delayed_free_all(heap); + // if (_mi_is_main_thread()) { mi_debug_show_arenas(true, false, false); } // collect retired pages _mi_heap_collect_retired(heap, force); // collect all pages owned by this thread mi_heap_visit_pages(heap, &mi_heap_page_collect, &collect, NULL); - mi_assert_internal( collect != MI_ABANDON || mi_atomic_load_ptr_acquire(mi_block_t,&heap->thread_delayed_free) == NULL ); - - // collect abandoned segments (in particular, decommit expired parts of segments in the abandoned segment list) - // note: forced decommit can be quite expensive if many threads are created/destroyed so we do not force on abandonment - _mi_abandoned_collect(heap, collect == MI_FORCE /* force? */, &heap->tld->segments); - - // collect segment local caches - if (force) { - _mi_segment_thread_collect(&heap->tld->segments); - } - // decommit in global segment caches - // note: forced decommit can be quite expensive if many threads are created/destroyed so we do not force on abandonment - _mi_segment_cache_collect( collect == MI_FORCE, &heap->tld->os); + // collect arenas (this is program wide so don't force purges on abandonment of threads) + //mi_atomic_storei64_release(&heap->tld->subproc->purge_expire, 1); + _mi_arenas_collect(collect == MI_FORCE /* force purge? */, collect >= MI_FORCE /* visit all? */, heap->tld); - // collect regions on program-exit (or shared library unload) - if (force && _mi_is_main_thread() && mi_heap_is_backing(heap)) { - //_mi_mem_collect(&heap->tld->os); - } + // merge statistics + if (collect <= MI_FORCE) { _mi_stats_merge_thread(heap->tld); } } void _mi_heap_collect_abandon(mi_heap_t* heap) { @@ -178,7 +142,7 @@ void mi_heap_collect(mi_heap_t* heap, bool force) mi_attr_noexcept { } void mi_collect(bool force) mi_attr_noexcept { - mi_heap_collect(mi_get_default_heap(), force); + mi_heap_collect(mi_prim_get_default_heap(), force); } @@ -187,66 +151,133 @@ void mi_collect(bool force) mi_attr_noexcept { ----------------------------------------------------------- */ mi_heap_t* mi_heap_get_default(void) { - mi_thread_init(); - return mi_get_default_heap(); + mi_heap_t* heap = mi_prim_get_default_heap(); + if mi_unlikely(!mi_heap_is_initialized(heap)) { + mi_thread_init(); + heap = mi_prim_get_default_heap(); + } + return heap; +} + +static bool mi_heap_is_default(const mi_heap_t* heap) { + return (heap == mi_prim_get_default_heap()); } + mi_heap_t* mi_heap_get_backing(void) { mi_heap_t* heap = mi_heap_get_default(); mi_assert_internal(heap!=NULL); mi_heap_t* bheap = heap->tld->heap_backing; mi_assert_internal(bheap!=NULL); - mi_assert_internal(bheap->thread_id == _mi_thread_id()); + mi_assert_internal(bheap->tld->thread_id == _mi_thread_id()); return bheap; } -mi_decl_nodiscard mi_heap_t* mi_heap_new_in_arena( mi_arena_id_t arena_id ) { - mi_heap_t* bheap = mi_heap_get_backing(); - mi_heap_t* heap = mi_heap_malloc_tp(bheap, mi_heap_t); // todo: OS allocate in secure mode? - if (heap==NULL) return NULL; +// todo: make order of parameters consistent (but would that break compat with CPython?) +void _mi_heap_init(mi_heap_t* heap, mi_arena_id_t arena_id, bool allow_destroy, uint8_t heap_tag, mi_tld_t* tld) +{ + mi_assert_internal(heap!=NULL); + mi_memid_t memid = heap->memid; _mi_memcpy_aligned(heap, &_mi_heap_empty, sizeof(mi_heap_t)); - heap->tld = bheap->tld; - heap->thread_id = _mi_thread_id(); - heap->arena_id = arena_id; - _mi_random_split(&bheap->random, &heap->random); + heap->memid = memid; + heap->tld = tld; // avoid reading the thread-local tld during initialization + heap->tag = heap_tag; + heap->numa_node = tld->numa_node; + heap->exclusive_arena = _mi_arena_from_id(arena_id); + heap->allow_page_reclaim = (!allow_destroy && mi_option_get(mi_option_page_reclaim_on_free) >= 0); + heap->allow_page_abandon = (!allow_destroy && mi_option_get(mi_option_page_full_retain) >= 0); + heap->page_full_retain = mi_option_get_clamp(mi_option_page_full_retain, -1, 32); + if (heap->tld->is_in_threadpool) { + // if we run as part of a thread pool it is better to not arbitrarily reclaim abandoned pages into our heap. + // this is checked in `free.c:mi_free_try_collect_mt` + // .. but abandoning is good in this case: halve the full page retain (possibly to 0) + // (so blocked threads do not hold on to too much memory) + if (heap->page_full_retain > 0) { + heap->page_full_retain = heap->page_full_retain / 4; + } + } + + if (heap->tld->heap_backing == NULL) { + heap->tld->heap_backing = heap; // first heap becomes the backing heap + _mi_random_init(&heap->random); + } + else { + _mi_random_split(&heap->tld->heap_backing->random, &heap->random); + } heap->cookie = _mi_heap_random_next(heap) | 1; - heap->keys[0] = _mi_heap_random_next(heap); - heap->keys[1] = _mi_heap_random_next(heap); - heap->no_reclaim = true; // don't reclaim abandoned pages or otherwise destroy is unsafe + //heap->keys[0] = _mi_heap_random_next(heap); + //heap->keys[1] = _mi_heap_random_next(heap);*/ + _mi_heap_guarded_init(heap); + // push on the thread local heaps list heap->next = heap->tld->heaps; heap->tld->heaps = heap; +} + +mi_heap_t* _mi_heap_create(int heap_tag, bool allow_destroy, mi_arena_id_t arena_id, mi_tld_t* tld) { + mi_assert_internal(tld!=NULL); + mi_assert(heap_tag >= 0 && heap_tag < 256); + // allocate and initialize a heap + mi_memid_t memid; + mi_heap_t* heap; + if (arena_id == _mi_arena_id_none()) { + heap = (mi_heap_t*)_mi_meta_zalloc(sizeof(mi_heap_t), &memid); + } + else { + // heaps associated wita a specific arena are allocated in that arena + // note: takes up at least one slice which is quite wasteful... + heap = (mi_heap_t*)_mi_arenas_alloc(_mi_subproc(), _mi_align_up(sizeof(mi_heap_t),MI_ARENA_MIN_OBJ_SIZE), true, true, _mi_arena_from_id(arena_id), tld->thread_seq, tld->numa_node, &memid); + } + if (heap==NULL) { + _mi_error_message(ENOMEM, "unable to allocate heap meta-data\n"); + return NULL; + } + heap->memid = memid; + _mi_heap_init(heap, arena_id, allow_destroy, (uint8_t)heap_tag, tld); return heap; } +mi_decl_nodiscard mi_heap_t* mi_heap_new_ex(int heap_tag, bool allow_destroy, mi_arena_id_t arena_id) { + mi_heap_t* bheap = mi_heap_get_backing(); + mi_assert_internal(bheap != NULL); + return _mi_heap_create(heap_tag, allow_destroy, arena_id, bheap->tld); +} + +mi_decl_nodiscard mi_heap_t* mi_heap_new_in_arena(mi_arena_id_t arena_id) { + return mi_heap_new_ex(0 /* default heap tag */, false /* allow destroy? */, arena_id); +} + mi_decl_nodiscard mi_heap_t* mi_heap_new(void) { - return mi_heap_new_in_arena(_mi_arena_id_none()); + // don't reclaim abandoned memory or otherwise destroy is unsafe + return mi_heap_new_ex(0 /* default heap tag */, true /* allow destroy? */, _mi_arena_id_none()); } -bool _mi_heap_memid_is_suitable(mi_heap_t* heap, size_t memid) { - return _mi_arena_memid_is_suitable(memid, heap->arena_id); +bool _mi_heap_memid_is_suitable(mi_heap_t* heap, mi_memid_t memid) { + return _mi_arena_memid_is_suitable(memid, heap->exclusive_arena); } uintptr_t _mi_heap_random_next(mi_heap_t* heap) { return _mi_random_next(&heap->random); } +void mi_heap_set_numa_affinity(mi_heap_t* heap, int numa_node) { + if (heap == NULL) return; + heap->numa_node = (numa_node < 0 ? -1 : numa_node % _mi_os_numa_node_count()); +} + // zero out the page queues static void mi_heap_reset_pages(mi_heap_t* heap) { mi_assert_internal(heap != NULL); mi_assert_internal(mi_heap_is_initialized(heap)); // TODO: copy full empty heap instead? - memset(&heap->pages_free_direct, 0, sizeof(heap->pages_free_direct)); -#ifdef MI_MEDIUM_DIRECT - memset(&heap->pages_free_medium, 0, sizeof(heap->pages_free_medium)); -#endif + _mi_memset(&heap->pages_free_direct, 0, sizeof(heap->pages_free_direct)); _mi_memcpy_aligned(&heap->pages, &_mi_heap_empty.pages, sizeof(heap->pages)); - heap->thread_delayed_free = NULL; + // heap->thread_delayed_free = NULL; heap->page_count = 0; } // called from `mi_heap_destroy` and `mi_heap_delete` to free the internal heap resources. -static void mi_heap_free(mi_heap_t* heap) { +static void mi_heap_free(mi_heap_t* heap, bool do_free_mem) { mi_assert(heap != NULL); mi_assert_internal(mi_heap_is_initialized(heap)); if (heap==NULL || !mi_heap_is_initialized(heap)) return; @@ -260,7 +291,7 @@ static void mi_heap_free(mi_heap_t* heap) { // remove ourselves from the thread local heaps list // linear search but we expect the number of heaps to be relatively small mi_heap_t* prev = NULL; - mi_heap_t* curr = heap->tld->heaps; + mi_heap_t* curr = heap->tld->heaps; while (curr != heap && curr != NULL) { prev = curr; curr = curr->next; @@ -273,9 +304,23 @@ static void mi_heap_free(mi_heap_t* heap) { mi_assert_internal(heap->tld->heaps != NULL); // and free the used memory - mi_free(heap); + if (do_free_mem) { + _mi_meta_free(heap, sizeof(*heap), heap->memid); + } } +// return a heap on the same thread as `heap` specialized for the specified tag (if it exists) +mi_heap_t* _mi_heap_by_tag(mi_heap_t* heap, uint8_t tag) { + if (heap->tag == tag) { + return heap; + } + for (mi_heap_t *curr = heap->tld->heaps; curr != NULL; curr = curr->next) { + if (curr->tag == tag) { + return curr; + } + } + return NULL; +} /* ----------------------------------------------------------- Heap destroy @@ -284,33 +329,27 @@ static void mi_heap_free(mi_heap_t* heap) { static bool _mi_heap_page_destroy(mi_heap_t* heap, mi_page_queue_t* pq, mi_page_t* page, void* arg1, void* arg2) { MI_UNUSED(arg1); MI_UNUSED(arg2); - MI_UNUSED(heap); MI_UNUSED(pq); // ensure no more thread_delayed_free will be added - _mi_page_use_delayed_free(page, MI_NEVER_DELAYED_FREE, false); + //_mi_page_use_delayed_free(page, MI_NEVER_DELAYED_FREE, false); // stats const size_t bsize = mi_page_block_size(page); - if (bsize > MI_MEDIUM_OBJ_SIZE_MAX) { - if (bsize <= MI_LARGE_OBJ_SIZE_MAX) { - mi_heap_stat_decrease(heap, large, bsize); - } - else { - mi_heap_stat_decrease(heap, huge, bsize); - } + if (bsize > MI_LARGE_MAX_OBJ_SIZE) { + mi_heap_stat_decrease(heap, malloc_huge, bsize); } -#if (MI_STAT) + #if (MI_STAT>0) _mi_page_free_collect(page, false); // update used count const size_t inuse = page->used; - if (bsize <= MI_LARGE_OBJ_SIZE_MAX) { - mi_heap_stat_decrease(heap, normal, bsize * inuse); -#if (MI_STAT>1) - mi_heap_stat_decrease(heap, normal_bins[_mi_bin(bsize)], inuse); -#endif + if (bsize <= MI_LARGE_MAX_OBJ_SIZE) { + mi_heap_stat_decrease(heap, malloc_normal, bsize * inuse); + #if (MI_STAT>1) + mi_heap_stat_decrease(heap, malloc_bins[_mi_bin(bsize)], inuse); + #endif } - mi_heap_stat_decrease(heap, malloc, bsize * inuse); // todo: off for aligned blocks... -#endif + // mi_heap_stat_decrease(heap, malloc_requested, bsize * inuse); // todo: off for aligned blocks... + #endif /// pretend it is all free now mi_assert_internal(mi_page_thread_free(page) == NULL); @@ -320,7 +359,8 @@ static bool _mi_heap_page_destroy(mi_heap_t* heap, mi_page_queue_t* pq, mi_page_ // mi_page_free(page,false); page->next = NULL; page->prev = NULL; - _mi_segment_page_free(page,false /* no force? */, &heap->tld->segments); + mi_page_set_heap(page, NULL); + _mi_arenas_page_free(page, heap->tld); return true; // keep going } @@ -330,62 +370,89 @@ void _mi_heap_destroy_pages(mi_heap_t* heap) { mi_heap_reset_pages(heap); } +#if MI_TRACK_HEAP_DESTROY +static bool mi_cdecl mi_heap_track_block_free(const mi_heap_t* heap, const mi_heap_area_t* area, void* block, size_t block_size, void* arg) { + MI_UNUSED(heap); MI_UNUSED(area); MI_UNUSED(arg); MI_UNUSED(block_size); + mi_track_free_size(block,mi_usable_size(block)); + return true; +} +#endif + void mi_heap_destroy(mi_heap_t* heap) { mi_assert(heap != NULL); mi_assert(mi_heap_is_initialized(heap)); - mi_assert(heap->no_reclaim); + mi_assert(!heap->allow_page_reclaim); + mi_assert(!heap->allow_page_abandon); mi_assert_expensive(mi_heap_is_valid(heap)); if (heap==NULL || !mi_heap_is_initialized(heap)) return; - if (!heap->no_reclaim) { - // don't free in case it may contain reclaimed pages + #if MI_GUARDED + // _mi_warning_message("'mi_heap_destroy' called but MI_GUARDED is enabled -- using `mi_heap_delete` instead (heap at %p)\n", heap); + mi_heap_delete(heap); + return; + #else + if (heap->allow_page_reclaim) { + _mi_warning_message("'mi_heap_destroy' called but ignored as the heap was not created with 'allow_destroy' (heap at %p)\n", heap); + // don't free in case it may contain reclaimed pages, mi_heap_delete(heap); } else { + // track all blocks as freed + #if MI_TRACK_HEAP_DESTROY + mi_heap_visit_blocks(heap, true, mi_heap_track_block_free, NULL); + #endif // free all pages _mi_heap_destroy_pages(heap); - mi_heap_free(heap); + mi_heap_free(heap,true); } + #endif } - +// forcefully destroy all heaps in the current thread +void _mi_heap_unsafe_destroy_all(mi_heap_t* heap) { + mi_assert_internal(heap != NULL); + if (heap == NULL) return; + mi_heap_t* curr = heap->tld->heaps; + while (curr != NULL) { + mi_heap_t* next = curr->next; + if (!curr->allow_page_reclaim) { + mi_heap_destroy(curr); + } + else { + _mi_heap_destroy_pages(curr); + } + curr = next; + } +} /* ----------------------------------------------------------- Safe Heap delete ----------------------------------------------------------- */ // Transfer the pages from one heap to the other -static void mi_heap_absorb(mi_heap_t* heap, mi_heap_t* from) { - mi_assert_internal(heap!=NULL); - if (from==NULL || from->page_count == 0) return; - - // reduce the size of the delayed frees - _mi_heap_delayed_free_partial(from); - - // transfer all pages by appending the queues; this will set a new heap field - // so threads may do delayed frees in either heap for a while. - // note: appending waits for each page to not be in the `MI_DELAYED_FREEING` state - // so after this only the new heap will get delayed frees - for (size_t i = 0; i <= MI_BIN_FULL; i++) { - mi_page_queue_t* pq = &heap->pages[i]; - mi_page_queue_t* append = &from->pages[i]; - size_t pcount = _mi_page_queue_append(heap, pq, append); - heap->page_count += pcount; - from->page_count -= pcount; - } - mi_assert_internal(from->page_count == 0); - - // and do outstanding delayed frees in the `from` heap - // note: be careful here as the `heap` field in all those pages no longer point to `from`, - // turns out to be ok as `_mi_heap_delayed_free` only visits the list and calls a - // the regular `_mi_free_delayed_block` which is safe. - _mi_heap_delayed_free_all(from); - #if !defined(_MSC_VER) || (_MSC_VER > 1900) // somehow the following line gives an error in VS2015, issue #353 - mi_assert_internal(mi_atomic_load_ptr_relaxed(mi_block_t,&from->thread_delayed_free) == NULL); - #endif - - // and reset the `from` heap - mi_heap_reset_pages(from); -} +//static void mi_heap_absorb(mi_heap_t* heap, mi_heap_t* from) { +// mi_assert_internal(heap!=NULL); +// if (from==NULL || from->page_count == 0) return; +// +// // transfer all pages by appending the queues; this will set a new heap field +// for (size_t i = 0; i <= MI_BIN_FULL; i++) { +// mi_page_queue_t* pq = &heap->pages[i]; +// mi_page_queue_t* append = &from->pages[i]; +// size_t pcount = _mi_page_queue_append(heap, pq, append); +// heap->page_count += pcount; +// from->page_count -= pcount; +// } +// mi_assert_internal(from->page_count == 0); +// +// // and reset the `from` heap +// mi_heap_reset_pages(from); +//} + +//// are two heaps compatible with respect to heap-tag, exclusive arena etc. +//static bool mi_heaps_are_compatible(mi_heap_t* heap1, mi_heap_t* heap2) { +// return (heap1->tag == heap2->tag && // store same kind of objects +// heap1->tld->subproc == heap2->tld->subproc && // same sub-process +// heap1->arena_id == heap2->arena_id); // same arena preference +//} // Safe delete a heap without freeing any still allocated blocks in that heap. void mi_heap_delete(mi_heap_t* heap) @@ -395,16 +462,11 @@ void mi_heap_delete(mi_heap_t* heap) mi_assert_expensive(mi_heap_is_valid(heap)); if (heap==NULL || !mi_heap_is_initialized(heap)) return; - if (!mi_heap_is_backing(heap)) { - // tranfer still used pages to the backing heap - mi_heap_absorb(heap->tld->heap_backing, heap); - } - else { - // the backing heap abandons its pages - _mi_heap_collect_abandon(heap); - } + // abandon all pages + _mi_heap_collect_abandon(heap); + mi_assert_internal(heap->page_count==0); - mi_heap_free(heap); + mi_heap_free(heap,true); } mi_heap_t* mi_heap_set_default(mi_heap_t* heap) { @@ -412,13 +474,69 @@ mi_heap_t* mi_heap_set_default(mi_heap_t* heap) { mi_assert(mi_heap_is_initialized(heap)); if (heap==NULL || !mi_heap_is_initialized(heap)) return NULL; mi_assert_expensive(mi_heap_is_valid(heap)); - mi_heap_t* old = mi_get_default_heap(); + mi_heap_t* old = mi_prim_get_default_heap(); _mi_heap_set_default_direct(heap); return old; } +/* ----------------------------------------------------------- + Load/unload heaps +----------------------------------------------------------- */ +void mi_heap_unload(mi_heap_t* heap) { + mi_assert(mi_heap_is_initialized(heap)); + mi_assert_expensive(mi_heap_is_valid(heap)); + if (heap==NULL || !mi_heap_is_initialized(heap)) return; + if (heap->exclusive_arena == NULL) { + _mi_warning_message("cannot unload heaps that are not associated with an exclusive arena\n"); + return; + } + // abandon all pages so all thread'id in the pages are cleared + _mi_heap_collect_abandon(heap); + mi_assert_internal(heap->page_count==0); + + // remove from heap list + mi_heap_free(heap, false /* but don't actually free the memory */); + + // disassociate from the current thread-local and static state + heap->tld = NULL; + return; +} + +bool mi_heap_reload(mi_heap_t* heap, mi_arena_id_t arena_id) { + mi_assert(mi_heap_is_initialized(heap)); + if (heap==NULL || !mi_heap_is_initialized(heap)) return false; + if (heap->exclusive_arena == NULL) { + _mi_warning_message("cannot reload heaps that were not associated with an exclusive arena\n"); + return false; + } + if (heap->tld != NULL) { + _mi_warning_message("cannot reload heaps that were not unloaded first\n"); + return false; + } + mi_arena_t* arena = _mi_arena_from_id(arena_id); + if (heap->exclusive_arena != arena) { + _mi_warning_message("trying to reload a heap at a different arena address: %p vs %p\n", heap->exclusive_arena, arena); + return false; + } + + mi_assert_internal(heap->page_count==0); + + // re-associate with the current thread-local and static state + heap->tld = mi_heap_get_default()->tld; + + // reinit direct pages (as we may be in a different process) + mi_assert_internal(heap->page_count == 0); + for (size_t i = 0; i < MI_PAGES_DIRECT; i++) { + heap->pages_free_direct[i] = (mi_page_t*)&_mi_page_empty; + } + + // push on the thread local heaps list + heap->next = heap->tld->heaps; + heap->tld->heaps = heap; + return true; +} /* ----------------------------------------------------------- Analysis @@ -427,11 +545,8 @@ mi_heap_t* mi_heap_set_default(mi_heap_t* heap) { // static since it is not thread safe to access heaps from other threads. static mi_heap_t* mi_heap_of_block(const void* p) { if (p == NULL) return NULL; - mi_segment_t* segment = _mi_ptr_segment(p); - bool valid = (_mi_ptr_cookie(segment) == segment->cookie); - mi_assert_internal(valid); - if mi_unlikely(!valid) return NULL; - return mi_page_heap(_mi_segment_page_of(segment,p)); + mi_page_t* page = _mi_ptr_page(p); // TODO: check pointer validity? + return mi_page_heap(page); } bool mi_heap_contains_block(mi_heap_t* heap, const void* p) { @@ -445,8 +560,7 @@ static bool mi_heap_page_check_owned(mi_heap_t* heap, mi_page_queue_t* pq, mi_pa MI_UNUSED(heap); MI_UNUSED(pq); bool* found = (bool*)vfound; - mi_segment_t* segment = _mi_page_segment(page); - void* start = _mi_page_start(segment, page, NULL); + void* start = mi_page_start(page); void* end = (uint8_t*)start + (page->capacity * mi_page_block_size(page)); *found = (p >= start && p < end); return (!*found); // continue if not found @@ -462,7 +576,7 @@ bool mi_heap_check_owned(mi_heap_t* heap, const void* p) { } bool mi_check_owned(const void* p) { - return mi_heap_check_owned(mi_get_default_heap(), p); + return mi_heap_check_owned(mi_prim_get_default_heap(), p); } /* ----------------------------------------------------------- @@ -471,90 +585,152 @@ bool mi_check_owned(const void* p) { enable visiting all blocks of all heaps across threads ----------------------------------------------------------- */ -// Separate struct to keep `mi_page_t` out of the public interface -typedef struct mi_heap_area_ex_s { - mi_heap_area_t area; - mi_page_t* page; -} mi_heap_area_ex_t; +void _mi_heap_area_init(mi_heap_area_t* area, mi_page_t* page) { + const size_t bsize = mi_page_block_size(page); + const size_t ubsize = mi_page_usable_block_size(page); + area->reserved = page->reserved * bsize; + area->committed = page->capacity * bsize; + area->blocks = mi_page_start(page); + area->used = page->used; // number of blocks in use (#553) + area->block_size = ubsize; + area->full_block_size = bsize; + area->heap_tag = page->heap_tag; +} -static bool mi_heap_area_visit_blocks(const mi_heap_area_ex_t* xarea, mi_block_visit_fun* visitor, void* arg) { - mi_assert(xarea != NULL); - if (xarea==NULL) return true; - const mi_heap_area_t* area = &xarea->area; - mi_page_t* page = xarea->page; + +static void mi_get_fast_divisor(size_t divisor, uint64_t* magic, size_t* shift) { + mi_assert_internal(divisor > 0 && divisor <= UINT32_MAX); + *shift = MI_SIZE_BITS - mi_clz(divisor - 1); + *magic = ((((uint64_t)1 << 32) * (((uint64_t)1 << *shift) - divisor)) / divisor + 1); +} + +static size_t mi_fast_divide(size_t n, uint64_t magic, size_t shift) { + mi_assert_internal(n <= UINT32_MAX); + const uint64_t hi = ((uint64_t)n * magic) >> 32; + return (size_t)((hi + n) >> shift); +} + +bool _mi_heap_area_visit_blocks(const mi_heap_area_t* area, mi_page_t* page, mi_block_visit_fun* visitor, void* arg) { + mi_assert(area != NULL); + if (area==NULL) return true; mi_assert(page != NULL); if (page == NULL) return true; - _mi_page_free_collect(page,true); + _mi_page_free_collect(page,true); // collect both thread_delayed and local_free mi_assert_internal(page->local_free == NULL); if (page->used == 0) return true; - const size_t bsize = mi_page_block_size(page); - const size_t ubsize = mi_page_usable_block_size(page); // without padding - size_t psize; - uint8_t* pstart = _mi_page_start(_mi_page_segment(page), page, &psize); + size_t psize; + uint8_t* const pstart = mi_page_area(page, &psize); + mi_heap_t* const heap = mi_page_heap(page); + const size_t bsize = mi_page_block_size(page); + const size_t ubsize = mi_page_usable_block_size(page); // without padding + // optimize page with one block if (page->capacity == 1) { - // optimize page with one block mi_assert_internal(page->used == 1 && page->free == NULL); return visitor(mi_page_heap(page), area, pstart, ubsize, arg); } + mi_assert(bsize <= UINT32_MAX); + + // optimize full pages + if (page->used == page->capacity) { + uint8_t* block = pstart; + for (size_t i = 0; i < page->capacity; i++) { + if (!visitor(heap, area, block, ubsize, arg)) return false; + block += bsize; + } + return true; + } // create a bitmap of free blocks. #define MI_MAX_BLOCKS (MI_SMALL_PAGE_SIZE / sizeof(void*)) - uintptr_t free_map[MI_MAX_BLOCKS / sizeof(uintptr_t)]; - memset(free_map, 0, sizeof(free_map)); + uintptr_t free_map[MI_MAX_BLOCKS / MI_INTPTR_BITS]; + const uintptr_t bmapsize = _mi_divide_up(page->capacity, MI_INTPTR_BITS); + memset(free_map, 0, bmapsize * sizeof(intptr_t)); + if (page->capacity % MI_INTPTR_BITS != 0) { + // mark left-over bits at the end as free + size_t shift = (page->capacity % MI_INTPTR_BITS); + uintptr_t mask = (UINTPTR_MAX << shift); + free_map[bmapsize - 1] = mask; + } + + // fast repeated division by the block size + uint64_t magic; + size_t shift; + mi_get_fast_divisor(bsize, &magic, &shift); + #if MI_DEBUG>1 size_t free_count = 0; - for (mi_block_t* block = page->free; block != NULL; block = mi_block_next(page,block)) { + #endif + for (mi_block_t* block = page->free; block != NULL; block = mi_block_next(page, block)) { + #if MI_DEBUG>1 free_count++; + #endif mi_assert_internal((uint8_t*)block >= pstart && (uint8_t*)block < (pstart + psize)); size_t offset = (uint8_t*)block - pstart; mi_assert_internal(offset % bsize == 0); - size_t blockidx = offset / bsize; // Todo: avoid division? - mi_assert_internal( blockidx < MI_MAX_BLOCKS); - size_t bitidx = (blockidx / sizeof(uintptr_t)); - size_t bit = blockidx - (bitidx * sizeof(uintptr_t)); + mi_assert_internal(offset <= UINT32_MAX); + size_t blockidx = mi_fast_divide(offset, magic, shift); + mi_assert_internal(blockidx == offset / bsize); + mi_assert_internal(blockidx < MI_MAX_BLOCKS); + size_t bitidx = (blockidx / MI_INTPTR_BITS); + size_t bit = blockidx - (bitidx * MI_INTPTR_BITS); free_map[bitidx] |= ((uintptr_t)1 << bit); } mi_assert_internal(page->capacity == (free_count + page->used)); // walk through all blocks skipping the free ones + #if MI_DEBUG>1 size_t used_count = 0; - for (size_t i = 0; i < page->capacity; i++) { - size_t bitidx = (i / sizeof(uintptr_t)); - size_t bit = i - (bitidx * sizeof(uintptr_t)); - uintptr_t m = free_map[bitidx]; - if (bit == 0 && m == UINTPTR_MAX) { - i += (sizeof(uintptr_t) - 1); // skip a run of free blocks + #endif + uint8_t* block = pstart; + for (size_t i = 0; i < bmapsize; i++) { + if (free_map[i] == 0) { + // every block is in use + for (size_t j = 0; j < MI_INTPTR_BITS; j++) { + #if MI_DEBUG>1 + used_count++; + #endif + if (!visitor(heap, area, block, ubsize, arg)) return false; + block += bsize; + } } - else if ((m & ((uintptr_t)1 << bit)) == 0) { - used_count++; - uint8_t* block = pstart + (i * bsize); - if (!visitor(mi_page_heap(page), area, block, ubsize, arg)) return false; + else { + // visit the used blocks in the mask + uintptr_t m = ~free_map[i]; + while (m != 0) { + #if MI_DEBUG>1 + used_count++; + #endif + size_t bitidx = mi_ctz(m); + if (!visitor(heap, area, block + (bitidx * bsize), ubsize, arg)) return false; + m &= m - 1; // clear least significant bit + } + block += bsize * MI_INTPTR_BITS; } } mi_assert_internal(page->used == used_count); return true; } -typedef bool (mi_heap_area_visit_fun)(const mi_heap_t* heap, const mi_heap_area_ex_t* area, void* arg); +// Separate struct to keep `mi_page_t` out of the public interface +typedef struct mi_heap_area_ex_s { + mi_heap_area_t area; + mi_page_t* page; +} mi_heap_area_ex_t; + +typedef bool (mi_heap_area_visit_fun)(const mi_heap_t* heap, const mi_heap_area_ex_t* area, void* arg); + static bool mi_heap_visit_areas_page(mi_heap_t* heap, mi_page_queue_t* pq, mi_page_t* page, void* vfun, void* arg) { MI_UNUSED(heap); MI_UNUSED(pq); mi_heap_area_visit_fun* fun = (mi_heap_area_visit_fun*)vfun; mi_heap_area_ex_t xarea; - const size_t bsize = mi_page_block_size(page); - const size_t ubsize = mi_page_usable_block_size(page); xarea.page = page; - xarea.area.reserved = page->reserved * bsize; - xarea.area.committed = page->capacity * bsize; - xarea.area.blocks = _mi_page_start(_mi_page_segment(page), page, NULL); - xarea.area.used = page->used; // number of blocks in use (#553) - xarea.area.block_size = ubsize; - xarea.area.full_block_size = bsize; + _mi_heap_area_init(&xarea.area, page); return fun(heap, &xarea, arg); } @@ -575,7 +751,7 @@ static bool mi_heap_area_visitor(const mi_heap_t* heap, const mi_heap_area_ex_t* mi_visit_blocks_args_t* args = (mi_visit_blocks_args_t*)arg; if (!args->visitor(heap, &xarea->area, NULL, xarea->area.block_size, args->arg)) return false; if (args->visit_blocks) { - return mi_heap_area_visit_blocks(xarea, args->visitor, args->arg); + return _mi_heap_area_visit_blocks(&xarea->area, xarea->page, args->visitor, args->arg); } else { return true; diff --git a/src/dashbls/depends/mimalloc/src/init.c b/src/dashbls/depends/mimalloc/src/init.c index 4f37b71761b3..73847a4b6af1 100644 --- a/src/dashbls/depends/mimalloc/src/init.c +++ b/src/dashbls/depends/mimalloc/src/init.c @@ -5,32 +5,37 @@ terms of the MIT license. A copy of the license can be found in the file "LICENSE" at the root of this distribution. -----------------------------------------------------------------------------*/ #include "mimalloc.h" -#include "mimalloc-internal.h" +#include "mimalloc/internal.h" +#include "mimalloc/prim.h" #include // memcpy, memset #include // atexit +#define MI_MEMID_INIT(kind) {{{NULL,0}}, kind, true /* pinned */, true /* committed */, false /* zero */ } +#define MI_MEMID_STATIC MI_MEMID_INIT(MI_MEM_STATIC) + // Empty page used to initialize the small free pages array const mi_page_t _mi_page_empty = { - 0, false, false, false, false, - 0, // capacity - 0, // reserved capacity - { 0 }, // flags - false, // is_zero - 0, // retire_expire - NULL, // free - #if MI_ENCODE_FREELIST - { 0, 0 }, - #endif - 0, // used - 0, // xblock_size - NULL, // local_free - MI_ATOMIC_VAR_INIT(0), // xthread_free - MI_ATOMIC_VAR_INIT(0), // xheap - NULL, NULL - #if MI_INTPTR_SIZE==8 - , { 0 } // padding + MI_ATOMIC_VAR_INIT(0), // xthread_id + NULL, // free + 0, // used + 0, // capacity + 0, // reserved capacity + 0, // block size shift + 0, // retire_expire + NULL, // local_free + MI_ATOMIC_VAR_INIT(0), // xthread_free + 0, // block_size + NULL, // page_start + 0, // heap tag + false, // is_zero + #if (MI_PADDING || MI_ENCODE_FREELIST) + { 0, 0 }, // keys #endif + NULL, // xheap + NULL, NULL, // next, prev + MI_ARENA_SLICE_SIZE, // page_committed + MI_MEMID_STATIC // memid }; #define MI_PAGE_EMPTY() ((mi_page_t*)&_mi_page_empty) @@ -45,7 +50,7 @@ const mi_page_t _mi_page_empty = { // Empty page queues for every bin -#define QNULL(sz) { NULL, NULL, (sz)*sizeof(uintptr_t) } +#define QNULL(sz) { NULL, NULL, 0, (sz)*sizeof(uintptr_t) } #define MI_PAGE_QUEUES_EMPTY \ { QNULL(1), \ QNULL( 1), QNULL( 2), QNULL( 3), QNULL( 4), QNULL( 5), QNULL( 6), QNULL( 7), QNULL( 8), /* 8 */ \ @@ -57,41 +62,29 @@ const mi_page_t _mi_page_empty = { QNULL( 10240), QNULL( 12288), QNULL( 14336), QNULL( 16384), QNULL( 20480), QNULL( 24576), QNULL( 28672), QNULL( 32768), /* 56 */ \ QNULL( 40960), QNULL( 49152), QNULL( 57344), QNULL( 65536), QNULL( 81920), QNULL( 98304), QNULL(114688), QNULL(131072), /* 64 */ \ QNULL(163840), QNULL(196608), QNULL(229376), QNULL(262144), QNULL(327680), QNULL(393216), QNULL(458752), QNULL(524288), /* 72 */ \ - QNULL(MI_MEDIUM_OBJ_WSIZE_MAX + 1 /* 655360, Huge queue */), \ - QNULL(MI_MEDIUM_OBJ_WSIZE_MAX + 2) /* Full queue */ } + QNULL(MI_LARGE_MAX_OBJ_WSIZE + 1 /* 655360, Huge queue */), \ + QNULL(MI_LARGE_MAX_OBJ_WSIZE + 2) /* Full queue */ } -#define MI_STAT_COUNT_NULL() {0,0,0,0} +#define MI_STAT_COUNT_NULL() {0,0,0} // Empty statistics -#if MI_STAT>1 -#define MI_STAT_COUNT_END_NULL() , { MI_STAT_COUNT_NULL(), MI_INIT32(MI_STAT_COUNT_NULL) } -#else -#define MI_STAT_COUNT_END_NULL() -#endif - #define MI_STATS_NULL \ - MI_STAT_COUNT_NULL(), MI_STAT_COUNT_NULL(), \ - MI_STAT_COUNT_NULL(), MI_STAT_COUNT_NULL(), \ - MI_STAT_COUNT_NULL(), MI_STAT_COUNT_NULL(), \ - MI_STAT_COUNT_NULL(), MI_STAT_COUNT_NULL(), \ - MI_STAT_COUNT_NULL(), MI_STAT_COUNT_NULL(), \ - MI_STAT_COUNT_NULL(), MI_STAT_COUNT_NULL(), \ - MI_STAT_COUNT_NULL(), MI_STAT_COUNT_NULL(), \ - { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, \ - { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } \ - MI_STAT_COUNT_END_NULL() - - -// Empty slice span queues for every bin -#define SQNULL(sz) { NULL, NULL, sz } -#define MI_SEGMENT_SPAN_QUEUES_EMPTY \ - { SQNULL(1), \ - SQNULL( 1), SQNULL( 2), SQNULL( 3), SQNULL( 4), SQNULL( 5), SQNULL( 6), SQNULL( 7), SQNULL( 10), /* 8 */ \ - SQNULL( 12), SQNULL( 14), SQNULL( 16), SQNULL( 20), SQNULL( 24), SQNULL( 28), SQNULL( 32), SQNULL( 40), /* 16 */ \ - SQNULL( 48), SQNULL( 56), SQNULL( 64), SQNULL( 80), SQNULL( 96), SQNULL( 112), SQNULL( 128), SQNULL( 160), /* 24 */ \ - SQNULL( 192), SQNULL( 224), SQNULL( 256), SQNULL( 320), SQNULL( 384), SQNULL( 448), SQNULL( 512), SQNULL( 640), /* 32 */ \ - SQNULL( 768), SQNULL( 896), SQNULL( 1024) /* 35 */ } - + MI_STAT_COUNT_NULL(), MI_STAT_COUNT_NULL(), MI_STAT_COUNT_NULL(), MI_STAT_COUNT_NULL(), \ + MI_STAT_COUNT_NULL(), MI_STAT_COUNT_NULL(), MI_STAT_COUNT_NULL(), MI_STAT_COUNT_NULL(), \ + MI_STAT_COUNT_NULL(), MI_STAT_COUNT_NULL(), MI_STAT_COUNT_NULL(), \ + { 0 }, { 0 }, { 0 }, { 0 }, \ + { 0 }, { 0 }, { 0 }, { 0 }, \ + \ + { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, \ + MI_INIT4(MI_STAT_COUNT_NULL), \ + { 0 }, { 0 }, { 0 }, { 0 }, \ + \ + { MI_INIT4(MI_STAT_COUNT_NULL) }, \ + { { 0 }, { 0 }, { 0 }, { 0 } }, \ + \ + { MI_INIT74(MI_STAT_COUNT_NULL) }, \ + { MI_INIT74(MI_STAT_COUNT_NULL) }, \ + { MI_INIT5(MI_STAT_COUNT_NULL) } // -------------------------------------------------------- // Statically allocate an empty heap as the initial @@ -102,198 +95,380 @@ const mi_page_t _mi_page_empty = { // may lead to allocation itself on some platforms) // -------------------------------------------------------- +static mi_decl_cache_align mi_subproc_t subproc_main +#if __cplusplus += { }; // empty initializer to prevent running the constructor (with msvc) +#else += { 0 }; // C zero initialize +#endif + +static mi_decl_cache_align mi_tld_t tld_empty = { + 0, // thread_id + 0, // thread_seq + 0, // default numa node + &subproc_main, // subproc + NULL, // heap_backing + NULL, // heaps list + 0, // heartbeat + false, // recurse + false, // is_in_threadpool + { MI_STAT_VERSION, MI_STATS_NULL }, // stats + MI_MEMID_STATIC // memid +}; + mi_decl_cache_align const mi_heap_t _mi_heap_empty = { - NULL, + &tld_empty, // tld + NULL, // exclusive_arena + 0, // preferred numa node + 0, // cookie + //{ 0, 0 }, // keys + { {0}, {0}, 0, true }, // random + 0, // page count + MI_BIN_FULL, 0, // page retired min/max + 0, 0, // generic count + NULL, // next + 0, // full page retain + false, // can reclaim + true, // can eager abandon + 0, // tag + #if MI_GUARDED + 0, 0, 0, 1, // count is 1 so we never write to it (see `internal.h:mi_heap_malloc_use_guarded`) + #endif MI_SMALL_PAGES_EMPTY, MI_PAGE_QUEUES_EMPTY, - MI_ATOMIC_VAR_INIT(NULL), - 0, // tid - 0, // cookie - 0, // arena id - { 0, 0 }, // keys - { {0}, {0}, 0 }, - 0, // page count - MI_BIN_FULL, 0, // page retired min/max - NULL, // next - false + MI_MEMID_STATIC }; -#define tld_empty_stats ((mi_stats_t*)((uint8_t*)&tld_empty + offsetof(mi_tld_t,stats))) -#define tld_empty_os ((mi_os_tld_t*)((uint8_t*)&tld_empty + offsetof(mi_tld_t,os))) +extern mi_decl_hidden mi_decl_cache_align mi_heap_t heap_main; + +static mi_decl_cache_align mi_tld_t tld_main = { + 0, // thread_id + 0, // thread_seq + 0, // numa node + &subproc_main, // subproc + &heap_main, // heap_backing + &heap_main, // heaps list + 0, // heartbeat + false, // recurse + false, // is_in_threadpool + { MI_STAT_VERSION, MI_STATS_NULL }, // stats + MI_MEMID_STATIC // memid +}; -mi_decl_cache_align static const mi_tld_t tld_empty = { - 0, - false, - NULL, NULL, - { MI_SEGMENT_SPAN_QUEUES_EMPTY, 0, 0, 0, 0, tld_empty_stats, tld_empty_os }, // segments - { 0, tld_empty_stats }, // os - { MI_STATS_NULL } // stats +mi_decl_cache_align mi_heap_t heap_main = { + &tld_main, // thread local data + NULL, // exclusive arena + 0, // preferred numa node + 0, // initial cookie + //{ 0, 0 }, // the key of the main heap can be fixed (unlike page keys that need to be secure!) + { {0x846ca68b}, {0}, 0, true }, // random + 0, // page count + MI_BIN_FULL, 0, // page retired min/max + 0, 0, // generic count + NULL, // next heap + 2, // full page retain + true, // allow page reclaim + true, // allow page abandon + 0, // tag + #if MI_GUARDED + 0, 0, 0, 0, + #endif + MI_SMALL_PAGES_EMPTY, + MI_PAGE_QUEUES_EMPTY, + MI_MEMID_STATIC }; + +mi_threadid_t _mi_thread_id(void) mi_attr_noexcept { + return _mi_prim_thread_id(); +} + // the thread-local default heap for allocation mi_decl_thread mi_heap_t* _mi_heap_default = (mi_heap_t*)&_mi_heap_empty; -extern mi_heap_t _mi_heap_main; -static mi_tld_t tld_main = { - 0, false, - &_mi_heap_main, & _mi_heap_main, - { MI_SEGMENT_SPAN_QUEUES_EMPTY, 0, 0, 0, 0, &tld_main.stats, &tld_main.os }, // segments - { 0, &tld_main.stats }, // os - { MI_STATS_NULL } // stats -}; +bool _mi_process_is_initialized = false; // set to `true` in `mi_process_init`. -mi_heap_t _mi_heap_main = { - &tld_main, - MI_SMALL_PAGES_EMPTY, - MI_PAGE_QUEUES_EMPTY, - MI_ATOMIC_VAR_INIT(NULL), - 0, // thread id - 0, // initial cookie - 0, // arena id - { 0, 0 }, // the key of the main heap can be fixed (unlike page keys that need to be secure!) - { {0x846ca68b}, {0}, 0 }, // random - 0, // page count - MI_BIN_FULL, 0, // page retired min/max - NULL, // next heap - false // can reclaim -}; +mi_stats_t _mi_stats_main = { MI_STAT_VERSION, MI_STATS_NULL }; -bool _mi_process_is_initialized = false; // set to `true` in `mi_process_init`. +#if MI_GUARDED +mi_decl_export void mi_heap_guarded_set_sample_rate(mi_heap_t* heap, size_t sample_rate, size_t seed) { + heap->guarded_sample_rate = sample_rate; + heap->guarded_sample_count = sample_rate; // count down samples + if (heap->guarded_sample_rate > 1) { + if (seed == 0) { + seed = _mi_heap_random_next(heap); + } + heap->guarded_sample_count = (seed % heap->guarded_sample_rate) + 1; // start at random count between 1 and `sample_rate` + } +} + +mi_decl_export void mi_heap_guarded_set_size_bound(mi_heap_t* heap, size_t min, size_t max) { + heap->guarded_size_min = min; + heap->guarded_size_max = (min > max ? min : max); +} + +void _mi_heap_guarded_init(mi_heap_t* heap) { + mi_heap_guarded_set_sample_rate(heap, + (size_t)mi_option_get_clamp(mi_option_guarded_sample_rate, 0, LONG_MAX), + (size_t)mi_option_get(mi_option_guarded_sample_seed)); + mi_heap_guarded_set_size_bound(heap, + (size_t)mi_option_get_clamp(mi_option_guarded_min, 0, LONG_MAX), + (size_t)mi_option_get_clamp(mi_option_guarded_max, 0, LONG_MAX) ); +} +#else +mi_decl_export void mi_heap_guarded_set_sample_rate(mi_heap_t* heap, size_t sample_rate, size_t seed) { + MI_UNUSED(heap); MI_UNUSED(sample_rate); MI_UNUSED(seed); +} + +mi_decl_export void mi_heap_guarded_set_size_bound(mi_heap_t* heap, size_t min, size_t max) { + MI_UNUSED(heap); MI_UNUSED(min); MI_UNUSED(max); +} +void _mi_heap_guarded_init(mi_heap_t* heap) { + MI_UNUSED(heap); +} +#endif -mi_stats_t _mi_stats_main = { MI_STATS_NULL }; +// Initialize main subproc +static void mi_subproc_main_init(void) { + if (subproc_main.memid.memkind != MI_MEM_STATIC) { + subproc_main.memid = _mi_memid_create(MI_MEM_STATIC); + mi_lock_init(&subproc_main.os_abandoned_pages_lock); + mi_lock_init(&subproc_main.arena_reserve_lock); + } +} +// Initialize main tld +static void mi_tld_main_init(void) { + if (tld_main.thread_id == 0) { + tld_main.thread_id = _mi_prim_thread_id(); + } +} +// Initialization of the (statically allocated) main heap, and the main tld and subproc. static void mi_heap_main_init(void) { - if (_mi_heap_main.cookie == 0) { - _mi_heap_main.thread_id = _mi_thread_id(); - _mi_heap_main.cookie = _mi_os_random_weak((uintptr_t)&mi_heap_main_init); - _mi_random_init(&_mi_heap_main.random); - _mi_heap_main.keys[0] = _mi_heap_random_next(&_mi_heap_main); - _mi_heap_main.keys[1] = _mi_heap_random_next(&_mi_heap_main); + if (heap_main.cookie == 0) { + // heap + heap_main.cookie = 1; + #if defined(__APPLE__) || defined(_WIN32) && !defined(MI_SHARED_LIB) + _mi_random_init_weak(&heap_main.random); // prevent allocation failure during bcrypt dll initialization with static linking + #else + _mi_random_init(&heap_main.random); + #endif + heap_main.cookie = _mi_heap_random_next(&heap_main); + //heap_main.keys[0] = _mi_heap_random_next(&heap_main); + //heap_main.keys[1] = _mi_heap_random_next(&heap_main); + _mi_heap_guarded_init(&heap_main); + heap_main.allow_page_reclaim = (mi_option_get(mi_option_page_reclaim_on_free) >= 0); + heap_main.allow_page_abandon = (mi_option_get(mi_option_page_full_retain) >= 0); + heap_main.page_full_retain = mi_option_get_clamp(mi_option_page_full_retain, -1, 32); + + mi_subproc_main_init(); + mi_tld_main_init(); } } mi_heap_t* _mi_heap_main_get(void) { mi_heap_main_init(); - return &_mi_heap_main; + return &heap_main; } /* ----------------------------------------------------------- - Initialization and freeing of the thread local heaps + Thread local data ----------------------------------------------------------- */ -// note: in x64 in release build `sizeof(mi_thread_data_t)` is under 4KiB (= OS page size). -typedef struct mi_thread_data_s { - mi_heap_t heap; // must come first due to cast in `_mi_heap_done` - mi_tld_t tld; -} mi_thread_data_t; - - -// Thread meta-data is allocated directly from the OS. For -// some programs that do not use thread pools and allocate and -// destroy many OS threads, this may causes too much overhead -// per thread so we maintain a small cache of recently freed metadata. - -#define TD_CACHE_SIZE (8) -static _Atomic(mi_thread_data_t*) td_cache[TD_CACHE_SIZE]; - -static mi_thread_data_t* mi_thread_data_alloc(void) { - // try to find thread metadata in the cache - mi_thread_data_t* td; - for (int i = 0; i < TD_CACHE_SIZE; i++) { - td = mi_atomic_load_ptr_relaxed(mi_thread_data_t, &td_cache[i]); - if (td != NULL) { - td = mi_atomic_exchange_ptr_acq_rel(mi_thread_data_t, &td_cache[i], NULL); - if (td != NULL) { - return td; - } - } +// Count current and total created threads +static _Atomic(size_t) thread_count = MI_ATOMIC_VAR_INIT(1); +static _Atomic(size_t) thread_total_count; + +size_t _mi_current_thread_count(void) { + return mi_atomic_load_relaxed(&thread_count); +} + + +// The mimalloc thread local data +mi_decl_thread mi_tld_t* thread_tld = &tld_empty; + +// Allocate fresh tld +static mi_tld_t* mi_tld_alloc(void) { + mi_atomic_increment_relaxed(&thread_count); + if (_mi_is_main_thread()) { + return &tld_main; } - // if that fails, allocate directly from the OS - td = (mi_thread_data_t*)_mi_os_alloc(sizeof(mi_thread_data_t), &_mi_stats_main); - if (td == NULL) { - // if this fails, try once more. (issue #257) - td = (mi_thread_data_t*)_mi_os_alloc(sizeof(mi_thread_data_t), &_mi_stats_main); - if (td == NULL) { - // really out of memory - _mi_error_message(ENOMEM, "unable to allocate thread local heap metadata (%zu bytes)\n", sizeof(mi_thread_data_t)); + else { + // allocate tld meta-data + // note: we need to be careful to not access the tld from `_mi_meta_zalloc` + // (and in turn from `_mi_arena_alloc_aligned` and `_mi_os_alloc_aligned`). + mi_memid_t memid; + mi_tld_t* tld = (mi_tld_t*)_mi_meta_zalloc(sizeof(mi_tld_t), &memid); + if (tld==NULL) { + _mi_error_message(ENOMEM, "unable to allocate memory for thread local data\n"); + return NULL; } + tld->memid = memid; + tld->heap_backing = NULL; + tld->heaps = NULL; + tld->subproc = &subproc_main; + tld->numa_node = _mi_os_numa_node(); + tld->thread_id = _mi_prim_thread_id(); + tld->thread_seq = mi_atomic_add_acq_rel(&thread_total_count, 1); + tld->is_in_threadpool = _mi_prim_thread_is_in_threadpool(); + return tld; } - return td; -} - -static void mi_thread_data_free( mi_thread_data_t* tdfree ) { - // try to add the thread metadata to the cache - for (int i = 0; i < TD_CACHE_SIZE; i++) { - mi_thread_data_t* td = mi_atomic_load_ptr_relaxed(mi_thread_data_t, &td_cache[i]); - if (td == NULL) { - mi_thread_data_t* expected = NULL; - if (mi_atomic_cas_ptr_weak_acq_rel(mi_thread_data_t, &td_cache[i], &expected, tdfree)) { - return; - } - } +} + +#define MI_TLD_INVALID ((mi_tld_t*)1) + +mi_decl_noinline static void mi_tld_free(mi_tld_t* tld) { + if (tld != NULL && tld != MI_TLD_INVALID) { + _mi_stats_done(&tld->stats); + _mi_meta_free(tld, sizeof(mi_tld_t), tld->memid); + } + #if 0 + // do not read/write to `thread_tld` on older macOS <= 14 as that will re-initialize the thread local storage + // (since we are calling this during pthread shutdown) + // (and this could happen on other systems as well, so let's never do it) + thread_tld = MI_TLD_INVALID; + #endif + mi_atomic_decrement_relaxed(&thread_count); +} + +static mi_tld_t* mi_tld(void) { + mi_tld_t* tld = thread_tld; + if (tld == MI_TLD_INVALID) { + _mi_error_message(EFAULT, "internal error: tld is accessed after the thread terminated\n"); + thread_tld = &tld_empty; + } + if (tld==&tld_empty) { + thread_tld = tld = mi_tld_alloc(); + } + return tld; +} + +mi_subproc_t* _mi_subproc(void) { + // should work without doing initialization (as it may be called from `_mi_tld -> mi_tld_alloc ... -> os_alloc -> _mi_subproc()` + // todo: this will still fail on OS systems where the first access to a thread-local causes allocation. + // on such systems we can check for this with the _mi_prim_get_default_heap as those are protected (by being + // stored in a TLS slot for example) + mi_heap_t* heap = mi_prim_get_default_heap(); + if (heap == NULL) { + return _mi_subproc_main(); + } + else { + return heap->tld->subproc; // avoid using thread local storage (`thread_tld`) + } +} + + +mi_tld_t* _mi_thread_tld(void) mi_attr_noexcept { + // should work without doing initialization (as it may be called from `_mi_tld -> mi_tld_alloc ... -> os_alloc -> _mi_subproc()` + mi_heap_t* heap = mi_prim_get_default_heap(); + if (heap == NULL) { + return &tld_empty; + } + else { + return heap->tld; } - // if that fails, just free it directly - _mi_os_free(tdfree, sizeof(mi_thread_data_t), &_mi_stats_main); -} - -static void mi_thread_data_collect(void) { - // free all thread metadata from the cache - for (int i = 0; i < TD_CACHE_SIZE; i++) { - mi_thread_data_t* td = mi_atomic_load_ptr_relaxed(mi_thread_data_t, &td_cache[i]); - if (td != NULL) { - td = mi_atomic_exchange_ptr_acq_rel(mi_thread_data_t, &td_cache[i], NULL); - if (td != NULL) { - _mi_os_free( td, sizeof(mi_thread_data_t), &_mi_stats_main ); - } +} + +/* ----------------------------------------------------------- + Sub process +----------------------------------------------------------- */ + +mi_subproc_t* _mi_subproc_main(void) { + return &subproc_main; +} + +mi_subproc_id_t mi_subproc_main(void) { + return NULL; +} + +mi_subproc_id_t mi_subproc_new(void) { + mi_memid_t memid; + mi_subproc_t* subproc = (mi_subproc_t*)_mi_meta_zalloc(sizeof(mi_subproc_t),&memid); + if (subproc == NULL) return NULL; + subproc->memid = memid; + mi_lock_init(&subproc->os_abandoned_pages_lock); + mi_lock_init(&subproc->arena_reserve_lock); + return subproc; +} + +mi_subproc_t* _mi_subproc_from_id(mi_subproc_id_t subproc_id) { + return (subproc_id == NULL ? &subproc_main : (mi_subproc_t*)subproc_id); +} + +void mi_subproc_delete(mi_subproc_id_t subproc_id) { + if (subproc_id == NULL) return; + mi_subproc_t* subproc = _mi_subproc_from_id(subproc_id); + // check if there are os pages still.. + bool safe_to_delete = false; + mi_lock(&subproc->os_abandoned_pages_lock) { + if (subproc->os_abandoned_pages == NULL) { + safe_to_delete = true; } } + if (!safe_to_delete) return; + + // merge stats back into the main subproc? + _mi_stats_merge_from(&_mi_subproc_main()->stats, &subproc->stats); + + // safe to release + // todo: should we refcount subprocesses? + mi_lock_done(&subproc->os_abandoned_pages_lock); + mi_lock_done(&subproc->arena_reserve_lock); + _mi_meta_free(subproc, sizeof(mi_subproc_t), subproc->memid); } +void mi_subproc_add_current_thread(mi_subproc_id_t subproc_id) { + mi_tld_t* tld = mi_tld(); + if (tld == NULL) return; + mi_assert(tld->subproc == &subproc_main); + if (tld->subproc != &subproc_main) return; + tld->subproc = _mi_subproc_from_id(subproc_id); +} + + +/* ----------------------------------------------------------- + Allocate heap data +----------------------------------------------------------- */ + // Initialize the thread local default heap, called from `mi_thread_init` -static bool _mi_heap_init(void) { - if (mi_heap_is_initialized(mi_get_default_heap())) return true; +static bool _mi_thread_heap_init(void) { + if (mi_heap_is_initialized(mi_prim_get_default_heap())) return true; if (_mi_is_main_thread()) { - // mi_assert_internal(_mi_heap_main.thread_id != 0); // can happen on freeBSD where alloc is called before any initialization + // mi_assert_internal(heap_main.thread_id != 0); // can happen on freeBSD where alloc is called before any initialization // the main heap is statically allocated mi_heap_main_init(); - _mi_heap_set_default_direct(&_mi_heap_main); - //mi_assert_internal(_mi_heap_default->tld->heap_backing == mi_get_default_heap()); + _mi_heap_set_default_direct(&heap_main); + //mi_assert_internal(_mi_heap_default->tld->heap_backing == mi_prim_get_default_heap()); } else { - // use `_mi_os_alloc` to allocate directly from the OS - mi_thread_data_t* td = mi_thread_data_alloc(); - if (td == NULL) return false; - - // OS allocated so already zero initialized - mi_tld_t* tld = &td->tld; - mi_heap_t* heap = &td->heap; - _mi_memcpy_aligned(tld, &tld_empty, sizeof(*tld)); - _mi_memcpy_aligned(heap, &_mi_heap_empty, sizeof(*heap)); - heap->thread_id = _mi_thread_id(); - _mi_random_init(&heap->random); - heap->cookie = _mi_heap_random_next(heap) | 1; - heap->keys[0] = _mi_heap_random_next(heap); - heap->keys[1] = _mi_heap_random_next(heap); - heap->tld = tld; - tld->heap_backing = heap; - tld->heaps = heap; - tld->segments.stats = &tld->stats; - tld->segments.os = &tld->os; - tld->os.stats = &tld->stats; - _mi_heap_set_default_direct(heap); + // allocates tld data + // note: we cannot access thread-locals yet as that can cause (recursive) allocation + // (on macOS <= 14 for example where the loader allocates thread-local data on demand). + mi_tld_t* tld = mi_tld_alloc(); + + // allocate and initialize the heap + mi_heap_t* heap = _mi_heap_create(0 /* default tag */, false /* allow destroy? */, _mi_arena_id_none(), tld); + + // associate the heap with this thread + // (this is safe, on macOS for example, the heap is set in a dedicated TLS slot and thus does not cause recursive allocation) + _mi_heap_set_default_direct(heap); + + // now that the heap is set for this thread, we can set the thread-local tld. + thread_tld = tld; } return false; } + // Free the thread local default heap (called from `mi_thread_done`) -static bool _mi_heap_done(mi_heap_t* heap) { +static bool _mi_thread_heap_done(mi_heap_t* heap) { if (!mi_heap_is_initialized(heap)) return true; // reset default heap - _mi_heap_set_default_direct(_mi_is_main_thread() ? &_mi_heap_main : (mi_heap_t*)&_mi_heap_empty); + _mi_heap_set_default_direct(_mi_is_main_thread() ? &heap_main : (mi_heap_t*)&_mi_heap_empty); // switch to backing heap heap = heap->tld->heap_backing; @@ -313,30 +488,22 @@ static bool _mi_heap_done(mi_heap_t* heap) { mi_assert_internal(mi_heap_is_backing(heap)); // collect if not the main thread - if (heap != &_mi_heap_main) { + if (heap != &heap_main) { _mi_heap_collect_abandon(heap); } - - // merge stats - _mi_stats_done(&heap->tld->stats); - - // free if not the main thread - if (heap != &_mi_heap_main) { - // the following assertion does not always hold for huge segments as those are always treated - // as abondened: one may allocate it in one thread, but deallocate in another in which case - // the count can be too large or negative. todo: perhaps not count huge segments? see issue #363 - // mi_assert_internal(heap->tld->segments.count == 0 || heap->thread_id != _mi_thread_id()); - mi_thread_data_free((mi_thread_data_t*)heap); - } - else { - mi_thread_data_collect(); // free cached thread metadata - #if 0 + + // free heap meta data + _mi_meta_free(heap, sizeof(mi_heap_t), heap->memid); + + if (heap == &heap_main) { + #if 0 // never free the main thread even in debug mode; if a dll is linked statically with mimalloc, // there may still be delete/free calls after the mi_fls_done is called. Issue #207 _mi_heap_destroy_pages(heap); - mi_assert_internal(heap->tld->heap_backing == &_mi_heap_main); + mi_assert_internal(heap->tld->heap_backing == &heap_main); #endif } + return false; } @@ -350,7 +517,7 @@ static bool _mi_heap_done(mi_heap_t* heap) { // 1. windows dynamic library: // call from DllMain on DLL_THREAD_DETACH // 2. windows static library: -// use `FlsAlloc` to call a destructor when the thread is done +// use special linker section to call a destructor when the thread is done // 3. unix, pthreads: // use a pthread key to call a destructor when a pthread is done // @@ -358,101 +525,74 @@ static bool _mi_heap_done(mi_heap_t* heap) { // to set up the thread local keys. // -------------------------------------------------------- -static void _mi_thread_done(mi_heap_t* default_heap); - -#if defined(_WIN32) && defined(MI_SHARED_LIB) - // nothing to do as it is done in DllMain -#elif defined(_WIN32) && !defined(MI_SHARED_LIB) - // use thread local storage keys to detect thread ending - #include - #include - #if (_WIN32_WINNT < 0x600) // before Windows Vista - WINBASEAPI DWORD WINAPI FlsAlloc( _In_opt_ PFLS_CALLBACK_FUNCTION lpCallback ); - WINBASEAPI PVOID WINAPI FlsGetValue( _In_ DWORD dwFlsIndex ); - WINBASEAPI BOOL WINAPI FlsSetValue( _In_ DWORD dwFlsIndex, _In_opt_ PVOID lpFlsData ); - WINBASEAPI BOOL WINAPI FlsFree(_In_ DWORD dwFlsIndex); - #endif - static DWORD mi_fls_key = (DWORD)(-1); - static void NTAPI mi_fls_done(PVOID value) { - if (value!=NULL) _mi_thread_done((mi_heap_t*)value); - } -#elif defined(MI_USE_PTHREADS) - // use pthread local storage keys to detect thread ending - // (and used with MI_TLS_PTHREADS for the default heap) - pthread_key_t _mi_heap_default_key = (pthread_key_t)(-1); - static void mi_pthread_done(void* value) { - if (value!=NULL) _mi_thread_done((mi_heap_t*)value); - } -#elif defined(__wasi__) -// no pthreads in the WebAssembly Standard Interface -#else - #pragma message("define a way to call mi_thread_done when a thread is done") -#endif - // Set up handlers so `mi_thread_done` is called automatically static void mi_process_setup_auto_thread_done(void) { static bool tls_initialized = false; // fine if it races if (tls_initialized) return; tls_initialized = true; - #if defined(_WIN32) && defined(MI_SHARED_LIB) - // nothing to do as it is done in DllMain - #elif defined(_WIN32) && !defined(MI_SHARED_LIB) - mi_fls_key = FlsAlloc(&mi_fls_done); - #elif defined(MI_USE_PTHREADS) - mi_assert_internal(_mi_heap_default_key == (pthread_key_t)(-1)); - pthread_key_create(&_mi_heap_default_key, &mi_pthread_done); - #endif - _mi_heap_set_default_direct(&_mi_heap_main); + _mi_prim_thread_init_auto_done(); + _mi_heap_set_default_direct(&heap_main); } bool _mi_is_main_thread(void) { - return (_mi_heap_main.thread_id==0 || _mi_heap_main.thread_id == _mi_thread_id()); + return (tld_main.thread_id==0 || tld_main.thread_id == _mi_thread_id()); } -static _Atomic(size_t) thread_count = MI_ATOMIC_VAR_INIT(1); - -size_t _mi_current_thread_count(void) { - return mi_atomic_load_relaxed(&thread_count); -} // This is called from the `mi_malloc_generic` void mi_thread_init(void) mi_attr_noexcept { // ensure our process has started already mi_process_init(); - + // initialize the thread local default heap // (this will call `_mi_heap_set_default_direct` and thus set the // fiber/pthread key to a non-zero value, ensuring `_mi_thread_done` is called) - if (_mi_heap_init()) return; // returns true if already initialized + if (_mi_thread_heap_init()) return; // returns true if already initialized - _mi_stat_increase(&_mi_stats_main.threads, 1); - mi_atomic_increment_relaxed(&thread_count); + mi_subproc_stat_increase(_mi_subproc_main(), threads, 1); //_mi_verbose_message("thread init: 0x%zx\n", _mi_thread_id()); } void mi_thread_done(void) mi_attr_noexcept { - _mi_thread_done(mi_get_default_heap()); + _mi_thread_done(NULL); } -static void _mi_thread_done(mi_heap_t* heap) { - mi_atomic_decrement_relaxed(&thread_count); - _mi_stat_decrease(&_mi_stats_main.threads, 1); +void _mi_thread_done(mi_heap_t* heap) +{ + // calling with NULL implies using the default heap + if (heap == NULL) { + heap = mi_prim_get_default_heap(); + if (heap == NULL) return; + } + + // prevent re-entrancy through heap_done/heap_set_default_direct (issue #699) + if (!mi_heap_is_initialized(heap)) { + return; + } + + // adjust stats + mi_subproc_stat_decrease(_mi_subproc_main(), threads, 1); // check thread-id as on Windows shutdown with FLS the main (exit) thread may call this on thread-local heaps... - if (heap->thread_id != _mi_thread_id()) return; - + if (heap->tld->thread_id != _mi_prim_thread_id()) return; + // abandon the thread local heap - if (_mi_heap_done(heap)) return; // returns true if already ran + // note: we store the tld as we should avoid reading `thread_tld` at this point (to avoid reinitializing the thread local storage) + mi_tld_t* tld = heap->tld; + _mi_thread_heap_done(heap); // returns true if already ran + + // free thread local data + mi_tld_free(tld); } void _mi_heap_set_default_direct(mi_heap_t* heap) { mi_assert_internal(heap != NULL); #if defined(MI_TLS_SLOT) - mi_tls_slot_set(MI_TLS_SLOT,heap); + mi_prim_tls_slot_set(MI_TLS_SLOT,heap); #elif defined(MI_TLS_PTHREAD_SLOT_OFS) - *mi_tls_pthread_heap_slot() = heap; + *mi_prim_tls_pthread_heap_slot() = heap; #elif defined(MI_TLS_PTHREAD) // we use _mi_heap_default_key #else @@ -461,134 +601,133 @@ void _mi_heap_set_default_direct(mi_heap_t* heap) { // ensure the default heap is passed to `_mi_thread_done` // setting to a non-NULL value also ensures `mi_thread_done` is called. - #if defined(_WIN32) && defined(MI_SHARED_LIB) - // nothing to do as it is done in DllMain - #elif defined(_WIN32) && !defined(MI_SHARED_LIB) - mi_assert_internal(mi_fls_key != 0); - FlsSetValue(mi_fls_key, heap); - #elif defined(MI_USE_PTHREADS) - if (_mi_heap_default_key != (pthread_key_t)(-1)) { // can happen during recursive invocation on freeBSD - pthread_setspecific(_mi_heap_default_key, heap); - } - #endif + _mi_prim_thread_associate_default_heap(heap); } +void mi_thread_set_in_threadpool(void) mi_attr_noexcept { + mi_tld_t* tld = mi_tld(); + if (tld!=NULL) { + tld->is_in_threadpool = true; + } +} // -------------------------------------------------------- // Run functions on process init/done, and thread init/done // -------------------------------------------------------- -static void mi_cdecl mi_process_done(void); - static bool os_preloading = true; // true until this module is initialized -static bool mi_redirected = false; // true if malloc redirects to mi_malloc // Returns true if this module has not been initialized; Don't use C runtime routines until it returns false. -bool _mi_preloading(void) { +bool mi_decl_noinline _mi_preloading(void) { return os_preloading; } +// Returns true if mimalloc was redirected mi_decl_nodiscard bool mi_is_redirected(void) mi_attr_noexcept { - return mi_redirected; -} - -// Communicate with the redirection module on Windows -#if defined(_WIN32) && defined(MI_SHARED_LIB) && !defined(MI_WIN_NOREDIRECT) -#ifdef __cplusplus -extern "C" { -#endif -mi_decl_export void _mi_redirect_entry(DWORD reason) { - // called on redirection; careful as this may be called before DllMain - if (reason == DLL_PROCESS_ATTACH) { - mi_redirected = true; - } - else if (reason == DLL_PROCESS_DETACH) { - mi_redirected = false; - } - else if (reason == DLL_THREAD_DETACH) { - mi_thread_done(); - } -} -__declspec(dllimport) bool mi_cdecl mi_allocator_init(const char** message); -__declspec(dllimport) void mi_cdecl mi_allocator_done(void); -#ifdef __cplusplus + return _mi_is_redirected(); } -#endif -#else -static bool mi_allocator_init(const char** message) { - if (message != NULL) *message = NULL; - return true; -} -static void mi_allocator_done(void) { - // nothing to do -} -#endif -// Called once by the process loader -static void mi_process_load(void) { +// Called once by the process loader from `src/prim/prim.c` +void _mi_auto_process_init(void) { mi_heap_main_init(); - #if defined(MI_TLS_RECURSE_GUARD) + #if defined(__APPLE__) || defined(MI_TLS_RECURSE_GUARD) volatile mi_heap_t* dummy = _mi_heap_default; // access TLS to allocate it before setting tls_initialized to true; - MI_UNUSED(dummy); + if (dummy == NULL) return; // use dummy or otherwise the access may get optimized away (issue #697) #endif os_preloading = false; - #if !(defined(_WIN32) && defined(MI_SHARED_LIB)) // use Dll process detach (see below) instead of atexit (issue #521) - atexit(&mi_process_done); - #endif + mi_assert_internal(_mi_is_main_thread()); _mi_options_init(); + mi_process_setup_auto_thread_done(); mi_process_init(); - //mi_stats_reset();- - if (mi_redirected) _mi_verbose_message("malloc is redirected.\n"); + if (_mi_is_redirected()) _mi_verbose_message("malloc is redirected.\n"); // show message from the redirector (if present) const char* msg = NULL; - mi_allocator_init(&msg); + _mi_allocator_init(&msg); if (msg != NULL && (mi_option_is_enabled(mi_option_verbose) || mi_option_is_enabled(mi_option_show_errors))) { _mi_fputs(NULL,NULL,NULL,msg); } + + // reseed random + _mi_random_reinit_if_weak(&heap_main.random); } -#if defined(_WIN32) && (defined(_M_IX86) || defined(_M_X64)) -#include +// CPU features mi_decl_cache_align bool _mi_cpu_has_fsrm = false; +mi_decl_cache_align bool _mi_cpu_has_erms = false; +mi_decl_cache_align bool _mi_cpu_has_popcnt = false; + +#if (MI_ARCH_X64 || MI_ARCH_X86) +#if defined(__GNUC__) +#include +static bool mi_cpuid(uint32_t* regs4, uint32_t level) { + return (__get_cpuid(level, ®s4[0], ®s4[1], ®s4[2], ®s4[3]) == 1); +} + +#elif defined(_MSC_VER) +static bool mi_cpuid(uint32_t* regs4, uint32_t level) { + __cpuid((int32_t*)regs4, (int32_t)level); + return true; +} +#else +static bool mi_cpuid(uint32_t* regs4, uint32_t level) { + MI_UNUSED(regs4); MI_UNUSED(level); + return false; +} +#endif static void mi_detect_cpu_features(void) { - // FSRM for fast rep movsb support (AMD Zen3+ (~2020) or Intel Ice Lake+ (~2017)) - int32_t cpu_info[4]; - __cpuid(cpu_info, 7); - _mi_cpu_has_fsrm = ((cpu_info[3] & (1 << 4)) != 0); // bit 4 of EDX : see + // FSRM for fast short rep movsb/stosb support (AMD Zen3+ (~2020) or Intel Ice Lake+ (~2017)) + // EMRS for fast enhanced rep movsb/stosb support + uint32_t cpu_info[4]; + if (mi_cpuid(cpu_info, 7)) { + _mi_cpu_has_fsrm = ((cpu_info[3] & (1 << 4)) != 0); // bit 4 of EDX : see + _mi_cpu_has_erms = ((cpu_info[1] & (1 << 9)) != 0); // bit 9 of EBX : see + } + if (mi_cpuid(cpu_info, 1)) { + _mi_cpu_has_popcnt = ((cpu_info[2] & (1 << 23)) != 0); // bit 23 of ECX : see + } } + #else static void mi_detect_cpu_features(void) { - // nothing + #if MI_ARCH_ARM64 + _mi_cpu_has_popcnt = true; + #endif } #endif + // Initialize the process; called by thread_init or the process loader void mi_process_init(void) mi_attr_noexcept { // ensure we are called once - if (_mi_process_is_initialized) return; - _mi_verbose_message("process init: 0x%zx\n", _mi_thread_id()); + static mi_atomic_once_t process_init; + #if _MSC_VER < 1920 + mi_heap_main_init(); // vs2017 can dynamically re-initialize heap_main + #endif + if (!mi_atomic_once(&process_init)) return; _mi_process_is_initialized = true; - mi_process_setup_auto_thread_done(); + _mi_verbose_message("process init: 0x%zx\n", _mi_thread_id()); - mi_detect_cpu_features(); + _mi_stats_init(); _mi_os_init(); + _mi_page_map_init(); mi_heap_main_init(); - #if (MI_DEBUG) - _mi_verbose_message("debug level : %d\n", MI_DEBUG); - #endif - _mi_verbose_message("secure level: %d\n", MI_SECURE); + mi_tld_main_init(); + // the following two can potentially allocate (on freeBSD for locks and thread keys) + mi_subproc_main_init(); + mi_process_setup_auto_thread_done(); mi_thread_init(); - #if defined(_WIN32) && !defined(MI_SHARED_LIB) - // When building as a static lib the FLS cleanup happens to early for the main thread. + #if defined(_WIN32) && defined(MI_WIN_USE_FLS) + // On windows, when building as a static lib the FLS cleanup happens to early for the main thread. // To avoid this, set the FLS value for the main thread to NULL so the fls cleanup // will not call _mi_thread_done on the (still executing) main thread. See issue #508. - FlsSetValue(mi_fls_key, NULL); + _mi_prim_thread_associate_default_heap(NULL); #endif - mi_stats_reset(); // only call stat reset *after* thread init (or the heap tld == NULL) + // mi_stats_reset(); // only call stat reset *after* thread init (or the heap tld == NULL) + mi_track_init(); if (mi_option_is_enabled(mi_option_reserve_huge_os_pages)) { size_t pages = mi_option_get_clamp(mi_option_reserve_huge_os_pages, 0, 128*1024); @@ -598,17 +737,17 @@ void mi_process_init(void) mi_attr_noexcept { } else { mi_reserve_huge_os_pages_interleave(pages, 0, pages*500); } - } + } if (mi_option_is_enabled(mi_option_reserve_os_memory)) { long ksize = mi_option_get(mi_option_reserve_os_memory); if (ksize > 0) { - mi_reserve_os_memory((size_t)ksize*MI_KiB, true /* commit? */, true /* allow large pages? */); + mi_reserve_os_memory((size_t)ksize*MI_KiB, true, true); } } } -// Called when the process is done (through `at_exit`) -static void mi_cdecl mi_process_done(void) { +// Called when the process is done (cdecl as it is used with `at_exit` on some platforms) +void mi_cdecl mi_process_done(void) mi_attr_noexcept { // only shutdown if we were initialized if (!_mi_process_is_initialized) return; // ensure we are called once @@ -616,80 +755,43 @@ static void mi_cdecl mi_process_done(void) { if (process_done) return; process_done = true; - #if defined(_WIN32) && !defined(MI_SHARED_LIB) - FlsFree(mi_fls_key); // call thread-done on all threads (except the main thread) to prevent dangling callback pointer if statically linked with a DLL; Issue #208 - #endif - + // get the default heap so we don't need to acces thread locals anymore + mi_heap_t* heap = mi_prim_get_default_heap(); // use prim to not initialize any heap + mi_assert_internal(heap != NULL); + + // release any thread specific resources and ensure _mi_thread_done is called on all but the main thread + _mi_prim_thread_done_auto_done(); + + #ifndef MI_SKIP_COLLECT_ON_EXIT - #if (MI_DEBUG != 0) || !defined(MI_SHARED_LIB) + #if (MI_DEBUG || !defined(MI_SHARED_LIB)) // free all memory if possible on process exit. This is not needed for a stand-alone process // but should be done if mimalloc is statically linked into another shared library which // is repeatedly loaded/unloaded, see issue #281. - mi_collect(true /* force */ ); + mi_heap_collect(heap, true /* force */ ); #endif #endif + // Forcefully release all retained memory; this can be dangerous in general if overriding regular malloc/free + // since after process_done there might still be other code running that calls `free` (like at_exit routines, + // or C-runtime termination code. + if (mi_option_is_enabled(mi_option_destroy_on_exit)) { + mi_heap_collect(heap, true /* force */); + _mi_heap_unsafe_destroy_all(heap); // forcefully release all memory held by all heaps (of this thread only!) + _mi_arenas_unsafe_destroy_all(heap->tld); + _mi_page_map_unsafe_destroy(_mi_subproc_main()); + } + //_mi_page_map_unsafe_destroy(_mi_subproc_main()); + if (mi_option_is_enabled(mi_option_show_stats) || mi_option_is_enabled(mi_option_verbose)) { - mi_stats_print(NULL); + _mi_stats_print(&_mi_subproc_main()->stats, NULL, NULL); // use always main subproc at process exit to avoid dereferencing the heap (as it may be destroyed by now) } - mi_allocator_done(); - _mi_verbose_message("process done: 0x%zx\n", _mi_heap_main.thread_id); + _mi_allocator_done(); + _mi_verbose_message("process done: 0x%zx\n", tld_main.thread_id); os_preloading = true; // don't call the C runtime anymore } - - -#if defined(_WIN32) && defined(MI_SHARED_LIB) - // Windows DLL: easy to hook into process_init and thread_done - __declspec(dllexport) BOOL WINAPI DllMain(HINSTANCE inst, DWORD reason, LPVOID reserved) { - MI_UNUSED(reserved); - MI_UNUSED(inst); - if (reason==DLL_PROCESS_ATTACH) { - mi_process_load(); - } - else if (reason==DLL_PROCESS_DETACH) { - mi_process_done(); - } - else if (reason==DLL_THREAD_DETACH) { - if (!mi_is_redirected()) { - mi_thread_done(); - } - } - return TRUE; - } - -#elif defined(_MSC_VER) - // MSVC: use data section magic for static libraries - // See - static int _mi_process_init(void) { - mi_process_load(); - return 0; - } - typedef int(*_mi_crt_callback_t)(void); - #if defined(_M_X64) || defined(_M_ARM64) - __pragma(comment(linker, "/include:" "_mi_msvc_initu")) - #pragma section(".CRT$XIU", long, read) - #else - __pragma(comment(linker, "/include:" "__mi_msvc_initu")) - #endif - #pragma data_seg(".CRT$XIU") - mi_decl_externc _mi_crt_callback_t _mi_msvc_initu[] = { &_mi_process_init }; - #pragma data_seg() - -#elif defined(__cplusplus) - // C++: use static initialization to detect process start - static bool _mi_process_init(void) { - mi_process_load(); - return (_mi_heap_main.thread_id != 0); - } - static bool mi_initialized = _mi_process_init(); - -#elif defined(__GNUC__) || defined(__clang__) - // GCC,Clang: use the constructor attribute - static void __attribute__((constructor)) _mi_process_init(void) { - mi_process_load(); - } - -#else -#pragma message("define a way to call mi_process_load on your platform") -#endif +void mi_cdecl _mi_auto_process_done(void) mi_attr_noexcept { + if (_mi_option_get_fast(mi_option_destroy_on_exit)>1) return; + mi_process_done(); +} diff --git a/src/dashbls/depends/mimalloc/src/libc.c b/src/dashbls/depends/mimalloc/src/libc.c new file mode 100644 index 000000000000..b40d1204d3bb --- /dev/null +++ b/src/dashbls/depends/mimalloc/src/libc.c @@ -0,0 +1,417 @@ +/* ---------------------------------------------------------------------------- +Copyright (c) 2018-2024, Microsoft Research, Daan Leijen +This is free software; you can redistribute it and/or modify it under the +terms of the MIT license. A copy of the license can be found in the file +"LICENSE" at the root of this distribution. +-----------------------------------------------------------------------------*/ + +// -------------------------------------------------------- +// This module defines various std libc functions to reduce +// the dependency on libc, and also prevent errors caused +// by some libc implementations when called before `main` +// executes (due to malloc redirection) +// -------------------------------------------------------- + +#include "mimalloc.h" +#include "mimalloc/internal.h" +#include "mimalloc/prim.h" // mi_prim_getenv + +char _mi_toupper(char c) { + if (c >= 'a' && c <= 'z') return (c - 'a' + 'A'); + else return c; +} + +int _mi_strnicmp(const char* s, const char* t, size_t n) { + if (n == 0) return 0; + for (; *s != 0 && *t != 0 && n > 0; s++, t++, n--) { + if (_mi_toupper(*s) != _mi_toupper(*t)) break; + } + return (n == 0 ? 0 : *s - *t); +} + +void _mi_strlcpy(char* dest, const char* src, size_t dest_size) { + if (dest==NULL || src==NULL || dest_size == 0) return; + // copy until end of src, or when dest is (almost) full + while (*src != 0 && dest_size > 1) { + *dest++ = *src++; + dest_size--; + } + // always zero terminate + *dest = 0; +} + +void _mi_strlcat(char* dest, const char* src, size_t dest_size) { + if (dest==NULL || src==NULL || dest_size == 0) return; + // find end of string in the dest buffer + while (*dest != 0 && dest_size > 1) { + dest++; + dest_size--; + } + // and catenate + _mi_strlcpy(dest, src, dest_size); +} + +size_t _mi_strlen(const char* s) { + if (s==NULL) return 0; + size_t len = 0; + while(s[len] != 0) { len++; } + return len; +} + +size_t _mi_strnlen(const char* s, size_t max_len) { + if (s==NULL) return 0; + size_t len = 0; + while(s[len] != 0 && len < max_len) { len++; } + return len; +} + +#ifdef MI_NO_GETENV +bool _mi_getenv(const char* name, char* result, size_t result_size) { + MI_UNUSED(name); + MI_UNUSED(result); + MI_UNUSED(result_size); + return false; +} +#else +bool _mi_getenv(const char* name, char* result, size_t result_size) { + if (name==NULL || result == NULL || result_size < 64) return false; + return _mi_prim_getenv(name,result,result_size); +} +#endif + +// -------------------------------------------------------- +// Define our own limited `_mi_vsnprintf` and `_mi_snprintf` +// This is mostly to avoid calling these when libc is not yet +// initialized (and to reduce dependencies) +// +// format: d i, p x u, s +// prec: z l ll L +// width: 10 +// align-left: - +// fill: 0 +// plus: + +// -------------------------------------------------------- + +static void mi_outc(char c, char** out, char* end) { + char* p = *out; + if (p >= end) return; + *p = c; + *out = p + 1; +} + +static void mi_outs(const char* s, char** out, char* end) { + if (s == NULL) return; + char* p = *out; + while (*s != 0 && p < end) { + *p++ = *s++; + } + *out = p; +} + +static void mi_out_fill(char fill, size_t len, char** out, char* end) { + char* p = *out; + for (size_t i = 0; i < len && p < end; i++) { + *p++ = fill; + } + *out = p; +} + +static void mi_out_alignright(char fill, char* start, size_t len, size_t extra, char* end) { + if (len == 0 || extra == 0) return; + if (start + len + extra >= end) return; + // move `len` characters to the right (in reverse since it can overlap) + for (size_t i = 1; i <= len; i++) { + start[len + extra - i] = start[len - i]; + } + // and fill the start + for (size_t i = 0; i < extra; i++) { + start[i] = fill; + } +} + + +static void mi_out_num(uintmax_t x, size_t base, char prefix, char** out, char* end) +{ + if (x == 0 || base == 0 || base > 16) { + if (prefix != 0) { mi_outc(prefix, out, end); } + mi_outc('0',out,end); + } + else { + // output digits in reverse + char* start = *out; + while (x > 0) { + char digit = (char)(x % base); + mi_outc((digit <= 9 ? '0' + digit : 'A' + digit - 10),out,end); + x = x / base; + } + if (prefix != 0) { + mi_outc(prefix, out, end); + } + size_t len = *out - start; + // and reverse in-place + for (size_t i = 0; i < (len / 2); i++) { + char c = start[len - i - 1]; + start[len - i - 1] = start[i]; + start[i] = c; + } + } +} + + +#define MI_NEXTC() c = *in; if (c==0) break; in++; + +int _mi_vsnprintf(char* buf, size_t bufsize, const char* fmt, va_list args) { + if (buf == NULL || bufsize == 0 || fmt == NULL) return 0; + buf[bufsize - 1] = 0; + char* const end = buf + (bufsize - 1); + const char* in = fmt; + char* out = buf; + while (true) { + if (out >= end) break; + char c; + MI_NEXTC(); + if (c != '%') { + if (c == '\\') { + MI_NEXTC(); + switch (c) { + case 'e': mi_outc('\x1B', &out, end); break; + case 't': mi_outc('\t', &out, end); break; + case 'n': mi_outc('\n', &out, end); break; + case 'r': mi_outc('\r', &out, end); break; + case '\\': mi_outc('\\', &out, end); break; + default: /* ignore */ break; + } + } + else if ((c >= ' ' && c <= '~') || c=='\n' || c=='\r' || c=='\t' || c=='\x1b') { // output visible ascii or standard control only + mi_outc(c, &out, end); + } + } + else { + MI_NEXTC(); + char fill = ' '; + size_t width = 0; + char numtype = 'd'; + char numplus = 0; + bool alignright = true; + if (c == '+' || c == ' ') { numplus = c; MI_NEXTC(); } + if (c == '-') { alignright = false; MI_NEXTC(); } + if (c == '0') { fill = '0'; MI_NEXTC(); } + if (c >= '1' && c <= '9') { + width = (c - '0'); MI_NEXTC(); + while (c >= '0' && c <= '9') { + width = (10 * width) + (c - '0'); MI_NEXTC(); + } + if (c == 0) break; // extra check due to while + } + if (c == 'z' || c == 't' || c == 'L') { numtype = c; MI_NEXTC(); } + else if (c == 'l') { + numtype = c; MI_NEXTC(); + if (c == 'l') { numtype = 'L'; MI_NEXTC(); } + } + + char* start = out; + if (c == '%') { + mi_outc('%', &out, end); + } + else if (c == 's') { + // string + const char* s = va_arg(args, const char*); + mi_outs(s, &out, end); + } + else if (c == 'p' || c == 'x' || c == 'u') { + // unsigned + uintmax_t x = 0; + if (c == 'x' || c == 'u') { + if (numtype == 'z') x = va_arg(args, size_t); + else if (numtype == 't') x = va_arg(args, uintptr_t); // unsigned ptrdiff_t + else if (numtype == 'L') x = va_arg(args, unsigned long long); + else if (numtype == 'l') x = va_arg(args, unsigned long); + else x = va_arg(args, unsigned int); + } + else if (c == 'p') { + x = va_arg(args, uintptr_t); + mi_outs("0x", &out, end); + start = out; + width = (width >= 2 ? width - 2 : 0); + } + if (width == 0 && (c == 'x' || c == 'p')) { + if (c == 'p') { width = 2 * (x <= UINT32_MAX ? 4 : ((x >> 16) <= UINT32_MAX ? 6 : sizeof(void*))); } + if (width == 0) { width = 2; } + fill = '0'; + } + mi_out_num(x, (c == 'x' || c == 'p' ? 16 : 10), numplus, &out, end); + } + else if (c == 'i' || c == 'd') { + // signed + intmax_t x = 0; + if (numtype == 'z') x = va_arg(args, intptr_t ); + else if (numtype == 't') x = va_arg(args, ptrdiff_t); + else if (numtype == 'L') x = va_arg(args, long long); + else if (numtype == 'l') x = va_arg(args, long); + else x = va_arg(args, int); + char pre = 0; + if (x < 0) { + pre = '-'; + if (x > INTMAX_MIN) { x = -x; } + } + else if (numplus != 0) { + pre = numplus; + } + mi_out_num((uintmax_t)x, 10, pre, &out, end); + } + else if (c >= ' ' && c <= '~') { + // unknown format + mi_outc('%', &out, end); + mi_outc(c, &out, end); + } + + // fill & align + mi_assert_internal(out <= end); + mi_assert_internal(out >= start); + const size_t len = out - start; + if (len < width) { + mi_out_fill(fill, width - len, &out, end); + if (alignright && out <= end) { + mi_out_alignright(fill, start, len, width - len, end); + } + } + } + } + mi_assert_internal(out <= end); + *out = 0; + return (int)(out - buf); +} + +int _mi_snprintf(char* buf, size_t buflen, const char* fmt, ...) { + va_list args; + va_start(args, fmt); + const int written = _mi_vsnprintf(buf, buflen, fmt, args); + va_end(args); + return written; +} + + + +// -------------------------------------------------------- +// generic trailing and leading zero count, and popcount +// -------------------------------------------------------- + +#if !MI_HAS_FAST_BITSCAN + +static size_t mi_ctz_generic32(uint32_t x) { + // de Bruijn multiplication, see + static const uint8_t debruijn[32] = { + 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, + 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9 + }; + if (x==0) return 32; + return debruijn[(uint32_t)((x & -(int32_t)x) * (uint32_t)(0x077CB531U)) >> 27]; +} + +static size_t mi_clz_generic32(uint32_t x) { + // de Bruijn multiplication, see + static const uint8_t debruijn[32] = { + 31, 22, 30, 21, 18, 10, 29, 2, 20, 17, 15, 13, 9, 6, 28, 1, + 23, 19, 11, 3, 16, 14, 7, 24, 12, 4, 8, 25, 5, 26, 27, 0 + }; + if (x==0) return 32; + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + x |= x >> 8; + x |= x >> 16; + return debruijn[(uint32_t)(x * (uint32_t)(0x07C4ACDDU)) >> 27]; +} + +size_t _mi_ctz_generic(size_t x) { + if (x==0) return MI_SIZE_BITS; + #if (MI_SIZE_BITS <= 32) + return mi_ctz_generic32((uint32_t)x); + #else + const uint32_t lo = (uint32_t)x; + if (lo != 0) { + return mi_ctz_generic32(lo); + } + else { + return (32 + mi_ctz_generic32((uint32_t)(x>>32))); + } + #endif +} + +size_t _mi_clz_generic(size_t x) { + if (x==0) return MI_SIZE_BITS; + #if (MI_SIZE_BITS <= 32) + return mi_clz_generic32((uint32_t)x); + #else + const uint32_t hi = (uint32_t)(x>>32); + if (hi != 0) { + return mi_clz_generic32(hi); + } + else { + return 32 + mi_clz_generic32((uint32_t)x); + } + #endif +} + +#endif // bit scan + + +#if MI_SIZE_SIZE == 4 +#define mi_mask_even_bits32 (0x55555555) +#define mi_mask_even_pairs32 (0x33333333) +#define mi_mask_even_nibbles32 (0x0F0F0F0F) + +// sum of all the bytes in `x` if it is guaranteed that the sum < 256! +static size_t mi_byte_sum32(uint32_t x) { + // perform `x * 0x01010101`: the highest byte contains the sum of all bytes. + x += (x << 8); + x += (x << 16); + return (size_t)(x >> 24); +} + +static size_t mi_popcount_generic32(uint32_t x) { + // first count each 2-bit group `a`, where: a==0b00 -> 00, a==0b01 -> 01, a==0b10 -> 01, a==0b11 -> 10 + // in other words, `a - (a>>1)`; to do this in parallel, we need to mask to prevent spilling a bit pair + // into the lower bit-pair: + x = x - ((x >> 1) & mi_mask_even_bits32); + // add the 2-bit pair results + x = (x & mi_mask_even_pairs32) + ((x >> 2) & mi_mask_even_pairs32); + // add the 4-bit nibble results + x = (x + (x >> 4)) & mi_mask_even_nibbles32; + // each byte now has a count of its bits, we can sum them now: + return mi_byte_sum32(x); +} + +mi_decl_noinline size_t _mi_popcount_generic(size_t x) { + if (x<=1) return x; + if (~x==0) return MI_SIZE_BITS; + return mi_popcount_generic32(x); +} + +#else +#define mi_mask_even_bits64 (0x5555555555555555) +#define mi_mask_even_pairs64 (0x3333333333333333) +#define mi_mask_even_nibbles64 (0x0F0F0F0F0F0F0F0F) + +// sum of all the bytes in `x` if it is guaranteed that the sum < 256! +static size_t mi_byte_sum64(uint64_t x) { + x += (x << 8); + x += (x << 16); + x += (x << 32); + return (size_t)(x >> 56); +} + +static size_t mi_popcount_generic64(uint64_t x) { + x = x - ((x >> 1) & mi_mask_even_bits64); + x = (x & mi_mask_even_pairs64) + ((x >> 2) & mi_mask_even_pairs64); + x = (x + (x >> 4)) & mi_mask_even_nibbles64; + return mi_byte_sum64(x); +} + +mi_decl_noinline size_t _mi_popcount_generic(size_t x) { + if (x<=1) return x; + if (~x==0) return MI_SIZE_BITS; + return mi_popcount_generic64(x); +} +#endif + diff --git a/src/dashbls/depends/mimalloc/src/options.c b/src/dashbls/depends/mimalloc/src/options.c index 367bc0d27784..540d9f36c271 100644 --- a/src/dashbls/depends/mimalloc/src/options.c +++ b/src/dashbls/depends/mimalloc/src/options.c @@ -5,19 +5,12 @@ terms of the MIT license. A copy of the license can be found in the file "LICENSE" at the root of this distribution. -----------------------------------------------------------------------------*/ #include "mimalloc.h" -#include "mimalloc-internal.h" -#include "mimalloc-atomic.h" - -#include -#include // strtol -#include // strncpy, strncat, strlen, strstr -#include // toupper -#include - -#ifdef _MSC_VER -#pragma warning(disable:4996) // strncpy, strncat -#endif +#include "mimalloc/internal.h" +#include "mimalloc/atomic.h" +#include "mimalloc/prim.h" // mi_prim_out_stderr +#include // stdin/stdout +#include // abort static long mi_max_error_count = 16; // stop outputting errors after this (use < 0 for no limit) static long mi_max_warning_count = 16; // stop outputting warnings after this (use < 0 for no limit) @@ -28,9 +21,6 @@ int mi_version(void) mi_attr_noexcept { return MI_MALLOC_VERSION; } -#ifdef _WIN32 -#include -#endif // -------------------------------------------------------- // Options @@ -38,89 +28,238 @@ int mi_version(void) mi_attr_noexcept { // concurrently initialized, but an initializing data race // is ok since they resolve to the same value. // -------------------------------------------------------- -typedef enum mi_init_e { - UNINIT, // not yet initialized - DEFAULTED, // not found in the environment, use default value - INITIALIZED // found in environment or set explicitly -} mi_init_t; - -typedef struct mi_option_desc_s { - long value; // the value - mi_init_t init; // is it initialized yet? (from the environment) - mi_option_t option; // for debugging: the option index should match the option - const char* name; // option name without `mimalloc_` prefix - const char* legacy_name; // potential legacy v1.x option name -} mi_option_desc_t; + #define MI_OPTION(opt) mi_option_##opt, #opt, NULL #define MI_OPTION_LEGACY(opt,legacy) mi_option_##opt, #opt, #legacy -static mi_option_desc_t options[_mi_option_last] = +// Some options can be set at build time for statically linked libraries +// (use `-DMI_EXTRA_CPPDEFS="opt1=val1;opt2=val2"`) +// +// This is useful if we cannot pass them as environment variables +// (and setting them programmatically would be too late) + +#ifndef MI_DEFAULT_VERBOSE +#define MI_DEFAULT_VERBOSE 0 +#endif + +#ifndef MI_DEFAULT_EAGER_COMMIT +#define MI_DEFAULT_EAGER_COMMIT 1 +#endif + +#ifndef MI_DEFAULT_ARENA_EAGER_COMMIT +#define MI_DEFAULT_ARENA_EAGER_COMMIT 2 +#endif + +// in KiB +#ifndef MI_DEFAULT_ARENA_RESERVE + #if (MI_INTPTR_SIZE>4) + #define MI_DEFAULT_ARENA_RESERVE 1024L*1024L + #else + #define MI_DEFAULT_ARENA_RESERVE 128L*1024L + #endif +#endif + +#ifndef MI_DEFAULT_DISALLOW_ARENA_ALLOC +#define MI_DEFAULT_DISALLOW_ARENA_ALLOC 0 +#endif + +#ifndef MI_DEFAULT_ALLOW_LARGE_OS_PAGES +#if defined(__linux__) && !defined(__ANDROID__) +#define MI_DEFAULT_ALLOW_LARGE_OS_PAGES 2 // enabled, but only use transparent huge pages through madvise +#else +#define MI_DEFAULT_ALLOW_LARGE_OS_PAGES 0 +#endif +#endif + +#ifndef MI_DEFAULT_RESERVE_HUGE_OS_PAGES +#define MI_DEFAULT_RESERVE_HUGE_OS_PAGES 0 +#endif + +#ifndef MI_DEFAULT_RESERVE_OS_MEMORY +#define MI_DEFAULT_RESERVE_OS_MEMORY 0 +#endif + +#ifndef MI_DEFAULT_GUARDED_SAMPLE_RATE +#if MI_GUARDED +#define MI_DEFAULT_GUARDED_SAMPLE_RATE 4000 +#else +#define MI_DEFAULT_GUARDED_SAMPLE_RATE 0 +#endif +#endif + +#ifndef MI_DEFAULT_PAGEMAP_COMMIT +#if defined(__APPLE__) // when overloading malloc, we still get mixed pointers sometimes on macOS; this avoids a bad access +#define MI_DEFAULT_PAGEMAP_COMMIT 1 +#else +#define MI_DEFAULT_PAGEMAP_COMMIT 0 +#endif +#endif + +#ifndef MI_DEFAULT_PAGE_MAX_RECLAIM +#define MI_DEFAULT_PAGE_MAX_RECLAIM (-1) // unlimited +#endif + +#ifndef MI_DEFAULT_PAGE_CROSS_THREAD_MAX_RECLAIM +#define MI_DEFAULT_PAGE_CROSS_THREAD_MAX_RECLAIM 32 +#endif + +// Static options +static mi_option_desc_t mi_options[_mi_option_last] = { // stable options - #if MI_DEBUG || defined(MI_SHOW_ERRORS) - { 1, UNINIT, MI_OPTION(show_errors) }, - #else - { 0, UNINIT, MI_OPTION(show_errors) }, - #endif - { 0, UNINIT, MI_OPTION(show_stats) }, - { 0, UNINIT, MI_OPTION(verbose) }, - - // Some of the following options are experimental and not all combinations are valid. Use with care. - { 1, UNINIT, MI_OPTION(eager_commit) }, // commit per segment directly (8MiB) (but see also `eager_commit_delay`) - { 0, UNINIT, MI_OPTION(deprecated_eager_region_commit) }, - { 0, UNINIT, MI_OPTION(deprecated_reset_decommits) }, - { 0, UNINIT, MI_OPTION(large_os_pages) }, // use large OS pages, use only with eager commit to prevent fragmentation of VMA's - { 0, UNINIT, MI_OPTION(reserve_huge_os_pages) }, // per 1GiB huge pages - { -1, UNINIT, MI_OPTION(reserve_huge_os_pages_at) }, // reserve huge pages at node N - { 0, UNINIT, MI_OPTION(reserve_os_memory) }, - { 0, UNINIT, MI_OPTION(deprecated_segment_cache) }, // cache N segments per thread - { 0, UNINIT, MI_OPTION(page_reset) }, // reset page memory on free - { 0, UNINIT, MI_OPTION_LEGACY(abandoned_page_decommit, abandoned_page_reset) },// decommit free page memory when a thread terminates - { 0, UNINIT, MI_OPTION(deprecated_segment_reset) }, - #if defined(__NetBSD__) - { 0, UNINIT, MI_OPTION(eager_commit_delay) }, // the first N segments per thread are not eagerly committed - #elif defined(_WIN32) - { 4, UNINIT, MI_OPTION(eager_commit_delay) }, // the first N segments per thread are not eagerly committed (but per page in the segment on demand) - #else - { 1, UNINIT, MI_OPTION(eager_commit_delay) }, // the first N segments per thread are not eagerly committed (but per page in the segment on demand) - #endif - { 25, UNINIT, MI_OPTION_LEGACY(decommit_delay, reset_delay) }, // page decommit delay in milli-seconds - { 0, UNINIT, MI_OPTION(use_numa_nodes) }, // 0 = use available numa nodes, otherwise use at most N nodes. - { 0, UNINIT, MI_OPTION(limit_os_alloc) }, // 1 = do not use OS memory for allocation (but only reserved arenas) - { 100, UNINIT, MI_OPTION(os_tag) }, // only apple specific for now but might serve more or less related purpose - { 16, UNINIT, MI_OPTION(max_errors) }, // maximum errors that are output - { 16, UNINIT, MI_OPTION(max_warnings) }, // maximum warnings that are output - { 8, UNINIT, MI_OPTION(max_segment_reclaim)},// max. number of segment reclaims from the abandoned segments per try. - { 1, UNINIT, MI_OPTION(allow_decommit) }, // decommit slices when no longer used (after decommit_delay milli-seconds) - { 500, UNINIT, MI_OPTION(segment_decommit_delay) }, // decommit delay in milli-seconds for freed segments - { 2, UNINIT, MI_OPTION(decommit_extend_delay) } +#if MI_DEBUG || defined(MI_SHOW_ERRORS) + { 1, MI_OPTION_UNINIT, MI_OPTION(show_errors) }, +#else + { 0, MI_OPTION_UNINIT, MI_OPTION(show_errors) }, +#endif + { 0, MI_OPTION_UNINIT, MI_OPTION(show_stats) }, + { MI_DEFAULT_VERBOSE, MI_OPTION_UNINIT, MI_OPTION(verbose) }, + + // some of the following options are experimental and not all combinations are allowed. + { MI_DEFAULT_EAGER_COMMIT, + MI_OPTION_UNINIT, MI_OPTION(eager_commit) }, // commit per segment directly (4MiB) (but see also `eager_commit_delay`) + { MI_DEFAULT_ARENA_EAGER_COMMIT, + MI_OPTION_UNINIT, MI_OPTION_LEGACY(arena_eager_commit,eager_region_commit) }, // eager commit arena's? 2 is used to enable this only on an OS that has overcommit (i.e. linux) + { 1, MI_OPTION_UNINIT, MI_OPTION_LEGACY(purge_decommits,reset_decommits) }, // purge decommits memory (instead of reset) (note: on linux this uses MADV_DONTNEED for decommit) + { MI_DEFAULT_ALLOW_LARGE_OS_PAGES, + MI_OPTION_UNINIT, MI_OPTION_LEGACY(allow_large_os_pages,large_os_pages) }, // use large OS pages, use only with eager commit to prevent fragmentation of VMA's + { MI_DEFAULT_RESERVE_HUGE_OS_PAGES, + MI_OPTION_UNINIT, MI_OPTION(reserve_huge_os_pages) }, // per 1GiB huge pages + {-1, MI_OPTION_UNINIT, MI_OPTION(reserve_huge_os_pages_at) }, // reserve huge pages at node N + { MI_DEFAULT_RESERVE_OS_MEMORY, + MI_OPTION_UNINIT, MI_OPTION(reserve_os_memory) }, // reserve N KiB OS memory in advance (use `option_get_size`) + { 0, MI_OPTION_UNINIT, MI_OPTION(deprecated_segment_cache) }, // cache N segments per thread + { 0, MI_OPTION_UNINIT, MI_OPTION(deprecated_page_reset) }, // reset page memory on free + { 0, MI_OPTION_UNINIT, MI_OPTION(abandoned_page_purge) }, // purge free page memory when a thread terminates + { 0, MI_OPTION_UNINIT, MI_OPTION(deprecated_segment_reset) }, // reset segment memory on free (needs eager commit) +#if defined(__NetBSD__) + { 0, MI_OPTION_UNINIT, MI_OPTION(eager_commit_delay) }, // the first N segments per thread are not eagerly committed +#else + { 1, MI_OPTION_UNINIT, MI_OPTION(eager_commit_delay) }, // the first N segments per thread are not eagerly committed (but per page in the segment on demand) +#endif + { 1000,MI_OPTION_UNINIT, MI_OPTION_LEGACY(purge_delay,reset_delay) }, // purge delay in milli-seconds + { 0, MI_OPTION_UNINIT, MI_OPTION(use_numa_nodes) }, // 0 = use available numa nodes, otherwise use at most N nodes. + { 0, MI_OPTION_UNINIT, MI_OPTION_LEGACY(disallow_os_alloc,limit_os_alloc) }, // 1 = do not use OS memory for allocation (but only reserved arenas) + { 100, MI_OPTION_UNINIT, MI_OPTION(os_tag) }, // only apple specific for now but might serve more or less related purpose + { 32, MI_OPTION_UNINIT, MI_OPTION(max_errors) }, // maximum errors that are output + { 32, MI_OPTION_UNINIT, MI_OPTION(max_warnings) }, // maximum warnings that are output + { 10, MI_OPTION_UNINIT, MI_OPTION(deprecated_max_segment_reclaim)}, // max. percentage of the abandoned segments to be reclaimed per try. + { 0, MI_OPTION_UNINIT, MI_OPTION(destroy_on_exit)}, // release all OS memory on process exit; careful with dangling pointer or after-exit frees! + { MI_DEFAULT_ARENA_RESERVE, MI_OPTION_UNINIT, MI_OPTION(arena_reserve) }, // reserve memory N KiB at a time (=1GiB) (use `option_get_size`) + { 1, MI_OPTION_UNINIT, MI_OPTION(arena_purge_mult) }, // purge delay multiplier for arena's + { 1, MI_OPTION_UNINIT, MI_OPTION_LEGACY(deprecated_purge_extend_delay, decommit_extend_delay) }, + { MI_DEFAULT_DISALLOW_ARENA_ALLOC, MI_OPTION_UNINIT, MI_OPTION(disallow_arena_alloc) }, // 1 = do not use arena's for allocation (except if using specific arena id's) + { 400, MI_OPTION_UNINIT, MI_OPTION(retry_on_oom) }, // windows only: retry on out-of-memory for N milli seconds (=400), set to 0 to disable retries. +#if defined(MI_VISIT_ABANDONED) + { 1, MI_OPTION_INITIALIZED, MI_OPTION(visit_abandoned) }, // allow visiting heap blocks in abandoned segments; requires taking locks during reclaim. +#else + { 0, MI_OPTION_UNINIT, MI_OPTION(visit_abandoned) }, +#endif + { 0, MI_OPTION_UNINIT, MI_OPTION(guarded_min) }, // only used when building with MI_GUARDED: minimal rounded object size for guarded objects + { MI_GiB, MI_OPTION_UNINIT, MI_OPTION(guarded_max) }, // only used when building with MI_GUARDED: maximal rounded object size for guarded objects + { 0, MI_OPTION_UNINIT, MI_OPTION(guarded_precise) }, // disregard minimal alignment requirement to always place guarded blocks exactly in front of a guard page (=0) + { MI_DEFAULT_GUARDED_SAMPLE_RATE, + MI_OPTION_UNINIT, MI_OPTION(guarded_sample_rate)}, // 1 out of N allocations in the min/max range will be guarded (=4000) + { 0, MI_OPTION_UNINIT, MI_OPTION(guarded_sample_seed)}, + { 10000, MI_OPTION_UNINIT, MI_OPTION(generic_collect) }, // collect heaps every N (=10000) generic allocation calls + { 0, MI_OPTION_UNINIT, MI_OPTION_LEGACY(page_reclaim_on_free, abandoned_reclaim_on_free) },// reclaim abandoned (small) pages on a free: -1 = disable completely, 0 = only reclaim into the originating heap, 1 = reclaim on free across heaps + { 2, MI_OPTION_UNINIT, MI_OPTION(page_full_retain) }, // number of (small) pages to retain in the free page queues + { 4, MI_OPTION_UNINIT, MI_OPTION(page_max_candidates) }, // max search to find a best page candidate + { 0, MI_OPTION_UNINIT, MI_OPTION(max_vabits) }, // max virtual address space bits + { MI_DEFAULT_PAGEMAP_COMMIT, + MI_OPTION_UNINIT, MI_OPTION(pagemap_commit) }, // commit the full pagemap upfront? + { 0, MI_OPTION_UNINIT, MI_OPTION(page_commit_on_demand) }, // commit pages on-demand (2 disables this only on overcommit systems (like Linux)) + { MI_DEFAULT_PAGE_MAX_RECLAIM, + MI_OPTION_UNINIT, MI_OPTION(page_max_reclaim) }, // don't reclaim (small) pages of the same originating heap if we already own N pages in that size class + { MI_DEFAULT_PAGE_CROSS_THREAD_MAX_RECLAIM, + MI_OPTION_UNINIT, MI_OPTION(page_cross_thread_max_reclaim) }, // don't reclaim (small) pages across threads if we already own N pages in that size class }; static void mi_option_init(mi_option_desc_t* desc); +static bool mi_option_has_size_in_kib(mi_option_t option) { + return (option == mi_option_reserve_os_memory || option == mi_option_arena_reserve); +} + void _mi_options_init(void) { - // called on process load; should not be called before the CRT is initialized! - // (e.g. do not call this from process_init as that may run before CRT initialization) + // called on process load mi_add_stderr_output(); // now it safe to use stderr for output for(int i = 0; i < _mi_option_last; i++ ) { mi_option_t option = (mi_option_t)i; long l = mi_option_get(option); MI_UNUSED(l); // initialize - if (option != mi_option_verbose) { - mi_option_desc_t* desc = &options[option]; - _mi_verbose_message("option '%s': %ld\n", desc->name, desc->value); - } } mi_max_error_count = mi_option_get(mi_option_max_errors); mi_max_warning_count = mi_option_get(mi_option_max_warnings); + #if MI_GUARDED + if (mi_option_get(mi_option_guarded_sample_rate) > 0) { + if (mi_option_is_enabled(mi_option_allow_large_os_pages)) { + mi_option_disable(mi_option_allow_large_os_pages); + _mi_warning_message("option 'allow_large_os_pages' is disabled to allow for guarded objects\n"); + } + } + #endif + if (mi_option_is_enabled(mi_option_verbose)) { mi_options_print(); } +} + +#define mi_stringifyx(str) #str // and stringify +#define mi_stringify(str) mi_stringifyx(str) // expand + +void mi_options_print(void) mi_attr_noexcept +{ + // show version + const int vermajor = MI_MALLOC_VERSION/100; + const int verminor = (MI_MALLOC_VERSION%100)/10; + const int verpatch = (MI_MALLOC_VERSION%10); + _mi_message("v%i.%i.%i%s%s (built on %s, %s)\n", vermajor, verminor, verpatch, + #if defined(MI_CMAKE_BUILD_TYPE) + ", " mi_stringify(MI_CMAKE_BUILD_TYPE) + #else + "" + #endif + , + #if defined(MI_GIT_DESCRIBE) + ", git " mi_stringify(MI_GIT_DESCRIBE) + #else + "" + #endif + , __DATE__, __TIME__); + + // show options + for (int i = 0; i < _mi_option_last; i++) { + mi_option_t option = (mi_option_t)i; + long l = mi_option_get(option); MI_UNUSED(l); // possibly initialize + mi_option_desc_t* desc = &mi_options[option]; + _mi_message("option '%s': %ld %s\n", desc->name, desc->value, (mi_option_has_size_in_kib(option) ? "KiB" : "")); + } + + // show build configuration + _mi_message("debug level : %d\n", MI_DEBUG ); + _mi_message("secure level: %d\n", MI_SECURE ); + _mi_message("mem tracking: %s\n", MI_TRACK_TOOL); + #if MI_GUARDED + _mi_message("guarded build: %s\n", mi_option_get(mi_option_guarded_sample_rate) != 0 ? "enabled" : "disabled"); + #endif + #if MI_TSAN + _mi_message("thread santizer enabled\n"); + #endif +} + +long _mi_option_get_fast(mi_option_t option) { + mi_assert(option >= 0 && option < _mi_option_last); + mi_option_desc_t* desc = &mi_options[option]; + mi_assert(desc->option == option); // index should match the option + //mi_assert(desc->init != MI_OPTION_UNINIT); + return desc->value; } + mi_decl_nodiscard long mi_option_get(mi_option_t option) { mi_assert(option >= 0 && option < _mi_option_last); if (option < 0 || option >= _mi_option_last) return 0; - mi_option_desc_t* desc = &options[option]; + mi_option_desc_t* desc = &mi_options[option]; mi_assert(desc->option == option); // index should match the option - if mi_unlikely(desc->init == UNINIT) { + if mi_unlikely(desc->init == MI_OPTION_UNINIT) { mi_option_init(desc); } return desc->value; @@ -131,20 +270,36 @@ mi_decl_nodiscard long mi_option_get_clamp(mi_option_t option, long min, long ma return (x < min ? min : (x > max ? max : x)); } +mi_decl_nodiscard size_t mi_option_get_size(mi_option_t option) { + const long x = mi_option_get(option); + size_t size = (x < 0 ? 0 : (size_t)x); + if (mi_option_has_size_in_kib(option)) { + size *= MI_KiB; + } + return size; +} + void mi_option_set(mi_option_t option, long value) { mi_assert(option >= 0 && option < _mi_option_last); if (option < 0 || option >= _mi_option_last) return; - mi_option_desc_t* desc = &options[option]; + mi_option_desc_t* desc = &mi_options[option]; mi_assert(desc->option == option); // index should match the option desc->value = value; - desc->init = INITIALIZED; + desc->init = MI_OPTION_INITIALIZED; + // ensure min/max range; be careful to not recurse. + if (desc->option == mi_option_guarded_min && _mi_option_get_fast(mi_option_guarded_max) < value) { + mi_option_set(mi_option_guarded_max, value); + } + else if (desc->option == mi_option_guarded_max && _mi_option_get_fast(mi_option_guarded_min) > value) { + mi_option_set(mi_option_guarded_min, value); + } } void mi_option_set_default(mi_option_t option, long value) { mi_assert(option >= 0 && option < _mi_option_last); if (option < 0 || option >= _mi_option_last) return; - mi_option_desc_t* desc = &options[option]; - if (desc->init != INITIALIZED) { + mi_option_desc_t* desc = &mi_options[option]; + if (desc->init != MI_OPTION_INITIALIZED) { desc->value = value; } } @@ -169,28 +324,11 @@ void mi_option_disable(mi_option_t option) { mi_option_set_enabled(option,false); } - static void mi_cdecl mi_out_stderr(const char* msg, void* arg) { MI_UNUSED(arg); - if (msg == NULL) return; - #ifdef _WIN32 - // on windows with redirection, the C runtime cannot handle locale dependent output - // after the main thread closes so we use direct console output. - if (!_mi_preloading()) { - // _cputs(msg); // _cputs cannot be used at is aborts if it fails to lock the console - static HANDLE hcon = INVALID_HANDLE_VALUE; - if (hcon == INVALID_HANDLE_VALUE) { - hcon = GetStdHandle(STD_ERROR_HANDLE); - } - const size_t len = strlen(msg); - if (hcon != INVALID_HANDLE_VALUE && len > 0 && len < UINT32_MAX) { - DWORD written = 0; - WriteConsoleA(hcon, msg, (DWORD)len, &written, NULL); - } + if (msg != NULL && msg[0] != 0) { + _mi_prim_out_stderr(msg); } - #else - fputs(msg, stderr); - #endif } // Since an output function can be registered earliest in the `main` @@ -198,16 +336,16 @@ static void mi_cdecl mi_out_stderr(const char* msg, void* arg) { // an output function is registered it is called immediately with // the output up to that point. #ifndef MI_MAX_DELAY_OUTPUT -#define MI_MAX_DELAY_OUTPUT ((size_t)(32*1024)) +#define MI_MAX_DELAY_OUTPUT ((size_t)(16*1024)) #endif -static char out_buf[MI_MAX_DELAY_OUTPUT+1]; +static char mi_output_buffer[MI_MAX_DELAY_OUTPUT+1]; static _Atomic(size_t) out_len; static void mi_cdecl mi_out_buf(const char* msg, void* arg) { MI_UNUSED(arg); if (msg==NULL) return; if (mi_atomic_load_relaxed(&out_len)>=MI_MAX_DELAY_OUTPUT) return; - size_t n = strlen(msg); + size_t n = _mi_strlen(msg); if (n==0) return; // claim space size_t start = mi_atomic_add_acq_rel(&out_len, n); @@ -216,7 +354,8 @@ static void mi_cdecl mi_out_buf(const char* msg, void* arg) { if (start+n >= MI_MAX_DELAY_OUTPUT) { n = MI_MAX_DELAY_OUTPUT-start-1; } - _mi_memcpy(&out_buf[start], msg, n); + mi_assert_internal(start + n <= MI_MAX_DELAY_OUTPUT); + _mi_memcpy(&mi_output_buffer[start], msg, n); } static void mi_out_buf_flush(mi_output_fun* out, bool no_more_buf, void* arg) { @@ -225,10 +364,10 @@ static void mi_out_buf_flush(mi_output_fun* out, bool no_more_buf, void* arg) { size_t count = mi_atomic_add_acq_rel(&out_len, (no_more_buf ? MI_MAX_DELAY_OUTPUT : 1)); // and output the current contents if (count>MI_MAX_DELAY_OUTPUT) count = MI_MAX_DELAY_OUTPUT; - out_buf[count] = 0; - out(out_buf,arg); + mi_output_buffer[count] = 0; + out(mi_output_buffer,arg); if (!no_more_buf) { - out_buf[count] = '\n'; // if continue with the buffer, insert a newline + mi_output_buffer[count] = '\n'; // if continue with the buffer, insert a newline } } @@ -264,10 +403,12 @@ void mi_register_output(mi_output_fun* out, void* arg) mi_attr_noexcept { } // add stderr to the delayed output after the module is loaded -static void mi_add_stderr_output() { +static void mi_add_stderr_output(void) { mi_assert_internal(mi_out_default == NULL); - mi_out_buf_flush(&mi_out_stderr, false, NULL); // flush current contents to stderr - mi_out_default = &mi_out_buf_stderr; // and add stderr to the delayed output + if (mi_out_default==NULL) { + mi_out_buf_flush(&mi_out_stderr, false, NULL); // flush current contents to stderr + mi_out_default = &mi_out_buf_stderr; // and add stderr to the delayed output + } } // -------------------------------------------------------- @@ -280,11 +421,11 @@ static _Atomic(size_t) warning_count; // = 0; // when >= max_warning_count stop // inside the C runtime causes another message. // In some cases (like on macOS) the loader already allocates which // calls into mimalloc; if we then access thread locals (like `recurse`) -// this may crash as the access may call _tlv_bootstrap that tries to +// this may crash as the access may call _tlv_bootstrap that tries to // (recursively) invoke malloc again to allocate space for the thread local // variables on demand. This is why we use a _mi_preloading test on such // platforms. However, C code generator may move the initial thread local address -// load before the `if` and we therefore split it out in a separate funcion. +// load before the `if` and we therefore split it out in a separate function. static mi_decl_thread bool recurse = false; static mi_decl_noinline bool mi_recurse_enter_prim(void) { @@ -298,21 +439,21 @@ static mi_decl_noinline void mi_recurse_exit_prim(void) { } static bool mi_recurse_enter(void) { - #if defined(__APPLE__) || defined(MI_TLS_RECURSE_GUARD) - if (_mi_preloading()) return true; + #if defined(__APPLE__) || defined(__ANDROID__) || defined(MI_TLS_RECURSE_GUARD) + if (_mi_preloading()) return false; #endif return mi_recurse_enter_prim(); } static void mi_recurse_exit(void) { - #if defined(__APPLE__) || defined(MI_TLS_RECURSE_GUARD) + #if defined(__APPLE__) || defined(__ANDROID__) || defined(MI_TLS_RECURSE_GUARD) if (_mi_preloading()) return; #endif mi_recurse_exit_prim(); } void _mi_fputs(mi_output_fun* out, void* arg, const char* prefix, const char* message) { - if (out==NULL || (FILE*)out==stdout || (FILE*)out==stderr) { // TODO: use mi_out_stderr for stderr? + if (out==NULL || (void*)out==(void*)stdout || (void*)out==(void*)stderr) { // TODO: use mi_out_stderr for stderr? if (!mi_recurse_enter()) return; out = mi_out_get_default(&arg); if (prefix != NULL) out(prefix, arg); @@ -326,12 +467,12 @@ void _mi_fputs(mi_output_fun* out, void* arg, const char* prefix, const char* me } // Define our own limited `fprintf` that avoids memory allocation. -// We do this using `snprintf` with a limited buffer. +// We do this using `_mi_vsnprintf` with a limited buffer. static void mi_vfprintf( mi_output_fun* out, void* arg, const char* prefix, const char* fmt, va_list args ) { - char buf[512]; + char buf[992]; if (fmt==NULL) return; if (!mi_recurse_enter()) return; - vsnprintf(buf,sizeof(buf)-1,fmt,args); + _mi_vsnprintf(buf, sizeof(buf)-1, fmt, args); mi_recurse_exit(); _mi_fputs(out,arg,prefix,buf); } @@ -344,9 +485,9 @@ void _mi_fprintf( mi_output_fun* out, void* arg, const char* fmt, ... ) { } static void mi_vfprintf_thread(mi_output_fun* out, void* arg, const char* prefix, const char* fmt, va_list args) { - if (prefix != NULL && strlen(prefix) <= 32 && !_mi_is_main_thread()) { + if (prefix != NULL && _mi_strnlen(prefix,33) <= 32 && !_mi_is_main_thread()) { char tprefix[64]; - snprintf(tprefix, sizeof(tprefix), "%sthread 0x%zx: ", prefix, _mi_thread_id()); + _mi_snprintf(tprefix, sizeof(tprefix), "%sthread 0x%tx: ", prefix, (uintptr_t)_mi_thread_id()); mi_vfprintf(out, arg, tprefix, fmt, args); } else { @@ -354,6 +495,20 @@ static void mi_vfprintf_thread(mi_output_fun* out, void* arg, const char* prefix } } +void _mi_raw_message(const char* fmt, ...) { + va_list args; + va_start(args, fmt); + mi_vfprintf(NULL, NULL, NULL, fmt, args); + va_end(args); +} + +void _mi_message(const char* fmt, ...) { + va_list args; + va_start(args, fmt); + mi_vfprintf_thread(NULL, NULL, "mimalloc: ", fmt, args); + va_end(args); +} + void _mi_trace_message(const char* fmt, ...) { if (mi_option_get(mi_option_verbose) <= 1) return; // only with verbose level 2 or higher va_list args; @@ -391,7 +546,7 @@ void _mi_warning_message(const char* fmt, ...) { #if MI_DEBUG -void _mi_assert_fail(const char* assertion, const char* fname, unsigned line, const char* func ) { +mi_decl_noreturn mi_decl_cold void _mi_assert_fail(const char* assertion, const char* fname, unsigned line, const char* func ) mi_attr_noexcept { _mi_fprintf(NULL, NULL, "mimalloc: assertion failed: at \"%s\":%u, %s\n assertion: \"%s\"\n", fname, line, (func==NULL?"":func), assertion); abort(); } @@ -406,7 +561,7 @@ static _Atomic(void*) mi_error_arg; // = NULL static void mi_error_default(int err) { MI_UNUSED(err); -#if (MI_DEBUG>0) +#if (MI_DEBUG>0) if (err==EFAULT) { #ifdef _MSC_VER __debugbreak(); @@ -450,178 +605,80 @@ void _mi_error_message(int err, const char* fmt, ...) { // Initialize options by checking the environment // -------------------------------------------------------- -static void mi_strlcpy(char* dest, const char* src, size_t dest_size) { - if (dest==NULL || src==NULL || dest_size == 0) return; - // copy until end of src, or when dest is (almost) full - while (*src != 0 && dest_size > 1) { - *dest++ = *src++; - dest_size--; - } - // always zero terminate - *dest = 0; -} - -static void mi_strlcat(char* dest, const char* src, size_t dest_size) { - if (dest==NULL || src==NULL || dest_size == 0) return; - // find end of string in the dest buffer - while (*dest != 0 && dest_size > 1) { - dest++; - dest_size--; - } - // and catenate - mi_strlcpy(dest, src, dest_size); -} +// TODO: implement ourselves to reduce dependencies on the C runtime +#include // strtol +#include // strstr -#ifdef MI_NO_GETENV -static bool mi_getenv(const char* name, char* result, size_t result_size) { - MI_UNUSED(name); - MI_UNUSED(result); - MI_UNUSED(result_size); - return false; -} -#else -static inline int mi_strnicmp(const char* s, const char* t, size_t n) { - if (n==0) return 0; - for (; *s != 0 && *t != 0 && n > 0; s++, t++, n--) { - if (toupper(*s) != toupper(*t)) break; - } - return (n==0 ? 0 : *s - *t); -} -#if defined _WIN32 -// On Windows use GetEnvironmentVariable instead of getenv to work -// reliably even when this is invoked before the C runtime is initialized. -// i.e. when `_mi_preloading() == true`. -// Note: on windows, environment names are not case sensitive. -#include -static bool mi_getenv(const char* name, char* result, size_t result_size) { - result[0] = 0; - size_t len = GetEnvironmentVariableA(name, result, (DWORD)result_size); - return (len > 0 && len < result_size); -} -#elif !defined(MI_USE_ENVIRON) || (MI_USE_ENVIRON!=0) -// On Posix systemsr use `environ` to acces environment variables -// even before the C runtime is initialized. -#if defined(__APPLE__) && defined(__has_include) && __has_include() -#include -static char** mi_get_environ(void) { - return (*_NSGetEnviron()); -} -#else -extern char** environ; -static char** mi_get_environ(void) { - return environ; -} -#endif -static bool mi_getenv(const char* name, char* result, size_t result_size) { - if (name==NULL) return false; - const size_t len = strlen(name); - if (len == 0) return false; - char** env = mi_get_environ(); - if (env == NULL) return false; - // compare up to 256 entries - for (int i = 0; i < 256 && env[i] != NULL; i++) { - const char* s = env[i]; - if (mi_strnicmp(name, s, len) == 0 && s[len] == '=') { // case insensitive - // found it - mi_strlcpy(result, s + len + 1, result_size); - return true; - } - } - return false; -} -#else -// fallback: use standard C `getenv` but this cannot be used while initializing the C runtime -static bool mi_getenv(const char* name, char* result, size_t result_size) { - // cannot call getenv() when still initializing the C runtime. - if (_mi_preloading()) return false; - const char* s = getenv(name); - if (s == NULL) { - // we check the upper case name too. - char buf[64+1]; - size_t len = strlen(name); - if (len >= sizeof(buf)) len = sizeof(buf) - 1; - for (size_t i = 0; i < len; i++) { - buf[i] = toupper(name[i]); - } - buf[len] = 0; - s = getenv(buf); - } - if (s != NULL && strlen(s) < result_size) { - mi_strlcpy(result, s, result_size); - return true; - } - else { - return false; - } -} -#endif // !MI_USE_ENVIRON -#endif // !MI_NO_GETENV -static void mi_option_init(mi_option_desc_t* desc) { +static void mi_option_init(mi_option_desc_t* desc) { // Read option value from the environment - char s[64+1]; + char s[64 + 1]; char buf[64+1]; - mi_strlcpy(buf, "mimalloc_", sizeof(buf)); - mi_strlcat(buf, desc->name, sizeof(buf)); - bool found = mi_getenv(buf,s,sizeof(s)); + _mi_strlcpy(buf, "mimalloc_", sizeof(buf)); + _mi_strlcat(buf, desc->name, sizeof(buf)); + bool found = _mi_getenv(buf, s, sizeof(s)); if (!found && desc->legacy_name != NULL) { - mi_strlcpy(buf, "mimalloc_", sizeof(buf)); - mi_strlcat(buf, desc->legacy_name, sizeof(buf)); - found = mi_getenv(buf,s,sizeof(s)); + _mi_strlcpy(buf, "mimalloc_", sizeof(buf)); + _mi_strlcat(buf, desc->legacy_name, sizeof(buf)); + found = _mi_getenv(buf, s, sizeof(s)); if (found) { - _mi_warning_message("environment option \"mimalloc_%s\" is deprecated -- use \"mimalloc_%s\" instead.\n", desc->legacy_name, desc->name ); - } + _mi_warning_message("environment option \"mimalloc_%s\" is deprecated -- use \"mimalloc_%s\" instead.\n", desc->legacy_name, desc->name); + } } if (found) { - size_t len = strlen(s); - if (len >= sizeof(buf)) len = sizeof(buf) - 1; + size_t len = _mi_strnlen(s, sizeof(buf) - 1); for (size_t i = 0; i < len; i++) { - buf[i] = (char)toupper(s[i]); + buf[i] = _mi_toupper(s[i]); } buf[len] = 0; - if (buf[0]==0 || strstr("1;TRUE;YES;ON", buf) != NULL) { + if (buf[0] == 0 || strstr("1;TRUE;YES;ON", buf) != NULL) { desc->value = 1; - desc->init = INITIALIZED; + desc->init = MI_OPTION_INITIALIZED; } else if (strstr("0;FALSE;NO;OFF", buf) != NULL) { desc->value = 0; - desc->init = INITIALIZED; + desc->init = MI_OPTION_INITIALIZED; } else { char* end = buf; long value = strtol(buf, &end, 10); - if (desc->option == mi_option_reserve_os_memory) { - // this option is interpreted in KiB to prevent overflow of `long` + if (mi_option_has_size_in_kib(desc->option)) { + // this option is interpreted in KiB to prevent overflow of `long` for large allocations + // (long is 32-bit on 64-bit windows, which allows for 4TiB max.) + size_t size = (value < 0 ? 0 : (size_t)value); + bool overflow = false; if (*end == 'K') { end++; } - else if (*end == 'M') { value *= MI_KiB; end++; } - else if (*end == 'G') { value *= MI_MiB; end++; } - else { value = (value + MI_KiB - 1) / MI_KiB; } - if (end[0] == 'I' && end[1] == 'B') { end += 2; } - else if (*end == 'B') { end++; } + else if (*end == 'M') { overflow = mi_mul_overflow(size,MI_KiB,&size); end++; } + else if (*end == 'G') { overflow = mi_mul_overflow(size,MI_MiB,&size); end++; } + else if (*end == 'T') { overflow = mi_mul_overflow(size,MI_GiB,&size); end++; } + else { size = (size + MI_KiB - 1) / MI_KiB; } + if (end[0] == 'I' && end[1] == 'B') { end += 2; } // KiB, MiB, GiB, TiB + else if (*end == 'B') { end++; } // Kb, Mb, Gb, Tb + if (overflow || size > MI_MAX_ALLOC_SIZE) { size = (MI_MAX_ALLOC_SIZE / MI_KiB); } + value = (size > LONG_MAX ? LONG_MAX : (long)size); } if (*end == 0) { - desc->value = value; - desc->init = INITIALIZED; + mi_option_set(desc->option, value); } else { // set `init` first to avoid recursion through _mi_warning_message on mimalloc_verbose. - desc->init = DEFAULTED; + desc->init = MI_OPTION_DEFAULTED; if (desc->option == mi_option_verbose && desc->value == 0) { // if the 'mimalloc_verbose' env var has a bogus value we'd never know // (since the value defaults to 'off') so in that case briefly enable verbose desc->value = 1; - _mi_warning_message("environment option mimalloc_%s has an invalid value.\n", desc->name ); + _mi_warning_message("environment option mimalloc_%s has an invalid value.\n", desc->name); desc->value = 0; } else { - _mi_warning_message("environment option mimalloc_%s has an invalid value.\n", desc->name ); + _mi_warning_message("environment option mimalloc_%s has an invalid value.\n", desc->name); } } } - mi_assert_internal(desc->init != UNINIT); + mi_assert_internal(desc->init != MI_OPTION_UNINIT); } else if (!_mi_preloading()) { - desc->init = DEFAULTED; + desc->init = MI_OPTION_DEFAULTED; } } diff --git a/src/dashbls/depends/mimalloc/src/os.c b/src/dashbls/depends/mimalloc/src/os.c index 6d72498730c9..0224bce62591 100644 --- a/src/dashbls/depends/mimalloc/src/os.c +++ b/src/dashbls/depends/mimalloc/src/os.c @@ -1,118 +1,80 @@ /* ---------------------------------------------------------------------------- -Copyright (c) 2018-2021, Microsoft Research, Daan Leijen +Copyright (c) 2018-2025, Microsoft Research, Daan Leijen This is free software; you can redistribute it and/or modify it under the terms of the MIT license. A copy of the license can be found in the file "LICENSE" at the root of this distribution. -----------------------------------------------------------------------------*/ -#ifndef _DEFAULT_SOURCE -#define _DEFAULT_SOURCE // ensure mmap flags are defined -#endif - -#if defined(__sun) -// illumos provides new mman.h api when any of these are defined -// otherwise the old api based on caddr_t which predates the void pointers one. -// stock solaris provides only the former, chose to atomically to discard those -// flags only here rather than project wide tough. -#undef _XOPEN_SOURCE -#undef _POSIX_C_SOURCE -#endif #include "mimalloc.h" -#include "mimalloc-internal.h" -#include "mimalloc-atomic.h" +#include "mimalloc/internal.h" +#include "mimalloc/atomic.h" +#include "mimalloc/prim.h" -#include // strerror - -#ifdef _MSC_VER -#pragma warning(disable:4996) // strerror +/* ----------------------------------------------------------- + Initialization. +----------------------------------------------------------- */ +#ifndef MI_DEFAULT_PHYSICAL_MEMORY_IN_KIB +#if MI_INTPTR_SIZE < 8 +#define MI_DEFAULT_PHYSICAL_MEMORY_IN_KIB 4*MI_MiB // 4 GiB +#else +#define MI_DEFAULT_PHYSICAL_MEMORY_IN_KIB 32*MI_MiB // 32 GiB #endif - -#if defined(__wasi__) -#define MI_USE_SBRK #endif -#if defined(_WIN32) -#include -#elif defined(__wasi__) -#include // sbrk +#if defined(__APPLE__) && defined(__aarch64__) +#define MI_PLATFORM_PAGE_SIZE 16*MI_KiB // 16 KiB +#elif defined(__EMSCRIPTEN__) +#define MI_PLATFORM_PAGE_SIZE 64*MI_KiB // 64 KiB #else -#include // mmap -#include // sysconf -#if defined(__linux__) -#include -#include -#if defined(__GLIBC__) -#include // linux mmap flags -#else -#include -#endif -#endif -#if defined(__APPLE__) -#include -#if !TARGET_IOS_IPHONE && !TARGET_IOS_SIMULATOR -#include -#endif -#endif -#if defined(__FreeBSD__) || defined(__DragonFly__) -#include -#if __FreeBSD_version >= 1200000 -#include -#include -#endif -#include -#endif +#define MI_PLATFORM_PAGE_SIZE 4*MI_KiB // 4 KiB #endif -/* ----------------------------------------------------------- - Initialization. - On windows initializes support for aligned allocation and - large OS pages (if MIMALLOC_LARGE_OS_PAGES is true). ------------------------------------------------------------ */ -bool _mi_os_decommit(void* addr, size_t size, mi_stats_t* stats); -bool _mi_os_commit(void* addr, size_t size, bool* is_zero, mi_stats_t* tld_stats); +static mi_os_mem_config_t mi_os_mem_config = { + MI_PLATFORM_PAGE_SIZE, // page size + 0, // large page size (usually 2MiB) + MI_PLATFORM_PAGE_SIZE, // allocation granularity + MI_DEFAULT_PHYSICAL_MEMORY_IN_KIB, + MI_MAX_VABITS, // in `bits.h` + true, // has overcommit? (if true we use MAP_NORESERVE on mmap systems) + false, // can we partially free allocated blocks? (on mmap systems we can free anywhere in a mapped range, but on Windows we must free the entire span) + true // has virtual reserve? (if true we can reserve virtual address space without using commit or physical memory) +}; -static void* mi_align_up_ptr(void* p, size_t alignment) { - return (void*)_mi_align_up((uintptr_t)p, alignment); +bool _mi_os_has_overcommit(void) { + return mi_os_mem_config.has_overcommit; } -static void* mi_align_down_ptr(void* p, size_t alignment) { - return (void*)_mi_align_down((uintptr_t)p, alignment); +bool _mi_os_has_virtual_reserve(void) { + return mi_os_mem_config.has_virtual_reserve; } -// page size (initialized properly in `os_init`) -static size_t os_page_size = 4096; - -// minimal allocation granularity -static size_t os_alloc_granularity = 4096; - -// if non-zero, use large page allocation -static size_t large_os_page_size = 0; - -// is memory overcommit allowed? -// set dynamically in _mi_os_init (and if true we use MAP_NORESERVE) -static bool os_overcommit = true; - -bool _mi_os_has_overcommit(void) { - return os_overcommit; -} - // OS (small) page size size_t _mi_os_page_size(void) { - return os_page_size; + return mi_os_mem_config.page_size; } // if large OS pages are supported (2 or 4MiB), then return the size, otherwise return the small page size (4KiB) size_t _mi_os_large_page_size(void) { - return (large_os_page_size != 0 ? large_os_page_size : _mi_os_page_size()); + return (mi_os_mem_config.large_page_size != 0 ? mi_os_mem_config.large_page_size : _mi_os_page_size()); +} + +size_t _mi_os_guard_page_size(void) { + const size_t gsize = _mi_os_page_size(); + mi_assert(gsize <= (MI_ARENA_SLICE_SIZE/8)); + return gsize; +} + +size_t _mi_os_virtual_address_bits(void) { + const size_t vbits = mi_os_mem_config.virtual_address_bits; + mi_assert(vbits <= MI_MAX_VABITS); + return vbits; } -#if !defined(MI_USE_SBRK) && !defined(__wasi__) -static bool use_large_os_page(size_t size, size_t alignment) { +bool _mi_os_use_large_page(size_t size, size_t alignment) { // if we have access, check the size and alignment requirements - if (large_os_page_size == 0 || !mi_option_is_enabled(mi_option_large_os_pages)) return false; - return ((size % large_os_page_size) == 0 && (alignment % large_os_page_size) == 0); + if (mi_os_mem_config.large_page_size == 0 || !mi_option_is_enabled(mi_option_allow_large_os_pages)) return false; + return ((size % mi_os_mem_config.large_page_size) == 0 && (alignment % mi_os_mem_config.large_page_size) == 0); } -#endif // round to a good OS allocation size (bounded by max 12.5% waste) size_t _mi_os_good_alloc_size(size_t size) { @@ -126,575 +88,147 @@ size_t _mi_os_good_alloc_size(size_t size) { return _mi_align_up(size, align_size); } -#if defined(_WIN32) -// We use VirtualAlloc2 for aligned allocation, but it is only supported on Windows 10 and Windows Server 2016. -// So, we need to look it up dynamically to run on older systems. (use __stdcall for 32-bit compatibility) -// NtAllocateVirtualAllocEx is used for huge OS page allocation (1GiB) -// We define a minimal MEM_EXTENDED_PARAMETER ourselves in order to be able to compile with older SDK's. -typedef enum MI_MEM_EXTENDED_PARAMETER_TYPE_E { - MiMemExtendedParameterInvalidType = 0, - MiMemExtendedParameterAddressRequirements, - MiMemExtendedParameterNumaNode, - MiMemExtendedParameterPartitionHandle, - MiMemExtendedParameterUserPhysicalHandle, - MiMemExtendedParameterAttributeFlags, - MiMemExtendedParameterMax -} MI_MEM_EXTENDED_PARAMETER_TYPE; - -typedef struct DECLSPEC_ALIGN(8) MI_MEM_EXTENDED_PARAMETER_S { - struct { DWORD64 Type : 8; DWORD64 Reserved : 56; } Type; - union { DWORD64 ULong64; PVOID Pointer; SIZE_T Size; HANDLE Handle; DWORD ULong; } Arg; -} MI_MEM_EXTENDED_PARAMETER; - -typedef struct MI_MEM_ADDRESS_REQUIREMENTS_S { - PVOID LowestStartingAddress; - PVOID HighestEndingAddress; - SIZE_T Alignment; -} MI_MEM_ADDRESS_REQUIREMENTS; - -#define MI_MEM_EXTENDED_PARAMETER_NONPAGED_HUGE 0x00000010 - -#include -typedef PVOID (__stdcall *PVirtualAlloc2)(HANDLE, PVOID, SIZE_T, ULONG, ULONG, MI_MEM_EXTENDED_PARAMETER*, ULONG); -typedef NTSTATUS (__stdcall *PNtAllocateVirtualMemoryEx)(HANDLE, PVOID*, SIZE_T*, ULONG, ULONG, MI_MEM_EXTENDED_PARAMETER*, ULONG); -static PVirtualAlloc2 pVirtualAlloc2 = NULL; -static PNtAllocateVirtualMemoryEx pNtAllocateVirtualMemoryEx = NULL; - -// Similarly, GetNumaProcesorNodeEx is only supported since Windows 7 -typedef struct MI_PROCESSOR_NUMBER_S { WORD Group; BYTE Number; BYTE Reserved; } MI_PROCESSOR_NUMBER; - -typedef VOID (__stdcall *PGetCurrentProcessorNumberEx)(MI_PROCESSOR_NUMBER* ProcNumber); -typedef BOOL (__stdcall *PGetNumaProcessorNodeEx)(MI_PROCESSOR_NUMBER* Processor, PUSHORT NodeNumber); -typedef BOOL (__stdcall* PGetNumaNodeProcessorMaskEx)(USHORT Node, PGROUP_AFFINITY ProcessorMask); -static PGetCurrentProcessorNumberEx pGetCurrentProcessorNumberEx = NULL; -static PGetNumaProcessorNodeEx pGetNumaProcessorNodeEx = NULL; -static PGetNumaNodeProcessorMaskEx pGetNumaNodeProcessorMaskEx = NULL; - -static bool mi_win_enable_large_os_pages(void) -{ - if (large_os_page_size > 0) return true; - - // Try to see if large OS pages are supported - // To use large pages on Windows, we first need access permission - // Set "Lock pages in memory" permission in the group policy editor - // - unsigned long err = 0; - HANDLE token = NULL; - BOOL ok = OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token); - if (ok) { - TOKEN_PRIVILEGES tp; - ok = LookupPrivilegeValue(NULL, TEXT("SeLockMemoryPrivilege"), &tp.Privileges[0].Luid); - if (ok) { - tp.PrivilegeCount = 1; - tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; - ok = AdjustTokenPrivileges(token, FALSE, &tp, 0, (PTOKEN_PRIVILEGES)NULL, 0); - if (ok) { - err = GetLastError(); - ok = (err == ERROR_SUCCESS); - if (ok) { - large_os_page_size = GetLargePageMinimum(); - } - } - } - CloseHandle(token); - } - if (!ok) { - if (err == 0) err = GetLastError(); - _mi_warning_message("cannot enable large OS page support, error %lu\n", err); - } - return (ok!=0); -} - -void _mi_os_init(void) -{ - os_overcommit = false; - // get the page size - SYSTEM_INFO si; - GetSystemInfo(&si); - if (si.dwPageSize > 0) os_page_size = si.dwPageSize; - if (si.dwAllocationGranularity > 0) os_alloc_granularity = si.dwAllocationGranularity; - // get the VirtualAlloc2 function - HINSTANCE hDll; - hDll = LoadLibrary(TEXT("kernelbase.dll")); - if (hDll != NULL) { - // use VirtualAlloc2FromApp if possible as it is available to Windows store apps - pVirtualAlloc2 = (PVirtualAlloc2)(void (*)(void))GetProcAddress(hDll, "VirtualAlloc2FromApp"); - if (pVirtualAlloc2==NULL) pVirtualAlloc2 = (PVirtualAlloc2)(void (*)(void))GetProcAddress(hDll, "VirtualAlloc2"); - FreeLibrary(hDll); - } - // NtAllocateVirtualMemoryEx is used for huge page allocation - hDll = LoadLibrary(TEXT("ntdll.dll")); - if (hDll != NULL) { - pNtAllocateVirtualMemoryEx = (PNtAllocateVirtualMemoryEx)(void (*)(void))GetProcAddress(hDll, "NtAllocateVirtualMemoryEx"); - FreeLibrary(hDll); - } - // Try to use Win7+ numa API - hDll = LoadLibrary(TEXT("kernel32.dll")); - if (hDll != NULL) { - pGetCurrentProcessorNumberEx = (PGetCurrentProcessorNumberEx)(void (*)(void))GetProcAddress(hDll, "GetCurrentProcessorNumberEx"); - pGetNumaProcessorNodeEx = (PGetNumaProcessorNodeEx)(void (*)(void))GetProcAddress(hDll, "GetNumaProcessorNodeEx"); - pGetNumaNodeProcessorMaskEx = (PGetNumaNodeProcessorMaskEx)(void (*)(void))GetProcAddress(hDll, "GetNumaNodeProcessorMaskEx"); - FreeLibrary(hDll); - } - if (mi_option_is_enabled(mi_option_large_os_pages) || mi_option_is_enabled(mi_option_reserve_huge_os_pages)) { - mi_win_enable_large_os_pages(); - } -} -#elif defined(__wasi__) -void _mi_os_init(void) { - os_overcommit = false; - os_page_size = 64*MI_KiB; // WebAssembly has a fixed page size: 64KiB - os_alloc_granularity = 16; -} - -#else // generic unix - -static void os_detect_overcommit(void) { -#if defined(__linux__) - int fd = open("/proc/sys/vm/overcommit_memory", O_RDONLY); - if (fd < 0) return; - char buf[32]; - ssize_t nread = read(fd, &buf, sizeof(buf)); - close(fd); - // - // 0: heuristic overcommit, 1: always overcommit, 2: never overcommit (ignore NORESERVE) - if (nread >= 1) { - os_overcommit = (buf[0] == '0' || buf[0] == '1'); - } -#elif defined(__FreeBSD__) - int val = 0; - size_t olen = sizeof(val); - if (sysctlbyname("vm.overcommit", &val, &olen, NULL, 0) == 0) { - os_overcommit = (val != 0); - } -#else - // default: overcommit is true -#endif -} - void _mi_os_init(void) { - // get the page size - long result = sysconf(_SC_PAGESIZE); - if (result > 0) { - os_page_size = (size_t)result; - os_alloc_granularity = os_page_size; - } - large_os_page_size = 2*MI_MiB; // TODO: can we query the OS for this? - os_detect_overcommit(); -} -#endif - - -#if defined(MADV_NORMAL) -static int mi_madvise(void* addr, size_t length, int advice) { - #if defined(__sun) - return madvise((caddr_t)addr, length, advice); // Solaris needs cast (issue #520) - #else - return madvise(addr, length, advice); - #endif + _mi_prim_mem_init(&mi_os_mem_config); } -#endif /* ----------------------------------------------------------- - aligned hinting + Util -------------------------------------------------------------- */ +bool _mi_os_decommit(void* addr, size_t size); +bool _mi_os_commit(void* addr, size_t size, bool* is_zero); -// On 64-bit systems, we can do efficient aligned allocation by using -// the 2TiB to 30TiB area to allocate those. -#if (MI_INTPTR_SIZE >= 8) -static mi_decl_cache_align _Atomic(uintptr_t)aligned_base; - -// Return a MI_SEGMENT_SIZE aligned address that is probably available. -// If this returns NULL, the OS will determine the address but on some OS's that may not be -// properly aligned which can be more costly as it needs to be adjusted afterwards. -// For a size > 1GiB this always returns NULL in order to guarantee good ASLR randomization; -// (otherwise an initial large allocation of say 2TiB has a 50% chance to include (known) addresses -// in the middle of the 2TiB - 6TiB address range (see issue #372)) - -#define MI_HINT_BASE ((uintptr_t)2 << 40) // 2TiB start -#define MI_HINT_AREA ((uintptr_t)4 << 40) // upto 6TiB (since before win8 there is "only" 8TiB available to processes) -#define MI_HINT_MAX ((uintptr_t)30 << 40) // wrap after 30TiB (area after 32TiB is used for huge OS pages) - -static void* mi_os_get_aligned_hint(size_t try_alignment, size_t size) -{ - if (try_alignment <= 1 || try_alignment > MI_SEGMENT_SIZE) return NULL; - size = _mi_align_up(size, MI_SEGMENT_SIZE); - if (size > 1*MI_GiB) return NULL; // guarantee the chance of fixed valid address is at most 1/(MI_HINT_AREA / 1<<30) = 1/4096. - #if (MI_SECURE>0) - size += MI_SEGMENT_SIZE; // put in `MI_SEGMENT_SIZE` virtual gaps between hinted blocks; this splits VLA's but increases guarded areas. - #endif - - uintptr_t hint = mi_atomic_add_acq_rel(&aligned_base, size); - if (hint == 0 || hint > MI_HINT_MAX) { // wrap or initialize - uintptr_t init = MI_HINT_BASE; - #if (MI_SECURE>0 || MI_DEBUG==0) // security: randomize start of aligned allocations unless in debug mode - uintptr_t r = _mi_heap_random_next(mi_get_default_heap()); - init = init + ((MI_SEGMENT_SIZE * ((r>>17) & 0xFFFFF)) % MI_HINT_AREA); // (randomly 20 bits)*4MiB == 0 to 4TiB - #endif - uintptr_t expected = hint + size; - mi_atomic_cas_strong_acq_rel(&aligned_base, &expected, init); - hint = mi_atomic_add_acq_rel(&aligned_base, size); // this may still give 0 or > MI_HINT_MAX but that is ok, it is a hint after all - } - if (hint%try_alignment != 0) return NULL; - return (void*)hint; -} -#else -static void* mi_os_get_aligned_hint(size_t try_alignment, size_t size) { +void* _mi_os_get_aligned_hint(size_t try_alignment, size_t size) { MI_UNUSED(try_alignment); MI_UNUSED(size); return NULL; } -#endif - -/* ----------------------------------------------------------- - Free memory --------------------------------------------------------------- */ - -static bool mi_os_mem_free(void* addr, size_t size, bool was_committed, mi_stats_t* stats) -{ - if (addr == NULL || size == 0) return true; // || _mi_os_is_huge_reserved(addr) - bool err = false; -#if defined(_WIN32) - DWORD errcode = 0; - err = (VirtualFree(addr, 0, MEM_RELEASE) == 0); - if (err) { errcode = GetLastError(); } - if (errcode == ERROR_INVALID_ADDRESS) { - // In mi_os_mem_alloc_aligned the fallback path may have returned a pointer inside - // the memory region returned by VirtualAlloc; in that case we need to free using - // the start of the region. - MEMORY_BASIC_INFORMATION info = { 0 }; - VirtualQuery(addr, &info, sizeof(info)); - if (info.AllocationBase < addr && ((uint8_t*)addr - (uint8_t*)info.AllocationBase) < (ptrdiff_t)MI_SEGMENT_SIZE) { - errcode = 0; - err = (VirtualFree(info.AllocationBase, 0, MEM_RELEASE) == 0); - if (err) { errcode = GetLastError(); } - } - } - if (errcode != 0) { - _mi_warning_message("unable to release OS memory: error code 0x%x, addr: %p, size: %zu\n", errcode, addr, size); - } -#elif defined(MI_USE_SBRK) || defined(__wasi__) - err = false; // sbrk heap cannot be shrunk -#else - err = (munmap(addr, size) == -1); - if (err) { - _mi_warning_message("unable to release OS memory: %s, addr: %p, size: %zu\n", strerror(errno), addr, size); - } -#endif - if (was_committed) { _mi_stat_decrease(&stats->committed, size); } - _mi_stat_decrease(&stats->reserved, size); - return !err; -} /* ----------------------------------------------------------- - Raw allocation on Windows (VirtualAlloc) --------------------------------------------------------------- */ - -#ifdef _WIN32 - -#define MEM_COMMIT_RESERVE (MEM_COMMIT|MEM_RESERVE) + Guard page allocation +----------------------------------------------------------- */ -static void* mi_win_virtual_allocx(void* addr, size_t size, size_t try_alignment, DWORD flags) { -#if (MI_INTPTR_SIZE >= 8) - // on 64-bit systems, try to use the virtual address area after 2TiB for 4MiB aligned allocations - if (addr == NULL) { - void* hint = mi_os_get_aligned_hint(try_alignment,size); - if (hint != NULL) { - void* p = VirtualAlloc(hint, size, flags, PAGE_READWRITE); - if (p != NULL) return p; - _mi_verbose_message("warning: unable to allocate hinted aligned OS memory (%zu bytes, error code: 0x%x, address: %p, alignment: %zu, flags: 0x%x)\n", size, GetLastError(), hint, try_alignment, flags); - // fall through on error - } - } -#endif - // on modern Windows try use VirtualAlloc2 for aligned allocation - if (try_alignment > 1 && (try_alignment % _mi_os_page_size()) == 0 && pVirtualAlloc2 != NULL) { - MI_MEM_ADDRESS_REQUIREMENTS reqs = { 0, 0, 0 }; - reqs.Alignment = try_alignment; - MI_MEM_EXTENDED_PARAMETER param = { {0, 0}, {0} }; - param.Type.Type = MiMemExtendedParameterAddressRequirements; - param.Arg.Pointer = &reqs; - void* p = (*pVirtualAlloc2)(GetCurrentProcess(), addr, size, flags, PAGE_READWRITE, ¶m, 1); - if (p != NULL) return p; - _mi_warning_message("unable to allocate aligned OS memory (%zu bytes, error code: 0x%x, address: %p, alignment: %zu, flags: 0x%x)\n", size, GetLastError(), addr, try_alignment, flags); - // fall through on error - } - // last resort - return VirtualAlloc(addr, size, flags, PAGE_READWRITE); +// In secure mode, return the size of a guard page, otherwise 0 +size_t _mi_os_secure_guard_page_size(void) { + #if MI_SECURE > 0 + return _mi_os_guard_page_size(); + #else + return 0; + #endif } -static void* mi_win_virtual_alloc(void* addr, size_t size, size_t try_alignment, DWORD flags, bool large_only, bool allow_large, bool* is_large) { - mi_assert_internal(!(large_only && !allow_large)); - static _Atomic(size_t) large_page_try_ok; // = 0; - void* p = NULL; - // Try to allocate large OS pages (2MiB) if allowed or required. - if ((large_only || use_large_os_page(size, try_alignment)) - && allow_large && (flags&MEM_COMMIT)!=0 && (flags&MEM_RESERVE)!=0) { - size_t try_ok = mi_atomic_load_acquire(&large_page_try_ok); - if (!large_only && try_ok > 0) { - // if a large page allocation fails, it seems the calls to VirtualAlloc get very expensive. - // therefore, once a large page allocation failed, we don't try again for `large_page_try_ok` times. - mi_atomic_cas_strong_acq_rel(&large_page_try_ok, &try_ok, try_ok - 1); +// In secure mode, try to decommit an area and output a warning if this fails. +bool _mi_os_secure_guard_page_set_at(void* addr, mi_memid_t memid) { + if (addr == NULL) return true; + #if MI_SECURE > 0 + bool ok = false; + if (!memid.is_pinned) { + mi_arena_t* const arena = mi_memid_arena(memid); + if (arena != NULL && arena->commit_fun != NULL) { + ok = (*(arena->commit_fun))(false /* decommit */, addr, _mi_os_secure_guard_page_size(), NULL, arena->commit_fun_arg); } else { - // large OS pages must always reserve and commit. - *is_large = true; - p = mi_win_virtual_allocx(addr, size, try_alignment, flags | MEM_LARGE_PAGES); - if (large_only) return p; - // fall back to non-large page allocation on error (`p == NULL`). - if (p == NULL) { - mi_atomic_store_release(&large_page_try_ok,10UL); // on error, don't try again for the next N allocations - } + ok = _mi_os_decommit(addr, _mi_os_secure_guard_page_size()); } } - // Fall back to regular page allocation - if (p == NULL) { - *is_large = ((flags&MEM_LARGE_PAGES) != 0); - p = mi_win_virtual_allocx(addr, size, try_alignment, flags); - } - if (p == NULL) { - _mi_warning_message("unable to allocate OS memory (%zu bytes, error code: 0x%x, address: %p, alignment: %zu, flags: 0x%x, large only: %d, allow large: %d)\n", size, GetLastError(), addr, try_alignment, flags, large_only, allow_large); + if (!ok) { + _mi_error_message(EINVAL, "secure level %d, but failed to commit guard page (at %p of size %zu)\n", MI_SECURE, addr, _mi_os_secure_guard_page_size()); } - return p; + return ok; + #else + MI_UNUSED(memid); + return true; + #endif } -/* ----------------------------------------------------------- - Raw allocation using `sbrk` or `wasm_memory_grow` --------------------------------------------------------------- */ - -#elif defined(MI_USE_SBRK) || defined(__wasi__) -#if defined(MI_USE_SBRK) - static void* mi_memory_grow( size_t size ) { - void* p = sbrk(size); - if (p == (void*)(-1)) return NULL; - #if !defined(__wasi__) // on wasi this is always zero initialized already (?) - memset(p,0,size); - #endif - return p; - } -#elif defined(__wasi__) - static void* mi_memory_grow( size_t size ) { - size_t base = (size > 0 ? __builtin_wasm_memory_grow(0,_mi_divide_up(size, _mi_os_page_size())) - : __builtin_wasm_memory_size(0)); - if (base == SIZE_MAX) return NULL; - return (void*)(base * _mi_os_page_size()); - } -#endif - -#if defined(MI_USE_PTHREADS) -static pthread_mutex_t mi_heap_grow_mutex = PTHREAD_MUTEX_INITIALIZER; -#endif +// In secure mode, try to decommit an area and output a warning if this fails. +bool _mi_os_secure_guard_page_set_before(void* addr, mi_memid_t memid) { + return _mi_os_secure_guard_page_set_at((uint8_t*)addr - _mi_os_secure_guard_page_size(), memid); +} -static void* mi_heap_grow(size_t size, size_t try_alignment) { - void* p = NULL; - if (try_alignment <= 1) { - // `sbrk` is not thread safe in general so try to protect it (we could skip this on WASM but leave it in for now) - #if defined(MI_USE_PTHREADS) - pthread_mutex_lock(&mi_heap_grow_mutex); - #endif - p = mi_memory_grow(size); - #if defined(MI_USE_PTHREADS) - pthread_mutex_unlock(&mi_heap_grow_mutex); - #endif - } - else { - void* base = NULL; - size_t alloc_size = 0; - // to allocate aligned use a lock to try to avoid thread interaction - // between getting the current size and actual allocation - // (also, `sbrk` is not thread safe in general) - #if defined(MI_USE_PTHREADS) - pthread_mutex_lock(&mi_heap_grow_mutex); - #endif - { - void* current = mi_memory_grow(0); // get current size - if (current != NULL) { - void* aligned_current = mi_align_up_ptr(current, try_alignment); // and align from there to minimize wasted space - alloc_size = _mi_align_up( ((uint8_t*)aligned_current - (uint8_t*)current) + size, _mi_os_page_size()); - base = mi_memory_grow(alloc_size); - } +// In secure mode, try to recommit an area +bool _mi_os_secure_guard_page_reset_at(void* addr, mi_memid_t memid) { + if (addr == NULL) return true; + #if MI_SECURE > 0 + if (!memid.is_pinned) { + mi_arena_t* const arena = mi_memid_arena(memid); + if (arena != NULL && arena->commit_fun != NULL) { + return (*(arena->commit_fun))(true, addr, _mi_os_secure_guard_page_size(), NULL, arena->commit_fun_arg); } - #if defined(MI_USE_PTHREADS) - pthread_mutex_unlock(&mi_heap_grow_mutex); - #endif - if (base != NULL) { - p = mi_align_up_ptr(base, try_alignment); - if ((uint8_t*)p + size > (uint8_t*)base + alloc_size) { - // another thread used wasm_memory_grow/sbrk in-between and we do not have enough - // space after alignment. Give up (and waste the space as we cannot shrink :-( ) - // (in `mi_os_mem_alloc_aligned` this will fall back to overallocation to align) - p = NULL; - } + else { + return _mi_os_commit(addr, _mi_os_secure_guard_page_size(), NULL); } } - if (p == NULL) { - _mi_warning_message("unable to allocate sbrk/wasm_memory_grow OS memory (%zu bytes, %zu alignment)\n", size, try_alignment); - errno = ENOMEM; - return NULL; - } - mi_assert_internal( try_alignment == 0 || (uintptr_t)p % try_alignment == 0 ); - return p; + #else + MI_UNUSED(memid); + #endif + return true; +} + +// In secure mode, try to recommit an area +bool _mi_os_secure_guard_page_reset_before(void* addr, mi_memid_t memid) { + return _mi_os_secure_guard_page_reset_at((uint8_t*)addr - _mi_os_secure_guard_page_size(), memid); } + /* ----------------------------------------------------------- - Raw allocation on Unix's (mmap) + Free memory -------------------------------------------------------------- */ -#else -#define MI_OS_USE_MMAP -static void* mi_unix_mmapx(void* addr, size_t size, size_t try_alignment, int protect_flags, int flags, int fd) { - MI_UNUSED(try_alignment); - #if defined(MAP_ALIGNED) // BSD - if (addr == NULL && try_alignment > 1 && (try_alignment % _mi_os_page_size()) == 0) { - size_t n = mi_bsr(try_alignment); - if (((size_t)1 << n) == try_alignment && n >= 12 && n <= 30) { // alignment is a power of 2 and 4096 <= alignment <= 1GiB - flags |= MAP_ALIGNED(n); - void* p = mmap(addr, size, protect_flags, flags | MAP_ALIGNED(n), fd, 0); - if (p!=MAP_FAILED) return p; - // fall back to regular mmap - } - } - #elif defined(MAP_ALIGN) // Solaris - if (addr == NULL && try_alignment > 1 && (try_alignment % _mi_os_page_size()) == 0) { - void* p = mmap((void*)try_alignment, size, protect_flags, flags | MAP_ALIGN, fd, 0); // addr parameter is the required alignment - if (p!=MAP_FAILED) return p; - // fall back to regular mmap + +static void mi_os_free_huge_os_pages(void* p, size_t size, mi_subproc_t* subproc); + +static void mi_os_prim_free(void* addr, size_t size, size_t commit_size, mi_subproc_t* subproc) { + mi_assert_internal((size % _mi_os_page_size()) == 0); + if (addr == NULL) return; // || _mi_os_is_huge_reserved(addr) + int err = _mi_prim_free(addr, size); // allow size==0 (issue #1041) + if (err != 0) { + _mi_warning_message("unable to free OS memory (error: %d (0x%x), size: 0x%zx bytes, address: %p)\n", err, err, size, addr); } - #endif - #if (MI_INTPTR_SIZE >= 8) && !defined(MAP_ALIGNED) - // on 64-bit systems, use the virtual address area after 2TiB for 4MiB aligned allocations - if (addr == NULL) { - void* hint = mi_os_get_aligned_hint(try_alignment, size); - if (hint != NULL) { - void* p = mmap(hint, size, protect_flags, flags, fd, 0); - if (p!=MAP_FAILED) return p; - // fall back to regular mmap - } + if (subproc == NULL) { subproc = _mi_subproc(); } // from `mi_arenas_unsafe_destroy` we pass subproc_main explicitly as we can no longer use the heap pointer + if (commit_size > 0) { + mi_subproc_stat_decrease(subproc, committed, commit_size); } - #endif - // regular mmap - void* p = mmap(addr, size, protect_flags, flags, fd, 0); - if (p!=MAP_FAILED) return p; - // failed to allocate - return NULL; -} - -static int mi_unix_mmap_fd(void) { -#if defined(VM_MAKE_TAG) - // macOS: tracking anonymous page with a specific ID. (All up to 98 are taken officially but LLVM sanitizers had taken 99) - int os_tag = (int)mi_option_get(mi_option_os_tag); - if (os_tag < 100 || os_tag > 255) os_tag = 100; - return VM_MAKE_TAG(os_tag); -#else - return -1; -#endif + mi_subproc_stat_decrease(subproc, reserved, size); } -static void* mi_unix_mmap(void* addr, size_t size, size_t try_alignment, int protect_flags, bool large_only, bool allow_large, bool* is_large) { - void* p = NULL; - #if !defined(MAP_ANONYMOUS) - #define MAP_ANONYMOUS MAP_ANON - #endif - #if !defined(MAP_NORESERVE) - #define MAP_NORESERVE 0 - #endif - const int fd = mi_unix_mmap_fd(); - int flags = MAP_PRIVATE | MAP_ANONYMOUS; - if (_mi_os_has_overcommit()) { - flags |= MAP_NORESERVE; - } - #if defined(PROT_MAX) - protect_flags |= PROT_MAX(PROT_READ | PROT_WRITE); // BSD - #endif - // huge page allocation - if ((large_only || use_large_os_page(size, try_alignment)) && allow_large) { - static _Atomic(size_t) large_page_try_ok; // = 0; - size_t try_ok = mi_atomic_load_acquire(&large_page_try_ok); - if (!large_only && try_ok > 0) { - // If the OS is not configured for large OS pages, or the user does not have - // enough permission, the `mmap` will always fail (but it might also fail for other reasons). - // Therefore, once a large page allocation failed, we don't try again for `large_page_try_ok` times - // to avoid too many failing calls to mmap. - mi_atomic_cas_strong_acq_rel(&large_page_try_ok, &try_ok, try_ok - 1); - } - else { - int lflags = flags & ~MAP_NORESERVE; // using NORESERVE on huge pages seems to fail on Linux - int lfd = fd; - #ifdef MAP_ALIGNED_SUPER - lflags |= MAP_ALIGNED_SUPER; - #endif - #ifdef MAP_HUGETLB - lflags |= MAP_HUGETLB; - #endif - #ifdef MAP_HUGE_1GB - static bool mi_huge_pages_available = true; - if ((size % MI_GiB) == 0 && mi_huge_pages_available) { - lflags |= MAP_HUGE_1GB; - } - else - #endif - { - #ifdef MAP_HUGE_2MB - lflags |= MAP_HUGE_2MB; - #endif +void _mi_os_free_ex(void* addr, size_t size, bool still_committed, mi_memid_t memid, mi_subproc_t* subproc /* can be NULL */) { + if (mi_memkind_is_os(memid.memkind)) { + size_t csize = memid.mem.os.size; + if (csize==0) { csize = _mi_os_good_alloc_size(size); } + mi_assert_internal(csize >= size); + size_t commit_size = (still_committed ? csize : 0); + void* base = addr; + // different base? (due to alignment) + if (memid.mem.os.base != base) { + mi_assert(memid.mem.os.base <= addr); + base = memid.mem.os.base; + const size_t diff = (uint8_t*)addr - (uint8_t*)memid.mem.os.base; + if (memid.mem.os.size==0) { + csize += diff; } - #ifdef VM_FLAGS_SUPERPAGE_SIZE_2MB - lfd |= VM_FLAGS_SUPERPAGE_SIZE_2MB; - #endif - if (large_only || lflags != flags) { - // try large OS page allocation - *is_large = true; - p = mi_unix_mmapx(addr, size, try_alignment, protect_flags, lflags, lfd); - #ifdef MAP_HUGE_1GB - if (p == NULL && (lflags & MAP_HUGE_1GB) != 0) { - mi_huge_pages_available = false; // don't try huge 1GiB pages again - _mi_warning_message("unable to allocate huge (1GiB) page, trying large (2MiB) pages instead (error %i)\n", errno); - lflags = ((lflags & ~MAP_HUGE_1GB) | MAP_HUGE_2MB); - p = mi_unix_mmapx(addr, size, try_alignment, protect_flags, lflags, lfd); - } - #endif - if (large_only) return p; - if (p == NULL) { - mi_atomic_store_release(&large_page_try_ok, (size_t)8); // on error, don't try again for the next N allocations - } + if (still_committed) { + commit_size -= diff; // the (addr-base) part was already un-committed } } - } - // regular allocation - if (p == NULL) { - *is_large = false; - p = mi_unix_mmapx(addr, size, try_alignment, protect_flags, flags, fd); - if (p != NULL) { - #if defined(MADV_HUGEPAGE) - // Many Linux systems don't allow MAP_HUGETLB but they support instead - // transparent huge pages (THP). Generally, it is not required to call `madvise` with MADV_HUGE - // though since properly aligned allocations will already use large pages if available - // in that case -- in particular for our large regions (in `memory.c`). - // However, some systems only allow THP if called with explicit `madvise`, so - // when large OS pages are enabled for mimalloc, we call `madvise` anyways. - if (allow_large && use_large_os_page(size, try_alignment)) { - if (mi_madvise(p, size, MADV_HUGEPAGE) == 0) { - *is_large = true; // possibly - }; - } - #elif defined(__sun) - if (allow_large && use_large_os_page(size, try_alignment)) { - struct memcntl_mha cmd = {0}; - cmd.mha_pagesize = large_os_page_size; - cmd.mha_cmd = MHA_MAPSIZE_VA; - if (memcntl((caddr_t)p, size, MC_HAT_ADVISE, (caddr_t)&cmd, 0, 0) == 0) { - *is_large = true; - } - } - #endif + // free it + if (memid.memkind == MI_MEM_OS_HUGE) { + mi_assert(memid.is_pinned); + mi_os_free_huge_os_pages(base, csize, subproc); + } + else { + mi_os_prim_free(base, csize, (still_committed ? commit_size : 0), subproc); } } - if (p == NULL) { - _mi_warning_message("unable to allocate OS memory (%zu bytes, error code: %i, address: %p, large only: %d, allow large: %d)\n", size, errno, addr, large_only, allow_large); + else { + // nothing to do + mi_assert(memid.memkind < MI_MEM_OS); } - return p; } -#endif + +void _mi_os_free(void* p, size_t size, mi_memid_t memid) { + _mi_os_free_ex(p, size, true, memid, NULL); +} /* ----------------------------------------------------------- @@ -702,148 +236,223 @@ static void* mi_unix_mmap(void* addr, size_t size, size_t try_alignment, int pro -------------------------------------------------------------- */ // Note: the `try_alignment` is just a hint and the returned pointer is not guaranteed to be aligned. -static void* mi_os_mem_alloc(size_t size, size_t try_alignment, bool commit, bool allow_large, bool* is_large, mi_stats_t* stats) { +// Also `hint_addr` is a hint and may be ignored. +static void* mi_os_prim_alloc_at(void* hint_addr, size_t size, size_t try_alignment, bool commit, bool allow_large, bool* is_large, bool* is_zero) { mi_assert_internal(size > 0 && (size % _mi_os_page_size()) == 0); + mi_assert_internal(is_zero != NULL); + mi_assert_internal(is_large != NULL); if (size == 0) return NULL; - if (!commit) allow_large = false; - if (try_alignment == 0) try_alignment = 1; // avoid 0 to ensure there will be no divide by zero when aligning - + if (!commit) { allow_large = false; } + if (try_alignment == 0) { try_alignment = 1; } // avoid 0 to ensure there will be no divide by zero when aligning + *is_zero = false; void* p = NULL; - /* - if (commit && allow_large) { - p = _mi_os_try_alloc_from_huge_reserved(size, try_alignment); - if (p != NULL) { - *is_large = true; - return p; - } + int err = _mi_prim_alloc(hint_addr, size, try_alignment, commit, allow_large, is_large, is_zero, &p); + if (err != 0) { + _mi_warning_message("unable to allocate OS memory (error: %d (0x%x), addr: %p, size: 0x%zx bytes, align: 0x%zx, commit: %d, allow large: %d)\n", err, err, hint_addr, size, try_alignment, commit, allow_large); } - */ - #if defined(_WIN32) - int flags = MEM_RESERVE; - if (commit) { flags |= MEM_COMMIT; } - p = mi_win_virtual_alloc(NULL, size, try_alignment, flags, false, allow_large, is_large); - #elif defined(MI_USE_SBRK) || defined(__wasi__) - MI_UNUSED(allow_large); - *is_large = false; - p = mi_heap_grow(size, try_alignment); - #else - int protect_flags = (commit ? (PROT_WRITE | PROT_READ) : PROT_NONE); - p = mi_unix_mmap(NULL, size, try_alignment, protect_flags, false, allow_large, is_large); - #endif - mi_stat_counter_increase(stats->mmap_calls, 1); + mi_os_stat_counter_increase(mmap_calls, 1); if (p != NULL) { - _mi_stat_increase(&stats->reserved, size); - if (commit) { _mi_stat_increase(&stats->committed, size); } + mi_os_stat_increase(reserved, size); + if (commit) { + mi_os_stat_increase(committed, size); + // seems needed for asan (or `mimalloc-test-api` fails) + #ifdef MI_TRACK_ASAN + if (*is_zero) { mi_track_mem_defined(p,size); } + else { mi_track_mem_undefined(p,size); } + #endif + } } return p; } +static void* mi_os_prim_alloc(size_t size, size_t try_alignment, bool commit, bool allow_large, bool* is_large, bool* is_zero) { + return mi_os_prim_alloc_at(NULL, size, try_alignment, commit, allow_large, is_large, is_zero); +} + // Primitive aligned allocation from the OS. // This function guarantees the allocated memory is aligned. -static void* mi_os_mem_alloc_aligned(size_t size, size_t alignment, bool commit, bool allow_large, bool* is_large, mi_stats_t* stats) { +static void* mi_os_prim_alloc_aligned(size_t size, size_t alignment, bool commit, bool allow_large, bool* is_large, bool* is_zero, void** base) { mi_assert_internal(alignment >= _mi_os_page_size() && ((alignment & (alignment - 1)) == 0)); mi_assert_internal(size > 0 && (size % _mi_os_page_size()) == 0); mi_assert_internal(is_large != NULL); + mi_assert_internal(is_zero != NULL); + mi_assert_internal(base != NULL); if (!commit) allow_large = false; if (!(alignment >= _mi_os_page_size() && ((alignment & (alignment - 1)) == 0))) return NULL; size = _mi_align_up(size, _mi_os_page_size()); - // try first with a hint (this will be aligned directly on Win 10+ or BSD) - void* p = mi_os_mem_alloc(size, alignment, commit, allow_large, is_large, stats); - if (p == NULL) return NULL; - - // if not aligned, free it, overallocate, and unmap around it - if (((uintptr_t)p % alignment != 0)) { - mi_os_mem_free(p, size, commit, stats); - _mi_warning_message("unable to allocate aligned OS memory directly, fall back to over-allocation (%zu bytes, address: %p, alignment: %zu, commit: %d)\n", size, p, alignment, commit); + // try a direct allocation if the alignment is below the default, or if larger than 1/8 fraction of the size. + const bool try_direct_alloc = (alignment <= mi_os_mem_config.alloc_granularity || alignment > size/8); + + void* p = NULL; + if (try_direct_alloc) { + p = mi_os_prim_alloc(size, alignment, commit, allow_large, is_large, is_zero); + } + + // aligned already? + if (p != NULL && ((uintptr_t)p % alignment) == 0) { + *base = p; + } + else { + // if not aligned, free it, overallocate, and unmap around it + #if !MI_TRACK_ASAN + if (try_direct_alloc) { + _mi_warning_message("unable to allocate aligned OS memory directly, fall back to over-allocation (size: 0x%zx bytes, address: %p, alignment: 0x%zx, commit: %d)\n", size, p, alignment, commit); + } + #endif + if (p != NULL) { mi_os_prim_free(p, size, (commit ? size : 0), NULL); } if (size >= (SIZE_MAX - alignment)) return NULL; // overflow const size_t over_size = size + alignment; -#if _WIN32 - // over-allocate uncommitted (virtual) memory - p = mi_os_mem_alloc(over_size, 0 /*alignment*/, false /* commit? */, false /* allow_large */, is_large, stats); - if (p == NULL) return NULL; - - // set p to the aligned part in the full region - // note: this is dangerous on Windows as VirtualFree needs the actual region pointer - // but in mi_os_mem_free we handle this (hopefully exceptional) situation. - p = mi_align_up_ptr(p, alignment); - - // explicitly commit only the aligned part - if (commit) { - _mi_os_commit(p, size, NULL, stats); + if (!mi_os_mem_config.has_partial_free) { // win32 virtualAlloc cannot free parts of an allocated block + // over-allocate uncommitted (virtual) memory + p = mi_os_prim_alloc(over_size, 1 /*alignment*/, false /* commit? */, false /* allow_large */, is_large, is_zero); + if (p == NULL) return NULL; + + // set p to the aligned part in the full region + // note: on Windows VirtualFree needs the actual base pointer + // this is handledby having the `base` field in the memid. + *base = p; // remember the base + p = _mi_align_up_ptr(p, alignment); + + // explicitly commit only the aligned part + if (commit) { + if (!_mi_os_commit(p, size, NULL)) { + mi_os_prim_free(*base, over_size, 0, NULL); + return NULL; + } + } + } + else { // mmap can free inside an allocation + // overallocate... + p = mi_os_prim_alloc(over_size, 1, commit, false, is_large, is_zero); + if (p == NULL) return NULL; + + // and selectively unmap parts around the over-allocated area. + void* aligned_p = _mi_align_up_ptr(p, alignment); + size_t pre_size = (uint8_t*)aligned_p - (uint8_t*)p; + size_t mid_size = _mi_align_up(size, _mi_os_page_size()); + size_t post_size = over_size - pre_size - mid_size; + mi_assert_internal(pre_size < over_size&& post_size < over_size&& mid_size >= size); + if (pre_size > 0) { mi_os_prim_free(p, pre_size, (commit ? pre_size : 0), NULL); } + if (post_size > 0) { mi_os_prim_free((uint8_t*)aligned_p + mid_size, post_size, (commit ? post_size : 0), NULL); } + // we can return the aligned pointer on `mmap` systems + p = aligned_p; + *base = aligned_p; // since we freed the pre part, `*base == p`. } -#else - // overallocate... - p = mi_os_mem_alloc(over_size, 1, commit, false, is_large, stats); - if (p == NULL) return NULL; - // and selectively unmap parts around the over-allocated area. (noop on sbrk) - void* aligned_p = mi_align_up_ptr(p, alignment); - size_t pre_size = (uint8_t*)aligned_p - (uint8_t*)p; - size_t mid_size = _mi_align_up(size, _mi_os_page_size()); - size_t post_size = over_size - pre_size - mid_size; - mi_assert_internal(pre_size < over_size && post_size < over_size && mid_size >= size); - if (pre_size > 0) mi_os_mem_free(p, pre_size, commit, stats); - if (post_size > 0) mi_os_mem_free((uint8_t*)aligned_p + mid_size, post_size, commit, stats); - // we can return the aligned pointer on `mmap` (and sbrk) systems - p = aligned_p; -#endif } - mi_assert_internal(p == NULL || (p != NULL && ((uintptr_t)p % alignment) == 0)); + mi_assert_internal(p == NULL || (p != NULL && *base != NULL && ((uintptr_t)p % alignment) == 0)); return p; } /* ----------------------------------------------------------- - OS API: alloc, free, alloc_aligned + OS API: alloc and alloc_aligned ----------------------------------------------------------- */ -void* _mi_os_alloc(size_t size, mi_stats_t* tld_stats) { - MI_UNUSED(tld_stats); - mi_stats_t* stats = &_mi_stats_main; +void* _mi_os_alloc(size_t size, mi_memid_t* memid) { + *memid = _mi_memid_none(); if (size == 0) return NULL; size = _mi_os_good_alloc_size(size); - bool is_large = false; - return mi_os_mem_alloc(size, 0, true, false, &is_large, stats); -} - -void _mi_os_free_ex(void* p, size_t size, bool was_committed, mi_stats_t* tld_stats) { - MI_UNUSED(tld_stats); - mi_stats_t* stats = &_mi_stats_main; - if (size == 0 || p == NULL) return; - size = _mi_os_good_alloc_size(size); - mi_os_mem_free(p, size, was_committed, stats); -} + bool os_is_large = false; + bool os_is_zero = false; + void* p = mi_os_prim_alloc(size, 0, true, false, &os_is_large, &os_is_zero); + if (p == NULL) return NULL; -void _mi_os_free(void* p, size_t size, mi_stats_t* stats) { - _mi_os_free_ex(p, size, true, stats); + *memid = _mi_memid_create_os(p, size, true, os_is_zero, os_is_large); + mi_assert_internal(memid->mem.os.size >= size); + mi_assert_internal(memid->initially_committed); + return p; } -void* _mi_os_alloc_aligned(size_t size, size_t alignment, bool commit, bool* large, mi_stats_t* tld_stats) +void* _mi_os_alloc_aligned(size_t size, size_t alignment, bool commit, bool allow_large, mi_memid_t* memid) { - MI_UNUSED(&mi_os_get_aligned_hint); // suppress unused warnings - MI_UNUSED(tld_stats); + MI_UNUSED(&_mi_os_get_aligned_hint); // suppress unused warnings + *memid = _mi_memid_none(); if (size == 0) return NULL; size = _mi_os_good_alloc_size(size); alignment = _mi_align_up(alignment, _mi_os_page_size()); - bool allow_large = false; - if (large != NULL) { - allow_large = *large; - *large = false; + + bool os_is_large = false; + bool os_is_zero = false; + void* os_base = NULL; + void* p = mi_os_prim_alloc_aligned(size, alignment, commit, allow_large, &os_is_large, &os_is_zero, &os_base ); + if (p == NULL) return NULL; + + *memid = _mi_memid_create_os(p, size, commit, os_is_zero, os_is_large); + memid->mem.os.base = os_base; + memid->mem.os.size += ((uint8_t*)p - (uint8_t*)os_base); // todo: return from prim_alloc_aligned? + + mi_assert_internal(memid->mem.os.size >= size); + mi_assert_internal(_mi_is_aligned(p,alignment)); + if (commit) { mi_assert_internal(memid->initially_committed); } + return p; +} + + +mi_decl_nodiscard static void* mi_os_ensure_zero(void* p, size_t size, mi_memid_t* memid) { + if (p==NULL || size==0) return p; + // ensure committed + if (!memid->initially_committed) { + bool is_zero = false; + if (!_mi_os_commit(p, size, &is_zero)) { + _mi_os_free(p, size, *memid); + return NULL; + } + memid->initially_committed = true; } - return mi_os_mem_alloc_aligned(size, alignment, commit, allow_large, (large!=NULL?large:&allow_large), &_mi_stats_main /*tld->stats*/ ); + // ensure zero'd + if (memid->initially_zero) return p; + _mi_memzero_aligned(p,size); + memid->initially_zero = true; + return p; } +void* _mi_os_zalloc(size_t size, mi_memid_t* memid) { + void* p = _mi_os_alloc(size,memid); + return mi_os_ensure_zero(p, size, memid); +} +/* ----------------------------------------------------------- + OS aligned allocation with an offset. This is used + for large alignments > MI_BLOCK_ALIGNMENT_MAX. We use a large mimalloc + page where the object can be aligned at an offset from the start of the segment. + As we may need to overallocate, we need to free such pointers using `mi_free_aligned` + to use the actual start of the memory region. +----------------------------------------------------------- */ + +void* _mi_os_alloc_aligned_at_offset(size_t size, size_t alignment, size_t offset, bool commit, bool allow_large, mi_memid_t* memid) { + mi_assert(offset <= size); + mi_assert((alignment % _mi_os_page_size()) == 0); + *memid = _mi_memid_none(); + if (offset == 0) { + // regular aligned allocation + return _mi_os_alloc_aligned(size, alignment, commit, allow_large, memid); + } + else { + // overallocate to align at an offset + const size_t extra = _mi_align_up(offset, alignment) - offset; + const size_t oversize = size + extra; + void* const start = _mi_os_alloc_aligned(oversize, alignment, commit, allow_large, memid); + if (start == NULL) return NULL; + + void* const p = (uint8_t*)start + extra; + mi_assert(_mi_is_aligned((uint8_t*)p + offset, alignment)); + // decommit the overallocation at the start + if (commit && extra > _mi_os_page_size()) { + _mi_os_decommit(start, extra); + } + return p; + } +} /* ----------------------------------------------------------- OS memory API: reset, commit, decommit, protect, unprotect. ----------------------------------------------------------- */ - // OS page align within a given area, either conservative (pages inside the area only), // or not (straddling pages outside the area is possible) static void* mi_os_page_align_areax(bool conservative, void* addr, size_t size, size_t* newsize) { @@ -851,11 +460,11 @@ static void* mi_os_page_align_areax(bool conservative, void* addr, size_t size, if (newsize != NULL) *newsize = 0; if (size == 0 || addr == NULL) return NULL; - // page align conservatively within the range - void* start = (conservative ? mi_align_up_ptr(addr, _mi_os_page_size()) + // page align conservatively within the range, or liberally straddling pages outside the range + void* start = (conservative ? _mi_align_up_ptr(addr, _mi_os_page_size()) : mi_align_down_ptr(addr, _mi_os_page_size())); void* end = (conservative ? mi_align_down_ptr((uint8_t*)addr + size, _mi_os_page_size()) - : mi_align_up_ptr((uint8_t*)addr + size, _mi_os_page_size())); + : _mi_align_up_ptr((uint8_t*)addr + size, _mi_os_page_size())); ptrdiff_t diff = (uint8_t*)end - (uint8_t*)start; if (diff <= 0) return NULL; @@ -868,188 +477,132 @@ static void* mi_os_page_align_area_conservative(void* addr, size_t size, size_t* return mi_os_page_align_areax(true, addr, size, newsize); } -static void mi_mprotect_hint(int err) { -#if defined(MI_OS_USE_MMAP) && (MI_SECURE>=2) // guard page around every mimalloc page - if (err == ENOMEM) { - _mi_warning_message("the previous warning may have been caused by a low memory map limit.\n" - " On Linux this is controlled by the vm.max_map_count. For example:\n" - " > sudo sysctl -w vm.max_map_count=262144\n"); - } -#else - MI_UNUSED(err); -#endif -} - -// Commit/Decommit memory. -// Usually commit is aligned liberal, while decommit is aligned conservative. -// (but not for the reset version where we want commit to be conservative as well) -static bool mi_os_commitx(void* addr, size_t size, bool commit, bool conservative, bool* is_zero, mi_stats_t* stats) { - // page align in the range, commit liberally, decommit conservative +bool _mi_os_commit_ex(void* addr, size_t size, bool* is_zero, size_t stat_size) { if (is_zero != NULL) { *is_zero = false; } + mi_os_stat_counter_increase(commit_calls, 1); + + // page align range size_t csize; - void* start = mi_os_page_align_areax(conservative, addr, size, &csize); - if (csize == 0) return true; // || _mi_os_is_huge_reserved(addr)) - int err = 0; - if (commit) { - _mi_stat_increase(&stats->committed, size); // use size for precise commit vs. decommit - _mi_stat_counter_increase(&stats->commit_calls, 1); - } - else { - _mi_stat_decrease(&stats->committed, size); - } + void* start = mi_os_page_align_areax(false /* conservative? */, addr, size, &csize); + if (csize == 0) return true; - #if defined(_WIN32) - if (commit) { - // *is_zero = true; // note: if the memory was already committed, the call succeeds but the memory is not zero'd - void* p = VirtualAlloc(start, csize, MEM_COMMIT, PAGE_READWRITE); - err = (p == start ? 0 : GetLastError()); - } - else { - BOOL ok = VirtualFree(start, csize, MEM_DECOMMIT); - err = (ok ? 0 : GetLastError()); - } - #elif defined(__wasi__) - // WebAssembly guests can't control memory protection - #elif 0 && defined(MAP_FIXED) && !defined(__APPLE__) - // Linux: disabled for now as mmap fixed seems much more expensive than MADV_DONTNEED (and splits VMA's?) - if (commit) { - // commit: just change the protection - err = mprotect(start, csize, (PROT_READ | PROT_WRITE)); - if (err != 0) { err = errno; } - } - else { - // decommit: use mmap with MAP_FIXED to discard the existing memory (and reduce rss) - const int fd = mi_unix_mmap_fd(); - void* p = mmap(start, csize, PROT_NONE, (MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE), fd, 0); - if (p != start) { err = errno; } + // commit + bool os_is_zero = false; + int err = _mi_prim_commit(start, csize, &os_is_zero); + if (err != 0) { + _mi_warning_message("cannot commit OS memory (error: %d (0x%x), address: %p, size: 0x%zx bytes)\n", err, err, start, csize); + return false; } - #else - // Linux, macOSX and others. - if (commit) { - // commit: ensure we can access the area - err = mprotect(start, csize, (PROT_READ | PROT_WRITE)); - if (err != 0) { err = errno; } - } - else { - #if defined(MADV_DONTNEED) && MI_DEBUG == 0 && MI_SECURE == 0 - // decommit: use MADV_DONTNEED as it decreases rss immediately (unlike MADV_FREE) - // (on the other hand, MADV_FREE would be good enough.. it is just not reflected in the stats :-( ) - err = madvise(start, csize, MADV_DONTNEED); - #else - // decommit: just disable access (also used in debug and secure mode to trap on illegal access) - err = mprotect(start, csize, PROT_NONE); - if (err != 0) { err = errno; } - #endif - //#if defined(MADV_FREE_REUSE) - // while ((err = mi_madvise(start, csize, MADV_FREE_REUSE)) != 0 && errno == EAGAIN) { errno = 0; } - //#endif + if (os_is_zero && is_zero != NULL) { + *is_zero = true; + mi_assert_expensive(mi_mem_is_zero(start, csize)); } + // note: the following seems required for asan (otherwise `mimalloc-test-stress` fails) + #ifdef MI_TRACK_ASAN + if (os_is_zero) { mi_track_mem_defined(start,csize); } + else { mi_track_mem_undefined(start,csize); } #endif + mi_os_stat_increase(committed, stat_size); // use size for precise commit vs. decommit + return true; +} + +bool _mi_os_commit(void* addr, size_t size, bool* is_zero) { + return _mi_os_commit_ex(addr, size, is_zero, size); +} + +static bool mi_os_decommit_ex(void* addr, size_t size, bool* needs_recommit, size_t stat_size) { + mi_assert_internal(needs_recommit!=NULL); + mi_os_stat_decrease(committed, stat_size); + + // page align + size_t csize; + void* start = mi_os_page_align_area_conservative(addr, size, &csize); + if (csize == 0) return true; + + // decommit + *needs_recommit = true; + int err = _mi_prim_decommit(start,csize,needs_recommit); if (err != 0) { - _mi_warning_message("%s error: start: %p, csize: 0x%zx, err: %i\n", commit ? "commit" : "decommit", start, csize, err); - mi_mprotect_hint(err); + _mi_warning_message("cannot decommit OS memory (error: %d (0x%x), address: %p, size: 0x%zx bytes)\n", err, err, start, csize); } mi_assert_internal(err == 0); return (err == 0); } -bool _mi_os_commit(void* addr, size_t size, bool* is_zero, mi_stats_t* tld_stats) { - MI_UNUSED(tld_stats); - mi_stats_t* stats = &_mi_stats_main; - return mi_os_commitx(addr, size, true, false /* liberal */, is_zero, stats); +bool _mi_os_decommit(void* addr, size_t size) { + bool needs_recommit; + return mi_os_decommit_ex(addr, size, &needs_recommit, size); } -bool _mi_os_decommit(void* addr, size_t size, mi_stats_t* tld_stats) { - MI_UNUSED(tld_stats); - mi_stats_t* stats = &_mi_stats_main; - bool is_zero; - return mi_os_commitx(addr, size, false, true /* conservative */, &is_zero, stats); -} - -/* -static bool mi_os_commit_unreset(void* addr, size_t size, bool* is_zero, mi_stats_t* stats) { - return mi_os_commitx(addr, size, true, true // conservative - , is_zero, stats); -} -*/ // Signal to the OS that the address range is no longer in use // but may be used later again. This will release physical memory // pages and reduce swapping while keeping the memory committed. // We page align to a conservative area inside the range to reset. -static bool mi_os_resetx(void* addr, size_t size, bool reset, mi_stats_t* stats) { +bool _mi_os_reset(void* addr, size_t size) { // page align conservatively within the range size_t csize; void* start = mi_os_page_align_area_conservative(addr, size, &csize); if (csize == 0) return true; // || _mi_os_is_huge_reserved(addr) - if (reset) _mi_stat_increase(&stats->reset, csize); - else _mi_stat_decrease(&stats->reset, csize); - if (!reset) return true; // nothing to do on unreset! + mi_os_stat_increase(reset, csize); + mi_os_stat_counter_increase(reset_calls, 1); - #if (MI_DEBUG>1) && !MI_TRACK_ENABLED - if (MI_SECURE==0) { - memset(start, 0, csize); // pretend it is eagerly reset - } + #if (MI_DEBUG>1) && !MI_SECURE && !MI_TRACK_ENABLED // && !MI_TSAN + memset(start, 0, csize); // pretend it is eagerly reset #endif -#if defined(_WIN32) - // Testing shows that for us (on `malloc-large`) MEM_RESET is 2x faster than DiscardVirtualMemory - void* p = VirtualAlloc(start, csize, MEM_RESET, PAGE_READWRITE); - mi_assert_internal(p == start); - #if 1 - if (p == start && start != NULL) { - VirtualUnlock(start,csize); // VirtualUnlock after MEM_RESET removes the memory from the working set - } - #endif - if (p != start) return false; -#else -#if defined(MADV_FREE) - static _Atomic(size_t) advice = MI_ATOMIC_VAR_INIT(MADV_FREE); - int oadvice = (int)mi_atomic_load_relaxed(&advice); - int err; - while ((err = mi_madvise(start, csize, oadvice)) != 0 && errno == EAGAIN) { errno = 0; }; - if (err != 0 && errno == EINVAL && oadvice == MADV_FREE) { - // if MADV_FREE is not supported, fall back to MADV_DONTNEED from now on - mi_atomic_store_release(&advice, (size_t)MADV_DONTNEED); - err = mi_madvise(start, csize, MADV_DONTNEED); - } -#elif defined(__wasi__) - int err = 0; -#else - int err = mi_madvise(start, csize, MADV_DONTNEED); -#endif + int err = _mi_prim_reset(start, csize); if (err != 0) { - _mi_warning_message("madvise reset error: start: %p, csize: 0x%zx, errno: %i\n", start, csize, errno); + _mi_warning_message("cannot reset OS memory (error: %d (0x%x), address: %p, size: 0x%zx bytes)\n", err, err, start, csize); } - //mi_assert(err == 0); - if (err != 0) return false; -#endif - return true; + return (err == 0); } -// Signal to the OS that the address range is no longer in use -// but may be used later again. This will release physical memory -// pages and reduce swapping while keeping the memory committed. -// We page align to a conservative area inside the range to reset. -bool _mi_os_reset(void* addr, size_t size, mi_stats_t* tld_stats) { - MI_UNUSED(tld_stats); - mi_stats_t* stats = &_mi_stats_main; - return mi_os_resetx(addr, size, true, stats); + +void _mi_os_reuse( void* addr, size_t size ) { + // page align conservatively within the range + size_t csize = 0; + void* const start = mi_os_page_align_area_conservative(addr, size, &csize); + if (csize == 0) return; + const int err = _mi_prim_reuse(start, csize); + if (err != 0) { + _mi_warning_message("cannot reuse OS memory (error: %d (0x%x), address: %p, size: 0x%zx bytes)\n", err, err, start, csize); + } } -/* -bool _mi_os_unreset(void* addr, size_t size, bool* is_zero, mi_stats_t* tld_stats) { - MI_UNUSED(tld_stats); - mi_stats_t* stats = &_mi_stats_main; - if (mi_option_is_enabled(mi_option_reset_decommits)) { - return mi_os_commit_unreset(addr, size, is_zero, stats); // re-commit it (conservatively!) +// either resets or decommits memory, returns true if the memory needs +// to be recommitted if it is to be re-used later on. +bool _mi_os_purge_ex(void* p, size_t size, bool allow_reset, size_t stat_size, mi_commit_fun_t* commit_fun, void* commit_fun_arg) +{ + if (mi_option_get(mi_option_purge_delay) < 0) return false; // is purging allowed? + mi_os_stat_counter_increase(purge_calls, 1); + mi_os_stat_increase(purged, size); + + if (commit_fun != NULL) { + bool decommitted = (*commit_fun)(false, p, size, NULL, commit_fun_arg); + return decommitted; // needs_recommit? + } + else if (mi_option_is_enabled(mi_option_purge_decommits) && // should decommit? + !_mi_preloading()) // don't decommit during preloading (unsafe) + { + bool needs_recommit = true; + mi_os_decommit_ex(p, size, &needs_recommit, stat_size); + return needs_recommit; } else { - *is_zero = false; - return mi_os_resetx(addr, size, false, stats); + if (allow_reset) { // this can sometimes be not allowed if the range is not fully committed (on Windows, we cannot reset uncommitted memory) + _mi_os_reset(p, size); + } + return false; // needs no recommit } } -*/ + +// either resets or decommits memory, returns true if the memory needs +// to be recommitted if it is to be re-used later on. +bool _mi_os_purge(void* p, size_t size) { + return _mi_os_purge_ex(p, size, true, size, NULL, NULL); +} + // Protect a region in memory to be not accessible. static bool mi_os_protectx(void* addr, size_t size, bool protect) { @@ -1062,20 +615,9 @@ static bool mi_os_protectx(void* addr, size_t size, bool protect) { _mi_warning_message("cannot mprotect memory allocated in huge OS pages\n"); } */ - int err = 0; -#ifdef _WIN32 - DWORD oldprotect = 0; - BOOL ok = VirtualProtect(start, csize, protect ? PAGE_NOACCESS : PAGE_READWRITE, &oldprotect); - err = (ok ? 0 : GetLastError()); -#elif defined(__wasi__) - err = 0; -#else - err = mprotect(start, csize, protect ? PROT_NONE : (PROT_READ | PROT_WRITE)); - if (err != 0) { err = errno; } -#endif + int err = _mi_prim_protect(start,csize,protect); if (err != 0) { - _mi_warning_message("mprotect error: start: %p, csize: 0x%zx, err: %i\n", start, csize, err); - mi_mprotect_hint(err); + _mi_warning_message("cannot %s OS memory (error: %d (0x%x), address: %p, size: 0x%zx bytes)\n", (protect ? "protect" : "unprotect"), err, err, start, csize); } return (err == 0); } @@ -1090,115 +632,12 @@ bool _mi_os_unprotect(void* addr, size_t size) { -bool _mi_os_shrink(void* p, size_t oldsize, size_t newsize, mi_stats_t* stats) { - // page align conservatively within the range - mi_assert_internal(oldsize > newsize && p != NULL); - if (oldsize < newsize || p == NULL) return false; - if (oldsize == newsize) return true; - - // oldsize and newsize should be page aligned or we cannot shrink precisely - void* addr = (uint8_t*)p + newsize; - size_t size = 0; - void* start = mi_os_page_align_area_conservative(addr, oldsize - newsize, &size); - if (size == 0 || start != addr) return false; - -#ifdef _WIN32 - // we cannot shrink on windows, but we can decommit - return _mi_os_decommit(start, size, stats); -#else - return mi_os_mem_free(start, size, true, stats); -#endif -} - - /* ---------------------------------------------------------------------------- Support for allocating huge OS pages (1Gib) that are reserved up-front and possibly associated with a specific NUMA node. (use `numa_node>=0`) -----------------------------------------------------------------------------*/ #define MI_HUGE_OS_PAGE_SIZE (MI_GiB) -#if defined(_WIN32) && (MI_INTPTR_SIZE >= 8) -static void* mi_os_alloc_huge_os_pagesx(void* addr, size_t size, int numa_node) -{ - mi_assert_internal(size%MI_GiB == 0); - mi_assert_internal(addr != NULL); - const DWORD flags = MEM_LARGE_PAGES | MEM_COMMIT | MEM_RESERVE; - - mi_win_enable_large_os_pages(); - - MI_MEM_EXTENDED_PARAMETER params[3] = { {{0,0},{0}},{{0,0},{0}},{{0,0},{0}} }; - // on modern Windows try use NtAllocateVirtualMemoryEx for 1GiB huge pages - static bool mi_huge_pages_available = true; - if (pNtAllocateVirtualMemoryEx != NULL && mi_huge_pages_available) { - params[0].Type.Type = MiMemExtendedParameterAttributeFlags; - params[0].Arg.ULong64 = MI_MEM_EXTENDED_PARAMETER_NONPAGED_HUGE; - ULONG param_count = 1; - if (numa_node >= 0) { - param_count++; - params[1].Type.Type = MiMemExtendedParameterNumaNode; - params[1].Arg.ULong = (unsigned)numa_node; - } - SIZE_T psize = size; - void* base = addr; - NTSTATUS err = (*pNtAllocateVirtualMemoryEx)(GetCurrentProcess(), &base, &psize, flags, PAGE_READWRITE, params, param_count); - if (err == 0 && base != NULL) { - return base; - } - else { - // fall back to regular large pages - mi_huge_pages_available = false; // don't try further huge pages - _mi_warning_message("unable to allocate using huge (1GiB) pages, trying large (2MiB) pages instead (status 0x%lx)\n", err); - } - } - // on modern Windows try use VirtualAlloc2 for numa aware large OS page allocation - if (pVirtualAlloc2 != NULL && numa_node >= 0) { - params[0].Type.Type = MiMemExtendedParameterNumaNode; - params[0].Arg.ULong = (unsigned)numa_node; - return (*pVirtualAlloc2)(GetCurrentProcess(), addr, size, flags, PAGE_READWRITE, params, 1); - } - - // otherwise use regular virtual alloc on older windows - return VirtualAlloc(addr, size, flags, PAGE_READWRITE); -} - -#elif defined(MI_OS_USE_MMAP) && (MI_INTPTR_SIZE >= 8) && !defined(__HAIKU__) -#include -#ifndef MPOL_PREFERRED -#define MPOL_PREFERRED 1 -#endif -#if defined(SYS_mbind) -static long mi_os_mbind(void* start, unsigned long len, unsigned long mode, const unsigned long* nmask, unsigned long maxnode, unsigned flags) { - return syscall(SYS_mbind, start, len, mode, nmask, maxnode, flags); -} -#else -static long mi_os_mbind(void* start, unsigned long len, unsigned long mode, const unsigned long* nmask, unsigned long maxnode, unsigned flags) { - MI_UNUSED(start); MI_UNUSED(len); MI_UNUSED(mode); MI_UNUSED(nmask); MI_UNUSED(maxnode); MI_UNUSED(flags); - return 0; -} -#endif -static void* mi_os_alloc_huge_os_pagesx(void* addr, size_t size, int numa_node) { - mi_assert_internal(size%MI_GiB == 0); - bool is_large = true; - void* p = mi_unix_mmap(addr, size, MI_SEGMENT_SIZE, PROT_READ | PROT_WRITE, true, true, &is_large); - if (p == NULL) return NULL; - if (numa_node >= 0 && numa_node < 8*MI_INTPTR_SIZE) { // at most 64 nodes - unsigned long numa_mask = (1UL << numa_node); - // TODO: does `mbind` work correctly for huge OS pages? should we - // use `set_mempolicy` before calling mmap instead? - // see: - long err = mi_os_mbind(p, size, MPOL_PREFERRED, &numa_mask, 8*MI_INTPTR_SIZE, 0); - if (err != 0) { - _mi_warning_message("failed to bind huge (1GiB) pages to numa node %d: %s\n", numa_node, strerror(errno)); - } - } - return p; -} -#else -static void* mi_os_alloc_huge_os_pagesx(void* addr, size_t size, int numa_node) { - MI_UNUSED(addr); MI_UNUSED(size); MI_UNUSED(numa_node); - return NULL; -} -#endif #if (MI_INTPTR_SIZE >= 8) // To ensure proper alignment, use our own area for huge OS pages @@ -1216,15 +655,14 @@ static uint8_t* mi_os_claim_huge_pages(size_t pages, size_t* total_size) { start = huge_start; if (start == 0) { // Initialize the start address after the 32TiB area - start = ((uintptr_t)32 << 40); // 32TiB virtual start address -#if (MI_SECURE>0 || MI_DEBUG==0) // security: randomize start of huge pages unless in debug mode - uintptr_t r = _mi_heap_random_next(mi_get_default_heap()); + start = ((uintptr_t)8 << 40); // 8TiB virtual start address + #if (MI_SECURE>0 || MI_DEBUG==0) // security: randomize start of huge pages unless in debug mode + uintptr_t r = _mi_heap_random_next(mi_prim_get_default_heap()); start = start + ((uintptr_t)MI_HUGE_OS_PAGE_SIZE * ((r>>17) & 0x0FFF)); // (randomly 12bits)*1GiB == between 0 to 4TiB -#endif + #endif } end = start + size; - mi_assert_internal(end % MI_SEGMENT_SIZE == 0); - } while (!mi_atomic_cas_strong_acq_rel(&mi_huge_start, &huge_start, end)); + } while (!mi_atomic_cas_weak_acq_rel(&mi_huge_start, &huge_start, end)); if (total_size != NULL) *total_size = size; return (uint8_t*)start; @@ -1237,37 +675,47 @@ static uint8_t* mi_os_claim_huge_pages(size_t pages, size_t* total_size) { } #endif -// Allocate MI_SEGMENT_SIZE aligned huge pages -void* _mi_os_alloc_huge_os_pages(size_t pages, int numa_node, mi_msecs_t max_msecs, size_t* pages_reserved, size_t* psize) { +// Allocate MI_ARENA_SLICE_ALIGN aligned huge pages +void* _mi_os_alloc_huge_os_pages(size_t pages, int numa_node, mi_msecs_t max_msecs, size_t* pages_reserved, size_t* psize, mi_memid_t* memid) { + *memid = _mi_memid_none(); if (psize != NULL) *psize = 0; if (pages_reserved != NULL) *pages_reserved = 0; size_t size = 0; - uint8_t* start = mi_os_claim_huge_pages(pages, &size); + uint8_t* const start = mi_os_claim_huge_pages(pages, &size); if (start == NULL) return NULL; // or 32-bit systems // Allocate one page at the time but try to place them contiguously // We allocate one page at the time to be able to abort if it takes too long // or to at least allocate as many as available on the system. mi_msecs_t start_t = _mi_clock_start(); - size_t page; - for (page = 0; page < pages; page++) { + size_t page = 0; + bool all_zero = true; + while (page < pages) { // allocate a page + bool is_zero = false; void* addr = start + (page * MI_HUGE_OS_PAGE_SIZE); - void* p = mi_os_alloc_huge_os_pagesx(addr, MI_HUGE_OS_PAGE_SIZE, numa_node); + void* p = NULL; + int err = _mi_prim_alloc_huge_os_pages(addr, MI_HUGE_OS_PAGE_SIZE, numa_node, &is_zero, &p); + if (!is_zero) { all_zero = false; } + if (err != 0) { + _mi_warning_message("unable to allocate huge OS page (error: %d (0x%x), address: %p, size: %zx bytes)\n", err, err, addr, MI_HUGE_OS_PAGE_SIZE); + break; + } // Did we succeed at a contiguous address? if (p != addr) { // no success, issue a warning and break if (p != NULL) { - _mi_warning_message("could not allocate contiguous huge page %zu at %p\n", page, addr); - _mi_os_free(p, MI_HUGE_OS_PAGE_SIZE, &_mi_stats_main); + _mi_warning_message("could not allocate contiguous huge OS page %zu at %p\n", page, addr); + mi_os_prim_free(p, MI_HUGE_OS_PAGE_SIZE, MI_HUGE_OS_PAGE_SIZE, NULL); } break; } // success, record it - _mi_stat_increase(&_mi_stats_main.committed, MI_HUGE_OS_PAGE_SIZE); - _mi_stat_increase(&_mi_stats_main.reserved, MI_HUGE_OS_PAGE_SIZE); + page++; // increase before timeout check (see issue #711) + mi_os_stat_increase(committed, MI_HUGE_OS_PAGE_SIZE); + mi_os_stat_increase(reserved, MI_HUGE_OS_PAGE_SIZE); // check for timeout if (max_msecs > 0) { @@ -1279,7 +727,7 @@ void* _mi_os_alloc_huge_os_pages(size_t pages, int numa_node, mi_msecs_t max_mse } } if (elapsed > max_msecs) { - _mi_warning_message("huge page allocation timed out\n"); + _mi_warning_message("huge OS page allocation timed out (after allocating %zu page(s))\n", page); break; } } @@ -1287,157 +735,117 @@ void* _mi_os_alloc_huge_os_pages(size_t pages, int numa_node, mi_msecs_t max_mse mi_assert_internal(page*MI_HUGE_OS_PAGE_SIZE <= size); if (pages_reserved != NULL) { *pages_reserved = page; } if (psize != NULL) { *psize = page * MI_HUGE_OS_PAGE_SIZE; } + if (page != 0) { + mi_assert(start != NULL); + *memid = _mi_memid_create_os(start, size, true /* is committed */, all_zero, true /* is_large */); + memid->memkind = MI_MEM_OS_HUGE; + mi_assert(memid->is_pinned); + #ifdef MI_TRACK_ASAN + if (all_zero) { mi_track_mem_defined(start,size); } + #endif + } return (page == 0 ? NULL : start); } // free every huge page in a range individually (as we allocated per page) // note: needed with VirtualAlloc but could potentially be done in one go on mmap'd systems. -void _mi_os_free_huge_pages(void* p, size_t size, mi_stats_t* stats) { +static void mi_os_free_huge_os_pages(void* p, size_t size, mi_subproc_t* subproc) { if (p==NULL || size==0) return; uint8_t* base = (uint8_t*)p; while (size >= MI_HUGE_OS_PAGE_SIZE) { - _mi_os_free(base, MI_HUGE_OS_PAGE_SIZE, stats); + mi_os_prim_free(base, MI_HUGE_OS_PAGE_SIZE, MI_HUGE_OS_PAGE_SIZE, subproc); size -= MI_HUGE_OS_PAGE_SIZE; base += MI_HUGE_OS_PAGE_SIZE; } } + /* ---------------------------------------------------------------------------- Support NUMA aware allocation -----------------------------------------------------------------------------*/ -#ifdef _WIN32 -static size_t mi_os_numa_nodex(void) { - USHORT numa_node = 0; - if (pGetCurrentProcessorNumberEx != NULL && pGetNumaProcessorNodeEx != NULL) { - // Extended API is supported - MI_PROCESSOR_NUMBER pnum; - (*pGetCurrentProcessorNumberEx)(&pnum); - USHORT nnode = 0; - BOOL ok = (*pGetNumaProcessorNodeEx)(&pnum, &nnode); - if (ok) numa_node = nnode; - } - else { - // Vista or earlier, use older API that is limited to 64 processors. Issue #277 - DWORD pnum = GetCurrentProcessorNumber(); - UCHAR nnode = 0; - BOOL ok = GetNumaProcessorNode((UCHAR)pnum, &nnode); - if (ok) numa_node = nnode; - } - return numa_node; -} -static size_t mi_os_numa_node_countx(void) { - ULONG numa_max = 0; - GetNumaHighestNodeNumber(&numa_max); - // find the highest node number that has actual processors assigned to it. Issue #282 - while(numa_max > 0) { - if (pGetNumaNodeProcessorMaskEx != NULL) { - // Extended API is supported - GROUP_AFFINITY affinity; - if ((*pGetNumaNodeProcessorMaskEx)((USHORT)numa_max, &affinity)) { - if (affinity.Mask != 0) break; // found the maximum non-empty node - } +static _Atomic(size_t) mi_numa_node_count; // = 0 // cache the node count + +int _mi_os_numa_node_count(void) { + size_t count = mi_atomic_load_acquire(&mi_numa_node_count); + if mi_unlikely(count == 0) { + long ncount = mi_option_get(mi_option_use_numa_nodes); // given explicitly? + if (ncount > 0 && ncount < INT_MAX) { + count = (size_t)ncount; } else { - // Vista or earlier, use older API that is limited to 64 processors. - ULONGLONG mask; - if (GetNumaNodeProcessorMask((UCHAR)numa_max, &mask)) { - if (mask != 0) break; // found the maximum non-empty node - }; + const size_t n = _mi_prim_numa_node_count(); // or detect dynamically + if (n == 0 || n > INT_MAX) { count = 1; } + else { count = n; } } - // max node was invalid or had no processor assigned, try again - numa_max--; + mi_atomic_store_release(&mi_numa_node_count, count); // save it + _mi_verbose_message("using %zd numa regions\n", count); } - return ((size_t)numa_max + 1); + mi_assert_internal(count > 0 && count <= INT_MAX); + return (int)count; } -#elif defined(__linux__) -#include // getcpu -#include // access - -static size_t mi_os_numa_nodex(void) { -#ifdef SYS_getcpu - unsigned long node = 0; - unsigned long ncpu = 0; - long err = syscall(SYS_getcpu, &ncpu, &node, NULL); - if (err != 0) return 0; - return node; -#else - return 0; -#endif + +static int mi_os_numa_node_get(void) { + int numa_count = _mi_os_numa_node_count(); + if (numa_count<=1) return 0; // optimize on single numa node systems: always node 0 + // never more than the node count and >= 0 + const size_t n = _mi_prim_numa_node(); + int numa_node = (n < INT_MAX ? (int)n : 0); + if (numa_node >= numa_count) { numa_node = numa_node % numa_count; } + return numa_node; } -static size_t mi_os_numa_node_countx(void) { - char buf[128]; - unsigned node = 0; - for(node = 0; node < 256; node++) { - // enumerate node entries -- todo: it there a more efficient way to do this? (but ensure there is no allocation) - snprintf(buf, 127, "/sys/devices/system/node/node%u", node + 1); - if (access(buf,R_OK) != 0) break; + +int _mi_os_numa_node(void) { + if mi_likely(mi_atomic_load_relaxed(&mi_numa_node_count) == 1) { + return 0; } - return (node+1); -} -#elif defined(__FreeBSD__) && __FreeBSD_version >= 1200000 -static size_t mi_os_numa_nodex(void) { - domainset_t dom; - size_t node; - int policy; - if (cpuset_getdomain(CPU_LEVEL_CPUSET, CPU_WHICH_PID, -1, sizeof(dom), &dom, &policy) == -1) return 0ul; - for (node = 0; node < MAXMEMDOM; node++) { - if (DOMAINSET_ISSET(node, &dom)) return node; + else { + return mi_os_numa_node_get(); } - return 0ul; -} -static size_t mi_os_numa_node_countx(void) { - size_t ndomains = 0; - size_t len = sizeof(ndomains); - if (sysctlbyname("vm.ndomains", &ndomains, &len, NULL, 0) == -1) return 0ul; - return ndomains; } -#elif defined(__DragonFly__) -static size_t mi_os_numa_nodex(void) { - // TODO: DragonFly does not seem to provide any userland means to get this information. - return 0ul; -} -static size_t mi_os_numa_node_countx(void) { - size_t ncpus = 0, nvirtcoresperphys = 0; - size_t len = sizeof(size_t); - if (sysctlbyname("hw.ncpu", &ncpus, &len, NULL, 0) == -1) return 0ul; - if (sysctlbyname("hw.cpu_topology_ht_ids", &nvirtcoresperphys, &len, NULL, 0) == -1) return 0ul; - return nvirtcoresperphys * ncpus; + + +/* ---------------------------------------------------------------------------- + Public API +-----------------------------------------------------------------------------*/ +#if 0 +mi_decl_export void* mi_os_alloc(size_t size, bool commit, size_t* full_size) { + return mi_os_alloc_aligned(size, mi_os_mem_config.alloc_granularity, commit, NULL, full_size); +} + +static void* mi_os_alloc_aligned_ex(size_t size, size_t alignment, bool commit, bool allow_large, bool* is_committed, bool* is_pinned, void** base, size_t* full_size) { + mi_memid_t memid = _mi_memid_none(); + void* p = _mi_os_alloc_aligned(size, alignment, commit, allow_large, &memid); + if (p == NULL) return p; + if (is_committed != NULL) { *is_committed = memid.initially_committed; } + if (is_pinned != NULL) { *is_pinned = memid.is_pinned; } + if (base != NULL) { *base = memid.mem.os.base; } + if (full_size != NULL) { *full_size = memid.mem.os.size; } + if (!memid.initially_zero && memid.initially_committed) { + _mi_memzero_aligned(memid.mem.os.base, memid.mem.os.size); + } + return p; } -#else -static size_t mi_os_numa_nodex(void) { - return 0; + +mi_decl_export void* mi_os_alloc_aligned(size_t size, size_t alignment, bool commit, void** base, size_t* full_size) { + return mi_os_alloc_aligned_ex(size, alignment, commit, false, NULL, NULL, base, full_size); } -static size_t mi_os_numa_node_countx(void) { - return 1; + +mi_decl_export void* mi_os_alloc_aligned_allow_large(size_t size, size_t alignment, bool commit, bool* is_committed, bool* is_pinned, void** base, size_t* full_size) { + return mi_os_alloc_aligned_ex(size, alignment, commit, true, is_committed, is_pinned, base, full_size); } -#endif -_Atomic(size_t) _mi_numa_node_count; // = 0 // cache the node count +mi_decl_export void mi_os_free(void* p, size_t size) { + if (p==NULL || size == 0) return; + mi_memid_t memid = _mi_memid_create_os(p, size, true, false, false); + _mi_os_free(p, size, memid); +} -size_t _mi_os_numa_node_count_get(void) { - size_t count = mi_atomic_load_acquire(&_mi_numa_node_count); - if (count <= 0) { - long ncount = mi_option_get(mi_option_use_numa_nodes); // given explicitly? - if (ncount > 0) { - count = (size_t)ncount; - } - else { - count = mi_os_numa_node_countx(); // or detect dynamically - if (count == 0) count = 1; - } - mi_atomic_store_release(&_mi_numa_node_count, count); // save it - _mi_verbose_message("using %zd numa regions\n", count); - } - return count; +mi_decl_export void mi_os_commit(void* p, size_t size) { + _mi_os_commit(p, size, NULL); } -int _mi_os_numa_node_get(mi_os_tld_t* tld) { - MI_UNUSED(tld); - size_t numa_count = _mi_os_numa_node_count(); - if (numa_count<=1) return 0; // optimize on single numa node systems: always node 0 - // never more than the node count and >= 0 - size_t numa_node = mi_os_numa_nodex(); - if (numa_node >= numa_count) { numa_node = numa_node % numa_count; } - return (int)numa_node; +mi_decl_export void mi_os_decommit(void* p, size_t size) { + _mi_os_decommit(p, size); } +#endif diff --git a/src/dashbls/depends/mimalloc/src/page-map.c b/src/dashbls/depends/mimalloc/src/page-map.c new file mode 100644 index 000000000000..ce70495b27de --- /dev/null +++ b/src/dashbls/depends/mimalloc/src/page-map.c @@ -0,0 +1,389 @@ +/*---------------------------------------------------------------------------- +Copyright (c) 2023-2024, Microsoft Research, Daan Leijen +This is free software; you can redistribute it and/or modify it under the +terms of the MIT license. A copy of the license can be found in the file +"LICENSE" at the root of this distribution. +-----------------------------------------------------------------------------*/ + +#include "mimalloc.h" +#include "mimalloc/internal.h" +#include "bitmap.h" + +static void mi_page_map_cannot_commit(void) { + _mi_error_message(EFAULT,"unable to commit memory for the page address map\n"); +} + +#if MI_PAGE_MAP_FLAT + +// The page-map contains a byte for each 64kb slice in the address space. +// For an address `a` where `ofs = _mi_page_map[a >> 16]`: +// 0 = unused +// 1 = the slice at `a & ~0xFFFF` is a mimalloc page. +// 1 < ofs <= 127 = the slice is part of a page, starting at `(((a>>16) - ofs - 1) << 16)`. +// +// 1 byte per slice => 1 TiB address space needs a 2^14 * 2^16 = 16 MiB page map. +// A full 256 TiB address space (48 bit) needs a 4 GiB page map. +// A full 4 GiB address space (32 bit) needs only a 64 KiB page map. + +mi_decl_cache_align uint8_t* _mi_page_map = NULL; +static void* mi_page_map_max_address = NULL; +static mi_memid_t mi_page_map_memid; + +#define MI_PAGE_MAP_ENTRIES_PER_COMMIT_BIT MI_ARENA_SLICE_SIZE +static mi_bitmap_t* mi_page_map_commit; // one bit per committed 64 KiB entries + +static void mi_page_map_ensure_committed(size_t idx, size_t slice_count); + +bool _mi_page_map_init(void) { + size_t vbits = (size_t)mi_option_get_clamp(mi_option_max_vabits, 0, MI_SIZE_BITS); + if (vbits == 0) { + vbits = _mi_os_virtual_address_bits(); + #if MI_ARCH_X64 // canonical address is limited to the first 128 TiB + if (vbits >= 48) { vbits = 47; } + #endif + } + + // Allocate the page map and commit bits + mi_page_map_max_address = (void*)(vbits >= MI_SIZE_BITS ? (SIZE_MAX - MI_ARENA_SLICE_SIZE + 1) : (MI_PU(1) << vbits)); + const size_t page_map_size = (MI_ZU(1) << (vbits - MI_ARENA_SLICE_SHIFT)); + const bool commit = (page_map_size <= 1*MI_MiB || mi_option_is_enabled(mi_option_pagemap_commit)); // _mi_os_has_overcommit(); // commit on-access on Linux systems? + const size_t commit_bits = _mi_divide_up(page_map_size, MI_PAGE_MAP_ENTRIES_PER_COMMIT_BIT); + const size_t bitmap_size = (commit ? 0 : mi_bitmap_size(commit_bits, NULL)); + const size_t reserve_size = bitmap_size + page_map_size; + uint8_t* const base = (uint8_t*)_mi_os_alloc_aligned(reserve_size, 1, commit, true /* allow large */, &mi_page_map_memid); + if (base==NULL) { + _mi_error_message(ENOMEM, "unable to reserve virtual memory for the page map (%zu KiB)\n", page_map_size / MI_KiB); + return false; + } + if (mi_page_map_memid.initially_committed && !mi_page_map_memid.initially_zero) { + _mi_warning_message("internal: the page map was committed but not zero initialized!\n"); + _mi_memzero_aligned(base, reserve_size); + } + if (bitmap_size > 0) { + mi_page_map_commit = (mi_bitmap_t*)base; + if (!_mi_os_commit(mi_page_map_commit, bitmap_size, NULL)) { + mi_page_map_cannot_commit(); + return false; + } + mi_bitmap_init(mi_page_map_commit, commit_bits, true); + } + _mi_page_map = base + bitmap_size; + + // commit the first part so NULL pointers get resolved without an access violation + if (!commit) { + mi_page_map_ensure_committed(0, 1); + } + _mi_page_map[0] = 1; // so _mi_ptr_page(NULL) == NULL + mi_assert_internal(_mi_ptr_page(NULL)==NULL); + return true; +} + +void _mi_page_map_unsafe_destroy(mi_subproc_t* subproc) { + mi_assert_internal(subproc != NULL); + mi_assert_internal(_mi_page_map != NULL); + if (_mi_page_map == NULL) return; + _mi_os_free_ex(mi_page_map_memid.mem.os.base, mi_page_map_memid.mem.os.size, true, mi_page_map_memid, subproc); + _mi_page_map = NULL; + mi_page_map_commit = NULL; + mi_page_map_max_address = NULL; + mi_page_map_memid = _mi_memid_none(); +} + + +static void mi_page_map_ensure_committed(size_t idx, size_t slice_count) { + // is the page map area that contains the page address committed? + // we always set the commit bits so we can track what ranges are in-use. + // we only actually commit if the map wasn't committed fully already. + if (mi_page_map_commit != NULL) { + const size_t commit_idx = idx / MI_PAGE_MAP_ENTRIES_PER_COMMIT_BIT; + const size_t commit_idx_hi = (idx + slice_count - 1) / MI_PAGE_MAP_ENTRIES_PER_COMMIT_BIT; + for (size_t i = commit_idx; i <= commit_idx_hi; i++) { // per bit to avoid crossing over bitmap chunks + if (mi_bitmap_is_clear(mi_page_map_commit, i)) { + // this may race, in which case we do multiple commits (which is ok) + bool is_zero; + uint8_t* const start = _mi_page_map + (i * MI_PAGE_MAP_ENTRIES_PER_COMMIT_BIT); + const size_t size = MI_PAGE_MAP_ENTRIES_PER_COMMIT_BIT; + if (!_mi_os_commit(start, size, &is_zero)) return; + if (!is_zero && !mi_page_map_memid.initially_zero) { _mi_memzero(start, size); } + mi_bitmap_set(mi_page_map_commit, i); + } + } + } + #if MI_DEBUG > 0 + _mi_page_map[idx] = 0; + _mi_page_map[idx+slice_count-1] = 0; + #endif +} + + +static size_t mi_page_map_get_idx(mi_page_t* page, uint8_t** page_start, size_t* slice_count) { + size_t page_size; + *page_start = mi_page_area(page, &page_size); + if (page_size > MI_LARGE_PAGE_SIZE) { page_size = MI_LARGE_PAGE_SIZE - MI_ARENA_SLICE_SIZE; } // furthest interior pointer + *slice_count = mi_slice_count_of_size(page_size) + (((uint8_t*)*page_start - (uint8_t*)page)/MI_ARENA_SLICE_SIZE); // add for large aligned blocks + return _mi_page_map_index(page); +} + +void _mi_page_map_register(mi_page_t* page) { + mi_assert_internal(page != NULL); + mi_assert_internal(_mi_is_aligned(page, MI_PAGE_ALIGN)); + mi_assert_internal(_mi_page_map != NULL); // should be initialized before multi-thread access! + if mi_unlikely(_mi_page_map == NULL) { + if (!_mi_page_map_init()) return; + } + mi_assert(_mi_page_map!=NULL); + uint8_t* page_start; + size_t slice_count; + const size_t idx = mi_page_map_get_idx(page, &page_start, &slice_count); + + mi_page_map_ensure_committed(idx, slice_count); + + // set the offsets + for (size_t i = 0; i < slice_count; i++) { + mi_assert_internal(i < 128); + _mi_page_map[idx + i] = (uint8_t)(i+1); + } +} + +void _mi_page_map_unregister(mi_page_t* page) { + mi_assert_internal(_mi_page_map != NULL); + // get index and count + uint8_t* page_start; + size_t slice_count; + const size_t idx = mi_page_map_get_idx(page, &page_start, &slice_count); + // unset the offsets + _mi_memzero(_mi_page_map + idx, slice_count); +} + +void _mi_page_map_unregister_range(void* start, size_t size) { + const size_t slice_count = _mi_divide_up(size, MI_ARENA_SLICE_SIZE); + const uintptr_t index = _mi_page_map_index(start); + mi_page_map_ensure_committed(index, slice_count); // we commit the range in total; todo: scan the commit bits and clear only those ranges? + _mi_memzero(&_mi_page_map[index], slice_count); +} + + +mi_page_t* _mi_safe_ptr_page(const void* p) { + if mi_unlikely(p >= mi_page_map_max_address) return NULL; + const uintptr_t idx = _mi_page_map_index(p); + if mi_unlikely(mi_page_map_commit != NULL && !mi_bitmap_is_set(mi_page_map_commit, idx/MI_PAGE_MAP_ENTRIES_PER_COMMIT_BIT)) return NULL; + const uintptr_t ofs = _mi_page_map[idx]; + if mi_unlikely(ofs == 0) return NULL; + return (mi_page_t*)((((uintptr_t)p >> MI_ARENA_SLICE_SHIFT) - ofs + 1) << MI_ARENA_SLICE_SHIFT); +} + +mi_decl_nodiscard mi_decl_export bool mi_is_in_heap_region(const void* p) mi_attr_noexcept { + return (_mi_safe_ptr_page(p) != NULL); +} + +#else + +// A 2-level page map +#define MI_PAGE_MAP_SUB_SIZE (MI_PAGE_MAP_SUB_COUNT * sizeof(mi_page_t*)) + +mi_decl_cache_align _Atomic(mi_page_t**)* _mi_page_map; +static size_t mi_page_map_count; +static void* mi_page_map_max_address; +static mi_memid_t mi_page_map_memid; + +// divide the main map in 64 (`MI_BFIELD_BITS`) parts commit those parts on demand +static _Atomic(mi_bfield_t) mi_page_map_commit; + +#define MI_PAGE_MAP_ENTRIES_PER_CBIT (MI_PAGE_MAP_COUNT / MI_BFIELD_BITS) + +static inline bool mi_page_map_is_committed(size_t idx, size_t* pbit_idx) { + mi_bfield_t commit = mi_atomic_load_relaxed(&mi_page_map_commit); + const size_t bit_idx = idx/MI_PAGE_MAP_ENTRIES_PER_CBIT; + mi_assert_internal(bit_idx < MI_BFIELD_BITS); + if (pbit_idx != NULL) { *pbit_idx = bit_idx; } + return ((commit & (MI_ZU(1) << bit_idx)) != 0); +} + +static mi_page_t** mi_page_map_ensure_committed(size_t idx) { + size_t bit_idx; + if mi_unlikely(!mi_page_map_is_committed(idx, &bit_idx)) { + uint8_t* start = (uint8_t*)&_mi_page_map[bit_idx * MI_PAGE_MAP_ENTRIES_PER_CBIT]; + if (!_mi_os_commit(start, MI_PAGE_MAP_ENTRIES_PER_CBIT * sizeof(mi_page_t**), NULL)) { + return NULL; + } + mi_atomic_or_acq_rel(&mi_page_map_commit, MI_ZU(1) << bit_idx); + } + return mi_atomic_load_ptr_acquire(mi_page_t*, &_mi_page_map[idx]); // _mi_page_map_at(idx); +} + +// initialize the page map +bool _mi_page_map_init(void) { + size_t vbits = (size_t)mi_option_get_clamp(mi_option_max_vabits, 0, MI_SIZE_BITS); + if (vbits == 0) { + vbits = _mi_os_virtual_address_bits(); + #if MI_ARCH_X64 // canonical address is limited to the first 128 TiB + if (vbits >= 48) { vbits = 47; } + #endif + } + + // Allocate the page map and commit bits + mi_assert(MI_MAX_VABITS >= vbits); + mi_page_map_max_address = (void*)(vbits >= MI_SIZE_BITS ? (SIZE_MAX - MI_ARENA_SLICE_SIZE + 1) : (MI_PU(1) << vbits)); + mi_page_map_count = (MI_ZU(1) << (vbits - MI_PAGE_MAP_SUB_SHIFT - MI_ARENA_SLICE_SHIFT)); + mi_assert(mi_page_map_count <= MI_PAGE_MAP_COUNT); + const size_t os_page_size = _mi_os_page_size(); + const size_t page_map_size = _mi_align_up( mi_page_map_count * sizeof(mi_page_t**), os_page_size); + const size_t submap_size = MI_PAGE_MAP_SUB_SIZE; + const size_t reserve_size = page_map_size + submap_size; + #if MI_SECURE + const bool commit = true; // the whole page map is valid and we can reliably check any pointer + #else + const bool commit = page_map_size <= 64*MI_KiB || + mi_option_is_enabled(mi_option_pagemap_commit) || _mi_os_has_overcommit(); + #endif + _mi_page_map = (_Atomic(mi_page_t**)*)_mi_os_alloc_aligned(reserve_size, 1, commit, true /* allow large */, &mi_page_map_memid); + if (_mi_page_map==NULL) { + _mi_error_message(ENOMEM, "unable to reserve virtual memory for the page map (%zu KiB)\n", page_map_size / MI_KiB); + return false; + } + if (mi_page_map_memid.initially_committed && !mi_page_map_memid.initially_zero) { + _mi_warning_message("internal: the page map was committed but not zero initialized!\n"); + _mi_memzero_aligned(_mi_page_map, page_map_size); + } + mi_atomic_store_release(&mi_page_map_commit, (mi_page_map_memid.initially_committed ? ~MI_ZU(0) : MI_ZU(0))); + + // ensure there is a submap for the NULL address + mi_page_t** const sub0 = (mi_page_t**)((uint8_t*)_mi_page_map + page_map_size); // we reserved a submap part at the end already + if (!mi_page_map_memid.initially_committed) { + if (!_mi_os_commit(sub0, submap_size, NULL)) { // commit full submap (issue #1087) + mi_page_map_cannot_commit(); + return false; + } + } + if (!mi_page_map_memid.initially_zero) { // initialize low addresses with NULL + _mi_memzero_aligned(sub0, submap_size); + } + mi_page_map_ensure_committed(0); + mi_atomic_store_ptr_release(mi_page_t*, &_mi_page_map[0], sub0); + + mi_assert_internal(_mi_ptr_page(NULL)==NULL); + return true; +} + + +void _mi_page_map_unsafe_destroy(mi_subproc_t* subproc) { + mi_assert_internal(subproc != NULL); + mi_assert_internal(_mi_page_map != NULL); + if (_mi_page_map == NULL) return; + for (size_t idx = 1; idx < mi_page_map_count; idx++) { // skip entry 0 (as we allocate that submap at the end of the page_map) + // free all sub-maps + if (mi_page_map_is_committed(idx, NULL)) { + mi_page_t** sub = _mi_page_map_at(idx); + if (sub != NULL) { + mi_memid_t memid = _mi_memid_create_os(sub, MI_PAGE_MAP_SUB_SIZE, true, false, false); + _mi_os_free_ex(memid.mem.os.base, memid.mem.os.size, true, memid, subproc); + mi_atomic_store_ptr_release(mi_page_t*, &_mi_page_map[idx], NULL); + } + } + } + _mi_os_free_ex(_mi_page_map, mi_page_map_memid.mem.os.size, true, mi_page_map_memid, subproc); + _mi_page_map = NULL; + mi_page_map_count = 0; + mi_page_map_memid = _mi_memid_none(); + mi_page_map_max_address = NULL; + mi_atomic_store_release(&mi_page_map_commit, 0); +} + + +static mi_page_t** mi_page_map_ensure_submap_at(size_t idx) { + mi_page_t** sub = mi_page_map_ensure_committed(idx); + if mi_unlikely(sub == NULL) { + // sub map not yet allocated, alloc now + mi_memid_t memid; + mi_page_t** expect = sub; + const size_t submap_size = MI_PAGE_MAP_SUB_SIZE; + sub = (mi_page_t**)_mi_os_zalloc(submap_size, &memid); + if (sub == NULL) { + _mi_error_message(EFAULT, "internal error: unable to extend the page map\n"); + return NULL; + } + if (!mi_atomic_cas_ptr_strong_acq_rel(mi_page_t*, &_mi_page_map[idx], &expect, sub)) { + // another thread already allocated it.. free and continue + _mi_os_free(sub, submap_size, memid); + sub = expect; + mi_assert_internal(sub!=NULL); + } + } + return sub; +} + +static void mi_page_map_set_range(mi_page_t* page, size_t idx, size_t sub_idx, size_t slice_count) { + // is the page map area that contains the page address committed? + while (slice_count > 0) { + mi_page_t** sub = mi_page_map_ensure_submap_at(idx); + // set the offsets for the page + while (sub_idx < MI_PAGE_MAP_SUB_COUNT) { + sub[sub_idx] = page; + slice_count--; if (slice_count == 0) return; + sub_idx++; + } + idx++; // potentially wrap around to the next idx + sub_idx = 0; + } +} + +static size_t mi_page_map_get_idx(mi_page_t* page, size_t* sub_idx, size_t* slice_count) { + size_t page_size; + uint8_t* page_start = mi_page_area(page, &page_size); + if (page_size > MI_LARGE_PAGE_SIZE) { page_size = MI_LARGE_PAGE_SIZE - MI_ARENA_SLICE_SIZE; } // furthest interior pointer + *slice_count = mi_slice_count_of_size(page_size) + ((page_start - (uint8_t*)page)/MI_ARENA_SLICE_SIZE); // add for large aligned blocks + return _mi_page_map_index(page, sub_idx); +} + +void _mi_page_map_register(mi_page_t* page) { + mi_assert_internal(page != NULL); + mi_assert_internal(_mi_is_aligned(page, MI_PAGE_ALIGN)); + mi_assert_internal(_mi_page_map != NULL); // should be initialized before multi-thread access! + if mi_unlikely(_mi_page_map == NULL) { + if (!_mi_page_map_init()) return; + } + mi_assert(_mi_page_map!=NULL); + size_t slice_count; + size_t sub_idx; + const size_t idx = mi_page_map_get_idx(page, &sub_idx, &slice_count); + mi_page_map_set_range(page, idx, sub_idx, slice_count); +} + +void _mi_page_map_unregister(mi_page_t* page) { + mi_assert_internal(_mi_page_map != NULL); + mi_assert_internal(page != NULL); + mi_assert_internal(_mi_is_aligned(page, MI_PAGE_ALIGN)); + if mi_unlikely(_mi_page_map == NULL) return; + // get index and count + size_t slice_count; + size_t sub_idx; + const size_t idx = mi_page_map_get_idx(page, &sub_idx, &slice_count); + // unset the offsets + mi_page_map_set_range(NULL, idx, sub_idx, slice_count); +} + +void _mi_page_map_unregister_range(void* start, size_t size) { + if mi_unlikely(_mi_page_map == NULL) return; + const size_t slice_count = _mi_divide_up(size, MI_ARENA_SLICE_SIZE); + size_t sub_idx; + const uintptr_t idx = _mi_page_map_index(start, &sub_idx); + mi_page_map_set_range(NULL, idx, sub_idx, slice_count); // todo: avoid committing if not already committed? +} + +// Return NULL for invalid pointers +mi_page_t* _mi_safe_ptr_page(const void* p) { + if (p==NULL) return NULL; + if mi_unlikely(p >= mi_page_map_max_address) return NULL; + size_t sub_idx; + const size_t idx = _mi_page_map_index(p,&sub_idx); + if mi_unlikely(!mi_page_map_is_committed(idx,NULL)) return NULL; + mi_page_t** const sub = _mi_page_map[idx]; + if mi_unlikely(sub==NULL) return NULL; + return sub[sub_idx]; +} + +mi_decl_nodiscard mi_decl_export bool mi_is_in_heap_region(const void* p) mi_attr_noexcept { + return (_mi_safe_ptr_page(p) != NULL); +} + +#endif diff --git a/src/dashbls/depends/mimalloc/src/page-queue.c b/src/dashbls/depends/mimalloc/src/page-queue.c index 92f933c2a0d7..91bb0ef9ddeb 100644 --- a/src/dashbls/depends/mimalloc/src/page-queue.c +++ b/src/dashbls/depends/mimalloc/src/page-queue.c @@ -1,5 +1,5 @@ /*---------------------------------------------------------------------------- -Copyright (c) 2018-2020, Microsoft Research, Daan Leijen +Copyright (c) 2018-2024, Microsoft Research, Daan Leijen This is free software; you can redistribute it and/or modify it under the terms of the MIT license. A copy of the license can be found in the file "LICENSE" at the root of this distribution. @@ -11,6 +11,10 @@ terms of the MIT license. A copy of the license can be found in the file #ifndef MI_IN_PAGE_C #error "this file should be included from 'page.c'" +// include to help an IDE +#include "mimalloc.h" +#include "mimalloc/internal.h" +#include "mimalloc/atomic.h" #endif /* ----------------------------------------------------------- @@ -34,15 +38,19 @@ terms of the MIT license. A copy of the license can be found in the file static inline bool mi_page_queue_is_huge(const mi_page_queue_t* pq) { - return (pq->block_size == (MI_MEDIUM_OBJ_SIZE_MAX+sizeof(uintptr_t))); + return (pq->block_size == (MI_LARGE_MAX_OBJ_SIZE+sizeof(uintptr_t))); } static inline bool mi_page_queue_is_full(const mi_page_queue_t* pq) { - return (pq->block_size == (MI_MEDIUM_OBJ_SIZE_MAX+(2*sizeof(uintptr_t)))); + return (pq->block_size == (MI_LARGE_MAX_OBJ_SIZE+(2*sizeof(uintptr_t)))); } static inline bool mi_page_queue_is_special(const mi_page_queue_t* pq) { - return (pq->block_size > MI_MEDIUM_OBJ_SIZE_MAX); + return (pq->block_size > MI_LARGE_MAX_OBJ_SIZE); +} + +static inline size_t mi_page_queue_count(const mi_page_queue_t* pq) { + return pq->count; } /* ----------------------------------------------------------- @@ -53,27 +61,23 @@ static inline bool mi_page_queue_is_special(const mi_page_queue_t* pq) { // Returns MI_BIN_HUGE if the size is too large. // We use `wsize` for the size in "machine word sizes", // i.e. byte size == `wsize*sizeof(void*)`. -static inline uint8_t mi_bin(size_t size) { +static mi_decl_noinline size_t mi_bin(size_t size) { size_t wsize = _mi_wsize_from_size(size); - uint8_t bin; - if (wsize <= 1) { - bin = 1; - } - #if defined(MI_ALIGN4W) - else if (wsize <= 4) { - bin = (uint8_t)((wsize+1)&~1); // round to double word sizes +#if defined(MI_ALIGN4W) + if mi_likely(wsize <= 4) { + return (wsize <= 1 ? 1 : (wsize+1)&~1); // round to double word sizes } - #elif defined(MI_ALIGN2W) - else if (wsize <= 8) { - bin = (uint8_t)((wsize+1)&~1); // round to double word sizes +#elif defined(MI_ALIGN2W) + if mi_likely(wsize <= 8) { + return (wsize <= 1 ? 1 : (wsize+1)&~1); // round to double word sizes } - #else - else if (wsize <= 8) { - bin = (uint8_t)wsize; +#else + if mi_likely(wsize <= 8) { + return (wsize == 0 ? 1 : wsize); } - #endif - else if (wsize > MI_MEDIUM_OBJ_WSIZE_MAX) { - bin = MI_BIN_HUGE; +#endif + else if mi_unlikely(wsize > MI_LARGE_MAX_OBJ_WSIZE) { + return MI_BIN_HUGE; } else { #if defined(MI_ALIGN4W) @@ -81,15 +85,14 @@ static inline uint8_t mi_bin(size_t size) { #endif wsize--; // find the highest bit - uint8_t b = (uint8_t)mi_bsr(wsize); // note: wsize != 0 + const size_t b = (MI_SIZE_BITS - 1 - mi_clz(wsize)); // note: wsize != 0 // and use the top 3 bits to determine the bin (~12.5% worst internal fragmentation). // - adjust with 3 because we use do not round the first 8 sizes // which each get an exact bin - bin = ((b << 2) + (uint8_t)((wsize >> (b - 2)) & 0x03)) - 3; - mi_assert_internal(bin < MI_BIN_HUGE); + const size_t bin = ((b << 2) + ((wsize >> (b - 2)) & 0x03)) - 3; + mi_assert_internal(bin > 0 && bin < MI_BIN_HUGE); + return bin; } - mi_assert_internal(bin > 0 && bin <= MI_BIN_HUGE); - return bin; } @@ -98,21 +101,22 @@ static inline uint8_t mi_bin(size_t size) { Queue of pages with free blocks ----------------------------------------------------------- */ -uint8_t _mi_bin(size_t size) { +size_t _mi_bin(size_t size) { return mi_bin(size); } -size_t _mi_bin_size(uint8_t bin) { +size_t _mi_bin_size(size_t bin) { + mi_assert_internal(bin <= MI_BIN_HUGE); return _mi_heap_empty.pages[bin].block_size; } // Good size for allocation -size_t mi_good_size(size_t size) mi_attr_noexcept { - if (size <= MI_MEDIUM_OBJ_SIZE_MAX) { - return _mi_bin_size(mi_bin(size)); +mi_decl_nodiscard mi_decl_export size_t mi_good_size(size_t size) mi_attr_noexcept { + if (size <= MI_LARGE_MAX_OBJ_SIZE) { + return _mi_bin_size(mi_bin(size + MI_PADDING_SIZE)); } else { - return _mi_align_up(size,_mi_os_page_size()); + return _mi_align_up(size + MI_PADDING_SIZE,_mi_os_page_size()); } } @@ -137,21 +141,53 @@ static bool mi_heap_contains_queue(const mi_heap_t* heap, const mi_page_queue_t* } #endif -static mi_page_queue_t* mi_page_queue_of(const mi_page_t* page) { - uint8_t bin = (mi_page_is_in_full(page) ? MI_BIN_FULL : mi_bin(page->xblock_size)); - mi_heap_t* heap = mi_page_heap(page); - mi_assert_internal(heap != NULL && bin <= MI_BIN_FULL); - mi_page_queue_t* pq = &heap->pages[bin]; - mi_assert_internal(bin >= MI_BIN_HUGE || page->xblock_size == pq->block_size); - mi_assert_expensive(mi_page_queue_contains(pq, page)); - return pq; +bool _mi_page_queue_is_valid(mi_heap_t* heap, const mi_page_queue_t* pq) { + MI_UNUSED_RELEASE(heap); + if (pq==NULL) return false; + size_t count = 0; MI_UNUSED_RELEASE(count); + mi_page_t* prev = NULL; MI_UNUSED_RELEASE(prev); + for (mi_page_t* page = pq->first; page != NULL; page = page->next) { + mi_assert_internal(page->prev == prev); + if (mi_page_is_in_full(page)) { + mi_assert_internal(_mi_wsize_from_size(pq->block_size) == MI_LARGE_MAX_OBJ_WSIZE + 2); + } + else if (mi_page_is_huge(page)) { + mi_assert_internal(_mi_wsize_from_size(pq->block_size) == MI_LARGE_MAX_OBJ_WSIZE + 1); + } + else { + mi_assert_internal(mi_page_block_size(page) == pq->block_size); + } + mi_assert_internal(page->heap == heap); + if (page->next == NULL) { + mi_assert_internal(pq->last == page); + } + count++; + prev = page; + } + mi_assert_internal(pq->count == count); + return true; } -static mi_page_queue_t* mi_heap_page_queue_of(mi_heap_t* heap, const mi_page_t* page) { - uint8_t bin = (mi_page_is_in_full(page) ? MI_BIN_FULL : mi_bin(page->xblock_size)); +size_t _mi_page_bin(const mi_page_t* page) { + const size_t bin = (mi_page_is_in_full(page) ? MI_BIN_FULL : (mi_page_is_huge(page) ? MI_BIN_HUGE : mi_bin(mi_page_block_size(page)))); mi_assert_internal(bin <= MI_BIN_FULL); + return bin; +} + +static mi_page_queue_t* mi_heap_page_queue_of(mi_heap_t* heap, const mi_page_t* page) { + mi_assert_internal(heap!=NULL); + const size_t bin = _mi_page_bin(page); mi_page_queue_t* pq = &heap->pages[bin]; - mi_assert_internal(mi_page_is_in_full(page) || page->xblock_size == pq->block_size); + mi_assert_internal((mi_page_block_size(page) == pq->block_size) || + (mi_page_is_huge(page) && mi_page_queue_is_huge(pq)) || + (mi_page_is_in_full(page) && mi_page_queue_is_full(pq))); + return pq; +} + +static mi_page_queue_t* mi_page_queue_of(const mi_page_t* page) { + mi_heap_t* heap = mi_page_heap(page); + mi_page_queue_t* pq = mi_heap_page_queue_of(heap, page); + mi_assert_expensive(mi_page_queue_contains(pq, page)); return pq; } @@ -181,7 +217,7 @@ static inline void mi_heap_queue_first_update(mi_heap_t* heap, const mi_page_que } else { // find previous size; due to minimal alignment upto 3 previous bins may need to be skipped - uint8_t bin = mi_bin(size); + size_t bin = mi_bin(size); const mi_page_queue_t* prev = pq - 1; while( bin == mi_bin(prev->block_size) && prev > &heap->pages[0]) { prev--; @@ -206,9 +242,11 @@ static bool mi_page_queue_is_empty(mi_page_queue_t* queue) { static void mi_page_queue_remove(mi_page_queue_t* queue, mi_page_t* page) { mi_assert_internal(page != NULL); mi_assert_expensive(mi_page_queue_contains(queue, page)); - mi_assert_internal(page->xblock_size == queue->block_size || (page->xblock_size > MI_MEDIUM_OBJ_SIZE_MAX && mi_page_queue_is_huge(queue)) || (mi_page_is_in_full(page) && mi_page_queue_is_full(queue))); + mi_assert_internal(queue->count >= 1); + mi_assert_internal(mi_page_block_size(page) == queue->block_size || + (mi_page_is_huge(page) && mi_page_queue_is_huge(queue)) || + (mi_page_is_in_full(page) && mi_page_queue_is_full(queue))); mi_heap_t* heap = mi_page_heap(page); - if (page->prev != NULL) page->prev->next = page->next; if (page->next != NULL) page->next->prev = page->prev; if (page == queue->last) queue->last = page->prev; @@ -219,9 +257,9 @@ static void mi_page_queue_remove(mi_page_queue_t* queue, mi_page_t* page) { mi_heap_queue_first_update(heap,queue); } heap->page_count--; + queue->count--; page->next = NULL; page->prev = NULL; - // mi_atomic_store_ptr_release(mi_atomic_cast(void*, &page->heap), NULL); mi_page_set_in_full(page,false); } @@ -229,14 +267,15 @@ static void mi_page_queue_remove(mi_page_queue_t* queue, mi_page_t* page) { static void mi_page_queue_push(mi_heap_t* heap, mi_page_queue_t* queue, mi_page_t* page) { mi_assert_internal(mi_page_heap(page) == heap); mi_assert_internal(!mi_page_queue_contains(queue, page)); - - mi_assert_internal(_mi_page_segment(page)->kind != MI_SEGMENT_HUGE); - mi_assert_internal(page->xblock_size == queue->block_size || - (page->xblock_size > MI_MEDIUM_OBJ_SIZE_MAX) || + #if MI_HUGE_PAGE_ABANDON + mi_assert_internal(_mi_page_segment(page)->page_kind != MI_PAGE_HUGE); + #endif + mi_assert_internal(mi_page_block_size(page) == queue->block_size || + (mi_page_is_huge(page) && mi_page_queue_is_huge(queue)) || (mi_page_is_in_full(page) && mi_page_queue_is_full(queue))); mi_page_set_in_full(page, mi_page_queue_is_full(queue)); - // mi_atomic_store_ptr_release(mi_atomic_cast(void*, &page->heap), heap); + page->next = queue->first; page->prev = NULL; if (queue->first != NULL) { @@ -247,25 +286,67 @@ static void mi_page_queue_push(mi_heap_t* heap, mi_page_queue_t* queue, mi_page_ else { queue->first = queue->last = page; } + queue->count++; // update direct mi_heap_queue_first_update(heap, queue); heap->page_count++; } +static void mi_page_queue_push_at_end(mi_heap_t* heap, mi_page_queue_t* queue, mi_page_t* page) { + mi_assert_internal(mi_page_heap(page) == heap); + mi_assert_internal(!mi_page_queue_contains(queue, page)); -static void mi_page_queue_enqueue_from(mi_page_queue_t* to, mi_page_queue_t* from, mi_page_t* page) { + mi_assert_internal(mi_page_block_size(page) == queue->block_size || + (mi_page_is_huge(page) && mi_page_queue_is_huge(queue)) || + (mi_page_is_in_full(page) && mi_page_queue_is_full(queue))); + + mi_page_set_in_full(page, mi_page_queue_is_full(queue)); + + page->prev = queue->last; + page->next = NULL; + if (queue->last != NULL) { + mi_assert_internal(queue->last->next == NULL); + queue->last->next = page; + queue->last = page; + } + else { + queue->first = queue->last = page; + } + queue->count++; + + // update direct + if (queue->first == page) { + mi_heap_queue_first_update(heap, queue); + } + heap->page_count++; +} + +static void mi_page_queue_move_to_front(mi_heap_t* heap, mi_page_queue_t* queue, mi_page_t* page) { + mi_assert_internal(mi_page_heap(page) == heap); + mi_assert_internal(mi_page_queue_contains(queue, page)); + if (queue->first == page) return; + mi_page_queue_remove(queue, page); + mi_page_queue_push(heap, queue, page); + mi_assert_internal(queue->first == page); +} + +static void mi_page_queue_enqueue_from_ex(mi_page_queue_t* to, mi_page_queue_t* from, bool enqueue_at_end, mi_page_t* page) { mi_assert_internal(page != NULL); + mi_assert_internal(from->count >= 1); mi_assert_expensive(mi_page_queue_contains(from, page)); mi_assert_expensive(!mi_page_queue_contains(to, page)); - - mi_assert_internal((page->xblock_size == to->block_size && page->xblock_size == from->block_size) || - (page->xblock_size == to->block_size && mi_page_queue_is_full(from)) || - (page->xblock_size == from->block_size && mi_page_queue_is_full(to)) || - (page->xblock_size > MI_LARGE_OBJ_SIZE_MAX && mi_page_queue_is_huge(to)) || - (page->xblock_size > MI_LARGE_OBJ_SIZE_MAX && mi_page_queue_is_full(to))); + const size_t bsize = mi_page_block_size(page); + MI_UNUSED(bsize); + mi_assert_internal((bsize == to->block_size && bsize == from->block_size) || + (bsize == to->block_size && mi_page_queue_is_full(from)) || + (bsize == from->block_size && mi_page_queue_is_full(to)) || + (mi_page_is_huge(page) && mi_page_queue_is_huge(to)) || + (mi_page_is_huge(page) && mi_page_queue_is_full(to))); mi_heap_t* heap = mi_page_heap(page); + + // delete from `from` if (page->prev != NULL) page->prev->next = page->next; if (page->next != NULL) page->next->prev = page->prev; if (page == from->last) from->last = page->prev; @@ -275,23 +356,62 @@ static void mi_page_queue_enqueue_from(mi_page_queue_t* to, mi_page_queue_t* fro mi_assert_internal(mi_heap_contains_queue(heap, from)); mi_heap_queue_first_update(heap, from); } - - page->prev = to->last; - page->next = NULL; - if (to->last != NULL) { - mi_assert_internal(heap == mi_page_heap(to->last)); - to->last->next = page; - to->last = page; + from->count--; + + // insert into `to` + to->count++; + if (enqueue_at_end) { + // enqueue at the end + page->prev = to->last; + page->next = NULL; + if (to->last != NULL) { + mi_assert_internal(heap == mi_page_heap(to->last)); + to->last->next = page; + to->last = page; + } + else { + to->first = page; + to->last = page; + mi_heap_queue_first_update(heap, to); + } } else { - to->first = page; - to->last = page; - mi_heap_queue_first_update(heap, to); + if (to->first != NULL) { + // enqueue at 2nd place + mi_assert_internal(heap == mi_page_heap(to->first)); + mi_page_t* next = to->first->next; + page->prev = to->first; + page->next = next; + to->first->next = page; + if (next != NULL) { + next->prev = page; + } + else { + to->last = page; + } + } + else { + // enqueue at the head (singleton list) + page->prev = NULL; + page->next = NULL; + to->first = page; + to->last = page; + mi_heap_queue_first_update(heap, to); + } } mi_page_set_in_full(page, mi_page_queue_is_full(to)); } +static void mi_page_queue_enqueue_from(mi_page_queue_t* to, mi_page_queue_t* from, mi_page_t* page) { + mi_page_queue_enqueue_from_ex(to, from, true /* enqueue at the end */, page); +} + +static void mi_page_queue_enqueue_from_full(mi_page_queue_t* to, mi_page_queue_t* from, mi_page_t* page) { + // note: we could insert at the front to increase reuse, but it slows down certain benchmarks (like `alloc-test`) + mi_page_queue_enqueue_from_ex(to, from, true /* enqueue at the end of the `to` queue? */, page); +} + // Only called from `mi_heap_absorb`. size_t _mi_page_queue_append(mi_heap_t* heap, mi_page_queue_t* pq, mi_page_queue_t* append) { mi_assert_internal(mi_heap_contains_queue(heap,pq)); @@ -302,15 +422,10 @@ size_t _mi_page_queue_append(mi_heap_t* heap, mi_page_queue_t* pq, mi_page_queue // set append pages to new heap and count size_t count = 0; for (mi_page_t* page = append->first; page != NULL; page = page->next) { - // inline `mi_page_set_heap` to avoid wrong assertion during absorption; - // in this case it is ok to be delayed freeing since both "to" and "from" heap are still alive. - mi_atomic_store_release(&page->xheap, (uintptr_t)heap); - // set the flag to delayed free (not overriding NEVER_DELAYED_FREE) which has as a - // side effect that it spins until any DELAYED_FREEING is finished. This ensures - // that after appending only the new heap will be used for delayed free operations. - _mi_page_use_delayed_free(page, MI_USE_DELAYED_FREE, false); + mi_page_set_heap(page, heap); count++; } + mi_assert_internal(count == append->count); if (pq->last==NULL) { // take over afresh @@ -327,5 +442,7 @@ size_t _mi_page_queue_append(mi_heap_t* heap, mi_page_queue_t* pq, mi_page_queue append->first->prev = pq->last; pq->last = append->last; } + pq->count += append->count; + return count; } diff --git a/src/dashbls/depends/mimalloc/src/page.c b/src/dashbls/depends/mimalloc/src/page.c index 4b321156c6a4..b80b4463b354 100644 --- a/src/dashbls/depends/mimalloc/src/page.c +++ b/src/dashbls/depends/mimalloc/src/page.c @@ -1,5 +1,5 @@ /*---------------------------------------------------------------------------- -Copyright (c) 2018-2020, Microsoft Research, Daan Leijen +Copyright (c) 2018-2024, Microsoft Research, Daan Leijen This is free software; you can redistribute it and/or modify it under the terms of the MIT license. A copy of the license can be found in the file "LICENSE" at the root of this distribution. @@ -12,8 +12,8 @@ terms of the MIT license. A copy of the license can be found in the file ----------------------------------------------------------- */ #include "mimalloc.h" -#include "mimalloc-internal.h" -#include "mimalloc-atomic.h" +#include "mimalloc/internal.h" +#include "mimalloc/atomic.h" /* ----------------------------------------------------------- Definition of page queues for each block size @@ -36,14 +36,15 @@ static inline mi_block_t* mi_page_block_at(const mi_page_t* page, void* page_sta return (mi_block_t*)((uint8_t*)page_start + (i * block_size)); } -static void mi_page_init(mi_heap_t* heap, mi_page_t* page, size_t size, mi_tld_t* tld); -static void mi_page_extend_free(mi_heap_t* heap, mi_page_t* page, mi_tld_t* tld); +//static void mi_page_init(mi_heap_t* heap, mi_page_t* page, size_t size, mi_tld_t* tld); +static bool mi_page_extend_free(mi_heap_t* heap, mi_page_t* page); #if (MI_DEBUG>=3) static size_t mi_page_list_count(mi_page_t* page, mi_block_t* head) { + mi_assert_internal(_mi_ptr_page(page) == page); size_t count = 0; while (head != NULL) { - mi_assert_internal(page == _mi_ptr_page(head)); + mi_assert_internal((uint8_t*)head - (uint8_t*)page > (ptrdiff_t)MI_LARGE_PAGE_SIZE || page == _mi_ptr_page(head)); count++; head = mi_block_next(page, head); } @@ -59,32 +60,38 @@ static inline uint8_t* mi_page_area(const mi_page_t* page) { static bool mi_page_list_is_valid(mi_page_t* page, mi_block_t* p) { size_t psize; - uint8_t* page_area = _mi_page_start(_mi_page_segment(page), page, &psize); + uint8_t* page_area = mi_page_area(page, &psize); mi_block_t* start = (mi_block_t*)page_area; mi_block_t* end = (mi_block_t*)(page_area + psize); while(p != NULL) { if (p < start || p >= end) return false; p = mi_block_next(page, p); } +#if MI_DEBUG>3 // generally too expensive to check this + if (page->free_is_zero) { + const size_t ubsize = mi_page_usable_block_size(page); + for (mi_block_t* block = page->free; block != NULL; block = mi_block_next(page, block)) { + mi_assert_expensive(mi_mem_is_zero(block + 1, ubsize - sizeof(mi_block_t))); + } + } +#endif return true; } static bool mi_page_is_valid_init(mi_page_t* page) { - mi_assert_internal(page->xblock_size > 0); + mi_assert_internal(mi_page_block_size(page) > 0); mi_assert_internal(page->used <= page->capacity); mi_assert_internal(page->capacity <= page->reserved); - mi_segment_t* segment = _mi_page_segment(page); - uint8_t* start = _mi_page_start(segment,page,NULL); - mi_assert_internal(start == _mi_segment_page_start(segment,page,NULL)); - //const size_t bsize = mi_page_block_size(page); + // const size_t bsize = mi_page_block_size(page); + // uint8_t* start = mi_page_start(page); //mi_assert_internal(start + page->capacity*page->block_size == page->top); mi_assert_internal(mi_page_list_is_valid(page,page->free)); mi_assert_internal(mi_page_list_is_valid(page,page->local_free)); #if MI_DEBUG>3 // generally too expensive to check this - if (page->is_zero) { + if (page->free_is_zero) { const size_t ubsize = mi_page_usable_block_size(page); for(mi_block_t* block = page->free; block != NULL; block = mi_block_next(page,block)) { mi_assert_expensive(mi_mem_is_zero(block + 1, ubsize - sizeof(mi_block_t))); @@ -92,10 +99,12 @@ static bool mi_page_is_valid_init(mi_page_t* page) { } #endif + #if !MI_TRACK_ENABLED && !MI_TSAN mi_block_t* tfree = mi_page_thread_free(page); mi_assert_internal(mi_page_list_is_valid(page, tfree)); //size_t tfree_count = mi_page_list_count(page, tfree); //mi_assert_internal(tfree_count <= page->thread_freed + 1); + #endif size_t free_count = mi_page_list_count(page, page->free) + mi_page_list_count(page, page->local_free); mi_assert_internal(page->used + free_count == page->capacity); @@ -103,89 +112,45 @@ static bool mi_page_is_valid_init(mi_page_t* page) { return true; } +extern mi_decl_hidden bool _mi_process_is_initialized; // has mi_process_init been called? + bool _mi_page_is_valid(mi_page_t* page) { mi_assert_internal(mi_page_is_valid_init(page)); #if MI_SECURE mi_assert_internal(page->keys[0] != 0); #endif - if (mi_page_heap(page)!=NULL) { - mi_segment_t* segment = _mi_page_segment(page); - - mi_assert_internal(!_mi_process_is_initialized || segment->thread_id==0 || segment->thread_id == mi_page_heap(page)->thread_id); - if (segment->kind != MI_SEGMENT_HUGE) { + if (!mi_page_is_abandoned(page)) { + //mi_assert_internal(!_mi_process_is_initialized); + { mi_page_queue_t* pq = mi_page_queue_of(page); mi_assert_internal(mi_page_queue_contains(pq, page)); - mi_assert_internal(pq->block_size==mi_page_block_size(page) || mi_page_block_size(page) > MI_MEDIUM_OBJ_SIZE_MAX || mi_page_is_in_full(page)); - mi_assert_internal(mi_heap_contains_queue(mi_page_heap(page),pq)); + mi_assert_internal(pq->block_size==mi_page_block_size(page) || mi_page_is_huge(page) || mi_page_is_in_full(page)); + // mi_assert_internal(mi_heap_contains_queue(mi_page_heap(page),pq)); } } return true; } #endif -void _mi_page_use_delayed_free(mi_page_t* page, mi_delayed_t delay, bool override_never) { - while (!_mi_page_try_use_delayed_free(page, delay, override_never)) { - mi_atomic_yield(); - } -} - -bool _mi_page_try_use_delayed_free(mi_page_t* page, mi_delayed_t delay, bool override_never) { - mi_thread_free_t tfreex; - mi_delayed_t old_delay; - mi_thread_free_t tfree; - size_t yield_count = 0; - do { - tfree = mi_atomic_load_acquire(&page->xthread_free); // note: must acquire as we can break/repeat this loop and not do a CAS; - tfreex = mi_tf_set_delayed(tfree, delay); - old_delay = mi_tf_delayed(tfree); - if mi_unlikely(old_delay == MI_DELAYED_FREEING) { - if (yield_count >= 4) return false; // give up after 4 tries - yield_count++; - mi_atomic_yield(); // delay until outstanding MI_DELAYED_FREEING are done. - // tfree = mi_tf_set_delayed(tfree, MI_NO_DELAYED_FREE); // will cause CAS to busy fail - } - else if (delay == old_delay) { - break; // avoid atomic operation if already equal - } - else if (!override_never && old_delay == MI_NEVER_DELAYED_FREE) { - break; // leave never-delayed flag set - } - } while ((old_delay == MI_DELAYED_FREEING) || - !mi_atomic_cas_weak_release(&page->xthread_free, &tfree, tfreex)); - - return true; // success -} /* ----------------------------------------------------------- Page collect the `local_free` and `thread_free` lists ----------------------------------------------------------- */ -// Collect the local `thread_free` list using an atomic exchange. -// Note: The exchange must be done atomically as this is used right after -// moving to the full list in `mi_page_collect_ex` and we need to -// ensure that there was no race where the page became unfull just before the move. -static void _mi_page_thread_free_collect(mi_page_t* page) +static void mi_page_thread_collect_to_local(mi_page_t* page, mi_block_t* head) { - mi_block_t* head; - mi_thread_free_t tfreex; - mi_thread_free_t tfree = mi_atomic_load_relaxed(&page->xthread_free); - do { - head = mi_tf_block(tfree); - tfreex = mi_tf_set_block(tfree,NULL); - } while (!mi_atomic_cas_weak_acq_rel(&page->xthread_free, &tfree, tfreex)); - - // return if the list is empty if (head == NULL) return; - // find the tail -- also to get a proper count (without data races) - uint32_t max_count = page->capacity; // cannot collect more than capacity - uint32_t count = 1; - mi_block_t* tail = head; + // find the last block in the list -- also to get a proper use count (without data races) + size_t max_count = page->capacity; // cannot collect more than capacity + size_t count = 1; + mi_block_t* last = head; mi_block_t* next; - while ((next = mi_block_next(page,tail)) != NULL && count <= max_count) { + while ((next = mi_block_next(page, last)) != NULL && count <= max_count) { count++; - tail = next; + last = next; } + // if `count > max_count` there was a memory corruption (possibly infinite list due to double multi-threaded free) if (count > max_count) { _mi_error_message(EFAULT, "corrupted thread-free list\n"); @@ -193,20 +158,37 @@ static void _mi_page_thread_free_collect(mi_page_t* page) } // and append the current local free list - mi_block_set_next(page,tail, page->local_free); + mi_block_set_next(page, last, page->local_free); page->local_free = head; // update counts now - page->used -= count; + mi_assert_internal(count <= UINT16_MAX); + page->used = page->used - (uint16_t)count; +} + +// Collect the local `thread_free` list using an atomic exchange. +static void mi_page_thread_free_collect(mi_page_t* page) +{ + // atomically capture the thread free list + mi_block_t* head; + mi_thread_free_t tfreex; + mi_thread_free_t tfree = mi_atomic_load_relaxed(&page->xthread_free); + do { + head = mi_tf_block(tfree); + if mi_likely(head == NULL) return; // return if the list is empty + tfreex = mi_tf_create(NULL,mi_tf_is_owned(tfree)); // set the thread free list to NULL + } while (!mi_atomic_cas_weak_acq_rel(&page->xthread_free, &tfree, tfreex)); // release is enough? + mi_assert_internal(head != NULL); + + // and move it to the local list + mi_page_thread_collect_to_local(page, head); } void _mi_page_free_collect(mi_page_t* page, bool force) { mi_assert_internal(page!=NULL); // collect the thread free list - if (force || mi_page_thread_free(page) != NULL) { // quick test to avoid an atomic operation - _mi_page_thread_free_collect(page); - } + mi_page_thread_free_collect(page); // and the local free list if (page->local_free != NULL) { @@ -214,7 +196,7 @@ void _mi_page_free_collect(mi_page_t* page, bool force) { // usual case page->free = page->local_free; page->local_free = NULL; - page->is_zero = false; + page->free_is_zero = false; } else if (force) { // append -- only on shutdown (force) as this is a linear operation @@ -226,45 +208,121 @@ void _mi_page_free_collect(mi_page_t* page, bool force) { mi_block_set_next(page, tail, page->free); page->free = page->local_free; page->local_free = NULL; - page->is_zero = false; + page->free_is_zero = false; } } mi_assert_internal(!force || page->local_free == NULL); } +// Collect elements in the thread-free list starting at `head`. This is an optimized +// version of `_mi_page_free_collect` to be used from `free.c:_mi_free_collect_mt` that avoids atomic access to `xthread_free`. +// +// `head` must be in the `xthread_free` list. It will not collect `head` itself +// so the `used` count is not fully updated in general. However, if the `head` is +// the last remaining element, it will be collected and the used count will become `0` (so `mi_page_all_free` becomes true). +void _mi_page_free_collect_partly(mi_page_t* page, mi_block_t* head) { + if (head == NULL) return; + mi_block_t* next = mi_block_next(page,head); // we cannot collect the head element itself as `page->thread_free` may point to it (and we want to avoid atomic ops) + if (next != NULL) { + mi_block_set_next(page, head, NULL); + mi_page_thread_collect_to_local(page, next); + if (page->local_free != NULL && page->free == NULL) { + page->free = page->local_free; + page->local_free = NULL; + page->free_is_zero = false; + } + } + if (page->used == 1) { + // all elements are free'd since we skipped the `head` element itself + mi_assert_internal(mi_tf_block(mi_atomic_load_relaxed(&page->xthread_free)) == head); + mi_assert_internal(mi_block_next(page,head) == NULL); + _mi_page_free_collect(page, false); // collect the final element + } +} /* ----------------------------------------------------------- Page fresh and retire ----------------------------------------------------------- */ +/* // called from segments when reclaiming abandoned pages void _mi_page_reclaim(mi_heap_t* heap, mi_page_t* page) { + // mi_page_set_heap(page, heap); + // _mi_page_use_delayed_free(page, MI_USE_DELAYED_FREE, true); // override never (after heap is set) + _mi_page_free_collect(page, false); // ensure used count is up to date + mi_assert_expensive(mi_page_is_valid_init(page)); + // mi_assert_internal(mi_page_heap(page) == heap); + // mi_assert_internal(mi_page_thread_free_flag(page) != MI_NEVER_DELAYED_FREE); - mi_assert_internal(mi_page_heap(page) == heap); - mi_assert_internal(mi_page_thread_free_flag(page) != MI_NEVER_DELAYED_FREE); - mi_assert_internal(_mi_page_segment(page)->kind != MI_SEGMENT_HUGE); - mi_assert_internal(!page->is_reset); // TODO: push on full queue immediately if it is full? - mi_page_queue_t* pq = mi_page_queue(heap, mi_page_block_size(page)); + mi_page_queue_t* pq = mi_heap_page_queue_of(heap, page); mi_page_queue_push(heap, pq, page); mi_assert_expensive(_mi_page_is_valid(page)); } +*/ + +// called from `mi_free` on a reclaim, and fresh_alloc if we get an abandoned page +void _mi_heap_page_reclaim(mi_heap_t* heap, mi_page_t* page) +{ + mi_assert_internal(_mi_is_aligned(page, MI_PAGE_ALIGN)); + mi_assert_internal(_mi_ptr_page(page)==page); + mi_assert_internal(mi_page_is_owned(page)); + mi_assert_internal(mi_page_is_abandoned(page)); + + mi_page_set_heap(page,heap); + _mi_page_free_collect(page, false); // ensure used count is up to date + mi_page_queue_t* pq = mi_heap_page_queue_of(heap, page); + mi_page_queue_push_at_end(heap, pq, page); + mi_assert_expensive(_mi_page_is_valid(page)); +} + +void _mi_page_abandon(mi_page_t* page, mi_page_queue_t* pq) { + _mi_page_free_collect(page, false); // ensure used count is up to date + if (mi_page_all_free(page)) { + _mi_page_free(page, pq); + } + else { + mi_page_queue_remove(pq, page); + mi_heap_t* heap = page->heap; + mi_page_set_heap(page, NULL); + page->heap = heap; // dont set heap to NULL so we can reclaim_on_free within the same heap + _mi_arenas_page_abandon(page, heap->tld); + _mi_arenas_collect(false, false, heap->tld); // allow purging + } +} + // allocate a fresh page from a segment -static mi_page_t* mi_page_fresh_alloc(mi_heap_t* heap, mi_page_queue_t* pq, size_t block_size) { - mi_assert_internal(pq==NULL||mi_heap_contains_queue(heap, pq)); - mi_page_t* page = _mi_segment_page_alloc(heap, block_size, &heap->tld->segments, &heap->tld->os); +static mi_page_t* mi_page_fresh_alloc(mi_heap_t* heap, mi_page_queue_t* pq, size_t block_size, size_t page_alignment) { + #if !MI_HUGE_PAGE_ABANDON + mi_assert_internal(pq != NULL); + mi_assert_internal(mi_heap_contains_queue(heap, pq)); + mi_assert_internal(page_alignment > 0 || block_size > MI_LARGE_MAX_OBJ_SIZE || block_size == pq->block_size); + #endif + mi_page_t* page = _mi_arenas_page_alloc(heap, block_size, page_alignment); if (page == NULL) { - // this may be out-of-memory, or an abandoned page was reclaimed (and in our queue) + // out-of-memory return NULL; } - mi_assert_internal(pq==NULL || _mi_page_segment(page)->kind != MI_SEGMENT_HUGE); - mi_page_init(heap, page, block_size, heap->tld); - mi_heap_stat_increase(heap, pages, 1); - if (pq!=NULL) mi_page_queue_push(heap, pq, page); // huge pages use pq==NULL + if (mi_page_is_abandoned(page)) { + _mi_heap_page_reclaim(heap, page); + if (!mi_page_immediate_available(page)) { + if (mi_page_is_expandable(page)) { + mi_page_extend_free(heap, page); + } + else { + mi_assert(false); // should not happen? + return NULL; + } + } + } + else if (pq != NULL) { + mi_page_queue_push(heap, pq, page); + } + mi_assert_internal(pq!=NULL || mi_page_block_size(page) >= block_size); mi_assert_expensive(_mi_page_is_valid(page)); return page; } @@ -272,58 +330,24 @@ static mi_page_t* mi_page_fresh_alloc(mi_heap_t* heap, mi_page_queue_t* pq, size // Get a fresh page to use static mi_page_t* mi_page_fresh(mi_heap_t* heap, mi_page_queue_t* pq) { mi_assert_internal(mi_heap_contains_queue(heap, pq)); - mi_page_t* page = mi_page_fresh_alloc(heap, pq, pq->block_size); + mi_page_t* page = mi_page_fresh_alloc(heap, pq, pq->block_size, 0); if (page==NULL) return NULL; mi_assert_internal(pq->block_size==mi_page_block_size(page)); - mi_assert_internal(pq==mi_page_queue(heap, mi_page_block_size(page))); + mi_assert_internal(pq==mi_heap_page_queue_of(heap, page)); return page; } -/* ----------------------------------------------------------- - Do any delayed frees - (put there by other threads if they deallocated in a full page) ------------------------------------------------------------ */ -void _mi_heap_delayed_free_all(mi_heap_t* heap) { - while (!_mi_heap_delayed_free_partial(heap)) { - mi_atomic_yield(); - } -} - -// returns true if all delayed frees were processed -bool _mi_heap_delayed_free_partial(mi_heap_t* heap) { - // take over the list (note: no atomic exchange since it is often NULL) - mi_block_t* block = mi_atomic_load_ptr_relaxed(mi_block_t, &heap->thread_delayed_free); - while (block != NULL && !mi_atomic_cas_ptr_weak_acq_rel(mi_block_t, &heap->thread_delayed_free, &block, NULL)) { /* nothing */ }; - bool all_freed = true; - - // and free them all - while(block != NULL) { - mi_block_t* next = mi_block_nextx(heap,block, heap->keys); - // use internal free instead of regular one to keep stats etc correct - if (!_mi_free_delayed_block(block)) { - // we might already start delayed freeing while another thread has not yet - // reset the delayed_freeing flag; in that case delay it further by reinserting the current block - // into the delayed free list - all_freed = false; - mi_block_t* dfree = mi_atomic_load_ptr_relaxed(mi_block_t, &heap->thread_delayed_free); - do { - mi_block_set_nextx(heap, block, dfree, heap->keys); - } while (!mi_atomic_cas_ptr_weak_release(mi_block_t,&heap->thread_delayed_free, &dfree, block)); - } - block = next; - } - return all_freed; -} /* ----------------------------------------------------------- Unfull, abandon, free and retire ----------------------------------------------------------- */ -// Move a page from the full list back to a regular list +// Move a page from the full list back to a regular list (called from thread-local mi_free) void _mi_page_unfull(mi_page_t* page) { mi_assert_internal(page != NULL); mi_assert_expensive(_mi_page_is_valid(page)); mi_assert_internal(mi_page_is_in_full(page)); + mi_assert_internal(!mi_page_heap(page)->allow_page_abandon); if (!mi_page_is_in_full(page)) return; mi_heap_t* heap = mi_page_heap(page); @@ -331,7 +355,7 @@ void _mi_page_unfull(mi_page_t* page) { mi_page_set_in_full(page, false); // to get the right queue mi_page_queue_t* pq = mi_heap_page_queue_of(heap, page); mi_page_set_in_full(page, true); - mi_page_queue_enqueue_from(pq, pqfull, page); + mi_page_queue_enqueue_from_full(pq, pqfull, page); } static void mi_page_to_full(mi_page_t* page, mi_page_queue_t* pq) { @@ -339,71 +363,43 @@ static void mi_page_to_full(mi_page_t* page, mi_page_queue_t* pq) { mi_assert_internal(!mi_page_immediate_available(page)); mi_assert_internal(!mi_page_is_in_full(page)); - if (mi_page_is_in_full(page)) return; - mi_page_queue_enqueue_from(&mi_page_heap(page)->pages[MI_BIN_FULL], pq, page); - _mi_page_free_collect(page,false); // try to collect right away in case another thread freed just before MI_USE_DELAYED_FREE was set -} - - -// Abandon a page with used blocks at the end of a thread. -// Note: only call if it is ensured that no references exist from -// the `page->heap->thread_delayed_free` into this page. -// Currently only called through `mi_heap_collect_ex` which ensures this. -void _mi_page_abandon(mi_page_t* page, mi_page_queue_t* pq) { - mi_assert_internal(page != NULL); - mi_assert_expensive(_mi_page_is_valid(page)); - mi_assert_internal(pq == mi_page_queue_of(page)); - mi_assert_internal(mi_page_heap(page) != NULL); - - mi_heap_t* pheap = mi_page_heap(page); - - // remove from our page list - mi_segments_tld_t* segments_tld = &pheap->tld->segments; - mi_page_queue_remove(pq, page); - - // page is no longer associated with our heap - mi_assert_internal(mi_page_thread_free_flag(page)==MI_NEVER_DELAYED_FREE); - mi_page_set_heap(page, NULL); - -#if MI_DEBUG>1 - // check there are no references left.. - for (mi_block_t* block = (mi_block_t*)pheap->thread_delayed_free; block != NULL; block = mi_block_nextx(pheap, block, pheap->keys)) { - mi_assert_internal(_mi_ptr_page(block) != page); + mi_heap_t* heap = mi_page_heap(page); + if (heap->allow_page_abandon) { + // abandon full pages (this is the usual case in order to allow for sharing of memory between heaps) + _mi_page_abandon(page, pq); + } + else if (!mi_page_is_in_full(page)) { + // put full pages in a heap local queue (this is for heaps that cannot abandon, for example, if the heap can be destroyed) + mi_page_queue_enqueue_from(&mi_page_heap(page)->pages[MI_BIN_FULL], pq, page); + _mi_page_free_collect(page, false); // try to collect right away in case another thread freed just before MI_USE_DELAYED_FREE was set } -#endif - - // and abandon it - mi_assert_internal(mi_page_heap(page) == NULL); - _mi_segment_page_abandon(page,segments_tld); } // Free a page with no more free blocks -void _mi_page_free(mi_page_t* page, mi_page_queue_t* pq, bool force) { +void _mi_page_free(mi_page_t* page, mi_page_queue_t* pq) { mi_assert_internal(page != NULL); mi_assert_expensive(_mi_page_is_valid(page)); mi_assert_internal(pq == mi_page_queue_of(page)); mi_assert_internal(mi_page_all_free(page)); - mi_assert_internal(mi_page_thread_free_flag(page)!=MI_DELAYED_FREEING); + // mi_assert_internal(mi_page_thread_free_flag(page)!=MI_DELAYED_FREEING); // no more aligned blocks in here mi_page_set_has_aligned(page, false); - mi_heap_t* heap = mi_page_heap(page); - // remove from the page list // (no need to do _mi_heap_delayed_free first as all blocks are already free) - mi_segments_tld_t* segments_tld = &heap->tld->segments; mi_page_queue_remove(pq, page); // and free it + mi_tld_t* const tld = page->heap->tld; mi_page_set_heap(page,NULL); - _mi_segment_page_free(page, force, segments_tld); + _mi_arenas_page_free(page,tld); + _mi_arenas_collect(false, false, tld); // allow purging } -// Retire parameters -#define MI_MAX_RETIRE_SIZE MI_MEDIUM_OBJ_SIZE_MAX -#define MI_RETIRE_CYCLES (8) +#define MI_MAX_RETIRE_SIZE MI_LARGE_OBJ_SIZE_MAX // should be less than size for MI_BIN_HUGE +#define MI_RETIRE_CYCLES (16) // Retire a page with no more used blocks // Important to not retire too quickly though as new @@ -415,7 +411,7 @@ void _mi_page_retire(mi_page_t* page) mi_attr_noexcept { mi_assert_internal(page != NULL); mi_assert_expensive(_mi_page_is_valid(page)); mi_assert_internal(mi_page_all_free(page)); - + mi_page_set_has_aligned(page, false); // don't retire too often.. @@ -425,21 +421,26 @@ void _mi_page_retire(mi_page_t* page) mi_attr_noexcept { // how to check this efficiently though... // for now, we don't retire if it is the only page left of this size class. mi_page_queue_t* pq = mi_page_queue_of(page); - if mi_likely(page->xblock_size <= MI_MAX_RETIRE_SIZE && !mi_page_is_in_full(page)) { + #if MI_RETIRE_CYCLES > 0 + const size_t bsize = mi_page_block_size(page); + if mi_likely( /* bsize < MI_MAX_RETIRE_SIZE && */ !mi_page_queue_is_special(pq)) { // not full or huge queue? if (pq->last==page && pq->first==page) { // the only page in the queue? - mi_stat_counter_increase(_mi_stats_main.page_no_retire,1); - page->retire_expire = 1 + (page->xblock_size <= MI_SMALL_OBJ_SIZE_MAX ? MI_RETIRE_CYCLES : MI_RETIRE_CYCLES/4); mi_heap_t* heap = mi_page_heap(page); + #if MI_STAT>0 + mi_heap_stat_counter_increase(heap, pages_retire, 1); + #endif + page->retire_expire = (bsize <= MI_SMALL_MAX_OBJ_SIZE ? MI_RETIRE_CYCLES : MI_RETIRE_CYCLES/4); mi_assert_internal(pq >= heap->pages); const size_t index = pq - heap->pages; mi_assert_internal(index < MI_BIN_FULL && index < MI_BIN_HUGE); if (index < heap->page_retired_min) heap->page_retired_min = index; if (index > heap->page_retired_max) heap->page_retired_max = index; mi_assert_internal(mi_page_all_free(page)); - return; // dont't free after all + return; // don't free after all } } - _mi_page_free(page, pq, false); + #endif + _mi_page_free(page, pq); } // free retired pages: we don't need to look at the entire queues @@ -454,7 +455,7 @@ void _mi_heap_collect_retired(mi_heap_t* heap, bool force) { if (mi_page_all_free(page)) { page->retire_expire--; if (force || page->retire_expire == 0) { - _mi_page_free(pq->first, pq, force); + _mi_page_free(pq->first, pq); } else { // keep retired, update min/max @@ -471,6 +472,29 @@ void _mi_heap_collect_retired(mi_heap_t* heap, bool force) { heap->page_retired_max = max; } +/* +static void mi_heap_collect_full_pages(mi_heap_t* heap) { + // note: normally full pages get immediately abandoned and the full queue is always empty + // this path is only used if abandoning is disabled due to a destroy-able heap or options + // set by the user. + mi_page_queue_t* pq = &heap->pages[MI_BIN_FULL]; + for (mi_page_t* page = pq->first; page != NULL; ) { + mi_page_t* next = page->next; // get next in case we free the page + _mi_page_free_collect(page, false); // register concurrent free's + // no longer full? + if (!mi_page_is_full(page)) { + if (mi_page_all_free(page)) { + _mi_page_free(page, pq); + } + else { + _mi_page_unfull(page); + } + } + page = next; + } +} +*/ + /* ----------------------------------------------------------- Initialize the initial free list in a page. @@ -484,13 +508,13 @@ void _mi_heap_collect_retired(mi_heap_t* heap, bool force) { static void mi_page_free_list_extend_secure(mi_heap_t* const heap, mi_page_t* const page, const size_t bsize, const size_t extend, mi_stats_t* const stats) { MI_UNUSED(stats); - #if (MI_SECURE<=2) + #if (MI_SECURE<3) mi_assert_internal(page->free == NULL); mi_assert_internal(page->local_free == NULL); #endif mi_assert_internal(page->capacity + extend <= page->reserved); mi_assert_internal(bsize == mi_page_block_size(page)); - void* const page_area = _mi_page_start(_mi_page_segment(page), page, NULL); + void* const page_area = mi_page_start(page); // initialize a randomized free list // set up `slice_count` slices to alternate between @@ -542,13 +566,13 @@ static void mi_page_free_list_extend_secure(mi_heap_t* const heap, mi_page_t* co static mi_decl_noinline void mi_page_free_list_extend( mi_page_t* const page, const size_t bsize, const size_t extend, mi_stats_t* const stats) { MI_UNUSED(stats); - #if (MI_SECURE <= 2) + #if (MI_SECURE<3) mi_assert_internal(page->free == NULL); mi_assert_internal(page->local_free == NULL); #endif mi_assert_internal(page->capacity + extend <= page->reserved); mi_assert_internal(bsize == mi_page_block_size(page)); - void* const page_area = _mi_page_start(_mi_page_segment(page), page, NULL ); + void* const page_area = mi_page_start(page); mi_block_t* const start = mi_page_block_at(page, page_area, bsize, page->capacity); @@ -570,7 +594,7 @@ static mi_decl_noinline void mi_page_free_list_extend( mi_page_t* const page, co ----------------------------------------------------------- */ #define MI_MAX_EXTEND_SIZE (4*1024) // heuristic, one OS page seems to work well. -#if (MI_SECURE>0) +#if (MI_SECURE>=3) #define MI_MIN_EXTEND (8*MI_SECURE) // extend at least by this many #else #define MI_MIN_EXTEND (1) @@ -581,29 +605,31 @@ static mi_decl_noinline void mi_page_free_list_extend( mi_page_t* const page, co // Note: we also experimented with "bump" allocation on the first // allocations but this did not speed up any benchmark (due to an // extra test in malloc? or cache effects?) -static void mi_page_extend_free(mi_heap_t* heap, mi_page_t* page, mi_tld_t* tld) { - MI_UNUSED(tld); +static bool mi_page_extend_free(mi_heap_t* heap, mi_page_t* page) { mi_assert_expensive(mi_page_is_valid_init(page)); - #if (MI_SECURE<=2) + #if (MI_SECURE<3) mi_assert(page->free == NULL); mi_assert(page->local_free == NULL); - if (page->free != NULL) return; + if (page->free != NULL) return true; #endif - if (page->capacity >= page->reserved) return; + if (page->capacity >= page->reserved) return true; size_t page_size; - _mi_page_start(_mi_page_segment(page), page, &page_size); - mi_stat_counter_increase(tld->stats.pages_extended, 1); + //uint8_t* page_start = + mi_page_area(page, &page_size); + #if MI_STAT>0 + mi_heap_stat_counter_increase(heap, pages_extended, 1); + #endif // calculate the extend count - const size_t bsize = (page->xblock_size < MI_HUGE_BLOCK_SIZE ? page->xblock_size : page_size); - size_t extend = page->reserved - page->capacity; + const size_t bsize = mi_page_block_size(page); + size_t extend = (size_t)page->reserved - page->capacity; mi_assert_internal(extend > 0); - size_t max_extend = (bsize >= MI_MAX_EXTEND_SIZE ? MI_MIN_EXTEND : MI_MAX_EXTEND_SIZE/(uint32_t)bsize); + size_t max_extend = (bsize >= MI_MAX_EXTEND_SIZE ? MI_MIN_EXTEND : MI_MAX_EXTEND_SIZE/bsize); if (max_extend < MI_MIN_EXTEND) { max_extend = MI_MIN_EXTEND; } mi_assert_internal(max_extend > 0); - + if (extend > max_extend) { // ensure we don't touch memory beyond the page to reduce page commit. // the `lean` benchmark tests this. Going from 1 to 8 increases rss by 50%. @@ -613,70 +639,76 @@ static void mi_page_extend_free(mi_heap_t* heap, mi_page_t* page, mi_tld_t* tld) mi_assert_internal(extend > 0 && extend + page->capacity <= page->reserved); mi_assert_internal(extend < (1UL<<16)); + // commit on demand? + if (page->slice_committed > 0) { + const size_t needed_size = (page->capacity + extend)*bsize; + const size_t needed_commit = _mi_align_up( mi_page_slice_offset_of(page, needed_size), MI_PAGE_MIN_COMMIT_SIZE ); + if (needed_commit > page->slice_committed) { + mi_assert_internal(((needed_commit - page->slice_committed) % _mi_os_page_size()) == 0); + if (!_mi_os_commit(mi_page_slice_start(page) + page->slice_committed, needed_commit - page->slice_committed, NULL)) { + return false; + } + page->slice_committed = needed_commit; + } + } + // and append the extend the free list - if (extend < MI_MIN_SLICES || MI_SECURE==0) { //!mi_option_is_enabled(mi_option_secure)) { - mi_page_free_list_extend(page, bsize, extend, &tld->stats ); + if (extend < MI_MIN_SLICES || MI_SECURE<3) { //!mi_option_is_enabled(mi_option_secure)) { + mi_page_free_list_extend(page, bsize, extend, &heap->tld->stats ); } else { - mi_page_free_list_extend_secure(heap, page, bsize, extend, &tld->stats); + mi_page_free_list_extend_secure(heap, page, bsize, extend, &heap->tld->stats); } // enable the new free list page->capacity += (uint16_t)extend; - mi_stat_increase(tld->stats.page_committed, extend * bsize); - - // extension into zero initialized memory preserves the zero'd free list - if (!page->is_zero_init) { - page->is_zero = false; - } + #if MI_STAT>0 + mi_heap_stat_increase(heap, page_committed, extend * bsize); + #endif mi_assert_expensive(mi_page_is_valid_init(page)); + return true; } -// Initialize a fresh page -static void mi_page_init(mi_heap_t* heap, mi_page_t* page, size_t block_size, mi_tld_t* tld) { +// Initialize a fresh page (that is already partially initialized) +mi_decl_nodiscard bool _mi_page_init(mi_heap_t* heap, mi_page_t* page) { mi_assert(page != NULL); - mi_segment_t* segment = _mi_page_segment(page); - mi_assert(segment != NULL); - mi_assert_internal(block_size > 0); - // set fields mi_page_set_heap(page, heap); - page->xblock_size = (block_size < MI_HUGE_BLOCK_SIZE ? (uint32_t)block_size : MI_HUGE_BLOCK_SIZE); // initialize before _mi_segment_page_start + size_t page_size; - const void* page_start = _mi_segment_page_start(segment, page, &page_size); - MI_UNUSED(page_start); + uint8_t* page_start = mi_page_area(page, &page_size); MI_UNUSED(page_start); mi_track_mem_noaccess(page_start,page_size); - mi_assert_internal(mi_page_block_size(page) <= page_size); - mi_assert_internal(page_size <= page->slice_count*MI_SEGMENT_SLICE_SIZE); - mi_assert_internal(page_size / block_size < (1L<<16)); - page->reserved = (uint16_t)(page_size / block_size); - #ifdef MI_ENCODE_FREELIST + mi_assert_internal(page_size / mi_page_block_size(page) < (1L<<16)); + mi_assert_internal(page->reserved > 0); + #if (MI_PADDING || MI_ENCODE_FREELIST) page->keys[0] = _mi_heap_random_next(heap); page->keys[1] = _mi_heap_random_next(heap); #endif - #if MI_DEBUG > 0 - page->is_zero = false; // ensure in debug mode we initialize with MI_DEBUG_UNINIT, see issue #501 - #else - page->is_zero = page->is_zero_init; + #if MI_DEBUG>2 + if (page->memid.initially_zero) { + mi_track_mem_defined(page->page_start, mi_page_committed(page)); + mi_assert_expensive(mi_mem_is_zero(page_start, mi_page_committed(page))); + } #endif - mi_assert_internal(page->is_committed); - mi_assert_internal(!page->is_reset); mi_assert_internal(page->capacity == 0); mi_assert_internal(page->free == NULL); mi_assert_internal(page->used == 0); - mi_assert_internal(page->xthread_free == 0); + mi_assert_internal(mi_page_is_owned(page)); + mi_assert_internal(page->xthread_free == 1); mi_assert_internal(page->next == NULL); mi_assert_internal(page->prev == NULL); mi_assert_internal(page->retire_expire == 0); mi_assert_internal(!mi_page_has_aligned(page)); - #if (MI_ENCODE_FREELIST) + #if (MI_PADDING || MI_ENCODE_FREELIST) mi_assert_internal(page->keys[0] != 0); mi_assert_internal(page->keys[1] != 0); #endif + mi_assert_internal(page->block_size_shift == 0 || (mi_page_block_size(page) == ((size_t)1 << page->block_size_shift))); mi_assert_expensive(mi_page_is_valid_init(page)); // initialize an initial free list - mi_page_extend_free(heap,page,tld); + if (!mi_page_extend_free(heap,page)) return false; mi_assert(mi_page_immediate_available(page)); + return true; } @@ -685,81 +717,139 @@ static void mi_page_init(mi_heap_t* heap, mi_page_t* page, size_t block_size, mi -------------------------------------------------------------*/ // Find a page with free blocks of `page->block_size`. -static mi_page_t* mi_page_queue_find_free_ex(mi_heap_t* heap, mi_page_queue_t* pq, bool first_try) +static mi_decl_noinline mi_page_t* mi_page_queue_find_free_ex(mi_heap_t* heap, mi_page_queue_t* pq, bool first_try) { // search through the pages in "next fit" order size_t count = 0; + long candidate_limit = 0; // we reset this on the first candidate to limit the search + long page_full_retain = (pq->block_size > MI_SMALL_MAX_OBJ_SIZE ? 0 : heap->page_full_retain); // only retain small pages + mi_page_t* page_candidate = NULL; // a page with free space mi_page_t* page = pq->first; + while (page != NULL) { - mi_page_t* next = page->next; // remember next + mi_page_t* next = page->next; // remember next (as this page can move to another queue) count++; + candidate_limit--; - // 0. collect freed blocks by us and other threads - _mi_page_free_collect(page, false); + // search up to N pages for a best candidate - // 1. if the page contains free blocks, we are done - if (mi_page_immediate_available(page)) { - break; // pick this one + // is the local free list non-empty? + bool immediate_available = mi_page_immediate_available(page); + if (!immediate_available) { + // collect freed blocks by us and other threads to we get a proper use count + _mi_page_free_collect(page, false); + immediate_available = mi_page_immediate_available(page); } - // 2. Try to extend - if (page->capacity < page->reserved) { - mi_page_extend_free(heap, page, heap->tld); - mi_assert_internal(mi_page_immediate_available(page)); - break; + // if the page is completely full, move it to the `mi_pages_full` + // queue so we don't visit long-lived pages too often. + if (!immediate_available && !mi_page_is_expandable(page)) { + page_full_retain--; + if (page_full_retain < 0) { + mi_assert_internal(!mi_page_is_in_full(page) && !mi_page_immediate_available(page)); + mi_page_to_full(page, pq); + } + } + else { + // the page has free space, make it a candidate + // we prefer non-expandable pages with high usage as candidates (to reduce commit, and increase chances of free-ing up pages) + if (page_candidate == NULL) { + page_candidate = page; + candidate_limit = _mi_option_get_fast(mi_option_page_max_candidates); + } + else if (mi_page_all_free(page_candidate)) { + _mi_page_free(page_candidate, pq); + page_candidate = page; + } + // prefer to reuse fuller pages (in the hope the less used page gets freed) + else if (page->used >= page_candidate->used && !mi_page_is_mostly_used(page)) { // && !mi_page_is_expandable(page)) { + page_candidate = page; + } + // if we find a non-expandable candidate, or searched for N pages, return with the best candidate + if (immediate_available || candidate_limit <= 0) { + mi_assert_internal(page_candidate!=NULL); + break; + } + } + + #if 0 + // first-fit algorithm without candidates + // If the page contains free blocks, we are done + if (mi_page_immediate_available(page) || mi_page_is_expandable(page)) { + break; // pick this one } - // 3. If the page is completely full, move it to the `mi_pages_full` + // If the page is completely full, move it to the `mi_pages_full` // queue so we don't visit long-lived pages too often. mi_assert_internal(!mi_page_is_in_full(page) && !mi_page_immediate_available(page)); mi_page_to_full(page, pq); + #endif page = next; } // for each page - mi_heap_stat_counter_increase(heap, searches, count); + mi_heap_stat_counter_increase(heap, page_searches, count); + + // set the page to the best candidate + if (page_candidate != NULL) { + page = page_candidate; + } + if (page != NULL) { + if (!mi_page_immediate_available(page)) { + mi_assert_internal(mi_page_is_expandable(page)); + if (!mi_page_extend_free(heap, page)) { + page = NULL; // failed to extend + } + } + mi_assert_internal(page == NULL || mi_page_immediate_available(page)); + } if (page == NULL) { - _mi_heap_collect_retired(heap, false); // perhaps make a page available? + _mi_heap_collect_retired(heap, false); // perhaps make a page available page = mi_page_fresh(heap, pq); + mi_assert_internal(page == NULL || mi_page_immediate_available(page)); if (page == NULL && first_try) { // out-of-memory _or_ an abandoned page with free blocks was reclaimed, try once again - page = mi_page_queue_find_free_ex(heap, pq, false); + page = mi_page_queue_find_free_ex(heap, pq, false); + mi_assert_internal(page == NULL || mi_page_immediate_available(page)); } } else { - mi_assert(pq->first == page); + mi_assert_internal(page == NULL || mi_page_immediate_available(page)); + // move the page to the front of the queue + mi_page_queue_move_to_front(heap, pq, page); page->retire_expire = 0; + // _mi_heap_collect_retired(heap, false); // update retire counts; note: increases rss on MemoryLoad bench so don't do this } mi_assert_internal(page == NULL || mi_page_immediate_available(page)); + + return page; } // Find a page with free blocks of `size`. -static inline mi_page_t* mi_find_free_page(mi_heap_t* heap, size_t size) { - mi_page_queue_t* pq = mi_page_queue(heap,size); +static mi_page_t* mi_find_free_page(mi_heap_t* heap, mi_page_queue_t* pq) { + // mi_page_queue_t* pq = mi_page_queue(heap, size); + mi_assert_internal(!mi_page_queue_is_huge(pq)); + + // check the first page: we even do this with candidate search or otherwise we re-search every time mi_page_t* page = pq->first; - if (page != NULL) { - #if (MI_SECURE>=3) // in secure mode, we extend half the time to increase randomness + if mi_likely(page != NULL && mi_page_immediate_available(page)) { + #if (MI_SECURE>=3) // in secure mode, we extend half the time to increase randomness if (page->capacity < page->reserved && ((_mi_heap_random_next(heap) & 1) == 1)) { - mi_page_extend_free(heap, page, heap->tld); + mi_page_extend_free(heap, page); mi_assert_internal(mi_page_immediate_available(page)); } - else - #endif - { - _mi_page_free_collect(page,false); - } - - if (mi_page_immediate_available(page)) { - page->retire_expire = 0; - return page; // fast path - } + #endif + page->retire_expire = 0; + return page; // fast path + } + else { + return mi_page_queue_find_free_ex(heap, pq, true); } - return mi_page_queue_find_free_ex(heap, pq, true); } @@ -792,40 +882,30 @@ void mi_register_deferred_free(mi_deferred_free_fun* fn, void* arg) mi_attr_noex General allocation ----------------------------------------------------------- */ -// Large and huge page allocation. -// Huge pages are allocated directly without being in a queue. -// Because huge pages contain just one block, and the segment contains -// just that page, we always treat them as abandoned and any thread -// that frees the block can free the whole page and segment directly. -static mi_page_t* mi_large_huge_page_alloc(mi_heap_t* heap, size_t size) { - size_t block_size = _mi_os_good_alloc_size(size); - mi_assert_internal(mi_bin(block_size) == MI_BIN_HUGE); - bool is_huge = (block_size > MI_LARGE_OBJ_SIZE_MAX); - mi_page_queue_t* pq = (is_huge ? NULL : mi_page_queue(heap, block_size)); - mi_page_t* page = mi_page_fresh_alloc(heap, pq, block_size); +// Huge pages contain just one block, and the segment contains just that page. +// Huge pages are also use if the requested alignment is very large (> MI_BLOCK_ALIGNMENT_MAX) +// so their size is not always `> MI_LARGE_OBJ_SIZE_MAX`. +static mi_page_t* mi_huge_page_alloc(mi_heap_t* heap, size_t size, size_t page_alignment, mi_page_queue_t* pq) { + const size_t block_size = _mi_os_good_alloc_size(size); + // mi_assert_internal(mi_bin(block_size) == MI_BIN_HUGE || page_alignment > 0); + #if MI_HUGE_PAGE_ABANDON + #error todo. + #else + // mi_page_queue_t* pq = mi_page_queue(heap, MI_LARGE_MAX_OBJ_SIZE+1); // always in the huge queue regardless of the block size + mi_assert_internal(mi_page_queue_is_huge(pq)); + #endif + mi_page_t* page = mi_page_fresh_alloc(heap, pq, block_size, page_alignment); if (page != NULL) { + mi_assert_internal(mi_page_block_size(page) >= size); mi_assert_internal(mi_page_immediate_available(page)); - - if (pq == NULL) { - // huge pages are directly abandoned - mi_assert_internal(_mi_page_segment(page)->kind == MI_SEGMENT_HUGE); - mi_assert_internal(_mi_page_segment(page)->used==1); - mi_assert_internal(_mi_page_segment(page)->thread_id==0); // abandoned, not in the huge queue - mi_page_set_heap(page, NULL); - } - else { - mi_assert_internal(_mi_page_segment(page)->kind != MI_SEGMENT_HUGE); - } - - const size_t bsize = mi_page_usable_block_size(page); // note: not `mi_page_block_size` to account for padding - if (bsize <= MI_LARGE_OBJ_SIZE_MAX) { - mi_heap_stat_increase(heap, large, bsize); - mi_heap_stat_counter_increase(heap, large_count, 1); - } - else { - mi_heap_stat_increase(heap, huge, bsize); - mi_heap_stat_counter_increase(heap, huge_count, 1); - } + mi_assert_internal(mi_page_is_huge(page)); + mi_assert_internal(mi_page_is_singleton(page)); + #if MI_HUGE_PAGE_ABANDON + mi_assert_internal(mi_page_is_abandoned(page)); + mi_page_set_heap(page, NULL); + #endif + mi_heap_stat_increase(heap, malloc_huge, mi_page_block_size(page)); + mi_heap_stat_counter_increase(heap, malloc_huge_count, 1); } return page; } @@ -833,70 +913,90 @@ static mi_page_t* mi_large_huge_page_alloc(mi_heap_t* heap, size_t size) { // Allocate a page // Note: in debug mode the size includes MI_PADDING_SIZE and might have overflowed. -static mi_page_t* mi_find_page(mi_heap_t* heap, size_t size) mi_attr_noexcept { +static mi_page_t* mi_find_page(mi_heap_t* heap, size_t size, size_t huge_alignment) mi_attr_noexcept { + const size_t req_size = size - MI_PADDING_SIZE; // correct for padding_size in case of an overflow on `size` + if mi_unlikely(req_size > MI_MAX_ALLOC_SIZE) { + _mi_error_message(EOVERFLOW, "allocation request is too large (%zu bytes)\n", req_size); + return NULL; + } + mi_page_queue_t* pq = mi_page_queue(heap, (huge_alignment > 0 ? MI_LARGE_MAX_OBJ_SIZE+1 : size)); // huge allocation? - const size_t req_size = size - MI_PADDING_SIZE; // correct for padding_size in case of an overflow on `size` - if mi_unlikely(req_size > (MI_MEDIUM_OBJ_SIZE_MAX - MI_PADDING_SIZE)) { - if mi_unlikely(req_size > PTRDIFF_MAX) { // we don't allocate more than PTRDIFF_MAX (see ) - _mi_error_message(EOVERFLOW, "allocation request is too large (%zu bytes)\n", req_size); - return NULL; - } - else { - return mi_large_huge_page_alloc(heap,size); - } + if mi_unlikely(mi_page_queue_is_huge(pq) || req_size > MI_MAX_ALLOC_SIZE) { + return mi_huge_page_alloc(heap,size,huge_alignment,pq); } else { // otherwise find a page with free blocks in our size segregated queues + #if MI_PADDING mi_assert_internal(size >= MI_PADDING_SIZE); - return mi_find_free_page(heap, size); + #endif + return mi_find_free_page(heap, pq); } } + // Generic allocation routine if the fast path (`alloc.c:mi_page_malloc`) does not succeed. // Note: in debug mode the size includes MI_PADDING_SIZE and might have overflowed. -void* _mi_malloc_generic(mi_heap_t* heap, size_t size, bool zero) mi_attr_noexcept +// The `huge_alignment` is normally 0 but is set to a multiple of MI_SLICE_SIZE for +// very large requested alignments in which case we use a huge singleton page. +void* _mi_malloc_generic(mi_heap_t* heap, size_t size, bool zero, size_t huge_alignment) mi_attr_noexcept { mi_assert_internal(heap != NULL); // initialize if necessary if mi_unlikely(!mi_heap_is_initialized(heap)) { - mi_thread_init(); // calls `_mi_heap_init` in turn - heap = mi_get_default_heap(); + heap = mi_heap_get_default(); // calls mi_thread_init if mi_unlikely(!mi_heap_is_initialized(heap)) { return NULL; } } mi_assert_internal(mi_heap_is_initialized(heap)); - // call potential deferred free routines - _mi_deferred_free(heap, false); - - // free delayed frees from other threads (but skip contended ones) - _mi_heap_delayed_free_partial(heap); + // do administrative tasks every N generic mallocs + if mi_unlikely(++heap->generic_count >= 1000) { + heap->generic_collect_count += heap->generic_count; + heap->generic_count = 0; + // call potential deferred free routines + _mi_deferred_free(heap, false); + + // collect every once in a while (10000 by default) + const long generic_collect = mi_option_get_clamp(mi_option_generic_collect, 1, 1000000L); + if (heap->generic_collect_count >= generic_collect) { + heap->generic_collect_count = 0; + mi_heap_collect(heap, false /* force? */); + } + } // find (or allocate) a page of the right size - mi_page_t* page = mi_find_page(heap, size); + mi_page_t* page = mi_find_page(heap, size, huge_alignment); if mi_unlikely(page == NULL) { // first time out of memory, try to collect and retry the allocation once more - mi_heap_collect(heap, true /* force */); - page = mi_find_page(heap, size); + mi_heap_collect(heap, true /* force? */); + page = mi_find_page(heap, size, huge_alignment); } if mi_unlikely(page == NULL) { // out of memory - const size_t req_size = size - MI_PADDING_SIZE; // correct for padding_size in case of an overflow on `size` + const size_t req_size = size - MI_PADDING_SIZE; // correct for padding_size in case of an overflow on `size` _mi_error_message(ENOMEM, "unable to allocate memory (%zu bytes)\n", req_size); return NULL; } mi_assert_internal(mi_page_immediate_available(page)); mi_assert_internal(mi_page_block_size(page) >= size); + mi_assert_internal(_mi_is_aligned(page, MI_PAGE_ALIGN)); + mi_assert_internal(_mi_ptr_page(page)==page); // and try again, this time succeeding! (i.e. this should never recurse through _mi_page_malloc) - if mi_unlikely(zero && page->xblock_size == 0) { + void* p; + if mi_unlikely(zero && mi_page_is_huge(page)) { // note: we cannot call _mi_page_malloc with zeroing for huge blocks; we zero it afterwards in that case. - void* p = _mi_page_malloc(heap, page, size, false); + p = _mi_page_malloc(heap, page, size); mi_assert_internal(p != NULL); _mi_memzero_aligned(p, mi_page_usable_block_size(page)); - return p; } else { - return _mi_page_malloc(heap, page, size, zero); + p = _mi_page_malloc_zero(heap, page, size, zero); + mi_assert_internal(p != NULL); + } + // move singleton pages to the full queue + if (page->reserved == page->used) { + mi_page_to_full(page, mi_page_queue_of(page)); } + return p; } diff --git a/src/dashbls/depends/mimalloc/src/prim/emscripten/prim.c b/src/dashbls/depends/mimalloc/src/prim/emscripten/prim.c new file mode 100644 index 000000000000..9ddec5df5415 --- /dev/null +++ b/src/dashbls/depends/mimalloc/src/prim/emscripten/prim.c @@ -0,0 +1,252 @@ +/* ---------------------------------------------------------------------------- +Copyright (c) 2018-2025, Microsoft Research, Daan Leijen, Alon Zakai +This is free software; you can redistribute it and/or modify it under the +terms of the MIT license. A copy of the license can be found in the file +"LICENSE" at the root of this distribution. +-----------------------------------------------------------------------------*/ + +// This file is included in `src/prim/prim.c` + +#include "mimalloc.h" +#include "mimalloc/internal.h" +#include "mimalloc/atomic.h" +#include "mimalloc/prim.h" + +// Design +// ====== +// +// mimalloc is built on top of emmalloc. emmalloc is a minimal allocator on top +// of sbrk. The reason for having three layers here is that we want mimalloc to +// be able to allocate and release system memory properly, the same way it would +// when using VirtualAlloc on Windows or mmap on POSIX, and sbrk is too limited. +// Specifically, sbrk can only go up and down, and not "skip" over regions, and +// so we end up either never freeing memory to the system, or we can get stuck +// with holes. +// +// Atm wasm generally does *not* free memory back the system: once grown, we do +// not shrink back down (https://github.com/WebAssembly/design/issues/1397). +// However, that is expected to improve +// (https://github.com/WebAssembly/memory-control/blob/main/proposals/memory-control/Overview.md) +// and so we do not want to bake those limitations in here. +// +// Even without that issue, we want our system allocator to handle holes, that +// is, it should merge freed regions and allow allocating new content there of +// the full size, etc., so that we do not waste space. That means that the +// system allocator really does need to handle the general problem of allocating +// and freeing variable-sized chunks of memory in a random order, like malloc/ +// free do. And so it makes sense to layer mimalloc on top of such an +// implementation. +// +// emmalloc makes sense for the lower level because it is small and simple while +// still fully handling merging of holes etc. It is not the most efficient +// allocator, but our assumption is that mimalloc needs to be fast while the +// system allocator underneath it is called much less frequently. +// + +//--------------------------------------------- +// init +//--------------------------------------------- + +void _mi_prim_mem_init( mi_os_mem_config_t* config) { + config->page_size = 64*MI_KiB; // WebAssembly has a fixed page size: 64KiB + config->alloc_granularity = 16; + config->has_overcommit = false; + config->has_partial_free = false; + config->has_virtual_reserve = false; +} + +extern void emmalloc_free(void*); + +int _mi_prim_free(void* addr, size_t size) { + if (size==0) return 0; + emmalloc_free(addr); + return 0; +} + + +//--------------------------------------------- +// Allocation +//--------------------------------------------- + +extern void* emmalloc_memalign(size_t alignment, size_t size); + +// Note: the `try_alignment` is just a hint and the returned pointer is not guaranteed to be aligned. +int _mi_prim_alloc(void* hint_addr, size_t size, size_t try_alignment, bool commit, bool allow_large, bool* is_large, bool* is_zero, void** addr) { + MI_UNUSED(try_alignment); MI_UNUSED(allow_large); MI_UNUSED(commit); MI_UNUSED(hint_addr); + *is_large = false; + // TODO: Track the highest address ever seen; first uses of it are zeroes. + // That assumes no one else uses sbrk but us (they could go up, + // scribble, and then down), but we could assert on that perhaps. + *is_zero = false; + // emmalloc has a minimum alignment size. + #define MIN_EMMALLOC_ALIGN 8 + if (try_alignment < MIN_EMMALLOC_ALIGN) { + try_alignment = MIN_EMMALLOC_ALIGN; + } + void* p = emmalloc_memalign(try_alignment, size); + *addr = p; + if (p == 0) { + return ENOMEM; + } + return 0; +} + + +//--------------------------------------------- +// Commit/Reset +//--------------------------------------------- + +int _mi_prim_commit(void* addr, size_t size, bool* is_zero) { + MI_UNUSED(addr); MI_UNUSED(size); + // See TODO above. + *is_zero = false; + return 0; +} + +int _mi_prim_decommit(void* addr, size_t size, bool* needs_recommit) { + MI_UNUSED(addr); MI_UNUSED(size); + *needs_recommit = false; + return 0; +} + +int _mi_prim_reset(void* addr, size_t size) { + MI_UNUSED(addr); MI_UNUSED(size); + return 0; +} + +int _mi_prim_reuse(void* addr, size_t size) { + MI_UNUSED(addr); MI_UNUSED(size); + return 0; +} + +int _mi_prim_protect(void* addr, size_t size, bool protect) { + MI_UNUSED(addr); MI_UNUSED(size); MI_UNUSED(protect); + return 0; +} + + +//--------------------------------------------- +// Huge pages and NUMA nodes +//--------------------------------------------- + +int _mi_prim_alloc_huge_os_pages(void* hint_addr, size_t size, int numa_node, bool* is_zero, void** addr) { + MI_UNUSED(hint_addr); MI_UNUSED(size); MI_UNUSED(numa_node); + *is_zero = true; + *addr = NULL; + return ENOSYS; +} + +size_t _mi_prim_numa_node(void) { + return 0; +} + +size_t _mi_prim_numa_node_count(void) { + return 1; +} + + +//---------------------------------------------------------------- +// Clock +//---------------------------------------------------------------- + +#include + +mi_msecs_t _mi_prim_clock_now(void) { + return emscripten_date_now(); +} + + +//---------------------------------------------------------------- +// Process info +//---------------------------------------------------------------- + +void _mi_prim_process_info(mi_process_info_t* pinfo) +{ + // use defaults + MI_UNUSED(pinfo); +} + + +//---------------------------------------------------------------- +// Output +//---------------------------------------------------------------- + +#include + +void _mi_prim_out_stderr( const char* msg) { + emscripten_console_error(msg); +} + + +//---------------------------------------------------------------- +// Environment +//---------------------------------------------------------------- + +bool _mi_prim_getenv(const char* name, char* result, size_t result_size) { + // For code size reasons, do not support environ customization for now. + MI_UNUSED(name); + MI_UNUSED(result); + MI_UNUSED(result_size); + return false; +} + + +//---------------------------------------------------------------- +// Random +//---------------------------------------------------------------- + +bool _mi_prim_random_buf(void* buf, size_t buf_len) { + int err = getentropy(buf, buf_len); + return !err; +} + + +//---------------------------------------------------------------- +// Thread init/done +//---------------------------------------------------------------- + +#if defined(MI_USE_PTHREADS) + +// use pthread local storage keys to detect thread ending +// (and used with MI_TLS_PTHREADS for the default heap) +pthread_key_t _mi_heap_default_key = (pthread_key_t)(-1); + +static void mi_pthread_done(void* value) { + if (value!=NULL) { + _mi_thread_done((mi_heap_t*)value); + } +} + +void _mi_prim_thread_init_auto_done(void) { + mi_assert_internal(_mi_heap_default_key == (pthread_key_t)(-1)); + pthread_key_create(&_mi_heap_default_key, &mi_pthread_done); +} + +void _mi_prim_thread_done_auto_done(void) { + // nothing to do +} + +void _mi_prim_thread_associate_default_heap(mi_heap_t* heap) { + if (_mi_heap_default_key != (pthread_key_t)(-1)) { // can happen during recursive invocation on freeBSD + pthread_setspecific(_mi_heap_default_key, heap); + } +} + +#else + +void _mi_prim_thread_init_auto_done(void) { + // nothing +} + +void _mi_prim_thread_done_auto_done(void) { + // nothing +} + +void _mi_prim_thread_associate_default_heap(mi_heap_t* heap) { + MI_UNUSED(heap); +} +#endif + +bool _mi_prim_thread_is_in_threadpool(void) { + return false; +} diff --git a/src/dashbls/depends/mimalloc/src/alloc-override-osx.c b/src/dashbls/depends/mimalloc/src/prim/osx/alloc-override-zone.c similarity index 93% rename from src/dashbls/depends/mimalloc/src/alloc-override-osx.c rename to src/dashbls/depends/mimalloc/src/prim/osx/alloc-override-zone.c index ba2313a2a06a..a8f5fbc68268 100644 --- a/src/dashbls/depends/mimalloc/src/alloc-override-osx.c +++ b/src/dashbls/depends/mimalloc/src/prim/osx/alloc-override-zone.c @@ -6,7 +6,7 @@ terms of the MIT license. A copy of the license can be found in the file -----------------------------------------------------------------------------*/ #include "mimalloc.h" -#include "mimalloc-internal.h" +#include "mimalloc/internal.h" #if defined(MI_MALLOC_OVERRIDE) @@ -19,8 +19,8 @@ terms of the MIT license. A copy of the license can be found in the file This is done through the malloc zone interface. It seems to be most robust in combination with interposing though or otherwise we may get zone errors as there are could - be allocations done by the time we take over the - zone. + be allocations done by the time we take over the + zone. ------------------------------------------------------ */ #include @@ -64,7 +64,8 @@ static void* zone_valloc(malloc_zone_t* zone, size_t size) { static void zone_free(malloc_zone_t* zone, void* p) { MI_UNUSED(zone); - mi_cfree(p); + // mi_cfree(p); // checked free as `zone_free` may be called with invalid pointers + mi_free(p); // with the page_map and pagemap_commit=1 we can use the regular free } static void* zone_realloc(malloc_zone_t* zone, void* p, size_t newsize) { @@ -195,7 +196,7 @@ static malloc_introspection_t mi_introspect = { .log = &intro_log, .force_lock = &intro_force_lock, .force_unlock = &intro_force_unlock, -#if defined(MAC_OS_X_VERSION_10_6) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6) +#if defined(MAC_OS_X_VERSION_10_6) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6) && !defined(__ppc__) .statistics = &intro_statistics, .zone_locked = &intro_zone_locked, #endif @@ -215,8 +216,8 @@ static malloc_zone_t mi_malloc_zone = { .zone_name = "mimalloc", .batch_malloc = &zone_batch_malloc, .batch_free = &zone_batch_free, - .introspect = &mi_introspect, -#if defined(MAC_OS_X_VERSION_10_6) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6) + .introspect = &mi_introspect, +#if defined(MAC_OS_X_VERSION_10_6) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6) && !defined(__ppc__) #if defined(MAC_OS_X_VERSION_10_14) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_14) .version = 10, #else @@ -225,7 +226,9 @@ static malloc_zone_t mi_malloc_zone = { // switch to version 9+ on OSX 10.6 to support memalign. .memalign = &zone_memalign, .free_definite_size = &zone_free_definite_size, + #if defined(MAC_OS_X_VERSION_10_7) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7) .pressure_relief = &zone_pressure_relief, + #endif #if defined(MAC_OS_X_VERSION_10_14) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_14) .claimed_address = &zone_claimed_address, #endif @@ -242,7 +245,7 @@ static malloc_zone_t mi_malloc_zone = { #if defined(MI_OSX_INTERPOSE) && defined(MI_SHARED_LIB_EXPORT) // ------------------------------------------------------ -// Override malloc_xxx and malloc_zone_xxx api's to use only +// Override malloc_xxx and malloc_zone_xxx api's to use only // our mimalloc zone. Since even the loader uses malloc // on macOS, this ensures that all allocations go through // mimalloc (as all calls are interposed). @@ -254,7 +257,7 @@ static malloc_zone_t mi_malloc_zone = { static inline malloc_zone_t* mi_get_default_zone(void) { static bool init; - if mi_unlikely(!init) { + if mi_unlikely(!init) { init = true; malloc_zone_register(&mi_malloc_zone); // by calling register we avoid a zone error on free (see ) } @@ -272,7 +275,7 @@ static malloc_zone_t* mi_malloc_create_zone(vm_size_t size, unsigned flags) { return mi_get_default_zone(); } -static malloc_zone_t* mi_malloc_default_zone (void) { +static malloc_zone_t* mi_malloc_default_zone (void) { return mi_get_default_zone(); } @@ -292,11 +295,11 @@ static kern_return_t mi_malloc_get_all_zones (task_t task, memory_reader_t mr, v return KERN_SUCCESS; } -static const char* mi_malloc_get_zone_name(malloc_zone_t* zone) { +static const char* mi_malloc_get_zone_name(malloc_zone_t* zone) { return (zone == NULL ? mi_malloc_zone.zone_name : zone->zone_name); } -static void mi_malloc_set_zone_name(malloc_zone_t* zone, const char* name) { +static void mi_malloc_set_zone_name(malloc_zone_t* zone, const char* name) { MI_UNUSED(zone); MI_UNUSED(name); } @@ -306,7 +309,7 @@ static int mi_malloc_jumpstart(uintptr_t cookie) { } static void mi__malloc_fork_prepare(void) { - // nothing + // nothing } static void mi__malloc_fork_parent(void) { // nothing @@ -367,13 +370,13 @@ __attribute__((used)) static const struct mi_interpose_s _mi_zone_interposes[] MI_INTERPOSE_MI(malloc_destroy_zone), MI_INTERPOSE_MI(malloc_get_all_zones), MI_INTERPOSE_MI(malloc_get_zone_name), - MI_INTERPOSE_MI(malloc_jumpstart), + MI_INTERPOSE_MI(malloc_jumpstart), MI_INTERPOSE_MI(malloc_printf), MI_INTERPOSE_MI(malloc_set_zone_name), MI_INTERPOSE_MI(_malloc_fork_child), MI_INTERPOSE_MI(_malloc_fork_parent), MI_INTERPOSE_MI(_malloc_fork_prepare), - + MI_INTERPOSE_ZONE(zone_batch_free), MI_INTERPOSE_ZONE(zone_batch_malloc), MI_INTERPOSE_ZONE(zone_calloc), @@ -416,11 +419,12 @@ static inline malloc_zone_t* mi_get_default_zone(void) } #if defined(__clang__) -__attribute__((constructor(0))) +__attribute__((constructor(101))) // highest priority #else -__attribute__((constructor)) // seems not supported by g++-11 on the M1 +__attribute__((constructor)) // priority level is not supported by gcc #endif -static void _mi_macos_override_malloc() { +__attribute__((used)) +static void _mi_macos_override_malloc(void) { malloc_zone_t* purgeable_zone = NULL; #if defined(MAC_OS_X_VERSION_10_6) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6) diff --git a/src/dashbls/depends/mimalloc/src/prim/osx/prim.c b/src/dashbls/depends/mimalloc/src/prim/osx/prim.c new file mode 100644 index 000000000000..8a2f4e8aa473 --- /dev/null +++ b/src/dashbls/depends/mimalloc/src/prim/osx/prim.c @@ -0,0 +1,9 @@ +/* ---------------------------------------------------------------------------- +Copyright (c) 2018-2023, Microsoft Research, Daan Leijen +This is free software; you can redistribute it and/or modify it under the +terms of the MIT license. A copy of the license can be found in the file +"LICENSE" at the root of this distribution. +-----------------------------------------------------------------------------*/ + +// We use the unix/prim.c with the mmap API on macOSX +#include "../unix/prim.c" diff --git a/src/dashbls/depends/mimalloc/src/prim/prim.c b/src/dashbls/depends/mimalloc/src/prim/prim.c new file mode 100644 index 000000000000..1864a3afcc1f --- /dev/null +++ b/src/dashbls/depends/mimalloc/src/prim/prim.c @@ -0,0 +1,76 @@ +/* ---------------------------------------------------------------------------- +Copyright (c) 2018-2023, Microsoft Research, Daan Leijen +This is free software; you can redistribute it and/or modify it under the +terms of the MIT license. A copy of the license can be found in the file +"LICENSE" at the root of this distribution. +-----------------------------------------------------------------------------*/ + +// Select the implementation of the primitives +// depending on the OS. + +#if defined(_WIN32) +#include "windows/prim.c" // VirtualAlloc (Windows) + +#elif defined(__APPLE__) +#include "osx/prim.c" // macOSX (actually defers to mmap in unix/prim.c) + +#elif defined(__EMSCRIPTEN__) +#include "emscripten/prim.c" // emmalloc_*, + pthread support + +#elif defined(__wasi__) +#define MI_USE_SBRK +#include "wasi/prim.c" // memory-grow or sbrk (Wasm) + +#else +#include "unix/prim.c" // mmap() (Linux, macOSX, BSD, Illumnos, Haiku, DragonFly, etc.) + +#endif + +// Generic process initialization +#ifndef MI_PRIM_HAS_PROCESS_ATTACH +#if defined(__GNUC__) || defined(__clang__) + // gcc,clang: use the constructor/destructor attribute + // which for both seem to run before regular constructors/destructors + #if defined(__clang__) + #define mi_attr_constructor __attribute__((constructor(101))) + #define mi_attr_destructor __attribute__((destructor(101))) + #else + #define mi_attr_constructor __attribute__((constructor)) + #define mi_attr_destructor __attribute__((destructor)) + #endif + static void mi_attr_constructor mi_process_attach(void) { + _mi_auto_process_init(); + } + static void mi_attr_destructor mi_process_detach(void) { + _mi_auto_process_done(); + } +#elif defined(__cplusplus) + // C++: use static initialization to detect process start/end + // This is not guaranteed to be first/last but the best we can generally do? + struct mi_init_done_t { + mi_init_done_t() { + _mi_auto_process_init(); + } + ~mi_init_done_t() { + _mi_auto_process_done(); + } + }; + static mi_init_done_t mi_init_done; + #else + #pragma message("define a way to call _mi_auto_process_init/done on your platform") +#endif +#endif + +// Generic allocator init/done callback +#ifndef MI_PRIM_HAS_ALLOCATOR_INIT +bool _mi_is_redirected(void) { + return false; +} +bool _mi_allocator_init(const char** message) { + if (message != NULL) { *message = NULL; } + return true; +} +void _mi_allocator_done(void) { + // nothing to do +} +#endif diff --git a/src/dashbls/depends/mimalloc/src/prim/readme.md b/src/dashbls/depends/mimalloc/src/prim/readme.md new file mode 100644 index 000000000000..380dd3a71784 --- /dev/null +++ b/src/dashbls/depends/mimalloc/src/prim/readme.md @@ -0,0 +1,9 @@ +## Portability Primitives + +This is the portability layer where all primitives needed from the OS are defined. + +- `include/mimalloc/prim.h`: primitive portability API definition. +- `prim.c`: Selects one of `unix/prim.c`, `wasi/prim.c`, or `windows/prim.c` depending on the host platform + (and on macOS, `osx/prim.c` defers to `unix/prim.c`). + +Note: still work in progress, there may still be places in the sources that still depend on OS ifdef's. \ No newline at end of file diff --git a/src/dashbls/depends/mimalloc/src/prim/unix/prim.c b/src/dashbls/depends/mimalloc/src/prim/unix/prim.c new file mode 100644 index 000000000000..a25be2512ce1 --- /dev/null +++ b/src/dashbls/depends/mimalloc/src/prim/unix/prim.c @@ -0,0 +1,973 @@ +/* ---------------------------------------------------------------------------- +Copyright (c) 2018-2025, Microsoft Research, Daan Leijen +This is free software; you can redistribute it and/or modify it under the +terms of the MIT license. A copy of the license can be found in the file +"LICENSE" at the root of this distribution. +-----------------------------------------------------------------------------*/ + +// This file is included in `src/prim/prim.c` + +#ifndef _DEFAULT_SOURCE +#define _DEFAULT_SOURCE // ensure mmap flags and syscall are defined +#endif + +#if defined(__sun) +// illumos provides new mman.h api when any of these are defined +// otherwise the old api based on caddr_t which predates the void pointers one. +// stock solaris provides only the former, chose to atomically to discard those +// flags only here rather than project wide tough. +#undef _XOPEN_SOURCE +#undef _POSIX_C_SOURCE +#endif + +#include "mimalloc.h" +#include "mimalloc/internal.h" +#include "mimalloc/prim.h" + +#include // mmap +#include // sysconf +#include // open, close, read, access +#include // getenv, arc4random_buf + +#if defined(__linux__) + #include + #include // THP disable, PR_SET_VMA + #include // sysinfo + #if defined(__GLIBC__) && !defined(PR_SET_VMA) + #include + #endif + #if defined(__GLIBC__) + #include // linux mmap flags + #else + #include + #endif +#elif defined(__APPLE__) + #include + #include + #if !defined(TARGET_OS_OSX) || TARGET_OS_OSX // see issue #879, used to be (!TARGET_IOS_IPHONE && !TARGET_IOS_SIMULATOR) + #include // VM_MAKE_TAG, VM_FLAGS_SUPERPAGE_SIZE_2MB, etc. + #endif + #if !defined(MAC_OS_X_VERSION_10_7) + #define MAC_OS_X_VERSION_10_7 1070 + #endif + #include +#elif defined(__FreeBSD__) || defined(__DragonFly__) + #include + #if __FreeBSD_version >= 1200000 + #include + #include + #endif + #include +#endif + +#if (defined(__linux__) && !defined(__ANDROID__)) || defined(__FreeBSD__) + #define MI_HAS_SYSCALL_H + #include +#endif + +#if !defined(MADV_DONTNEED) && defined(POSIX_MADV_DONTNEED) // QNX +#define MADV_DONTNEED POSIX_MADV_DONTNEED +#endif +#if !defined(MADV_FREE) && defined(POSIX_MADV_FREE) // QNX +#define MADV_FREE POSIX_MADV_FREE +#endif + +#define MI_UNIX_LARGE_PAGE_SIZE (2*MI_MiB) // TODO: can we query the OS for this? + +//------------------------------------------------------------------------------------ +// Use syscalls for some primitives to allow for libraries that override open/read/close etc. +// and do allocation themselves; using syscalls prevents recursion when mimalloc is +// still initializing (issue #713) +// Declare inline to avoid unused function warnings. +//------------------------------------------------------------------------------------ + +#if defined(MI_HAS_SYSCALL_H) && defined(SYS_open) && defined(SYS_close) && defined(SYS_read) && defined(SYS_access) + +static inline int mi_prim_open(const char* fpath, int open_flags) { + return syscall(SYS_open,fpath,open_flags,0); +} +static inline ssize_t mi_prim_read(int fd, void* buf, size_t bufsize) { + return syscall(SYS_read,fd,buf,bufsize); +} +static inline int mi_prim_close(int fd) { + return syscall(SYS_close,fd); +} +static inline int mi_prim_access(const char *fpath, int mode) { + return syscall(SYS_access,fpath,mode); +} + +#else + +static inline int mi_prim_open(const char* fpath, int open_flags) { + return open(fpath,open_flags); +} +static inline ssize_t mi_prim_read(int fd, void* buf, size_t bufsize) { + return read(fd,buf,bufsize); +} +static inline int mi_prim_close(int fd) { + return close(fd); +} +static inline int mi_prim_access(const char *fpath, int mode) { + return access(fpath,mode); +} + +#endif + + + +//--------------------------------------------- +// init +//--------------------------------------------- + +static bool unix_detect_overcommit(void) { + bool os_overcommit = true; + #if defined(__linux__) + int fd = mi_prim_open("/proc/sys/vm/overcommit_memory", O_RDONLY); + if (fd >= 0) { + char buf[32]; + ssize_t nread = mi_prim_read(fd, &buf, sizeof(buf)); + mi_prim_close(fd); + // + // 0: heuristic overcommit, 1: always overcommit, 2: never overcommit (ignore NORESERVE) + if (nread >= 1) { + os_overcommit = (buf[0] == '0' || buf[0] == '1'); + } + } + #elif defined(__FreeBSD__) + int val = 0; + size_t olen = sizeof(val); + if (sysctlbyname("vm.overcommit", &val, &olen, NULL, 0) == 0) { + os_overcommit = (val != 0); + } + #else + // default: overcommit is true + #endif + return os_overcommit; +} + +// try to detect the physical memory dynamically (if possible) +static void unix_detect_physical_memory( size_t page_size, size_t* physical_memory_in_kib ) { + #if defined(CTL_HW) && (defined(HW_PHYSMEM64) || defined(HW_MEMSIZE)) // freeBSD, macOS + MI_UNUSED(page_size); + int64_t physical_memory = 0; + size_t length = sizeof(int64_t); + #if defined(HW_PHYSMEM64) + int mib[2] = { CTL_HW, HW_PHYSMEM64 }; + #else + int mib[2] = { CTL_HW, HW_MEMSIZE }; + #endif + const int err = sysctl(mib, 2, &physical_memory, &length, NULL, 0); + if (err==0 && physical_memory > 0) { + const int64_t phys_in_kib = physical_memory / MI_KiB; + if (phys_in_kib > 0 && (uint64_t)phys_in_kib <= SIZE_MAX) { + *physical_memory_in_kib = (size_t)phys_in_kib; + } + } + #elif defined(__linux__) + MI_UNUSED(page_size); + struct sysinfo info; _mi_memzero_var(info); + const int err = sysinfo(&info); + if (err==0 && info.totalram > 0 && info.totalram <= SIZE_MAX) { + *physical_memory_in_kib = (size_t)info.totalram / MI_KiB; + } + #elif defined(_SC_PHYS_PAGES) // do not use by default as it might cause allocation (by using `fopen` to parse /proc/meminfo) (issue #1100) + const long pphys = sysconf(_SC_PHYS_PAGES); + const size_t psize_in_kib = page_size / MI_KiB; + if (psize_in_kib > 0 && pphys > 0 && (unsigned long)pphys <= SIZE_MAX && (size_t)pphys <= (SIZE_MAX/psize_in_kib)) { + *physical_memory_in_kib = (size_t)pphys * psize_in_kib; + } + #endif +} + +void _mi_prim_mem_init( mi_os_mem_config_t* config ) +{ + long psize = sysconf(_SC_PAGESIZE); + if (psize > 0 && (unsigned long)psize < SIZE_MAX) { + config->page_size = (size_t)psize; + config->alloc_granularity = (size_t)psize; + unix_detect_physical_memory(config->page_size, &config->physical_memory_in_kib); + } + config->large_page_size = MI_UNIX_LARGE_PAGE_SIZE; + config->has_overcommit = unix_detect_overcommit(); + config->has_partial_free = true; // mmap can free in parts + config->has_virtual_reserve = true; // todo: check if this true for NetBSD? (for anonymous mmap with PROT_NONE) + + // disable transparent huge pages for this process? + #if (defined(__linux__) || defined(__ANDROID__)) && defined(PR_GET_THP_DISABLE) + #if defined(MI_NO_THP) + if (true) + #else + if (!mi_option_is_enabled(mi_option_allow_large_os_pages)) // disable THP also if large OS pages are not allowed in the options + #endif + { + int val = 0; + if (prctl(PR_GET_THP_DISABLE, &val, 0, 0, 0) != 0) { + // Most likely since distros often come with always/madvise settings. + val = 1; + // Disabling only for mimalloc process rather than touching system wide settings + (void)prctl(PR_SET_THP_DISABLE, &val, 0, 0, 0); + } + } + #endif +} + + +//--------------------------------------------- +// free +//--------------------------------------------- + +int _mi_prim_free(void* addr, size_t size ) { + if (size==0) return 0; + bool err = (munmap(addr, size) == -1); + return (err ? errno : 0); +} + + +//--------------------------------------------- +// mmap +//--------------------------------------------- + +static int unix_madvise(void* addr, size_t size, int advice) { + #if defined(__sun) + int res = madvise((caddr_t)addr, size, advice); // Solaris needs cast (issue #520) + #elif defined(__QNX__) + int res = posix_madvise(addr, size, advice); + #else + int res = madvise(addr, size, advice); + #endif + return (res==0 ? 0 : errno); +} + +static void* unix_mmap_prim(void* addr, size_t size, int protect_flags, int flags, int fd) { + void* p = mmap(addr, size, protect_flags, flags, fd, 0 /* offset */); + #if defined(__linux__) && defined(PR_SET_VMA) + if (p!=MAP_FAILED && p!=NULL) { + prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, p, size, "mimalloc"); + } + #endif + return p; +} + +static void* unix_mmap_prim_aligned(void* addr, size_t size, size_t try_alignment, int protect_flags, int flags, int fd) { + MI_UNUSED(try_alignment); + void* p = NULL; + #if defined(MAP_ALIGNED) // BSD + if (addr == NULL && try_alignment > 1 && (try_alignment % _mi_os_page_size()) == 0) { + size_t n = 0; + mi_bsr(try_alignment, &n); + if (((size_t)1 << n) == try_alignment && n >= 12 && n <= 30) { // alignment is a power of 2 and 4096 <= alignment <= 1GiB + p = unix_mmap_prim(addr, size, protect_flags, flags | MAP_ALIGNED(n), fd); + if (p==MAP_FAILED || !_mi_is_aligned(p,try_alignment)) { + int err = errno; + _mi_trace_message("unable to directly request aligned OS memory (error: %d (0x%x), size: 0x%zx bytes, alignment: 0x%zx, hint address: %p)\n", err, err, size, try_alignment, addr); + } + if (p!=MAP_FAILED) return p; + // fall back to regular mmap + } + } + #elif defined(MAP_ALIGN) // Solaris + if (addr == NULL && try_alignment > 1 && (try_alignment % _mi_os_page_size()) == 0) { + p = unix_mmap_prim((void*)try_alignment, size, protect_flags, flags | MAP_ALIGN, fd); // addr parameter is the required alignment + if (p!=MAP_FAILED) return p; + // fall back to regular mmap + } + #endif + #if (MI_INTPTR_SIZE >= 8) && !defined(MAP_ALIGNED) + // on 64-bit systems, use the virtual address area after 2TiB for 4MiB aligned allocations + if (addr == NULL) { + void* hint = _mi_os_get_aligned_hint(try_alignment, size); + if (hint != NULL) { + p = unix_mmap_prim(hint, size, protect_flags, flags, fd); + if (p==MAP_FAILED || !_mi_is_aligned(p,try_alignment)) { + #if MI_TRACK_ENABLED // asan sometimes does not instrument errno correctly? + int err = 0; + #else + int err = errno; + #endif + _mi_trace_message("unable to directly request hinted aligned OS memory (error: %d (0x%x), size: 0x%zx bytes, alignment: 0x%zx, hint address: %p)\n", err, err, size, try_alignment, hint); + } + if (p!=MAP_FAILED) return p; + // fall back to regular mmap + } + } + #endif + // regular mmap + p = unix_mmap_prim(addr, size, protect_flags, flags, fd); + if (p!=MAP_FAILED) return p; + // failed to allocate + return NULL; +} + +static int unix_mmap_fd(void) { + #if defined(VM_MAKE_TAG) + // macOS: tracking anonymous page with a specific ID. (All up to 98 are taken officially but LLVM sanitizers had taken 99) + int os_tag = (int)mi_option_get(mi_option_os_tag); + if (os_tag < 100 || os_tag > 255) { os_tag = 254; } + return VM_MAKE_TAG(os_tag); + #else + return -1; + #endif +} + +static void* unix_mmap(void* addr, size_t size, size_t try_alignment, int protect_flags, bool large_only, bool allow_large, bool* is_large) { + #if !defined(MAP_ANONYMOUS) + #define MAP_ANONYMOUS MAP_ANON + #endif + #if !defined(MAP_NORESERVE) + #define MAP_NORESERVE 0 + #endif + void* p = NULL; + const int fd = unix_mmap_fd(); + int flags = MAP_PRIVATE | MAP_ANONYMOUS; + if (_mi_os_has_overcommit()) { + flags |= MAP_NORESERVE; + } + #if defined(PROT_MAX) + protect_flags |= PROT_MAX(PROT_READ | PROT_WRITE); // BSD + #endif + // huge page allocation + if (allow_large && (large_only || (_mi_os_use_large_page(size, try_alignment) && mi_option_get(mi_option_allow_large_os_pages) == 1))) { + static _Atomic(size_t) large_page_try_ok; // = 0; + size_t try_ok = mi_atomic_load_acquire(&large_page_try_ok); + if (!large_only && try_ok > 0) { + // If the OS is not configured for large OS pages, or the user does not have + // enough permission, the `mmap` will always fail (but it might also fail for other reasons). + // Therefore, once a large page allocation failed, we don't try again for `large_page_try_ok` times + // to avoid too many failing calls to mmap. + mi_atomic_cas_strong_acq_rel(&large_page_try_ok, &try_ok, try_ok - 1); + } + else { + int lflags = flags & ~MAP_NORESERVE; // using NORESERVE on huge pages seems to fail on Linux + int lfd = fd; + #ifdef MAP_ALIGNED_SUPER + lflags |= MAP_ALIGNED_SUPER; + #endif + #ifdef MAP_HUGETLB + lflags |= MAP_HUGETLB; + #endif + #ifdef MAP_HUGE_1GB + static bool mi_huge_pages_available = true; + if (large_only && (size % MI_GiB) == 0 && mi_huge_pages_available) { + lflags |= MAP_HUGE_1GB; + } + else + #endif + { + #ifdef MAP_HUGE_2MB + lflags |= MAP_HUGE_2MB; + #endif + } + #ifdef VM_FLAGS_SUPERPAGE_SIZE_2MB + lfd |= VM_FLAGS_SUPERPAGE_SIZE_2MB; + #endif + if (large_only || lflags != flags) { + // try large OS page allocation + *is_large = true; + p = unix_mmap_prim_aligned(addr, size, try_alignment, protect_flags, lflags, lfd); + #ifdef MAP_HUGE_1GB + if (p == NULL && (lflags & MAP_HUGE_1GB) == MAP_HUGE_1GB) { + mi_huge_pages_available = false; // don't try huge 1GiB pages again + if (large_only) { + _mi_warning_message("unable to allocate huge (1GiB) page, trying large (2MiB) pages instead (errno: %i)\n", errno); + } + lflags = ((lflags & ~MAP_HUGE_1GB) | MAP_HUGE_2MB); + p = unix_mmap_prim_aligned(addr, size, try_alignment, protect_flags, lflags, lfd); + } + #endif + if (large_only) return p; + if (p == NULL) { + mi_atomic_store_release(&large_page_try_ok, (size_t)8); // on error, don't try again for the next N allocations + } + } + } + } + // regular allocation + if (p == NULL) { + *is_large = false; + p = unix_mmap_prim_aligned(addr, size, try_alignment, protect_flags, flags, fd); + if (p != NULL) { + #if defined(MADV_HUGEPAGE) + // Many Linux systems don't allow MAP_HUGETLB but they support instead + // transparent huge pages (THP). Generally, it is not required to call `madvise` with MADV_HUGE + // though since properly aligned allocations will already use large pages if available + // in that case -- in particular for our large regions (in `memory.c`). + // However, some systems only allow THP if called with explicit `madvise`, so + // when large OS pages are enabled for mimalloc, we call `madvise` anyways. + if (allow_large && _mi_os_use_large_page(size, try_alignment)) { + if (unix_madvise(p, size, MADV_HUGEPAGE) == 0) { + // *is_large = true; // possibly + }; + } + #elif defined(__sun) + if (allow_large && _mi_os_use_large_page(size, try_alignment)) { + struct memcntl_mha cmd = {0}; + cmd.mha_pagesize = _mi_os_large_page_size(); + cmd.mha_cmd = MHA_MAPSIZE_VA; + if (memcntl((caddr_t)p, size, MC_HAT_ADVISE, (caddr_t)&cmd, 0, 0) == 0) { + // *is_large = true; // possibly + } + } + #endif + } + } + return p; +} + +// Note: the `try_alignment` is just a hint and the returned pointer is not guaranteed to be aligned. +int _mi_prim_alloc(void* hint_addr, size_t size, size_t try_alignment, bool commit, bool allow_large, bool* is_large, bool* is_zero, void** addr) { + mi_assert_internal(size > 0 && (size % _mi_os_page_size()) == 0); + mi_assert_internal(commit || !allow_large); + mi_assert_internal(try_alignment > 0); + if (hint_addr == NULL && size >= 8*MI_UNIX_LARGE_PAGE_SIZE && try_alignment > 1 && _mi_is_power_of_two(try_alignment) && try_alignment < MI_UNIX_LARGE_PAGE_SIZE) { + try_alignment = MI_UNIX_LARGE_PAGE_SIZE; // try to align along large page size for larger allocations + } + + *is_zero = true; + int protect_flags = (commit ? (PROT_WRITE | PROT_READ) : PROT_NONE); + *addr = unix_mmap(hint_addr, size, try_alignment, protect_flags, false, allow_large, is_large); + return (*addr != NULL ? 0 : errno); +} + + +//--------------------------------------------- +// Commit/Reset +//--------------------------------------------- + +static void unix_mprotect_hint(int err) { + #if defined(__linux__) && (MI_SECURE>=2) // guard page around every mimalloc page + if (err == ENOMEM) { + _mi_warning_message("The next warning may be caused by a low memory map limit.\n" + " On Linux this is controlled by the vm.max_map_count -- maybe increase it?\n" + " For example: sudo sysctl -w vm.max_map_count=262144\n"); + } + #else + MI_UNUSED(err); + #endif +} + + + + + +int _mi_prim_commit(void* start, size_t size, bool* is_zero) { + // commit: ensure we can access the area + // note: we may think that *is_zero can be true since the memory + // was either from mmap PROT_NONE, or from decommit MADV_DONTNEED, but + // we sometimes call commit on a range with still partially committed + // memory and `mprotect` does not zero the range. + *is_zero = false; + int err = mprotect(start, size, (PROT_READ | PROT_WRITE)); + if (err != 0) { + err = errno; + unix_mprotect_hint(err); + } + return err; +} + +int _mi_prim_reuse(void* start, size_t size) { + MI_UNUSED(start); MI_UNUSED(size); + #if defined(__APPLE__) && defined(MADV_FREE_REUSE) + return unix_madvise(start, size, MADV_FREE_REUSE); + #endif + return 0; +} + +int _mi_prim_decommit(void* start, size_t size, bool* needs_recommit) { + int err = 0; + #if defined(__APPLE__) && defined(MADV_FREE_REUSABLE) + // decommit on macOS: use MADV_FREE_REUSABLE as it does immediate rss accounting (issue #1097) + err = unix_madvise(start, size, MADV_FREE_REUSABLE); + if (err) { err = unix_madvise(start, size, MADV_DONTNEED); } + #else + // decommit: use MADV_DONTNEED as it decreases rss immediately (unlike MADV_FREE) + err = unix_madvise(start, size, MADV_DONTNEED); + #endif + #if !MI_DEBUG && MI_SECURE<=2 + *needs_recommit = false; + #else + *needs_recommit = true; + mprotect(start, size, PROT_NONE); + #endif + /* + // decommit: use mmap with MAP_FIXED and PROT_NONE to discard the existing memory (and reduce rss) + *needs_recommit = true; + const int fd = unix_mmap_fd(); + void* p = mmap(start, size, PROT_NONE, (MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE), fd, 0); + if (p != start) { err = errno; } + */ + return err; +} + +int _mi_prim_reset(void* start, size_t size) { + int err = 0; + + // on macOS can use MADV_FREE_REUSABLE (but we disable this for now as it seems slower) + #if 0 && defined(__APPLE__) && defined(MADV_FREE_REUSABLE) + err = unix_madvise(start, size, MADV_FREE_REUSABLE); + if (err==0) return 0; + // fall through + #endif + + #if defined(MADV_FREE) + // Otherwise, we try to use `MADV_FREE` as that is the fastest. A drawback though is that it + // will not reduce the `rss` stats in tools like `top` even though the memory is available + // to other processes. With the default `MIMALLOC_PURGE_DECOMMITS=1` we ensure that by + // default `MADV_DONTNEED` is used though. + static _Atomic(size_t) advice = MI_ATOMIC_VAR_INIT(MADV_FREE); + int oadvice = (int)mi_atomic_load_relaxed(&advice); + while ((err = unix_madvise(start, size, oadvice)) != 0 && errno == EAGAIN) { errno = 0; }; + if (err != 0 && errno == EINVAL && oadvice == MADV_FREE) { + // if MADV_FREE is not supported, fall back to MADV_DONTNEED from now on + mi_atomic_store_release(&advice, (size_t)MADV_DONTNEED); + err = unix_madvise(start, size, MADV_DONTNEED); + } + #else + err = unix_madvise(start, size, MADV_DONTNEED); + #endif + return err; +} + +int _mi_prim_protect(void* start, size_t size, bool protect) { + int err = mprotect(start, size, protect ? PROT_NONE : (PROT_READ | PROT_WRITE)); + if (err != 0) { err = errno; } + unix_mprotect_hint(err); + return err; +} + + + +//--------------------------------------------- +// Huge page allocation +//--------------------------------------------- + +#if (MI_INTPTR_SIZE >= 8) && !defined(__HAIKU__) && !defined(__CYGWIN__) + +#ifndef MPOL_PREFERRED +#define MPOL_PREFERRED 1 +#endif + +#if defined(MI_HAS_SYSCALL_H) && defined(SYS_mbind) +static long mi_prim_mbind(void* start, unsigned long len, unsigned long mode, const unsigned long* nmask, unsigned long maxnode, unsigned flags) { + return syscall(SYS_mbind, start, len, mode, nmask, maxnode, flags); +} +#else +static long mi_prim_mbind(void* start, unsigned long len, unsigned long mode, const unsigned long* nmask, unsigned long maxnode, unsigned flags) { + MI_UNUSED(start); MI_UNUSED(len); MI_UNUSED(mode); MI_UNUSED(nmask); MI_UNUSED(maxnode); MI_UNUSED(flags); + return 0; +} +#endif + +int _mi_prim_alloc_huge_os_pages(void* hint_addr, size_t size, int numa_node, bool* is_zero, void** addr) { + bool is_large = true; + *is_zero = true; + *addr = unix_mmap(hint_addr, size, MI_ARENA_SLICE_ALIGN, PROT_READ | PROT_WRITE, true, true, &is_large); + if (*addr != NULL && numa_node >= 0 && numa_node < 8*MI_INTPTR_SIZE) { // at most 64 nodes + unsigned long numa_mask = (1UL << numa_node); + // TODO: does `mbind` work correctly for huge OS pages? should we + // use `set_mempolicy` before calling mmap instead? + // see: + long err = mi_prim_mbind(*addr, size, MPOL_PREFERRED, &numa_mask, 8*MI_INTPTR_SIZE, 0); + if (err != 0) { + err = errno; + _mi_warning_message("failed to bind huge (1GiB) pages to numa node %d (error: %d (0x%x))\n", numa_node, err, err); + } + } + return (*addr != NULL ? 0 : errno); +} + +#else + +int _mi_prim_alloc_huge_os_pages(void* hint_addr, size_t size, int numa_node, bool* is_zero, void** addr) { + MI_UNUSED(hint_addr); MI_UNUSED(size); MI_UNUSED(numa_node); + *is_zero = false; + *addr = NULL; + return ENOMEM; +} + +#endif + +//--------------------------------------------- +// NUMA nodes +//--------------------------------------------- + +#if defined(__linux__) + +size_t _mi_prim_numa_node(void) { + #if defined(MI_HAS_SYSCALL_H) && defined(SYS_getcpu) + unsigned long node = 0; + unsigned long ncpu = 0; + long err = syscall(SYS_getcpu, &ncpu, &node, NULL); + if (err != 0) return 0; + return node; + #else + return 0; + #endif +} + +size_t _mi_prim_numa_node_count(void) { + char buf[128]; + unsigned node = 0; + for(node = 0; node < 256; node++) { + // enumerate node entries -- todo: it there a more efficient way to do this? (but ensure there is no allocation) + _mi_snprintf(buf, 127, "/sys/devices/system/node/node%u", node + 1); + if (mi_prim_access(buf,R_OK) != 0) break; + } + return (node+1); +} + +#elif defined(__FreeBSD__) && __FreeBSD_version >= 1200000 + +size_t _mi_prim_numa_node(void) { + domainset_t dom; + size_t node; + int policy; + if (cpuset_getdomain(CPU_LEVEL_CPUSET, CPU_WHICH_PID, -1, sizeof(dom), &dom, &policy) == -1) return 0ul; + for (node = 0; node < MAXMEMDOM; node++) { + if (DOMAINSET_ISSET(node, &dom)) return node; + } + return 0ul; +} + +size_t _mi_prim_numa_node_count(void) { + size_t ndomains = 0; + size_t len = sizeof(ndomains); + if (sysctlbyname("vm.ndomains", &ndomains, &len, NULL, 0) == -1) return 0ul; + return ndomains; +} + +#elif defined(__DragonFly__) + +size_t _mi_prim_numa_node(void) { + // TODO: DragonFly does not seem to provide any userland means to get this information. + return 0ul; +} + +size_t _mi_prim_numa_node_count(void) { + size_t ncpus = 0, nvirtcoresperphys = 0; + size_t len = sizeof(size_t); + if (sysctlbyname("hw.ncpu", &ncpus, &len, NULL, 0) == -1) return 0ul; + if (sysctlbyname("hw.cpu_topology_ht_ids", &nvirtcoresperphys, &len, NULL, 0) == -1) return 0ul; + return nvirtcoresperphys * ncpus; +} + +#else + +size_t _mi_prim_numa_node(void) { + return 0; +} + +size_t _mi_prim_numa_node_count(void) { + return 1; +} + +#endif + +// ---------------------------------------------------------------- +// Clock +// ---------------------------------------------------------------- + +#include + +#if defined(CLOCK_REALTIME) || defined(CLOCK_MONOTONIC) + +mi_msecs_t _mi_prim_clock_now(void) { + struct timespec t; + #ifdef CLOCK_MONOTONIC + clock_gettime(CLOCK_MONOTONIC, &t); + #else + clock_gettime(CLOCK_REALTIME, &t); + #endif + return ((mi_msecs_t)t.tv_sec * 1000) + ((mi_msecs_t)t.tv_nsec / 1000000); +} + +#else + +// low resolution timer +mi_msecs_t _mi_prim_clock_now(void) { + #if !defined(CLOCKS_PER_SEC) || (CLOCKS_PER_SEC == 1000) || (CLOCKS_PER_SEC == 0) + return (mi_msecs_t)clock(); + #elif (CLOCKS_PER_SEC < 1000) + return (mi_msecs_t)clock() * (1000 / (mi_msecs_t)CLOCKS_PER_SEC); + #else + return (mi_msecs_t)clock() / ((mi_msecs_t)CLOCKS_PER_SEC / 1000); + #endif +} + +#endif + + + + +//---------------------------------------------------------------- +// Process info +//---------------------------------------------------------------- + +#if defined(__unix__) || defined(__unix) || defined(unix) || defined(__APPLE__) || defined(__HAIKU__) +#include +#include +#include + +#if defined(__APPLE__) +#include +#endif + +#if defined(__HAIKU__) +#include +#endif + +static mi_msecs_t timeval_secs(const struct timeval* tv) { + return ((mi_msecs_t)tv->tv_sec * 1000L) + ((mi_msecs_t)tv->tv_usec / 1000L); +} + +void _mi_prim_process_info(mi_process_info_t* pinfo) +{ + struct rusage rusage; + getrusage(RUSAGE_SELF, &rusage); + pinfo->utime = timeval_secs(&rusage.ru_utime); + pinfo->stime = timeval_secs(&rusage.ru_stime); +#if !defined(__HAIKU__) + pinfo->page_faults = rusage.ru_majflt; +#endif +#if defined(__HAIKU__) + // Haiku does not have (yet?) a way to + // get these stats per process + thread_info tid; + area_info mem; + ssize_t c; + get_thread_info(find_thread(0), &tid); + while (get_next_area_info(tid.team, &c, &mem) == B_OK) { + pinfo->peak_rss += mem.ram_size; + } + pinfo->page_faults = 0; +#elif defined(__APPLE__) + pinfo->peak_rss = rusage.ru_maxrss; // macos reports in bytes + #ifdef MACH_TASK_BASIC_INFO + struct mach_task_basic_info info; + mach_msg_type_number_t infoCount = MACH_TASK_BASIC_INFO_COUNT; + if (task_info(mach_task_self(), MACH_TASK_BASIC_INFO, (task_info_t)&info, &infoCount) == KERN_SUCCESS) { + pinfo->current_rss = (size_t)info.resident_size; + } + #else + struct task_basic_info info; + mach_msg_type_number_t infoCount = TASK_BASIC_INFO_COUNT; + if (task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&info, &infoCount) == KERN_SUCCESS) { + pinfo->current_rss = (size_t)info.resident_size; + } + #endif +#else + pinfo->peak_rss = rusage.ru_maxrss * 1024; // Linux/BSD report in KiB +#endif + // use defaults for commit +} + +#else + +#ifndef __wasi__ +// WebAssembly instances are not processes +#pragma message("define a way to get process info") +#endif + +void _mi_prim_process_info(mi_process_info_t* pinfo) +{ + // use defaults + MI_UNUSED(pinfo); +} + +#endif + + +//---------------------------------------------------------------- +// Output +//---------------------------------------------------------------- + +void _mi_prim_out_stderr( const char* msg ) { + fputs(msg,stderr); +} + + +//---------------------------------------------------------------- +// Environment +//---------------------------------------------------------------- + +#if !defined(MI_USE_ENVIRON) || (MI_USE_ENVIRON!=0) +// On Posix systemsr use `environ` to access environment variables +// even before the C runtime is initialized. +#if defined(__APPLE__) && defined(__has_include) && __has_include() +#include +static char** mi_get_environ(void) { + return (*_NSGetEnviron()); +} +#else +extern char** environ; +static char** mi_get_environ(void) { + return environ; +} +#endif +bool _mi_prim_getenv(const char* name, char* result, size_t result_size) { + if (name==NULL) return false; + const size_t len = _mi_strlen(name); + if (len == 0) return false; + char** env = mi_get_environ(); + if (env == NULL) return false; + // compare up to 10000 entries + for (int i = 0; i < 10000 && env[i] != NULL; i++) { + const char* s = env[i]; + if (_mi_strnicmp(name, s, len) == 0 && s[len] == '=') { // case insensitive + // found it + _mi_strlcpy(result, s + len + 1, result_size); + return true; + } + } + return false; +} +#else +// fallback: use standard C `getenv` but this cannot be used while initializing the C runtime +bool _mi_prim_getenv(const char* name, char* result, size_t result_size) { + // cannot call getenv() when still initializing the C runtime. + if (_mi_preloading()) return false; + const char* s = getenv(name); + if (s == NULL) { + // we check the upper case name too. + char buf[64+1]; + size_t len = _mi_strnlen(name,sizeof(buf)-1); + for (size_t i = 0; i < len; i++) { + buf[i] = _mi_toupper(name[i]); + } + buf[len] = 0; + s = getenv(buf); + } + if (s == NULL || _mi_strnlen(s,result_size) >= result_size) return false; + _mi_strlcpy(result, s, result_size); + return true; +} +#endif // !MI_USE_ENVIRON + + +//---------------------------------------------------------------- +// Random +//---------------------------------------------------------------- + +#if defined(__APPLE__) && defined(MAC_OS_X_VERSION_10_15) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_15) +#include +#include + +bool _mi_prim_random_buf(void* buf, size_t buf_len) { + // We prefer CCRandomGenerateBytes as it returns an error code while arc4random_buf + // may fail silently on macOS. See PR #390, and + return (CCRandomGenerateBytes(buf, buf_len) == kCCSuccess); +} + +#elif defined(__ANDROID__) || defined(__DragonFly__) || \ + defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || \ + defined(__sun) || \ + (defined(__APPLE__) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_7)) + +bool _mi_prim_random_buf(void* buf, size_t buf_len) { + arc4random_buf(buf, buf_len); + return true; +} + +#elif defined(__APPLE__) || defined(__linux__) || defined(__HAIKU__) // also for old apple versions < 10.7 (issue #829) + +#include +#include +#include + +bool _mi_prim_random_buf(void* buf, size_t buf_len) { + // Modern Linux provides `getrandom` but different distributions either use `sys/random.h` or `linux/random.h` + // and for the latter the actual `getrandom` call is not always defined. + // (see ) + // We therefore use a syscall directly and fall back dynamically to /dev/urandom when needed. + #if defined(MI_HAS_SYSCALL_H) && defined(SYS_getrandom) + #ifndef GRND_NONBLOCK + #define GRND_NONBLOCK (1) + #endif + static _Atomic(uintptr_t) no_getrandom; // = 0 + if (mi_atomic_load_acquire(&no_getrandom)==0) { + ssize_t ret = syscall(SYS_getrandom, buf, buf_len, GRND_NONBLOCK); + if (ret >= 0) return (buf_len == (size_t)ret); + if (errno != ENOSYS) return false; + mi_atomic_store_release(&no_getrandom, (uintptr_t)1); // don't call again, and fall back to /dev/urandom + } + #endif + int flags = O_RDONLY; + #if defined(O_CLOEXEC) + flags |= O_CLOEXEC; + #endif + int fd = mi_prim_open("/dev/urandom", flags); + if (fd < 0) return false; + size_t count = 0; + while(count < buf_len) { + ssize_t ret = mi_prim_read(fd, (char*)buf + count, buf_len - count); + if (ret<=0) { + if (errno!=EAGAIN && errno!=EINTR) break; + } + else { + count += ret; + } + } + mi_prim_close(fd); + return (count==buf_len); +} + +#else + +bool _mi_prim_random_buf(void* buf, size_t buf_len) { + return false; +} + +#endif + + +//---------------------------------------------------------------- +// Thread init/done +//---------------------------------------------------------------- + +#if defined(MI_USE_PTHREADS) + +// use pthread local storage keys to detect thread ending +// (and used with MI_TLS_PTHREADS for the default heap) +pthread_key_t _mi_heap_default_key = (pthread_key_t)(-1); + +static void mi_pthread_done(void* value) { + if (value!=NULL) { + _mi_thread_done((mi_heap_t*)value); + } +} + +void _mi_prim_thread_init_auto_done(void) { + mi_assert_internal(_mi_heap_default_key == (pthread_key_t)(-1)); + pthread_key_create(&_mi_heap_default_key, &mi_pthread_done); +} + +void _mi_prim_thread_done_auto_done(void) { + if (_mi_heap_default_key != (pthread_key_t)(-1)) { // do not leak the key, see issue #809 + pthread_key_delete(_mi_heap_default_key); + } +} + +void _mi_prim_thread_associate_default_heap(mi_heap_t* heap) { + if (_mi_heap_default_key != (pthread_key_t)(-1)) { // can happen during recursive invocation on freeBSD + pthread_setspecific(_mi_heap_default_key, heap); + } +} + +#else + +void _mi_prim_thread_init_auto_done(void) { + // nothing +} + +void _mi_prim_thread_done_auto_done(void) { + // nothing +} + +void _mi_prim_thread_associate_default_heap(mi_heap_t* heap) { + MI_UNUSED(heap); +} + +#endif + +bool _mi_prim_thread_is_in_threadpool(void) { + return false; +} diff --git a/src/dashbls/depends/mimalloc/src/prim/wasi/prim.c b/src/dashbls/depends/mimalloc/src/prim/wasi/prim.c new file mode 100644 index 000000000000..1855a7ab3ccf --- /dev/null +++ b/src/dashbls/depends/mimalloc/src/prim/wasi/prim.c @@ -0,0 +1,288 @@ +/* ---------------------------------------------------------------------------- +Copyright (c) 2018-2023, Microsoft Research, Daan Leijen +This is free software; you can redistribute it and/or modify it under the +terms of the MIT license. A copy of the license can be found in the file +"LICENSE" at the root of this distribution. +-----------------------------------------------------------------------------*/ + +// This file is included in `src/prim/prim.c` + +#include "mimalloc.h" +#include "mimalloc/internal.h" +#include "mimalloc/prim.h" + +#include // fputs +#include // getenv + +//--------------------------------------------- +// Initialize +//--------------------------------------------- + +void _mi_prim_mem_init( mi_os_mem_config_t* config ) { + config->page_size = 64*MI_KiB; // WebAssembly has a fixed page size: 64KiB + config->alloc_granularity = 16; + config->has_overcommit = false; + config->has_partial_free = false; + config->has_virtual_reserve = false; +} + +//--------------------------------------------- +// Free +//--------------------------------------------- + +int _mi_prim_free(void* addr, size_t size ) { + MI_UNUSED(addr); MI_UNUSED(size); + // wasi heap cannot be shrunk + return 0; +} + + +//--------------------------------------------- +// Allocation: sbrk or memory_grow +//--------------------------------------------- + +#if defined(MI_USE_SBRK) + #include // for sbrk + + static void* mi_memory_grow( size_t size ) { + void* p = sbrk(size); + if (p == (void*)(-1)) return NULL; + #if !defined(__wasi__) // on wasi this is always zero initialized already (?) + memset(p,0,size); + #endif + return p; + } +#elif defined(__wasi__) + static void* mi_memory_grow( size_t size ) { + size_t base = (size > 0 ? __builtin_wasm_memory_grow(0,_mi_divide_up(size, _mi_os_page_size())) + : __builtin_wasm_memory_size(0)); + if (base == SIZE_MAX) return NULL; + return (void*)(base * _mi_os_page_size()); + } +#endif + +#if defined(MI_USE_PTHREADS) +static pthread_mutex_t mi_heap_grow_mutex = PTHREAD_MUTEX_INITIALIZER; +#endif + +static void* mi_prim_mem_grow(size_t size, size_t try_alignment) { + void* p = NULL; + if (try_alignment <= 1) { + // `sbrk` is not thread safe in general so try to protect it (we could skip this on WASM but leave it in for now) + #if defined(MI_USE_PTHREADS) + pthread_mutex_lock(&mi_heap_grow_mutex); + #endif + p = mi_memory_grow(size); + #if defined(MI_USE_PTHREADS) + pthread_mutex_unlock(&mi_heap_grow_mutex); + #endif + } + else { + void* base = NULL; + size_t alloc_size = 0; + // to allocate aligned use a lock to try to avoid thread interaction + // between getting the current size and actual allocation + // (also, `sbrk` is not thread safe in general) + #if defined(MI_USE_PTHREADS) + pthread_mutex_lock(&mi_heap_grow_mutex); + #endif + { + void* current = mi_memory_grow(0); // get current size + if (current != NULL) { + void* aligned_current = _mi_align_up_ptr(current, try_alignment); // and align from there to minimize wasted space + alloc_size = _mi_align_up( ((uint8_t*)aligned_current - (uint8_t*)current) + size, _mi_os_page_size()); + base = mi_memory_grow(alloc_size); + } + } + #if defined(MI_USE_PTHREADS) + pthread_mutex_unlock(&mi_heap_grow_mutex); + #endif + if (base != NULL) { + p = _mi_align_up_ptr(base, try_alignment); + if ((uint8_t*)p + size > (uint8_t*)base + alloc_size) { + // another thread used wasm_memory_grow/sbrk in-between and we do not have enough + // space after alignment. Give up (and waste the space as we cannot shrink :-( ) + // (in `mi_os_mem_alloc_aligned` this will fall back to overallocation to align) + p = NULL; + } + } + } + /* + if (p == NULL) { + _mi_warning_message("unable to allocate sbrk/wasm_memory_grow OS memory (%zu bytes, %zu alignment)\n", size, try_alignment); + errno = ENOMEM; + return NULL; + } + */ + mi_assert_internal( p == NULL || try_alignment == 0 || (uintptr_t)p % try_alignment == 0 ); + return p; +} + +// Note: the `try_alignment` is just a hint and the returned pointer is not guaranteed to be aligned. +int _mi_prim_alloc(void* hint_addr, size_t size, size_t try_alignment, bool commit, bool allow_large, bool* is_large, bool* is_zero, void** addr) { + MI_UNUSED(allow_large); MI_UNUSED(commit); MI_UNUSED(hint_addr); + *is_large = false; + *is_zero = false; + *addr = mi_prim_mem_grow(size, try_alignment); + return (*addr != NULL ? 0 : ENOMEM); +} + + +//--------------------------------------------- +// Commit/Reset/Protect +//--------------------------------------------- + +int _mi_prim_commit(void* addr, size_t size, bool* is_zero) { + MI_UNUSED(addr); MI_UNUSED(size); + *is_zero = false; + return 0; +} + +int _mi_prim_decommit(void* addr, size_t size, bool* needs_recommit) { + MI_UNUSED(addr); MI_UNUSED(size); + *needs_recommit = false; + return 0; +} + +int _mi_prim_reset(void* addr, size_t size) { + MI_UNUSED(addr); MI_UNUSED(size); + return 0; +} + +int _mi_prim_reuse(void* addr, size_t size) { + MI_UNUSED(addr); MI_UNUSED(size); + return 0; +} + +int _mi_prim_protect(void* addr, size_t size, bool protect) { + MI_UNUSED(addr); MI_UNUSED(size); MI_UNUSED(protect); + return 0; +} + + +//--------------------------------------------- +// Huge pages and NUMA nodes +//--------------------------------------------- + +int _mi_prim_alloc_huge_os_pages(void* hint_addr, size_t size, int numa_node, bool* is_zero, void** addr) { + MI_UNUSED(hint_addr); MI_UNUSED(size); MI_UNUSED(numa_node); + *is_zero = true; + *addr = NULL; + return ENOSYS; +} + +size_t _mi_prim_numa_node(void) { + return 0; +} + +size_t _mi_prim_numa_node_count(void) { + return 1; +} + + +//---------------------------------------------------------------- +// Clock +//---------------------------------------------------------------- + +#include + +#if defined(CLOCK_REALTIME) || defined(CLOCK_MONOTONIC) + +mi_msecs_t _mi_prim_clock_now(void) { + struct timespec t; + #ifdef CLOCK_MONOTONIC + clock_gettime(CLOCK_MONOTONIC, &t); + #else + clock_gettime(CLOCK_REALTIME, &t); + #endif + return ((mi_msecs_t)t.tv_sec * 1000) + ((mi_msecs_t)t.tv_nsec / 1000000); +} + +#else + +// low resolution timer +mi_msecs_t _mi_prim_clock_now(void) { + #if !defined(CLOCKS_PER_SEC) || (CLOCKS_PER_SEC == 1000) || (CLOCKS_PER_SEC == 0) + return (mi_msecs_t)clock(); + #elif (CLOCKS_PER_SEC < 1000) + return (mi_msecs_t)clock() * (1000 / (mi_msecs_t)CLOCKS_PER_SEC); + #else + return (mi_msecs_t)clock() / ((mi_msecs_t)CLOCKS_PER_SEC / 1000); + #endif +} + +#endif + + +//---------------------------------------------------------------- +// Process info +//---------------------------------------------------------------- + +void _mi_prim_process_info(mi_process_info_t* pinfo) +{ + // use defaults + MI_UNUSED(pinfo); +} + + +//---------------------------------------------------------------- +// Output +//---------------------------------------------------------------- + +void _mi_prim_out_stderr( const char* msg ) { + fputs(msg,stderr); +} + + +//---------------------------------------------------------------- +// Environment +//---------------------------------------------------------------- + +bool _mi_prim_getenv(const char* name, char* result, size_t result_size) { + // cannot call getenv() when still initializing the C runtime. + if (_mi_preloading()) return false; + const char* s = getenv(name); + if (s == NULL) { + // we check the upper case name too. + char buf[64+1]; + size_t len = _mi_strnlen(name,sizeof(buf)-1); + for (size_t i = 0; i < len; i++) { + buf[i] = _mi_toupper(name[i]); + } + buf[len] = 0; + s = getenv(buf); + } + if (s == NULL || _mi_strnlen(s,result_size) >= result_size) return false; + _mi_strlcpy(result, s, result_size); + return true; +} + + +//---------------------------------------------------------------- +// Random +//---------------------------------------------------------------- + +bool _mi_prim_random_buf(void* buf, size_t buf_len) { + return false; +} + + +//---------------------------------------------------------------- +// Thread init/done +//---------------------------------------------------------------- + +void _mi_prim_thread_init_auto_done(void) { + // nothing +} + +void _mi_prim_thread_done_auto_done(void) { + // nothing +} + +void _mi_prim_thread_associate_default_heap(mi_heap_t* heap) { + MI_UNUSED(heap); +} + +bool _mi_prim_thread_is_in_threadpool(void) { + return false; +} diff --git a/src/dashbls/depends/mimalloc/src/prim/windows/etw-mimalloc.wprp b/src/dashbls/depends/mimalloc/src/prim/windows/etw-mimalloc.wprp new file mode 100644 index 000000000000..b00cd7adf228 --- /dev/null +++ b/src/dashbls/depends/mimalloc/src/prim/windows/etw-mimalloc.wprp @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/dashbls/depends/mimalloc/src/prim/windows/etw.h b/src/dashbls/depends/mimalloc/src/prim/windows/etw.h new file mode 100644 index 000000000000..4e0a092a10f4 --- /dev/null +++ b/src/dashbls/depends/mimalloc/src/prim/windows/etw.h @@ -0,0 +1,905 @@ +//**********************************************************************` +//* This is an include file generated by Message Compiler. *` +//* *` +//* Copyright (c) Microsoft Corporation. All Rights Reserved. *` +//**********************************************************************` +#pragma once + +//***************************************************************************** +// +// Notes on the ETW event code generated by MC: +// +// - Structures and arrays of structures are treated as an opaque binary blob. +// The caller is responsible for packing the data for the structure into a +// single region of memory, with no padding between values. The macro will +// have an extra parameter for the length of the blob. +// - Arrays of nul-terminated strings must be packed by the caller into a +// single binary blob containing the correct number of strings, with a nul +// after each string. The size of the blob is specified in characters, and +// includes the final nul. +// - Arrays of SID are treated as a single binary blob. The caller is +// responsible for packing the SID values into a single region of memory with +// no padding. +// - The length attribute on the data element in the manifest is significant +// for values with intype win:UnicodeString, win:AnsiString, or win:Binary. +// The length attribute must be specified for win:Binary, and is optional for +// win:UnicodeString and win:AnsiString (if no length is given, the strings +// are assumed to be nul-terminated). For win:UnicodeString, the length is +// measured in characters, not bytes. +// - For an array of win:UnicodeString, win:AnsiString, or win:Binary, the +// length attribute applies to every value in the array, so every value in +// the array must have the same length. The values in the array are provided +// to the macro via a single pointer -- the caller is responsible for packing +// all of the values into a single region of memory with no padding between +// values. +// - Values of type win:CountedUnicodeString, win:CountedAnsiString, and +// win:CountedBinary can be generated and collected on Vista or later. +// However, they may not decode properly without the Windows 10 2018 Fall +// Update. +// - Arrays of type win:CountedUnicodeString, win:CountedAnsiString, and +// win:CountedBinary must be packed by the caller into a single region of +// memory. The format for each item is a UINT16 byte-count followed by that +// many bytes of data. When providing the array to the generated macro, you +// must provide the total size of the packed array data, including the UINT16 +// sizes for each item. In the case of win:CountedUnicodeString, the data +// size is specified in WCHAR (16-bit) units. In the case of +// win:CountedAnsiString and win:CountedBinary, the data size is specified in +// bytes. +// +//***************************************************************************** + +#include +#include +#include + +#ifndef ETW_INLINE + #ifdef _ETW_KM_ + // In kernel mode, save stack space by never inlining templates. + #define ETW_INLINE DECLSPEC_NOINLINE __inline + #else + // In user mode, save code size by inlining templates as appropriate. + #define ETW_INLINE __inline + #endif +#endif // ETW_INLINE + +#if defined(__cplusplus) +extern "C" { +#endif + +// +// MCGEN_DISABLE_PROVIDER_CODE_GENERATION macro: +// Define this macro to have the compiler skip the generated functions in this +// header. +// +#ifndef MCGEN_DISABLE_PROVIDER_CODE_GENERATION + +// +// MCGEN_USE_KERNEL_MODE_APIS macro: +// Controls whether the generated code uses kernel-mode or user-mode APIs. +// - Set to 0 to use Windows user-mode APIs such as EventRegister. +// - Set to 1 to use Windows kernel-mode APIs such as EtwRegister. +// Default is based on whether the _ETW_KM_ macro is defined (i.e. by wdm.h). +// Note that the APIs can also be overridden directly, e.g. by setting the +// MCGEN_EVENTWRITETRANSFER or MCGEN_EVENTREGISTER macros. +// +#ifndef MCGEN_USE_KERNEL_MODE_APIS + #ifdef _ETW_KM_ + #define MCGEN_USE_KERNEL_MODE_APIS 1 + #else + #define MCGEN_USE_KERNEL_MODE_APIS 0 + #endif +#endif // MCGEN_USE_KERNEL_MODE_APIS + +// +// MCGEN_HAVE_EVENTSETINFORMATION macro: +// Controls how McGenEventSetInformation uses the EventSetInformation API. +// - Set to 0 to disable the use of EventSetInformation +// (McGenEventSetInformation will always return an error). +// - Set to 1 to directly invoke MCGEN_EVENTSETINFORMATION. +// - Set to 2 to to locate EventSetInformation at runtime via GetProcAddress +// (user-mode) or MmGetSystemRoutineAddress (kernel-mode). +// Default is determined as follows: +// - If MCGEN_EVENTSETINFORMATION has been customized, set to 1 +// (i.e. use MCGEN_EVENTSETINFORMATION). +// - Else if the target OS version has EventSetInformation, set to 1 +// (i.e. use MCGEN_EVENTSETINFORMATION). +// - Else set to 2 (i.e. try to dynamically locate EventSetInformation). +// Note that an McGenEventSetInformation function will only be generated if one +// or more provider in a manifest has provider traits. +// +#ifndef MCGEN_HAVE_EVENTSETINFORMATION + #ifdef MCGEN_EVENTSETINFORMATION // if MCGEN_EVENTSETINFORMATION has been customized, + #define MCGEN_HAVE_EVENTSETINFORMATION 1 // directly invoke MCGEN_EVENTSETINFORMATION(...). + #elif MCGEN_USE_KERNEL_MODE_APIS // else if using kernel-mode APIs, + #if NTDDI_VERSION >= 0x06040000 // if target OS is Windows 10 or later, + #define MCGEN_HAVE_EVENTSETINFORMATION 1 // directly invoke MCGEN_EVENTSETINFORMATION(...). + #else // else + #define MCGEN_HAVE_EVENTSETINFORMATION 2 // find "EtwSetInformation" via MmGetSystemRoutineAddress. + #endif // else (using user-mode APIs) + #else // if target OS and SDK is Windows 8 or later, + #if WINVER >= 0x0602 && defined(EVENT_FILTER_TYPE_SCHEMATIZED) + #define MCGEN_HAVE_EVENTSETINFORMATION 1 // directly invoke MCGEN_EVENTSETINFORMATION(...). + #else // else + #define MCGEN_HAVE_EVENTSETINFORMATION 2 // find "EventSetInformation" via GetModuleHandleExW/GetProcAddress. + #endif + #endif +#endif // MCGEN_HAVE_EVENTSETINFORMATION + +// +// MCGEN Override Macros +// +// The following override macros may be defined before including this header +// to control the APIs used by this header: +// +// - MCGEN_EVENTREGISTER +// - MCGEN_EVENTUNREGISTER +// - MCGEN_EVENTSETINFORMATION +// - MCGEN_EVENTWRITETRANSFER +// +// If the the macro is undefined, the MC implementation will default to the +// corresponding ETW APIs. For example, if the MCGEN_EVENTREGISTER macro is +// undefined, the EventRegister[MyProviderName] macro will use EventRegister +// in user mode and will use EtwRegister in kernel mode. +// +// To prevent issues from conflicting definitions of these macros, the value +// of the override macro will be used as a suffix in certain internal function +// names. Because of this, the override macros must follow certain rules: +// +// - The macro must be defined before any MC-generated header is included and +// must not be undefined or redefined after any MC-generated header is +// included. Different translation units (i.e. different .c or .cpp files) +// may set the macros to different values, but within a translation unit +// (within a single .c or .cpp file), the macro must be set once and not +// changed. +// - The override must be an object-like macro, not a function-like macro +// (i.e. the override macro must not have a parameter list). +// - The override macro's value must be a simple identifier, i.e. must be +// something that starts with a letter or '_' and contains only letters, +// numbers, and '_' characters. +// - If the override macro's value is the name of a second object-like macro, +// the second object-like macro must follow the same rules. (The override +// macro's value can also be the name of a function-like macro, in which +// case the function-like macro does not need to follow the same rules.) +// +// For example, the following will cause compile errors: +// +// #define MCGEN_EVENTWRITETRANSFER MyNamespace::MyClass::MyFunction // Value has non-identifier characters (colon). +// #define MCGEN_EVENTWRITETRANSFER GetEventWriteFunctionPointer(7) // Value has non-identifier characters (parentheses). +// #define MCGEN_EVENTWRITETRANSFER(h,e,a,r,c,d) EventWrite(h,e,c,d) // Override is defined as a function-like macro. +// #define MY_OBJECT_LIKE_MACRO MyNamespace::MyClass::MyEventWriteFunction +// #define MCGEN_EVENTWRITETRANSFER MY_OBJECT_LIKE_MACRO // Evaluates to something with non-identifier characters (colon). +// +// The following would be ok: +// +// #define MCGEN_EVENTWRITETRANSFER MyEventWriteFunction1 // OK, suffix will be "MyEventWriteFunction1". +// #define MY_OBJECT_LIKE_MACRO MyEventWriteFunction2 +// #define MCGEN_EVENTWRITETRANSFER MY_OBJECT_LIKE_MACRO // OK, suffix will be "MyEventWriteFunction2". +// #define MY_FUNCTION_LIKE_MACRO(h,e,a,r,c,d) MyNamespace::MyClass::MyEventWriteFunction3(h,e,c,d) +// #define MCGEN_EVENTWRITETRANSFER MY_FUNCTION_LIKE_MACRO // OK, suffix will be "MY_FUNCTION_LIKE_MACRO". +// +#ifndef MCGEN_EVENTREGISTER + #if MCGEN_USE_KERNEL_MODE_APIS + #define MCGEN_EVENTREGISTER EtwRegister + #else + #define MCGEN_EVENTREGISTER EventRegister + #endif +#endif // MCGEN_EVENTREGISTER +#ifndef MCGEN_EVENTUNREGISTER + #if MCGEN_USE_KERNEL_MODE_APIS + #define MCGEN_EVENTUNREGISTER EtwUnregister + #else + #define MCGEN_EVENTUNREGISTER EventUnregister + #endif +#endif // MCGEN_EVENTUNREGISTER +#ifndef MCGEN_EVENTSETINFORMATION + #if MCGEN_USE_KERNEL_MODE_APIS + #define MCGEN_EVENTSETINFORMATION EtwSetInformation + #else + #define MCGEN_EVENTSETINFORMATION EventSetInformation + #endif +#endif // MCGEN_EVENTSETINFORMATION +#ifndef MCGEN_EVENTWRITETRANSFER + #if MCGEN_USE_KERNEL_MODE_APIS + #define MCGEN_EVENTWRITETRANSFER EtwWriteTransfer + #else + #define MCGEN_EVENTWRITETRANSFER EventWriteTransfer + #endif +#endif // MCGEN_EVENTWRITETRANSFER + +// +// MCGEN_EVENT_ENABLED macro: +// Override to control how the EventWrite[EventName] macros determine whether +// an event is enabled. The default behavior is for EventWrite[EventName] to +// use the EventEnabled[EventName] macros. +// +#ifndef MCGEN_EVENT_ENABLED +#define MCGEN_EVENT_ENABLED(EventName) EventEnabled##EventName() +#endif + +// +// MCGEN_EVENT_ENABLED_FORCONTEXT macro: +// Override to control how the EventWrite[EventName]_ForContext macros +// determine whether an event is enabled. The default behavior is for +// EventWrite[EventName]_ForContext to use the +// EventEnabled[EventName]_ForContext macros. +// +#ifndef MCGEN_EVENT_ENABLED_FORCONTEXT +#define MCGEN_EVENT_ENABLED_FORCONTEXT(pContext, EventName) EventEnabled##EventName##_ForContext(pContext) +#endif + +// +// MCGEN_ENABLE_CHECK macro: +// Determines whether the specified event would be considered as enabled +// based on the state of the specified context. Slightly faster than calling +// McGenEventEnabled directly. +// +#ifndef MCGEN_ENABLE_CHECK +#define MCGEN_ENABLE_CHECK(Context, Descriptor) (Context.IsEnabled && McGenEventEnabled(&Context, &Descriptor)) +#endif + +#if !defined(MCGEN_TRACE_CONTEXT_DEF) +#define MCGEN_TRACE_CONTEXT_DEF +// This structure is for use by MC-generated code and should not be used directly. +typedef struct _MCGEN_TRACE_CONTEXT +{ + TRACEHANDLE RegistrationHandle; + TRACEHANDLE Logger; // Used as pointer to provider traits. + ULONGLONG MatchAnyKeyword; + ULONGLONG MatchAllKeyword; + ULONG Flags; + ULONG IsEnabled; + UCHAR Level; + UCHAR Reserve; + USHORT EnableBitsCount; + PULONG EnableBitMask; + const ULONGLONG* EnableKeyWords; + const UCHAR* EnableLevel; +} MCGEN_TRACE_CONTEXT, *PMCGEN_TRACE_CONTEXT; +#endif // MCGEN_TRACE_CONTEXT_DEF + +#if !defined(MCGEN_LEVEL_KEYWORD_ENABLED_DEF) +#define MCGEN_LEVEL_KEYWORD_ENABLED_DEF +// +// Determines whether an event with a given Level and Keyword would be +// considered as enabled based on the state of the specified context. +// Note that you may want to use MCGEN_ENABLE_CHECK instead of calling this +// function directly. +// +FORCEINLINE +BOOLEAN +McGenLevelKeywordEnabled( + _In_ PMCGEN_TRACE_CONTEXT EnableInfo, + _In_ UCHAR Level, + _In_ ULONGLONG Keyword + ) +{ + // + // Check if the event Level is lower than the level at which + // the channel is enabled. + // If the event Level is 0 or the channel is enabled at level 0, + // all levels are enabled. + // + + if ((Level <= EnableInfo->Level) || // This also covers the case of Level == 0. + (EnableInfo->Level == 0)) { + + // + // Check if Keyword is enabled + // + + if ((Keyword == (ULONGLONG)0) || + ((Keyword & EnableInfo->MatchAnyKeyword) && + ((Keyword & EnableInfo->MatchAllKeyword) == EnableInfo->MatchAllKeyword))) { + return TRUE; + } + } + + return FALSE; +} +#endif // MCGEN_LEVEL_KEYWORD_ENABLED_DEF + +#if !defined(MCGEN_EVENT_ENABLED_DEF) +#define MCGEN_EVENT_ENABLED_DEF +// +// Determines whether the specified event would be considered as enabled based +// on the state of the specified context. Note that you may want to use +// MCGEN_ENABLE_CHECK instead of calling this function directly. +// +FORCEINLINE +BOOLEAN +McGenEventEnabled( + _In_ PMCGEN_TRACE_CONTEXT EnableInfo, + _In_ PCEVENT_DESCRIPTOR EventDescriptor + ) +{ + return McGenLevelKeywordEnabled(EnableInfo, EventDescriptor->Level, EventDescriptor->Keyword); +} +#endif // MCGEN_EVENT_ENABLED_DEF + +#if !defined(MCGEN_CONTROL_CALLBACK) +#define MCGEN_CONTROL_CALLBACK + +// This function is for use by MC-generated code and should not be used directly. +DECLSPEC_NOINLINE __inline +VOID +__stdcall +McGenControlCallbackV2( + _In_ LPCGUID SourceId, + _In_ ULONG ControlCode, + _In_ UCHAR Level, + _In_ ULONGLONG MatchAnyKeyword, + _In_ ULONGLONG MatchAllKeyword, + _In_opt_ PEVENT_FILTER_DESCRIPTOR FilterData, + _Inout_opt_ PVOID CallbackContext + ) +/*++ + +Routine Description: + + This is the notification callback for Windows Vista and later. + +Arguments: + + SourceId - The GUID that identifies the session that enabled the provider. + + ControlCode - The parameter indicates whether the provider + is being enabled or disabled. + + Level - The level at which the event is enabled. + + MatchAnyKeyword - The bitmask of keywords that the provider uses to + determine the category of events that it writes. + + MatchAllKeyword - This bitmask additionally restricts the category + of events that the provider writes. + + FilterData - The provider-defined data. + + CallbackContext - The context of the callback that is defined when the provider + called EtwRegister to register itself. + +Remarks: + + ETW calls this function to notify provider of enable/disable + +--*/ +{ + PMCGEN_TRACE_CONTEXT Ctx = (PMCGEN_TRACE_CONTEXT)CallbackContext; + ULONG Ix; +#ifndef MCGEN_PRIVATE_ENABLE_CALLBACK_V2 + UNREFERENCED_PARAMETER(SourceId); + UNREFERENCED_PARAMETER(FilterData); +#endif + + if (Ctx == NULL) { + return; + } + + switch (ControlCode) { + + case EVENT_CONTROL_CODE_ENABLE_PROVIDER: + Ctx->Level = Level; + Ctx->MatchAnyKeyword = MatchAnyKeyword; + Ctx->MatchAllKeyword = MatchAllKeyword; + Ctx->IsEnabled = EVENT_CONTROL_CODE_ENABLE_PROVIDER; + + for (Ix = 0; Ix < Ctx->EnableBitsCount; Ix += 1) { + if (McGenLevelKeywordEnabled(Ctx, Ctx->EnableLevel[Ix], Ctx->EnableKeyWords[Ix]) != FALSE) { + Ctx->EnableBitMask[Ix >> 5] |= (1 << (Ix % 32)); + } else { + Ctx->EnableBitMask[Ix >> 5] &= ~(1 << (Ix % 32)); + } + } + break; + + case EVENT_CONTROL_CODE_DISABLE_PROVIDER: + Ctx->IsEnabled = EVENT_CONTROL_CODE_DISABLE_PROVIDER; + Ctx->Level = 0; + Ctx->MatchAnyKeyword = 0; + Ctx->MatchAllKeyword = 0; + if (Ctx->EnableBitsCount > 0) { +#pragma warning(suppress: 26451) // Arithmetic overflow cannot occur, no matter the value of EnableBitCount + RtlZeroMemory(Ctx->EnableBitMask, (((Ctx->EnableBitsCount - 1) / 32) + 1) * sizeof(ULONG)); + } + break; + + default: + break; + } + +#ifdef MCGEN_PRIVATE_ENABLE_CALLBACK_V2 + // + // Call user defined callback + // + MCGEN_PRIVATE_ENABLE_CALLBACK_V2( + SourceId, + ControlCode, + Level, + MatchAnyKeyword, + MatchAllKeyword, + FilterData, + CallbackContext + ); +#endif // MCGEN_PRIVATE_ENABLE_CALLBACK_V2 + + return; +} + +#endif // MCGEN_CONTROL_CALLBACK + +#ifndef _mcgen_PENABLECALLBACK + #if MCGEN_USE_KERNEL_MODE_APIS + #define _mcgen_PENABLECALLBACK PETWENABLECALLBACK + #else + #define _mcgen_PENABLECALLBACK PENABLECALLBACK + #endif +#endif // _mcgen_PENABLECALLBACK + +#if !defined(_mcgen_PASTE2) +// This macro is for use by MC-generated code and should not be used directly. +#define _mcgen_PASTE2(a, b) _mcgen_PASTE2_imp(a, b) +#define _mcgen_PASTE2_imp(a, b) a##b +#endif // _mcgen_PASTE2 + +#if !defined(_mcgen_PASTE3) +// This macro is for use by MC-generated code and should not be used directly. +#define _mcgen_PASTE3(a, b, c) _mcgen_PASTE3_imp(a, b, c) +#define _mcgen_PASTE3_imp(a, b, c) a##b##_##c +#endif // _mcgen_PASTE3 + +// +// Macro validation +// + +// Validate MCGEN_EVENTREGISTER: + +// Trigger an error if MCGEN_EVENTREGISTER is not an unqualified (simple) identifier: +struct _mcgen_PASTE2(MCGEN_EVENTREGISTER_definition_must_be_an_unqualified_identifier_, MCGEN_EVENTREGISTER); + +// Trigger an error if MCGEN_EVENTREGISTER is redefined: +typedef struct _mcgen_PASTE2(MCGEN_EVENTREGISTER_definition_must_be_an_unqualified_identifier_, MCGEN_EVENTREGISTER) + MCGEN_EVENTREGISTER_must_not_be_redefined_between_headers; + +// Trigger an error if MCGEN_EVENTREGISTER is defined as a function-like macro: +typedef void MCGEN_EVENTREGISTER_must_not_be_a_functionLike_macro_MCGEN_EVENTREGISTER; +typedef int _mcgen_PASTE2(MCGEN_EVENTREGISTER_must_not_be_a_functionLike_macro_, MCGEN_EVENTREGISTER); + +// Validate MCGEN_EVENTUNREGISTER: + +// Trigger an error if MCGEN_EVENTUNREGISTER is not an unqualified (simple) identifier: +struct _mcgen_PASTE2(MCGEN_EVENTUNREGISTER_definition_must_be_an_unqualified_identifier_, MCGEN_EVENTUNREGISTER); + +// Trigger an error if MCGEN_EVENTUNREGISTER is redefined: +typedef struct _mcgen_PASTE2(MCGEN_EVENTUNREGISTER_definition_must_be_an_unqualified_identifier_, MCGEN_EVENTUNREGISTER) + MCGEN_EVENTUNREGISTER_must_not_be_redefined_between_headers; + +// Trigger an error if MCGEN_EVENTUNREGISTER is defined as a function-like macro: +typedef void MCGEN_EVENTUNREGISTER_must_not_be_a_functionLike_macro_MCGEN_EVENTUNREGISTER; +typedef int _mcgen_PASTE2(MCGEN_EVENTUNREGISTER_must_not_be_a_functionLike_macro_, MCGEN_EVENTUNREGISTER); + +// Validate MCGEN_EVENTSETINFORMATION: + +// Trigger an error if MCGEN_EVENTSETINFORMATION is not an unqualified (simple) identifier: +struct _mcgen_PASTE2(MCGEN_EVENTSETINFORMATION_definition_must_be_an_unqualified_identifier_, MCGEN_EVENTSETINFORMATION); + +// Trigger an error if MCGEN_EVENTSETINFORMATION is redefined: +typedef struct _mcgen_PASTE2(MCGEN_EVENTSETINFORMATION_definition_must_be_an_unqualified_identifier_, MCGEN_EVENTSETINFORMATION) + MCGEN_EVENTSETINFORMATION_must_not_be_redefined_between_headers; + +// Trigger an error if MCGEN_EVENTSETINFORMATION is defined as a function-like macro: +typedef void MCGEN_EVENTSETINFORMATION_must_not_be_a_functionLike_macro_MCGEN_EVENTSETINFORMATION; +typedef int _mcgen_PASTE2(MCGEN_EVENTSETINFORMATION_must_not_be_a_functionLike_macro_, MCGEN_EVENTSETINFORMATION); + +// Validate MCGEN_EVENTWRITETRANSFER: + +// Trigger an error if MCGEN_EVENTWRITETRANSFER is not an unqualified (simple) identifier: +struct _mcgen_PASTE2(MCGEN_EVENTWRITETRANSFER_definition_must_be_an_unqualified_identifier_, MCGEN_EVENTWRITETRANSFER); + +// Trigger an error if MCGEN_EVENTWRITETRANSFER is redefined: +typedef struct _mcgen_PASTE2(MCGEN_EVENTWRITETRANSFER_definition_must_be_an_unqualified_identifier_, MCGEN_EVENTWRITETRANSFER) + MCGEN_EVENTWRITETRANSFER_must_not_be_redefined_between_headers;; + +// Trigger an error if MCGEN_EVENTWRITETRANSFER is defined as a function-like macro: +typedef void MCGEN_EVENTWRITETRANSFER_must_not_be_a_functionLike_macro_MCGEN_EVENTWRITETRANSFER; +typedef int _mcgen_PASTE2(MCGEN_EVENTWRITETRANSFER_must_not_be_a_functionLike_macro_, MCGEN_EVENTWRITETRANSFER); + +#ifndef McGenEventWrite_def +#define McGenEventWrite_def + +// This macro is for use by MC-generated code and should not be used directly. +#define McGenEventWrite _mcgen_PASTE2(McGenEventWrite_, MCGEN_EVENTWRITETRANSFER) + +// This function is for use by MC-generated code and should not be used directly. +DECLSPEC_NOINLINE __inline +ULONG __stdcall +McGenEventWrite( + _In_ PMCGEN_TRACE_CONTEXT Context, + _In_ PCEVENT_DESCRIPTOR Descriptor, + _In_opt_ LPCGUID ActivityId, + _In_range_(1, 128) ULONG EventDataCount, + _Pre_cap_(EventDataCount) EVENT_DATA_DESCRIPTOR* EventData + ) +{ + const USHORT UNALIGNED* Traits; + + // Some customized MCGEN_EVENTWRITETRANSFER macros might ignore ActivityId. + UNREFERENCED_PARAMETER(ActivityId); + + Traits = (const USHORT UNALIGNED*)(UINT_PTR)Context->Logger; + + if (Traits == NULL) { + EventData[0].Ptr = 0; + EventData[0].Size = 0; + EventData[0].Reserved = 0; + } else { + EventData[0].Ptr = (ULONG_PTR)Traits; + EventData[0].Size = *Traits; + EventData[0].Reserved = 2; // EVENT_DATA_DESCRIPTOR_TYPE_PROVIDER_METADATA + } + + return MCGEN_EVENTWRITETRANSFER( + Context->RegistrationHandle, + Descriptor, + ActivityId, + NULL, + EventDataCount, + EventData); +} +#endif // McGenEventWrite_def + +#if !defined(McGenEventRegisterUnregister) +#define McGenEventRegisterUnregister + +// This macro is for use by MC-generated code and should not be used directly. +#define McGenEventRegister _mcgen_PASTE2(McGenEventRegister_, MCGEN_EVENTREGISTER) + +#pragma warning(push) +#pragma warning(disable:6103) +// This function is for use by MC-generated code and should not be used directly. +DECLSPEC_NOINLINE __inline +ULONG __stdcall +McGenEventRegister( + _In_ LPCGUID ProviderId, + _In_opt_ _mcgen_PENABLECALLBACK EnableCallback, + _In_opt_ PVOID CallbackContext, + _Inout_ PREGHANDLE RegHandle + ) +/*++ + +Routine Description: + + This function registers the provider with ETW. + +Arguments: + + ProviderId - Provider ID to register with ETW. + + EnableCallback - Callback to be used. + + CallbackContext - Context for the callback. + + RegHandle - Pointer to registration handle. + +Remarks: + + Should not be called if the provider is already registered (i.e. should not + be called if *RegHandle != 0). Repeatedly registering a provider is a bug + and may indicate a race condition. However, for compatibility with previous + behavior, this function will return SUCCESS in this case. + +--*/ +{ + ULONG Error; + + if (*RegHandle != 0) + { + Error = 0; // ERROR_SUCCESS + } + else + { + Error = MCGEN_EVENTREGISTER(ProviderId, EnableCallback, CallbackContext, RegHandle); + } + + return Error; +} +#pragma warning(pop) + +// This macro is for use by MC-generated code and should not be used directly. +#define McGenEventUnregister _mcgen_PASTE2(McGenEventUnregister_, MCGEN_EVENTUNREGISTER) + +// This function is for use by MC-generated code and should not be used directly. +DECLSPEC_NOINLINE __inline +ULONG __stdcall +McGenEventUnregister(_Inout_ PREGHANDLE RegHandle) +/*++ + +Routine Description: + + Unregister from ETW and set *RegHandle = 0. + +Arguments: + + RegHandle - the pointer to the provider registration handle + +Remarks: + + If provider has not been registered (i.e. if *RegHandle == 0), + return SUCCESS. It is safe to call McGenEventUnregister even if the + call to McGenEventRegister returned an error. + +--*/ +{ + ULONG Error; + + if(*RegHandle == 0) + { + Error = 0; // ERROR_SUCCESS + } + else + { + Error = MCGEN_EVENTUNREGISTER(*RegHandle); + *RegHandle = (REGHANDLE)0; + } + + return Error; +} + +#endif // McGenEventRegisterUnregister + +#ifndef _mcgen_EVENT_BIT_SET + #if defined(_M_IX86) || defined(_M_X64) + // This macro is for use by MC-generated code and should not be used directly. + #define _mcgen_EVENT_BIT_SET(EnableBits, BitPosition) ((((const unsigned char*)EnableBits)[BitPosition >> 3] & (1u << (BitPosition & 7))) != 0) + #else // CPU type + // This macro is for use by MC-generated code and should not be used directly. + #define _mcgen_EVENT_BIT_SET(EnableBits, BitPosition) ((EnableBits[BitPosition >> 5] & (1u << (BitPosition & 31))) != 0) + #endif // CPU type +#endif // _mcgen_EVENT_BIT_SET + +#endif // MCGEN_DISABLE_PROVIDER_CODE_GENERATION + +//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// Provider "microsoft-windows-mimalloc" event count 2 +//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +// Provider GUID = 138f4dbb-ee04-4899-aa0a-572ad4475779 +EXTERN_C __declspec(selectany) const GUID ETW_MI_Provider = {0x138f4dbb, 0xee04, 0x4899, {0xaa, 0x0a, 0x57, 0x2a, 0xd4, 0x47, 0x57, 0x79}}; + +#ifndef ETW_MI_Provider_Traits +#define ETW_MI_Provider_Traits NULL +#endif // ETW_MI_Provider_Traits + +// +// Event Descriptors +// +EXTERN_C __declspec(selectany) const EVENT_DESCRIPTOR ETW_MI_ALLOC = {0x64, 0x1, 0x0, 0x4, 0x0, 0x0, 0x0}; +#define ETW_MI_ALLOC_value 0x64 +EXTERN_C __declspec(selectany) const EVENT_DESCRIPTOR ETW_MI_FREE = {0x65, 0x1, 0x0, 0x4, 0x0, 0x0, 0x0}; +#define ETW_MI_FREE_value 0x65 + +// +// MCGEN_DISABLE_PROVIDER_CODE_GENERATION macro: +// Define this macro to have the compiler skip the generated functions in this +// header. +// +#ifndef MCGEN_DISABLE_PROVIDER_CODE_GENERATION + +// +// Event Enablement Bits +// These variables are for use by MC-generated code and should not be used directly. +// +EXTERN_C __declspec(selectany) DECLSPEC_CACHEALIGN ULONG microsoft_windows_mimallocEnableBits[1]; +EXTERN_C __declspec(selectany) const ULONGLONG microsoft_windows_mimallocKeywords[1] = {0x0}; +EXTERN_C __declspec(selectany) const unsigned char microsoft_windows_mimallocLevels[1] = {4}; + +// +// Provider context +// +EXTERN_C __declspec(selectany) MCGEN_TRACE_CONTEXT ETW_MI_Provider_Context = {0, (ULONG_PTR)ETW_MI_Provider_Traits, 0, 0, 0, 0, 0, 0, 1, microsoft_windows_mimallocEnableBits, microsoft_windows_mimallocKeywords, microsoft_windows_mimallocLevels}; + +// +// Provider REGHANDLE +// +#define microsoft_windows_mimallocHandle (ETW_MI_Provider_Context.RegistrationHandle) + +// +// This macro is set to 0, indicating that the EventWrite[Name] macros do not +// have an Activity parameter. This is controlled by the -km and -um options. +// +#define ETW_MI_Provider_EventWriteActivity 0 + +// +// Register with ETW using the control GUID specified in the manifest. +// Invoke this macro during module initialization (i.e. program startup, +// DLL process attach, or driver load) to initialize the provider. +// Note that if this function returns an error, the error means that +// will not work, but no action needs to be taken -- even if EventRegister +// returns an error, it is generally safe to use EventWrite and +// EventUnregister macros (they will be no-ops if EventRegister failed). +// +#ifndef EventRegistermicrosoft_windows_mimalloc +#define EventRegistermicrosoft_windows_mimalloc() McGenEventRegister(&ETW_MI_Provider, McGenControlCallbackV2, &ETW_MI_Provider_Context, µsoft_windows_mimallocHandle) +#endif + +// +// Register with ETW using a specific control GUID (i.e. a GUID other than what +// is specified in the manifest). Advanced scenarios only. +// +#ifndef EventRegisterByGuidmicrosoft_windows_mimalloc +#define EventRegisterByGuidmicrosoft_windows_mimalloc(Guid) McGenEventRegister(&(Guid), McGenControlCallbackV2, &ETW_MI_Provider_Context, µsoft_windows_mimallocHandle) +#endif + +// +// Unregister with ETW and close the provider. +// Invoke this macro during module shutdown (i.e. program exit, DLL process +// detach, or driver unload) to unregister the provider. +// Note that you MUST call EventUnregister before DLL or driver unload +// (not optional): failure to unregister a provider before DLL or driver unload +// will result in crashes. +// +#ifndef EventUnregistermicrosoft_windows_mimalloc +#define EventUnregistermicrosoft_windows_mimalloc() McGenEventUnregister(µsoft_windows_mimallocHandle) +#endif + +// +// MCGEN_ENABLE_FORCONTEXT_CODE_GENERATION macro: +// Define this macro to enable support for caller-allocated provider context. +// +#ifdef MCGEN_ENABLE_FORCONTEXT_CODE_GENERATION + +// +// Advanced scenarios: Caller-allocated provider context. +// Use when multiple differently-configured provider handles are needed, +// e.g. for container-aware drivers, one context per container. +// +// Usage: +// +// - Caller enables the feature before including this header, e.g. +// #define MCGEN_ENABLE_FORCONTEXT_CODE_GENERATION 1 +// - Caller allocates memory, e.g. pContext = malloc(sizeof(McGenContext_microsoft_windows_mimalloc)); +// - Caller registers the provider, e.g. EventRegistermicrosoft_windows_mimalloc_ForContext(pContext); +// - Caller writes events, e.g. EventWriteMyEvent_ForContext(pContext, ...); +// - Caller unregisters, e.g. EventUnregistermicrosoft_windows_mimalloc_ForContext(pContext); +// - Caller frees memory, e.g. free(pContext); +// + +typedef struct tagMcGenContext_microsoft_windows_mimalloc { + // The fields of this structure are subject to change and should + // not be accessed directly. To access the provider's REGHANDLE, + // use microsoft_windows_mimallocHandle_ForContext(pContext). + MCGEN_TRACE_CONTEXT Context; + ULONG EnableBits[1]; +} McGenContext_microsoft_windows_mimalloc; + +#define EventRegistermicrosoft_windows_mimalloc_ForContext(pContext) _mcgen_PASTE2(_mcgen_RegisterForContext_microsoft_windows_mimalloc_, MCGEN_EVENTREGISTER)(&ETW_MI_Provider, pContext) +#define EventRegisterByGuidmicrosoft_windows_mimalloc_ForContext(Guid, pContext) _mcgen_PASTE2(_mcgen_RegisterForContext_microsoft_windows_mimalloc_, MCGEN_EVENTREGISTER)(&(Guid), pContext) +#define EventUnregistermicrosoft_windows_mimalloc_ForContext(pContext) McGenEventUnregister(&(pContext)->Context.RegistrationHandle) + +// +// Provider REGHANDLE for caller-allocated context. +// +#define microsoft_windows_mimallocHandle_ForContext(pContext) ((pContext)->Context.RegistrationHandle) + +// This function is for use by MC-generated code and should not be used directly. +// Initialize and register the caller-allocated context. +__inline +ULONG __stdcall +_mcgen_PASTE2(_mcgen_RegisterForContext_microsoft_windows_mimalloc_, MCGEN_EVENTREGISTER)( + _In_ LPCGUID pProviderId, + _Out_ McGenContext_microsoft_windows_mimalloc* pContext) +{ + RtlZeroMemory(pContext, sizeof(*pContext)); + pContext->Context.Logger = (ULONG_PTR)ETW_MI_Provider_Traits; + pContext->Context.EnableBitsCount = 1; + pContext->Context.EnableBitMask = pContext->EnableBits; + pContext->Context.EnableKeyWords = microsoft_windows_mimallocKeywords; + pContext->Context.EnableLevel = microsoft_windows_mimallocLevels; + return McGenEventRegister( + pProviderId, + McGenControlCallbackV2, + &pContext->Context, + &pContext->Context.RegistrationHandle); +} + +// This function is for use by MC-generated code and should not be used directly. +// Trigger a compile error if called with the wrong parameter type. +FORCEINLINE +_Ret_ McGenContext_microsoft_windows_mimalloc* +_mcgen_CheckContextType_microsoft_windows_mimalloc(_In_ McGenContext_microsoft_windows_mimalloc* pContext) +{ + return pContext; +} + +#endif // MCGEN_ENABLE_FORCONTEXT_CODE_GENERATION + +// +// Enablement check macro for event "ETW_MI_ALLOC" +// +#define EventEnabledETW_MI_ALLOC() _mcgen_EVENT_BIT_SET(microsoft_windows_mimallocEnableBits, 0) +#define EventEnabledETW_MI_ALLOC_ForContext(pContext) _mcgen_EVENT_BIT_SET(_mcgen_CheckContextType_microsoft_windows_mimalloc(pContext)->EnableBits, 0) + +// +// Event write macros for event "ETW_MI_ALLOC" +// +#define EventWriteETW_MI_ALLOC(Address, Size) \ + MCGEN_EVENT_ENABLED(ETW_MI_ALLOC) \ + ? _mcgen_TEMPLATE_FOR_ETW_MI_ALLOC(&ETW_MI_Provider_Context, &ETW_MI_ALLOC, Address, Size) : 0 +#define EventWriteETW_MI_ALLOC_AssumeEnabled(Address, Size) \ + _mcgen_TEMPLATE_FOR_ETW_MI_ALLOC(&ETW_MI_Provider_Context, &ETW_MI_ALLOC, Address, Size) +#define EventWriteETW_MI_ALLOC_ForContext(pContext, Address, Size) \ + MCGEN_EVENT_ENABLED_FORCONTEXT(pContext, ETW_MI_ALLOC) \ + ? _mcgen_TEMPLATE_FOR_ETW_MI_ALLOC(&(pContext)->Context, &ETW_MI_ALLOC, Address, Size) : 0 +#define EventWriteETW_MI_ALLOC_ForContextAssumeEnabled(pContext, Address, Size) \ + _mcgen_TEMPLATE_FOR_ETW_MI_ALLOC(&_mcgen_CheckContextType_microsoft_windows_mimalloc(pContext)->Context, &ETW_MI_ALLOC, Address, Size) + +// This macro is for use by MC-generated code and should not be used directly. +#define _mcgen_TEMPLATE_FOR_ETW_MI_ALLOC _mcgen_PASTE2(McTemplateU0xx_, MCGEN_EVENTWRITETRANSFER) + +// +// Enablement check macro for event "ETW_MI_FREE" +// +#define EventEnabledETW_MI_FREE() _mcgen_EVENT_BIT_SET(microsoft_windows_mimallocEnableBits, 0) +#define EventEnabledETW_MI_FREE_ForContext(pContext) _mcgen_EVENT_BIT_SET(_mcgen_CheckContextType_microsoft_windows_mimalloc(pContext)->EnableBits, 0) + +// +// Event write macros for event "ETW_MI_FREE" +// +#define EventWriteETW_MI_FREE(Address, Size) \ + MCGEN_EVENT_ENABLED(ETW_MI_FREE) \ + ? _mcgen_TEMPLATE_FOR_ETW_MI_FREE(&ETW_MI_Provider_Context, &ETW_MI_FREE, Address, Size) : 0 +#define EventWriteETW_MI_FREE_AssumeEnabled(Address, Size) \ + _mcgen_TEMPLATE_FOR_ETW_MI_FREE(&ETW_MI_Provider_Context, &ETW_MI_FREE, Address, Size) +#define EventWriteETW_MI_FREE_ForContext(pContext, Address, Size) \ + MCGEN_EVENT_ENABLED_FORCONTEXT(pContext, ETW_MI_FREE) \ + ? _mcgen_TEMPLATE_FOR_ETW_MI_FREE(&(pContext)->Context, &ETW_MI_FREE, Address, Size) : 0 +#define EventWriteETW_MI_FREE_ForContextAssumeEnabled(pContext, Address, Size) \ + _mcgen_TEMPLATE_FOR_ETW_MI_FREE(&_mcgen_CheckContextType_microsoft_windows_mimalloc(pContext)->Context, &ETW_MI_FREE, Address, Size) + +// This macro is for use by MC-generated code and should not be used directly. +#define _mcgen_TEMPLATE_FOR_ETW_MI_FREE _mcgen_PASTE2(McTemplateU0xx_, MCGEN_EVENTWRITETRANSFER) + +#endif // MCGEN_DISABLE_PROVIDER_CODE_GENERATION + +// +// MCGEN_DISABLE_PROVIDER_CODE_GENERATION macro: +// Define this macro to have the compiler skip the generated functions in this +// header. +// +#ifndef MCGEN_DISABLE_PROVIDER_CODE_GENERATION + +// +// Template Functions +// + +// +// Function for template "ETW_CUSTOM_HEAP_ALLOC_DATA" (and possibly others). +// This function is for use by MC-generated code and should not be used directly. +// +#ifndef McTemplateU0xx_def +#define McTemplateU0xx_def +ETW_INLINE +ULONG +_mcgen_PASTE2(McTemplateU0xx_, MCGEN_EVENTWRITETRANSFER)( + _In_ PMCGEN_TRACE_CONTEXT Context, + _In_ PCEVENT_DESCRIPTOR Descriptor, + _In_ const unsigned __int64 _Arg0, + _In_ const unsigned __int64 _Arg1 + ) +{ +#define McTemplateU0xx_ARGCOUNT 2 + + EVENT_DATA_DESCRIPTOR EventData[McTemplateU0xx_ARGCOUNT + 1]; + + EventDataDescCreate(&EventData[1],&_Arg0, sizeof(const unsigned __int64) ); + + EventDataDescCreate(&EventData[2],&_Arg1, sizeof(const unsigned __int64) ); + + return McGenEventWrite(Context, Descriptor, NULL, McTemplateU0xx_ARGCOUNT + 1, EventData); +} +#endif // McTemplateU0xx_def + +#endif // MCGEN_DISABLE_PROVIDER_CODE_GENERATION + +#if defined(__cplusplus) +} +#endif diff --git a/src/dashbls/depends/mimalloc/src/prim/windows/etw.man b/src/dashbls/depends/mimalloc/src/prim/windows/etw.man new file mode 100644 index 000000000000..cfd1f8a9eaac Binary files /dev/null and b/src/dashbls/depends/mimalloc/src/prim/windows/etw.man differ diff --git a/src/dashbls/depends/mimalloc/src/prim/windows/prim.c b/src/dashbls/depends/mimalloc/src/prim/windows/prim.c new file mode 100644 index 000000000000..6ac32cea09e4 --- /dev/null +++ b/src/dashbls/depends/mimalloc/src/prim/windows/prim.c @@ -0,0 +1,915 @@ +/* ---------------------------------------------------------------------------- +Copyright (c) 2018-2023, Microsoft Research, Daan Leijen +This is free software; you can redistribute it and/or modify it under the +terms of the MIT license. A copy of the license can be found in the file +"LICENSE" at the root of this distribution. +-----------------------------------------------------------------------------*/ + +// This file is included in `src/prim/prim.c` + +#include "mimalloc.h" +#include "mimalloc/internal.h" +#include "mimalloc/prim.h" +#include // fputs, stderr + +// xbox has no console IO +#if !defined(WINAPI_FAMILY_PARTITION) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) +#define MI_HAS_CONSOLE_IO +#endif + +//--------------------------------------------- +// Dynamically bind Windows API points for portability +//--------------------------------------------- + +#if defined(_MSC_VER) +#pragma warning(disable:4996) // don't use GetVersionExW +#endif + +static DWORD win_major_version = 6; +static DWORD win_minor_version = 0; + +// We use VirtualAlloc2 for aligned allocation, but it is only supported on Windows 10 and Windows Server 2016. +// So, we need to look it up dynamically to run on older systems. (use __stdcall for 32-bit compatibility) +// NtAllocateVirtualAllocEx is used for huge OS page allocation (1GiB) +// We define a minimal MEM_EXTENDED_PARAMETER ourselves in order to be able to compile with older SDK's. +typedef enum MI_MEM_EXTENDED_PARAMETER_TYPE_E { + MiMemExtendedParameterInvalidType = 0, + MiMemExtendedParameterAddressRequirements, + MiMemExtendedParameterNumaNode, + MiMemExtendedParameterPartitionHandle, + MiMemExtendedParameterUserPhysicalHandle, + MiMemExtendedParameterAttributeFlags, + MiMemExtendedParameterMax +} MI_MEM_EXTENDED_PARAMETER_TYPE; + +typedef struct DECLSPEC_ALIGN(8) MI_MEM_EXTENDED_PARAMETER_S { + struct { DWORD64 Type : 8; DWORD64 Reserved : 56; } Type; + union { DWORD64 ULong64; PVOID Pointer; SIZE_T Size; HANDLE Handle; DWORD ULong; } Arg; +} MI_MEM_EXTENDED_PARAMETER; + +typedef struct MI_MEM_ADDRESS_REQUIREMENTS_S { + PVOID LowestStartingAddress; + PVOID HighestEndingAddress; + SIZE_T Alignment; +} MI_MEM_ADDRESS_REQUIREMENTS; + +#define MI_MEM_EXTENDED_PARAMETER_NONPAGED_HUGE 0x00000010 + +#include +typedef PVOID (__stdcall *PVirtualAlloc2)(HANDLE, PVOID, SIZE_T, ULONG, ULONG, MI_MEM_EXTENDED_PARAMETER*, ULONG); +typedef LONG (__stdcall *PNtAllocateVirtualMemoryEx)(HANDLE, PVOID*, SIZE_T*, ULONG, ULONG, MI_MEM_EXTENDED_PARAMETER*, ULONG); // avoid NTSTATUS as it is not defined on xbox (pr #1084) +static PVirtualAlloc2 pVirtualAlloc2 = NULL; +static PNtAllocateVirtualMemoryEx pNtAllocateVirtualMemoryEx = NULL; + +// Similarly, GetNumaProcessorNodeEx is only supported since Windows 7 (and GetNumaNodeProcessorMask is not supported on xbox) +typedef struct MI_PROCESSOR_NUMBER_S { WORD Group; BYTE Number; BYTE Reserved; } MI_PROCESSOR_NUMBER; + +typedef VOID (__stdcall *PGetCurrentProcessorNumberEx)(MI_PROCESSOR_NUMBER* ProcNumber); +typedef BOOL (__stdcall *PGetNumaProcessorNodeEx)(MI_PROCESSOR_NUMBER* Processor, PUSHORT NodeNumber); +typedef BOOL (__stdcall* PGetNumaNodeProcessorMaskEx)(USHORT Node, PGROUP_AFFINITY ProcessorMask); +typedef BOOL (__stdcall *PGetNumaProcessorNode)(UCHAR Processor, PUCHAR NodeNumber); +typedef BOOL (__stdcall* PGetNumaNodeProcessorMask)(UCHAR Node, PULONGLONG ProcessorMask); +typedef BOOL (__stdcall* PGetNumaHighestNodeNumber)(PULONG Node); +static PGetCurrentProcessorNumberEx pGetCurrentProcessorNumberEx = NULL; +static PGetNumaProcessorNodeEx pGetNumaProcessorNodeEx = NULL; +static PGetNumaNodeProcessorMaskEx pGetNumaNodeProcessorMaskEx = NULL; +static PGetNumaProcessorNode pGetNumaProcessorNode = NULL; +static PGetNumaNodeProcessorMask pGetNumaNodeProcessorMask = NULL; +static PGetNumaHighestNodeNumber pGetNumaHighestNodeNumber = NULL; + +// Not available on xbox +typedef SIZE_T(__stdcall* PGetLargePageMinimum)(VOID); +static PGetLargePageMinimum pGetLargePageMinimum = NULL; + +// Available after Windows XP +typedef BOOL (__stdcall *PGetPhysicallyInstalledSystemMemory)( PULONGLONG TotalMemoryInKilobytes ); +typedef BOOL (__stdcall* PGetVersionExW)(LPOSVERSIONINFOW lpVersionInformation); + + +//--------------------------------------------- +// Enable large page support dynamically (if possible) +//--------------------------------------------- + +static bool win_enable_large_os_pages(size_t* large_page_size) +{ + static bool large_initialized = false; + if (large_initialized) return (_mi_os_large_page_size() > 0); + large_initialized = true; + if (pGetLargePageMinimum==NULL) return false; // no large page support (xbox etc.) + + // Try to see if large OS pages are supported + // To use large pages on Windows, we first need access permission + // Set "Lock pages in memory" permission in the group policy editor + // + unsigned long err = 0; + HANDLE token = NULL; + BOOL ok = OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token); + if (ok) { + TOKEN_PRIVILEGES tp; + ok = LookupPrivilegeValue(NULL, TEXT("SeLockMemoryPrivilege"), &tp.Privileges[0].Luid); + if (ok) { + tp.PrivilegeCount = 1; + tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + ok = AdjustTokenPrivileges(token, FALSE, &tp, 0, (PTOKEN_PRIVILEGES)NULL, 0); + if (ok) { + err = GetLastError(); + ok = (err == ERROR_SUCCESS); + if (ok && large_page_size != NULL && pGetLargePageMinimum != NULL) { + *large_page_size = (*pGetLargePageMinimum)(); + } + } + } + CloseHandle(token); + } + if (!ok) { + if (err == 0) err = GetLastError(); + _mi_warning_message("cannot enable large OS page support, error %lu\n", err); + } + return (ok!=0); +} + + +//--------------------------------------------- +// Initialize +//--------------------------------------------- + +static DWORD win_allocation_granularity = 64*MI_KiB; + +void _mi_prim_mem_init( mi_os_mem_config_t* config ) +{ + config->has_overcommit = false; + config->has_partial_free = false; + config->has_virtual_reserve = true; + + // get the page size + SYSTEM_INFO si; _mi_memzero_var(si); + GetSystemInfo(&si); + if (si.dwPageSize > 0) { config->page_size = si.dwPageSize; } + if (si.dwAllocationGranularity > 0) { + config->alloc_granularity = si.dwAllocationGranularity; + win_allocation_granularity = si.dwAllocationGranularity; + } + // get virtual address bits + if ((uintptr_t)si.lpMaximumApplicationAddress > 0) { + const size_t vbits = MI_SIZE_BITS - mi_clz((uintptr_t)si.lpMaximumApplicationAddress); + config->virtual_address_bits = vbits; + } + + // get the VirtualAlloc2 function + HINSTANCE hDll = LoadLibrary(TEXT("kernelbase.dll")); + if (hDll != NULL) { + // use VirtualAlloc2FromApp if possible as it is available to Windows store apps + pVirtualAlloc2 = (PVirtualAlloc2)(void (*)(void))GetProcAddress(hDll, "VirtualAlloc2FromApp"); + if (pVirtualAlloc2==NULL) pVirtualAlloc2 = (PVirtualAlloc2)(void (*)(void))GetProcAddress(hDll, "VirtualAlloc2"); + FreeLibrary(hDll); + } + // NtAllocateVirtualMemoryEx is used for huge page allocation + hDll = LoadLibrary(TEXT("ntdll.dll")); + if (hDll != NULL) { + pNtAllocateVirtualMemoryEx = (PNtAllocateVirtualMemoryEx)(void (*)(void))GetProcAddress(hDll, "NtAllocateVirtualMemoryEx"); + FreeLibrary(hDll); + } + // Try to use Win7+ numa API + hDll = LoadLibrary(TEXT("kernel32.dll")); + if (hDll != NULL) { + pGetCurrentProcessorNumberEx = (PGetCurrentProcessorNumberEx)(void (*)(void))GetProcAddress(hDll, "GetCurrentProcessorNumberEx"); + pGetNumaProcessorNodeEx = (PGetNumaProcessorNodeEx)(void (*)(void))GetProcAddress(hDll, "GetNumaProcessorNodeEx"); + pGetNumaNodeProcessorMaskEx = (PGetNumaNodeProcessorMaskEx)(void (*)(void))GetProcAddress(hDll, "GetNumaNodeProcessorMaskEx"); + pGetNumaProcessorNode = (PGetNumaProcessorNode)(void (*)(void))GetProcAddress(hDll, "GetNumaProcessorNode"); + pGetNumaNodeProcessorMask = (PGetNumaNodeProcessorMask)(void (*)(void))GetProcAddress(hDll, "GetNumaNodeProcessorMask"); + pGetNumaHighestNodeNumber = (PGetNumaHighestNodeNumber)(void (*)(void))GetProcAddress(hDll, "GetNumaHighestNodeNumber"); + pGetLargePageMinimum = (PGetLargePageMinimum)(void (*)(void))GetProcAddress(hDll, "GetLargePageMinimum"); + // Get physical memory (not available on XP, so check dynamically) + PGetPhysicallyInstalledSystemMemory pGetPhysicallyInstalledSystemMemory = (PGetPhysicallyInstalledSystemMemory)(void (*)(void))GetProcAddress(hDll,"GetPhysicallyInstalledSystemMemory"); + if (pGetPhysicallyInstalledSystemMemory != NULL) { + ULONGLONG memInKiB = 0; + if ((*pGetPhysicallyInstalledSystemMemory)(&memInKiB)) { + if (memInKiB > 0 && memInKiB <= SIZE_MAX) { + config->physical_memory_in_kib = (size_t)memInKiB; + } + } + } + // Get Windows version + PGetVersionExW pGetVersionExW = (PGetVersionExW)(void (*)(void))GetProcAddress(hDll, "GetVersionExW"); + if (pGetVersionExW != NULL) { + OSVERSIONINFOW version; _mi_memzero_var(version); + version.dwOSVersionInfoSize = sizeof(version); + if ((*pGetVersionExW)(&version)) { + win_major_version = version.dwMajorVersion; + win_minor_version = version.dwMinorVersion; + } + } + FreeLibrary(hDll); + } + // Enable large/huge OS page support? + if (mi_option_is_enabled(mi_option_allow_large_os_pages) || mi_option_is_enabled(mi_option_reserve_huge_os_pages)) { + win_enable_large_os_pages(&config->large_page_size); + } +} + + +//--------------------------------------------- +// Free +//--------------------------------------------- + +int _mi_prim_free(void* addr, size_t size ) { + MI_UNUSED(size); + DWORD errcode = 0; + bool err = (VirtualFree(addr, 0, MEM_RELEASE) == 0); + if (err) { errcode = GetLastError(); } + if (errcode == ERROR_INVALID_ADDRESS) { + // In mi_os_mem_alloc_aligned the fallback path may have returned a pointer inside + // the memory region returned by VirtualAlloc; in that case we need to free using + // the start of the region. + MEMORY_BASIC_INFORMATION info; _mi_memzero_var(info); + VirtualQuery(addr, &info, sizeof(info)); + if (info.AllocationBase < addr && ((uint8_t*)addr - (uint8_t*)info.AllocationBase) < (ptrdiff_t)(4*MI_MiB)) { + errcode = 0; + err = (VirtualFree(info.AllocationBase, 0, MEM_RELEASE) == 0); + if (err) { errcode = GetLastError(); } + } + } + return (int)errcode; +} + + +//--------------------------------------------- +// VirtualAlloc +//--------------------------------------------- + +static void* win_virtual_alloc_prim_once(void* addr, size_t size, size_t try_alignment, DWORD flags) { + #if (MI_INTPTR_SIZE >= 8) + // on 64-bit systems, try to use the virtual address area after 2TiB for 4MiB aligned allocations + if (addr == NULL) { + void* hint = _mi_os_get_aligned_hint(try_alignment,size); + if (hint != NULL) { + void* p = VirtualAlloc(hint, size, flags, PAGE_READWRITE); + if (p != NULL) return p; + _mi_verbose_message("warning: unable to allocate hinted aligned OS memory (%zu bytes, error code: 0x%x, address: %p, alignment: %zu, flags: 0x%x)\n", size, GetLastError(), hint, try_alignment, flags); + // fall through on error + } + } + #endif + // on modern Windows try use VirtualAlloc2 for aligned allocation + if (addr == NULL && try_alignment > win_allocation_granularity && (try_alignment % _mi_os_page_size()) == 0 && pVirtualAlloc2 != NULL) { + MI_MEM_ADDRESS_REQUIREMENTS reqs = { 0, 0, 0 }; + reqs.Alignment = try_alignment; + MI_MEM_EXTENDED_PARAMETER param = { {0, 0}, {0} }; + param.Type.Type = MiMemExtendedParameterAddressRequirements; + param.Arg.Pointer = &reqs; + void* p = (*pVirtualAlloc2)(GetCurrentProcess(), addr, size, flags, PAGE_READWRITE, ¶m, 1); + if (p != NULL) return p; + _mi_warning_message("unable to allocate aligned OS memory (0x%zx bytes, error code: 0x%x, address: %p, alignment: 0x%zx, flags: 0x%x)\n", size, GetLastError(), addr, try_alignment, flags); + // fall through on error + } + // last resort + return VirtualAlloc(addr, size, flags, PAGE_READWRITE); +} + +static bool win_is_out_of_memory_error(DWORD err) { + switch (err) { + case ERROR_COMMITMENT_MINIMUM: + case ERROR_COMMITMENT_LIMIT: + case ERROR_PAGEFILE_QUOTA: + case ERROR_NOT_ENOUGH_MEMORY: + return true; + default: + return false; + } +} + +static void* win_virtual_alloc_prim(void* addr, size_t size, size_t try_alignment, DWORD flags) { + long max_retry_msecs = mi_option_get_clamp(mi_option_retry_on_oom, 0, 2000); // at most 2 seconds + if (max_retry_msecs == 1) { max_retry_msecs = 100; } // if one sets the option to "true" + for (long tries = 1; tries <= 10; tries++) { // try at most 10 times (=2200ms) + void* p = win_virtual_alloc_prim_once(addr, size, try_alignment, flags); + if (p != NULL) { + // success, return the address + return p; + } + else if (max_retry_msecs > 0 && (try_alignment <= 8*MI_MiB) && + (flags&MEM_COMMIT) != 0 && (flags&MEM_LARGE_PAGES) == 0 && + win_is_out_of_memory_error(GetLastError())) { + // if committing regular memory and being out-of-memory, + // keep trying for a bit in case memory frees up after all. See issue #894 + _mi_warning_message("out-of-memory on OS allocation, try again... (attempt %lu, 0x%zx bytes, error code: 0x%x, address: %p, alignment: 0x%zx, flags: 0x%x)\n", tries, size, GetLastError(), addr, try_alignment, flags); + long sleep_msecs = tries*40; // increasing waits + if (sleep_msecs > max_retry_msecs) { sleep_msecs = max_retry_msecs; } + max_retry_msecs -= sleep_msecs; + Sleep(sleep_msecs); + } + else { + // otherwise return with an error + break; + } + } + return NULL; +} + +static void* win_virtual_alloc(void* addr, size_t size, size_t try_alignment, DWORD flags, bool large_only, bool allow_large, bool* is_large) { + mi_assert_internal(!(large_only && !allow_large)); + static _Atomic(size_t) large_page_try_ok; // = 0; + void* p = NULL; + // Try to allocate large OS pages (2MiB) if allowed or required. + if ((large_only || _mi_os_use_large_page(size, try_alignment)) + && allow_large && (flags&MEM_COMMIT)!=0 && (flags&MEM_RESERVE)!=0) { + size_t try_ok = mi_atomic_load_acquire(&large_page_try_ok); + if (!large_only && try_ok > 0) { + // if a large page allocation fails, it seems the calls to VirtualAlloc get very expensive. + // therefore, once a large page allocation failed, we don't try again for `large_page_try_ok` times. + mi_atomic_cas_strong_acq_rel(&large_page_try_ok, &try_ok, try_ok - 1); + } + else { + // large OS pages must always reserve and commit. + *is_large = true; + p = win_virtual_alloc_prim(addr, size, try_alignment, flags | MEM_LARGE_PAGES); + if (large_only) return p; + // fall back to non-large page allocation on error (`p == NULL`). + if (p == NULL) { + mi_atomic_store_release(&large_page_try_ok,10UL); // on error, don't try again for the next N allocations + } + } + } + // Fall back to regular page allocation + if (p == NULL) { + *is_large = ((flags&MEM_LARGE_PAGES) != 0); + p = win_virtual_alloc_prim(addr, size, try_alignment, flags); + } + //if (p == NULL) { _mi_warning_message("unable to allocate OS memory (%zu bytes, error code: 0x%x, address: %p, alignment: %zu, flags: 0x%x, large only: %d, allow large: %d)\n", size, GetLastError(), addr, try_alignment, flags, large_only, allow_large); } + return p; +} + +int _mi_prim_alloc(void* hint_addr, size_t size, size_t try_alignment, bool commit, bool allow_large, bool* is_large, bool* is_zero, void** addr) { + mi_assert_internal(size > 0 && (size % _mi_os_page_size()) == 0); + mi_assert_internal(commit || !allow_large); + mi_assert_internal(try_alignment > 0); + *is_zero = true; + int flags = MEM_RESERVE; + if (commit) { flags |= MEM_COMMIT; } + *addr = win_virtual_alloc(hint_addr, size, try_alignment, flags, false, allow_large, is_large); + return (*addr != NULL ? 0 : (int)GetLastError()); +} + + +//--------------------------------------------- +// Commit/Reset/Protect +//--------------------------------------------- +#ifdef _MSC_VER +#pragma warning(disable:6250) // suppress warning calling VirtualFree without MEM_RELEASE (for decommit) +#endif + +int _mi_prim_commit(void* addr, size_t size, bool* is_zero) { + *is_zero = false; + /* + // zero'ing only happens on an initial commit... but checking upfront seems expensive.. + _MEMORY_BASIC_INFORMATION meminfo; _mi_memzero_var(meminfo); + if (VirtualQuery(addr, &meminfo, size) > 0) { + if ((meminfo.State & MEM_COMMIT) == 0) { + *is_zero = true; + } + } + */ + // commit + void* p = VirtualAlloc(addr, size, MEM_COMMIT, PAGE_READWRITE); + if (p == NULL) return (int)GetLastError(); + return 0; +} + +int _mi_prim_decommit(void* addr, size_t size, bool* needs_recommit) { + BOOL ok = VirtualFree(addr, size, MEM_DECOMMIT); + *needs_recommit = true; // for safety, assume always decommitted even in the case of an error. + return (ok ? 0 : (int)GetLastError()); +} + +int _mi_prim_reset(void* addr, size_t size) { + void* p = VirtualAlloc(addr, size, MEM_RESET, PAGE_READWRITE); + mi_assert_internal(p == addr); + #if 0 + if (p != NULL) { + VirtualUnlock(addr,size); // VirtualUnlock after MEM_RESET removes the memory directly from the working set + } + #endif + return (p != NULL ? 0 : (int)GetLastError()); +} + +int _mi_prim_reuse(void* addr, size_t size) { + MI_UNUSED(addr); MI_UNUSED(size); + return 0; +} + +int _mi_prim_protect(void* addr, size_t size, bool protect) { + DWORD oldprotect = 0; + BOOL ok = VirtualProtect(addr, size, protect ? PAGE_NOACCESS : PAGE_READWRITE, &oldprotect); + return (ok ? 0 : (int)GetLastError()); +} + + +//--------------------------------------------- +// Huge page allocation +//--------------------------------------------- + +static void* _mi_prim_alloc_huge_os_pagesx(void* hint_addr, size_t size, int numa_node) +{ + const DWORD flags = MEM_LARGE_PAGES | MEM_COMMIT | MEM_RESERVE; + + win_enable_large_os_pages(NULL); + + MI_MEM_EXTENDED_PARAMETER params[3] = { {{0,0},{0}},{{0,0},{0}},{{0,0},{0}} }; + // on modern Windows try use NtAllocateVirtualMemoryEx for 1GiB huge pages + static bool mi_huge_pages_available = true; + if (pNtAllocateVirtualMemoryEx != NULL && mi_huge_pages_available) { + params[0].Type.Type = MiMemExtendedParameterAttributeFlags; + params[0].Arg.ULong64 = MI_MEM_EXTENDED_PARAMETER_NONPAGED_HUGE; + ULONG param_count = 1; + if (numa_node >= 0) { + param_count++; + params[1].Type.Type = MiMemExtendedParameterNumaNode; + params[1].Arg.ULong = (unsigned)numa_node; + } + SIZE_T psize = size; + void* base = hint_addr; + LONG err = (*pNtAllocateVirtualMemoryEx)(GetCurrentProcess(), &base, &psize, flags, PAGE_READWRITE, params, param_count); + if (err == 0 && base != NULL) { + return base; + } + else { + // fall back to regular large pages + mi_huge_pages_available = false; // don't try further huge pages + _mi_warning_message("unable to allocate using huge (1GiB) pages, trying large (2MiB) pages instead (status 0x%lx)\n", err); + } + } + // on modern Windows try use VirtualAlloc2 for numa aware large OS page allocation + if (pVirtualAlloc2 != NULL && numa_node >= 0) { + params[0].Type.Type = MiMemExtendedParameterNumaNode; + params[0].Arg.ULong = (unsigned)numa_node; + return (*pVirtualAlloc2)(GetCurrentProcess(), hint_addr, size, flags, PAGE_READWRITE, params, 1); + } + + // otherwise use regular virtual alloc on older windows + return VirtualAlloc(hint_addr, size, flags, PAGE_READWRITE); +} + +int _mi_prim_alloc_huge_os_pages(void* hint_addr, size_t size, int numa_node, bool* is_zero, void** addr) { + *is_zero = true; + *addr = _mi_prim_alloc_huge_os_pagesx(hint_addr,size,numa_node); + return (*addr != NULL ? 0 : (int)GetLastError()); +} + + +//--------------------------------------------- +// Numa nodes +//--------------------------------------------- + +size_t _mi_prim_numa_node(void) { + USHORT numa_node = 0; + if (pGetCurrentProcessorNumberEx != NULL && pGetNumaProcessorNodeEx != NULL) { + // Extended API is supported + MI_PROCESSOR_NUMBER pnum; + (*pGetCurrentProcessorNumberEx)(&pnum); + USHORT nnode = 0; + BOOL ok = (*pGetNumaProcessorNodeEx)(&pnum, &nnode); + if (ok) { numa_node = nnode; } + } + else if (pGetNumaProcessorNode != NULL) { + // Vista or earlier, use older API that is limited to 64 processors. Issue #277 + DWORD pnum = GetCurrentProcessorNumber(); + UCHAR nnode = 0; + BOOL ok = pGetNumaProcessorNode((UCHAR)pnum, &nnode); + if (ok) { numa_node = nnode; } + } + return numa_node; +} + +size_t _mi_prim_numa_node_count(void) { + ULONG numa_max = 0; + if (pGetNumaHighestNodeNumber!=NULL) { + (*pGetNumaHighestNodeNumber)(&numa_max); + } + // find the highest node number that has actual processors assigned to it. Issue #282 + while (numa_max > 0) { + if (pGetNumaNodeProcessorMaskEx != NULL) { + // Extended API is supported + GROUP_AFFINITY affinity; + if ((*pGetNumaNodeProcessorMaskEx)((USHORT)numa_max, &affinity)) { + if (affinity.Mask != 0) break; // found the maximum non-empty node + } + } + else { + // Vista or earlier, use older API that is limited to 64 processors. + ULONGLONG mask; + if (pGetNumaNodeProcessorMask != NULL) { + if ((*pGetNumaNodeProcessorMask)((UCHAR)numa_max, &mask)) { + if (mask != 0) break; // found the maximum non-empty node + } + }; + } + // max node was invalid or had no processor assigned, try again + numa_max--; + } + return ((size_t)numa_max + 1); +} + + +//---------------------------------------------------------------- +// Clock +//---------------------------------------------------------------- + +static mi_msecs_t mi_to_msecs(LARGE_INTEGER t) { + static LARGE_INTEGER mfreq; // = 0 + if (mfreq.QuadPart == 0LL) { + LARGE_INTEGER f; + QueryPerformanceFrequency(&f); + mfreq.QuadPart = f.QuadPart/1000LL; + if (mfreq.QuadPart == 0) mfreq.QuadPart = 1; + } + return (mi_msecs_t)(t.QuadPart / mfreq.QuadPart); +} + +mi_msecs_t _mi_prim_clock_now(void) { + LARGE_INTEGER t; + QueryPerformanceCounter(&t); + return mi_to_msecs(t); +} + + +//---------------------------------------------------------------- +// Process Info +//---------------------------------------------------------------- + +#include + +static mi_msecs_t filetime_msecs(const FILETIME* ftime) { + ULARGE_INTEGER i; + i.LowPart = ftime->dwLowDateTime; + i.HighPart = ftime->dwHighDateTime; + mi_msecs_t msecs = (i.QuadPart / 10000); // FILETIME is in 100 nano seconds + return msecs; +} + +typedef BOOL (WINAPI *PGetProcessMemoryInfo)(HANDLE, PPROCESS_MEMORY_COUNTERS, DWORD); +static PGetProcessMemoryInfo pGetProcessMemoryInfo = NULL; + +void _mi_prim_process_info(mi_process_info_t* pinfo) +{ + FILETIME ct; + FILETIME ut; + FILETIME st; + FILETIME et; + GetProcessTimes(GetCurrentProcess(), &ct, &et, &st, &ut); + pinfo->utime = filetime_msecs(&ut); + pinfo->stime = filetime_msecs(&st); + + // load psapi on demand + if (pGetProcessMemoryInfo == NULL) { + HINSTANCE hDll = LoadLibrary(TEXT("psapi.dll")); + if (hDll != NULL) { + pGetProcessMemoryInfo = (PGetProcessMemoryInfo)(void (*)(void))GetProcAddress(hDll, "GetProcessMemoryInfo"); + } + } + + // get process info + PROCESS_MEMORY_COUNTERS info; _mi_memzero_var(info); + if (pGetProcessMemoryInfo != NULL) { + pGetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info)); + } + pinfo->current_rss = (size_t)info.WorkingSetSize; + pinfo->peak_rss = (size_t)info.PeakWorkingSetSize; + pinfo->current_commit = (size_t)info.PagefileUsage; + pinfo->peak_commit = (size_t)info.PeakPagefileUsage; + pinfo->page_faults = (size_t)info.PageFaultCount; +} + +//---------------------------------------------------------------- +// Output +//---------------------------------------------------------------- + +void _mi_prim_out_stderr( const char* msg ) +{ + // on windows with redirection, the C runtime cannot handle locale dependent output + // after the main thread closes so we use direct console output. + if (!_mi_preloading()) { + // _cputs(msg); // _cputs cannot be used as it aborts when failing to lock the console + static HANDLE hcon = INVALID_HANDLE_VALUE; + static bool hconIsConsole = false; + if (hcon == INVALID_HANDLE_VALUE) { + hcon = GetStdHandle(STD_ERROR_HANDLE); + #ifdef MI_HAS_CONSOLE_IO + CONSOLE_SCREEN_BUFFER_INFO sbi; + hconIsConsole = ((hcon != INVALID_HANDLE_VALUE) && GetConsoleScreenBufferInfo(hcon, &sbi)); + #endif + } + const size_t len = _mi_strlen(msg); + if (len > 0 && len < UINT32_MAX) { + DWORD written = 0; + if (hconIsConsole) { + #ifdef MI_HAS_CONSOLE_IO + WriteConsoleA(hcon, msg, (DWORD)len, &written, NULL); + #endif + } + else if (hcon != INVALID_HANDLE_VALUE) { + // use direct write if stderr was redirected + WriteFile(hcon, msg, (DWORD)len, &written, NULL); + } + else { + // finally fall back to fputs after all + fputs(msg, stderr); + } + } + } +} + + +//---------------------------------------------------------------- +// Environment +//---------------------------------------------------------------- + +// On Windows use GetEnvironmentVariable instead of getenv to work +// reliably even when this is invoked before the C runtime is initialized. +// i.e. when `_mi_preloading() == true`. +// Note: on windows, environment names are not case sensitive. +bool _mi_prim_getenv(const char* name, char* result, size_t result_size) { + result[0] = 0; + size_t len = GetEnvironmentVariableA(name, result, (DWORD)result_size); + return (len > 0 && len < result_size); +} + + +//---------------------------------------------------------------- +// Random +//---------------------------------------------------------------- + +#if defined(MI_USE_RTLGENRANDOM) // || defined(__cplusplus) +// We prefer to use BCryptGenRandom instead of (the unofficial) RtlGenRandom but when using +// dynamic overriding, we observed it can raise an exception when compiled with C++, and +// sometimes deadlocks when also running under the VS debugger. +// In contrast, issue #623 implies that on Windows Server 2019 we need to use BCryptGenRandom. +// To be continued.. +#pragma comment (lib,"advapi32.lib") +#define RtlGenRandom SystemFunction036 +mi_decl_externc BOOLEAN NTAPI RtlGenRandom(PVOID RandomBuffer, ULONG RandomBufferLength); + +bool _mi_prim_random_buf(void* buf, size_t buf_len) { + return (RtlGenRandom(buf, (ULONG)buf_len) != 0); +} + +#else + +#ifndef BCRYPT_USE_SYSTEM_PREFERRED_RNG +#define BCRYPT_USE_SYSTEM_PREFERRED_RNG 0x00000002 +#endif + +typedef LONG (NTAPI *PBCryptGenRandom)(HANDLE, PUCHAR, ULONG, ULONG); +static PBCryptGenRandom pBCryptGenRandom = NULL; + +bool _mi_prim_random_buf(void* buf, size_t buf_len) { + if (pBCryptGenRandom == NULL) { + HINSTANCE hDll = LoadLibrary(TEXT("bcrypt.dll")); + if (hDll != NULL) { + pBCryptGenRandom = (PBCryptGenRandom)(void (*)(void))GetProcAddress(hDll, "BCryptGenRandom"); + } + if (pBCryptGenRandom == NULL) return false; + } + return (pBCryptGenRandom(NULL, (PUCHAR)buf, (ULONG)buf_len, BCRYPT_USE_SYSTEM_PREFERRED_RNG) >= 0); +} + +#endif // MI_USE_RTLGENRANDOM + + + +//---------------------------------------------------------------- +// Process & Thread Init/Done +//---------------------------------------------------------------- + +#if MI_WIN_USE_FIXED_TLS==1 +mi_decl_cache_align size_t _mi_win_tls_offset = 0; +#endif + +//static void mi_debug_out(const char* s) { +// HANDLE h = GetStdHandle(STD_ERROR_HANDLE); +// WriteConsole(h, s, (DWORD)_mi_strlen(s), NULL, NULL); +//} + +static void mi_win_tls_init(DWORD reason) { + if (reason==DLL_PROCESS_ATTACH || reason==DLL_THREAD_ATTACH) { + #if MI_WIN_USE_FIXED_TLS==1 // we must allocate a TLS slot dynamically + if (_mi_win_tls_offset == 0 && reason == DLL_PROCESS_ATTACH) { + const DWORD tls_slot = TlsAlloc(); // usually returns slot 1 + if (tls_slot == TLS_OUT_OF_INDEXES) { + _mi_error_message(EFAULT, "unable to allocate the a TLS slot (rebuild without MI_WIN_USE_FIXED_TLS?)\n"); + } + _mi_win_tls_offset = (size_t)tls_slot * sizeof(void*); + } + #endif + #if MI_HAS_TLS_SLOT >= 2 // we must initialize the TLS slot before any allocation + if (mi_prim_get_default_heap() == NULL) { + _mi_heap_set_default_direct((mi_heap_t*)&_mi_heap_empty); + #if MI_DEBUG && MI_WIN_USE_FIXED_TLS==1 + void* const p = TlsGetValue((DWORD)(_mi_win_tls_offset / sizeof(void*))); + mi_assert_internal(p == (void*)&_mi_heap_empty); + #endif + } + #endif + } +} + +static void NTAPI mi_win_main(PVOID module, DWORD reason, LPVOID reserved) { + MI_UNUSED(reserved); + MI_UNUSED(module); + mi_win_tls_init(reason); + if (reason==DLL_PROCESS_ATTACH) { + _mi_auto_process_init(); + } + else if (reason==DLL_PROCESS_DETACH) { + _mi_auto_process_done(); + } + else if (reason==DLL_THREAD_DETACH && !_mi_is_redirected()) { + _mi_thread_done(NULL); + } +} + + +#if defined(MI_SHARED_LIB) + #define MI_PRIM_HAS_PROCESS_ATTACH 1 + + // Windows DLL: easy to hook into process_init and thread_done + BOOL WINAPI DllMain(HINSTANCE inst, DWORD reason, LPVOID reserved) { + mi_win_main((PVOID)inst,reason,reserved); + return TRUE; + } + + // nothing to do since `_mi_thread_done` is handled through the DLL_THREAD_DETACH event. + void _mi_prim_thread_init_auto_done(void) { } + void _mi_prim_thread_done_auto_done(void) { } + void _mi_prim_thread_associate_default_heap(mi_heap_t* heap) { + MI_UNUSED(heap); + } + +#elif !defined(MI_WIN_USE_FLS) + #define MI_PRIM_HAS_PROCESS_ATTACH 1 + + static void NTAPI mi_win_main_attach(PVOID module, DWORD reason, LPVOID reserved) { + if (reason == DLL_PROCESS_ATTACH || reason == DLL_THREAD_ATTACH) { + mi_win_main(module, reason, reserved); + } + } + static void NTAPI mi_win_main_detach(PVOID module, DWORD reason, LPVOID reserved) { + if (reason == DLL_PROCESS_DETACH || reason == DLL_THREAD_DETACH) { + mi_win_main(module, reason, reserved); + } + } + + // Set up TLS callbacks in a statically linked library by using special data sections. + // See + // We use 2 entries to ensure we call attach events before constructors + // are called, and detach events after destructors are called. + #if defined(__cplusplus) + extern "C" { + #endif + + #if defined(_WIN64) + #pragma comment(linker, "/INCLUDE:_tls_used") + #pragma comment(linker, "/INCLUDE:_mi_tls_callback_pre") + #pragma comment(linker, "/INCLUDE:_mi_tls_callback_post") + #pragma const_seg(".CRT$XLB") + extern const PIMAGE_TLS_CALLBACK _mi_tls_callback_pre[]; + const PIMAGE_TLS_CALLBACK _mi_tls_callback_pre[] = { &mi_win_main_attach }; + #pragma const_seg() + #pragma const_seg(".CRT$XLY") + extern const PIMAGE_TLS_CALLBACK _mi_tls_callback_post[]; + const PIMAGE_TLS_CALLBACK _mi_tls_callback_post[] = { &mi_win_main_detach }; + #pragma const_seg() + #else + #pragma comment(linker, "/INCLUDE:__tls_used") + #pragma comment(linker, "/INCLUDE:__mi_tls_callback_pre") + #pragma comment(linker, "/INCLUDE:__mi_tls_callback_post") + #pragma data_seg(".CRT$XLB") + PIMAGE_TLS_CALLBACK _mi_tls_callback_pre[] = { &mi_win_main_attach }; + #pragma data_seg() + #pragma data_seg(".CRT$XLY") + PIMAGE_TLS_CALLBACK _mi_tls_callback_post[] = { &mi_win_main_detach }; + #pragma data_seg() + #endif + + #if defined(__cplusplus) + } + #endif + + // nothing to do since `_mi_thread_done` is handled through the DLL_THREAD_DETACH event. + void _mi_prim_thread_init_auto_done(void) { } + void _mi_prim_thread_done_auto_done(void) { } + void _mi_prim_thread_associate_default_heap(mi_heap_t* heap) { + MI_UNUSED(heap); + } + +#else // deprecated: statically linked, use fiber api + + #if defined(_MSC_VER) // on clang/gcc use the constructor attribute (in `src/prim/prim.c`) + // MSVC: use data section magic for static libraries + // See + #define MI_PRIM_HAS_PROCESS_ATTACH 1 + + static int mi_process_attach(void) { + mi_win_main(NULL,DLL_PROCESS_ATTACH,NULL); + atexit(&_mi_auto_process_done); + return 0; + } + typedef int(*mi_crt_callback_t)(void); + #if defined(_WIN64) + #pragma comment(linker, "/INCLUDE:_mi_tls_callback") + #pragma section(".CRT$XIU", long, read) + #else + #pragma comment(linker, "/INCLUDE:__mi_tls_callback") + #endif + #pragma data_seg(".CRT$XIU") + mi_decl_externc mi_crt_callback_t _mi_tls_callback[] = { &mi_process_attach }; + #pragma data_seg() + #endif + + // use the fiber api for calling `_mi_thread_done`. + #include + #if (_WIN32_WINNT < 0x600) // before Windows Vista + WINBASEAPI DWORD WINAPI FlsAlloc( _In_opt_ PFLS_CALLBACK_FUNCTION lpCallback ); + WINBASEAPI PVOID WINAPI FlsGetValue( _In_ DWORD dwFlsIndex ); + WINBASEAPI BOOL WINAPI FlsSetValue( _In_ DWORD dwFlsIndex, _In_opt_ PVOID lpFlsData ); + WINBASEAPI BOOL WINAPI FlsFree(_In_ DWORD dwFlsIndex); + #endif + + static DWORD mi_fls_key = (DWORD)(-1); + + static void NTAPI mi_fls_done(PVOID value) { + mi_heap_t* heap = (mi_heap_t*)value; + if (heap != NULL) { + _mi_thread_done(heap); + FlsSetValue(mi_fls_key, NULL); // prevent recursion as _mi_thread_done may set it back to the main heap, issue #672 + } + } + + void _mi_prim_thread_init_auto_done(void) { + mi_fls_key = FlsAlloc(&mi_fls_done); + } + + void _mi_prim_thread_done_auto_done(void) { + // call thread-done on all threads (except the main thread) to prevent + // dangling callback pointer if statically linked with a DLL; Issue #208 + FlsFree(mi_fls_key); + } + + void _mi_prim_thread_associate_default_heap(mi_heap_t* heap) { + mi_assert_internal(mi_fls_key != (DWORD)(-1)); + FlsSetValue(mi_fls_key, heap); + } +#endif + +// ---------------------------------------------------- +// Communicate with the redirection module on Windows +// ---------------------------------------------------- +#if defined(MI_SHARED_LIB) && !defined(MI_WIN_NOREDIRECT) + #define MI_PRIM_HAS_ALLOCATOR_INIT 1 + + static bool mi_redirected = false; // true if malloc redirects to mi_malloc + + bool _mi_is_redirected(void) { + return mi_redirected; + } + + #ifdef __cplusplus + extern "C" { + #endif + mi_decl_export void _mi_redirect_entry(DWORD reason) { + // called on redirection; careful as this may be called before DllMain + mi_win_tls_init(reason); + if (reason == DLL_PROCESS_ATTACH) { + mi_redirected = true; + } + else if (reason == DLL_PROCESS_DETACH) { + mi_redirected = false; + } + else if (reason == DLL_THREAD_DETACH) { + _mi_thread_done(NULL); + } + } + __declspec(dllimport) bool mi_cdecl mi_allocator_init(const char** message); + __declspec(dllimport) void mi_cdecl mi_allocator_done(void); + #ifdef __cplusplus + } + #endif + bool _mi_allocator_init(const char** message) { + return mi_allocator_init(message); + } + void _mi_allocator_done(void) { + mi_allocator_done(); + } +#endif + +bool _mi_prim_thread_is_in_threadpool(void) { + #if (MI_ARCH_X64 || MI_ARCH_X86 || MI_ARCH_ARM64) + if (win_major_version >= 6) { + // check if this thread belongs to a windows threadpool + // see: + struct _TEB* const teb = NtCurrentTeb(); + void* const pool_data = *((void**)((uint8_t*)teb + (MI_SIZE_BITS == 32 ? 0x0F90 : 0x1778))); + return (pool_data != NULL); + } + #endif + return false; +} diff --git a/src/dashbls/depends/mimalloc/src/prim/windows/readme.md b/src/dashbls/depends/mimalloc/src/prim/windows/readme.md new file mode 100644 index 000000000000..217c3d174db4 --- /dev/null +++ b/src/dashbls/depends/mimalloc/src/prim/windows/readme.md @@ -0,0 +1,17 @@ +## Primitives: + +- `prim.c` contains Windows primitives for OS allocation. + +## Event Tracing for Windows (ETW) + +- `etw.h` is generated from `etw.man` which contains the manifest for mimalloc events. + (100 is an allocation, 101 is for a free) + +- `etw-mimalloc.wprp` is a profile for the Windows Performance Recorder (WPR). + In an admin prompt, you can use: + ``` + > wpr -start src\prim\windows\etw-mimalloc.wprp -filemode + > + > wpr -stop test.etl + ``` + and then open `test.etl` in the Windows Performance Analyzer (WPA). \ No newline at end of file diff --git a/src/dashbls/depends/mimalloc/src/random.c b/src/dashbls/depends/mimalloc/src/random.c index a5f5e6b829c3..990e4894f3be 100644 --- a/src/dashbls/depends/mimalloc/src/random.c +++ b/src/dashbls/depends/mimalloc/src/random.c @@ -4,14 +4,9 @@ This is free software; you can redistribute it and/or modify it under the terms of the MIT license. A copy of the license can be found in the file "LICENSE" at the root of this distribution. -----------------------------------------------------------------------------*/ -#ifndef _DEFAULT_SOURCE -#define _DEFAULT_SOURCE // for syscall() on Linux -#endif - #include "mimalloc.h" -#include "mimalloc-internal.h" - -#include // memset +#include "mimalloc/internal.h" +#include "mimalloc/prim.h" // _mi_prim_random_buf /* ---------------------------------------------------------------------------- We use our own PRNG to keep predictable performance of random number generation @@ -37,15 +32,11 @@ The implementation uses regular C code which compiles very well on modern compil (gcc x64 has no register spills, and clang 6+ uses SSE instructions) -----------------------------------------------------------------------------*/ -static inline uint32_t rotl(uint32_t x, uint32_t shift) { - return (x << shift) | (x >> (32 - shift)); -} - static inline void qround(uint32_t x[16], size_t a, size_t b, size_t c, size_t d) { - x[a] += x[b]; x[d] = rotl(x[d] ^ x[a], 16); - x[c] += x[d]; x[b] = rotl(x[b] ^ x[c], 12); - x[a] += x[b]; x[d] = rotl(x[d] ^ x[a], 8); - x[c] += x[d]; x[b] = rotl(x[b] ^ x[c], 7); + x[a] += x[b]; x[d] = mi_rotl32(x[d] ^ x[a], 16); + x[c] += x[d]; x[b] = mi_rotl32(x[b] ^ x[c], 12); + x[a] += x[b]; x[d] = mi_rotl32(x[d] ^ x[a], 8); + x[c] += x[d]; x[b] = mi_rotl32(x[b] ^ x[c], 7); } static void chacha_block(mi_random_ctx_t* ctx) @@ -103,7 +94,7 @@ static void chacha_init(mi_random_ctx_t* ctx, const uint8_t key[32], uint64_t no // since we only use chacha for randomness (and not encryption) we // do not _need_ to read 32-bit values as little endian but we do anyways // just for being compatible :-) - memset(ctx, 0, sizeof(*ctx)); + _mi_memzero(ctx, sizeof(*ctx)); for (size_t i = 0; i < 4; i++) { const uint8_t* sigma = (uint8_t*)"expand 32-byte k"; ctx->input[i] = read32(sigma,i); @@ -118,7 +109,7 @@ static void chacha_init(mi_random_ctx_t* ctx, const uint8_t key[32], uint64_t no } static void chacha_split(mi_random_ctx_t* ctx, uint64_t nonce, mi_random_ctx_t* ctx_new) { - memset(ctx_new, 0, sizeof(*ctx_new)); + _mi_memzero(ctx_new, sizeof(*ctx_new)); _mi_memcpy(ctx_new->input, ctx->input, sizeof(ctx_new->input)); ctx_new->input[12] = 0; ctx_new->input[13] = 0; @@ -147,179 +138,72 @@ void _mi_random_split(mi_random_ctx_t* ctx, mi_random_ctx_t* ctx_new) { uintptr_t _mi_random_next(mi_random_ctx_t* ctx) { mi_assert_internal(mi_random_is_initialized(ctx)); - #if MI_INTPTR_SIZE <= 4 - return chacha_next32(ctx); - #elif MI_INTPTR_SIZE == 8 - return (((uintptr_t)chacha_next32(ctx) << 32) | chacha_next32(ctx)); - #else - # error "define mi_random_next for this platform" - #endif + uintptr_t r; + do { + #if MI_INTPTR_SIZE <= 4 + r = chacha_next32(ctx); + #elif MI_INTPTR_SIZE == 8 + r = (((uintptr_t)chacha_next32(ctx) << 32) | chacha_next32(ctx)); + #else + # error "define mi_random_next for this platform" + #endif + } while (r==0); + return r; } /* ---------------------------------------------------------------------------- -To initialize a fresh random context we rely on the OS: -- Windows : BCryptGenRandom (or RtlGenRandom) -- macOS : CCRandomGenerateBytes, arc4random_buf -- bsd,wasi : arc4random_buf -- Linux : getrandom,/dev/urandom +To initialize a fresh random context. If we cannot get good randomness, we fall back to weak randomness based on a timer and ASLR. -----------------------------------------------------------------------------*/ -#if defined(_WIN32) - -#if defined(MI_USE_RTLGENRANDOM) || defined(__cplusplus) -// We prefer to use BCryptGenRandom instead of (the unofficial) RtlGenRandom but when using -// dynamic overriding, we observed it can raise an exception when compiled with C++, and -// sometimes deadlocks when also running under the VS debugger. -// In contrast, issue #623 implies that on Windows Server 2019 we need to use BCryptGenRandom. -// To be continued.. -#pragma comment (lib,"advapi32.lib") -#define RtlGenRandom SystemFunction036 -#ifdef __cplusplus -extern "C" { -#endif -BOOLEAN NTAPI RtlGenRandom(PVOID RandomBuffer, ULONG RandomBufferLength); -#ifdef __cplusplus -} -#endif -static bool os_random_buf(void* buf, size_t buf_len) { - return (RtlGenRandom(buf, (ULONG)buf_len) != 0); -} -#else -#pragma comment (lib,"bcrypt.lib") -#include -static bool os_random_buf(void* buf, size_t buf_len) { - return (BCryptGenRandom(NULL, (PUCHAR)buf, (ULONG)buf_len, BCRYPT_USE_SYSTEM_PREFERRED_RNG) >= 0); -} -#endif - -#elif defined(__APPLE__) -#include -#if defined(MAC_OS_X_VERSION_10_10) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_10 -#include -#include -#endif -static bool os_random_buf(void* buf, size_t buf_len) { - #if defined(MAC_OS_X_VERSION_10_15) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_15 - // We prefere CCRandomGenerateBytes as it returns an error code while arc4random_buf - // may fail silently on macOS. See PR #390, and - return (CCRandomGenerateBytes(buf, buf_len) == kCCSuccess); - #else - // fall back on older macOS - arc4random_buf(buf, buf_len); - return true; - #endif -} - -#elif defined(__ANDROID__) || defined(__DragonFly__) || \ - defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || \ - defined(__sun) // todo: what to use with __wasi__? -#include -static bool os_random_buf(void* buf, size_t buf_len) { - arc4random_buf(buf, buf_len); - return true; -} -#elif defined(__linux__) || defined(__HAIKU__) -#if defined(__linux__) -#include -#endif -#include -#include -#include -#include -#include -static bool os_random_buf(void* buf, size_t buf_len) { - // Modern Linux provides `getrandom` but different distributions either use `sys/random.h` or `linux/random.h` - // and for the latter the actual `getrandom` call is not always defined. - // (see ) - // We therefore use a syscall directly and fall back dynamically to /dev/urandom when needed. -#ifdef SYS_getrandom - #ifndef GRND_NONBLOCK - #define GRND_NONBLOCK (1) - #endif - static _Atomic(uintptr_t) no_getrandom; // = 0 - if (mi_atomic_load_acquire(&no_getrandom)==0) { - ssize_t ret = syscall(SYS_getrandom, buf, buf_len, GRND_NONBLOCK); - if (ret >= 0) return (buf_len == (size_t)ret); - if (errno != ENOSYS) return false; - mi_atomic_store_release(&no_getrandom, 1UL); // don't call again, and fall back to /dev/urandom - } -#endif - int flags = O_RDONLY; - #if defined(O_CLOEXEC) - flags |= O_CLOEXEC; - #endif - int fd = open("/dev/urandom", flags, 0); - if (fd < 0) return false; - size_t count = 0; - while(count < buf_len) { - ssize_t ret = read(fd, (char*)buf + count, buf_len - count); - if (ret<=0) { - if (errno!=EAGAIN && errno!=EINTR) break; - } - else { - count += ret; - } - } - close(fd); - return (count==buf_len); -} -#else -static bool os_random_buf(void* buf, size_t buf_len) { - return false; -} -#endif - -#if defined(_WIN32) -#include -#elif defined(__APPLE__) -#include -#else -#include -#endif - uintptr_t _mi_os_random_weak(uintptr_t extra_seed) { uintptr_t x = (uintptr_t)&_mi_os_random_weak ^ extra_seed; // ASLR makes the address random - - #if defined(_WIN32) - LARGE_INTEGER pcount; - QueryPerformanceCounter(&pcount); - x ^= (uintptr_t)(pcount.QuadPart); - #elif defined(__APPLE__) - x ^= (uintptr_t)mach_absolute_time(); - #else - struct timespec time; - clock_gettime(CLOCK_MONOTONIC, &time); - x ^= (uintptr_t)time.tv_sec; - x ^= (uintptr_t)time.tv_nsec; - #endif + x ^= _mi_prim_clock_now(); // and do a few randomization steps uintptr_t max = ((x ^ (x >> 17)) & 0x0F) + 1; - for (uintptr_t i = 0; i < max; i++) { + for (uintptr_t i = 0; i < max || x==0; i++, x++) { x = _mi_random_shuffle(x); } mi_assert_internal(x != 0); return x; } -void _mi_random_init(mi_random_ctx_t* ctx) { +static void mi_random_init_ex(mi_random_ctx_t* ctx, bool use_weak) { uint8_t key[32]; - if (!os_random_buf(key, sizeof(key))) { + if (use_weak || !_mi_prim_random_buf(key, sizeof(key))) { // if we fail to get random data from the OS, we fall back to a // weak random source based on the current time #if !defined(__wasi__) - _mi_warning_message("unable to use secure randomness\n"); + if (!use_weak) { _mi_warning_message("unable to use secure randomness\n"); } #endif uintptr_t x = _mi_os_random_weak(0); - for (size_t i = 0; i < 8; i++) { // key is eight 32-bit words. + for (size_t i = 0; i < 8; i++, x++) { // key is eight 32-bit words. x = _mi_random_shuffle(x); ((uint32_t*)key)[i] = (uint32_t)x; } + ctx->weak = true; + } + else { + ctx->weak = false; } chacha_init(ctx, key, (uintptr_t)ctx /*nonce*/ ); } +void _mi_random_init(mi_random_ctx_t* ctx) { + mi_random_init_ex(ctx, false); +} + +void _mi_random_init_weak(mi_random_ctx_t * ctx) { + mi_random_init_ex(ctx, true); +} + +void _mi_random_reinit_if_weak(mi_random_ctx_t * ctx) { + if (ctx->weak) { + _mi_random_init(ctx); + } +} + /* -------------------------------------------------------- test vectors from ----------------------------------------------------------- */ diff --git a/src/dashbls/depends/mimalloc/src/region.c b/src/dashbls/depends/mimalloc/src/region.c deleted file mode 100644 index 8b04387dfe08..000000000000 --- a/src/dashbls/depends/mimalloc/src/region.c +++ /dev/null @@ -1,506 +0,0 @@ -/* ---------------------------------------------------------------------------- -Copyright (c) 2019-2020, Microsoft Research, Daan Leijen -This is free software; you can redistribute it and/or modify it under the -terms of the MIT license. A copy of the license can be found in the file -"LICENSE" at the root of this distribution. ------------------------------------------------------------------------------*/ - -/* ---------------------------------------------------------------------------- -This implements a layer between the raw OS memory (VirtualAlloc/mmap/sbrk/..) -and the segment and huge object allocation by mimalloc. There may be multiple -implementations of this (one could be the identity going directly to the OS, -another could be a simple cache etc), but the current one uses large "regions". -In contrast to the rest of mimalloc, the "regions" are shared between threads and -need to be accessed using atomic operations. -We need this memory layer between the raw OS calls because of: -1. on `sbrk` like systems (like WebAssembly) we need our own memory maps in order - to reuse memory effectively. -2. It turns out that for large objects, between 1MiB and 32MiB (?), the cost of - an OS allocation/free is still (much) too expensive relative to the accesses - in that object :-( (`malloc-large` tests this). This means we need a cheaper - way to reuse memory. -3. This layer allows for NUMA aware allocation. - -Possible issues: -- (2) can potentially be addressed too with a small cache per thread which is much - simpler. Generally though that requires shrinking of huge pages, and may overuse - memory per thread. (and is not compatible with `sbrk`). -- Since the current regions are per-process, we need atomic operations to - claim blocks which may be contended -- In the worst case, we need to search the whole region map (16KiB for 256GiB) - linearly. At what point will direct OS calls be faster? Is there a way to - do this better without adding too much complexity? ------------------------------------------------------------------------------*/ -#include "mimalloc.h" -#include "mimalloc-internal.h" -#include "mimalloc-atomic.h" - -#include // memset - -#include "bitmap.h" - -// Internal raw OS interface -size_t _mi_os_large_page_size(void); -bool _mi_os_protect(void* addr, size_t size); -bool _mi_os_unprotect(void* addr, size_t size); -bool _mi_os_commit(void* p, size_t size, bool* is_zero, mi_stats_t* stats); -bool _mi_os_decommit(void* p, size_t size, mi_stats_t* stats); -bool _mi_os_reset(void* p, size_t size, mi_stats_t* stats); -bool _mi_os_unreset(void* p, size_t size, bool* is_zero, mi_stats_t* stats); - -// arena.c -mi_arena_id_t _mi_arena_id_none(void); -void _mi_arena_free(void* p, size_t size, size_t memid, bool all_committed, mi_stats_t* stats); -void* _mi_arena_alloc(size_t size, bool* commit, bool* large, bool* is_pinned, bool* is_zero, mi_arena_id_t req_arena_id, size_t* memid, mi_os_tld_t* tld); -void* _mi_arena_alloc_aligned(size_t size, size_t alignment, bool* commit, bool* large, bool* is_pinned, bool* is_zero, mi_arena_id_t req_arena_id, size_t* memid, mi_os_tld_t* tld); - - - -// Constants -#if (MI_INTPTR_SIZE==8) -#define MI_HEAP_REGION_MAX_SIZE (256 * MI_GiB) // 64KiB for the region map -#elif (MI_INTPTR_SIZE==4) -#define MI_HEAP_REGION_MAX_SIZE (3 * MI_GiB) // ~ KiB for the region map -#else -#error "define the maximum heap space allowed for regions on this platform" -#endif - -#define MI_SEGMENT_ALIGN MI_SEGMENT_SIZE - -#define MI_REGION_MAX_BLOCKS MI_BITMAP_FIELD_BITS -#define MI_REGION_SIZE (MI_SEGMENT_SIZE * MI_BITMAP_FIELD_BITS) // 256MiB (64MiB on 32 bits) -#define MI_REGION_MAX (MI_HEAP_REGION_MAX_SIZE / MI_REGION_SIZE) // 1024 (48 on 32 bits) -#define MI_REGION_MAX_OBJ_BLOCKS (MI_REGION_MAX_BLOCKS/4) // 64MiB -#define MI_REGION_MAX_OBJ_SIZE (MI_REGION_MAX_OBJ_BLOCKS*MI_SEGMENT_SIZE) - -// Region info -typedef union mi_region_info_u { - size_t value; - struct { - bool valid; // initialized? - bool is_large:1; // allocated in fixed large/huge OS pages - bool is_pinned:1; // pinned memory cannot be decommitted - short numa_node; // the associated NUMA node (where -1 means no associated node) - } x; -} mi_region_info_t; - - -// A region owns a chunk of REGION_SIZE (256MiB) (virtual) memory with -// a bit map with one bit per MI_SEGMENT_SIZE (4MiB) block. -typedef struct mem_region_s { - _Atomic(size_t) info; // mi_region_info_t.value - _Atomic(void*) start; // start of the memory area - mi_bitmap_field_t in_use; // bit per in-use block - mi_bitmap_field_t dirty; // track if non-zero per block - mi_bitmap_field_t commit; // track if committed per block - mi_bitmap_field_t reset; // track if reset per block - _Atomic(size_t) arena_memid; // if allocated from a (huge page) arena - _Atomic(size_t) padding; // round to 8 fields (needs to be atomic for msvc, see issue #508) -} mem_region_t; - -// The region map -static mem_region_t regions[MI_REGION_MAX]; - -// Allocated regions -static _Atomic(size_t) regions_count; // = 0; - - -/* ---------------------------------------------------------------------------- -Utility functions ------------------------------------------------------------------------------*/ - -// Blocks (of 4MiB) needed for the given size. -static size_t mi_region_block_count(size_t size) { - return _mi_divide_up(size, MI_SEGMENT_SIZE); -} - -/* -// Return a rounded commit/reset size such that we don't fragment large OS pages into small ones. -static size_t mi_good_commit_size(size_t size) { - if (size > (SIZE_MAX - _mi_os_large_page_size())) return size; - return _mi_align_up(size, _mi_os_large_page_size()); -} -*/ - -// Return if a pointer points into a region reserved by us. -mi_decl_nodiscard bool mi_is_in_heap_region(const void* p) mi_attr_noexcept { - if (p==NULL) return false; - size_t count = mi_atomic_load_relaxed(®ions_count); - for (size_t i = 0; i < count; i++) { - uint8_t* start = (uint8_t*)mi_atomic_load_ptr_relaxed(uint8_t, ®ions[i].start); - if (start != NULL && (uint8_t*)p >= start && (uint8_t*)p < start + MI_REGION_SIZE) return true; - } - return false; -} - - -static void* mi_region_blocks_start(const mem_region_t* region, mi_bitmap_index_t bit_idx) { - uint8_t* start = (uint8_t*)mi_atomic_load_ptr_acquire(uint8_t, &((mem_region_t*)region)->start); - mi_assert_internal(start != NULL); - return (start + (bit_idx * MI_SEGMENT_SIZE)); -} - -static size_t mi_memid_create(mem_region_t* region, mi_bitmap_index_t bit_idx) { - mi_assert_internal(bit_idx < MI_BITMAP_FIELD_BITS); - size_t idx = region - regions; - mi_assert_internal(®ions[idx] == region); - return (idx*MI_BITMAP_FIELD_BITS + bit_idx)<<1; -} - -static size_t mi_memid_create_from_arena(size_t arena_memid) { - return (arena_memid << 1) | 1; -} - - -static bool mi_memid_is_arena(size_t id, mem_region_t** region, mi_bitmap_index_t* bit_idx, size_t* arena_memid) { - if ((id&1)==1) { - if (arena_memid != NULL) *arena_memid = (id>>1); - return true; - } - else { - size_t idx = (id >> 1) / MI_BITMAP_FIELD_BITS; - *bit_idx = (mi_bitmap_index_t)(id>>1) % MI_BITMAP_FIELD_BITS; - *region = ®ions[idx]; - return false; - } -} - - -/* ---------------------------------------------------------------------------- - Allocate a region is allocated from the OS (or an arena) ------------------------------------------------------------------------------*/ - -static bool mi_region_try_alloc_os(size_t blocks, bool commit, bool allow_large, mem_region_t** region, mi_bitmap_index_t* bit_idx, mi_os_tld_t* tld) -{ - // not out of regions yet? - if (mi_atomic_load_relaxed(®ions_count) >= MI_REGION_MAX - 1) return false; - - // try to allocate a fresh region from the OS - bool region_commit = (commit && mi_option_is_enabled(mi_option_eager_region_commit)); - bool region_large = (commit && allow_large); - bool is_zero = false; - bool is_pinned = false; - size_t arena_memid = 0; - void* const start = _mi_arena_alloc_aligned(MI_REGION_SIZE, MI_SEGMENT_ALIGN, ®ion_commit, ®ion_large, &is_pinned, &is_zero, _mi_arena_id_none(), & arena_memid, tld); - if (start == NULL) return false; - mi_assert_internal(!(region_large && !allow_large)); - mi_assert_internal(!region_large || region_commit); - - // claim a fresh slot - const size_t idx = mi_atomic_increment_acq_rel(®ions_count); - if (idx >= MI_REGION_MAX) { - mi_atomic_decrement_acq_rel(®ions_count); - _mi_arena_free(start, MI_REGION_SIZE, arena_memid, region_commit, tld->stats); - _mi_warning_message("maximum regions used: %zu GiB (perhaps recompile with a larger setting for MI_HEAP_REGION_MAX_SIZE)", _mi_divide_up(MI_HEAP_REGION_MAX_SIZE, MI_GiB)); - return false; - } - - // allocated, initialize and claim the initial blocks - mem_region_t* r = ®ions[idx]; - r->arena_memid = arena_memid; - mi_atomic_store_release(&r->in_use, (size_t)0); - mi_atomic_store_release(&r->dirty, (is_zero ? 0 : MI_BITMAP_FIELD_FULL)); - mi_atomic_store_release(&r->commit, (region_commit ? MI_BITMAP_FIELD_FULL : 0)); - mi_atomic_store_release(&r->reset, (size_t)0); - *bit_idx = 0; - _mi_bitmap_claim(&r->in_use, 1, blocks, *bit_idx, NULL); - mi_atomic_store_ptr_release(void,&r->start, start); - - // and share it - mi_region_info_t info; - info.value = 0; // initialize the full union to zero - info.x.valid = true; - info.x.is_large = region_large; - info.x.is_pinned = is_pinned; - info.x.numa_node = (short)_mi_os_numa_node(tld); - mi_atomic_store_release(&r->info, info.value); // now make it available to others - *region = r; - return true; -} - -/* ---------------------------------------------------------------------------- - Try to claim blocks in suitable regions ------------------------------------------------------------------------------*/ - -static bool mi_region_is_suitable(const mem_region_t* region, int numa_node, bool allow_large ) { - // initialized at all? - mi_region_info_t info; - info.value = mi_atomic_load_relaxed(&((mem_region_t*)region)->info); - if (info.value==0) return false; - - // numa correct - if (numa_node >= 0) { // use negative numa node to always succeed - int rnode = info.x.numa_node; - if (rnode >= 0 && rnode != numa_node) return false; - } - - // check allow-large - if (!allow_large && info.x.is_large) return false; - - return true; -} - - -static bool mi_region_try_claim(int numa_node, size_t blocks, bool allow_large, mem_region_t** region, mi_bitmap_index_t* bit_idx, mi_os_tld_t* tld) -{ - // try all regions for a free slot - const size_t count = mi_atomic_load_relaxed(®ions_count); // monotonic, so ok to be relaxed - size_t idx = tld->region_idx; // Or start at 0 to reuse low addresses? Starting at 0 seems to increase latency though - for (size_t visited = 0; visited < count; visited++, idx++) { - if (idx >= count) idx = 0; // wrap around - mem_region_t* r = ®ions[idx]; - // if this region suits our demand (numa node matches, large OS page matches) - if (mi_region_is_suitable(r, numa_node, allow_large)) { - // then try to atomically claim a segment(s) in this region - if (_mi_bitmap_try_find_claim_field(&r->in_use, 0, blocks, bit_idx)) { - tld->region_idx = idx; // remember the last found position - *region = r; - return true; - } - } - } - return false; -} - - -static void* mi_region_try_alloc(size_t blocks, bool* commit, bool* large, bool* is_pinned, bool* is_zero, size_t* memid, mi_os_tld_t* tld) -{ - mi_assert_internal(blocks <= MI_BITMAP_FIELD_BITS); - mem_region_t* region; - mi_bitmap_index_t bit_idx; - const int numa_node = (_mi_os_numa_node_count() <= 1 ? -1 : _mi_os_numa_node(tld)); - // try to claim in existing regions - if (!mi_region_try_claim(numa_node, blocks, *large, ®ion, &bit_idx, tld)) { - // otherwise try to allocate a fresh region and claim in there - if (!mi_region_try_alloc_os(blocks, *commit, *large, ®ion, &bit_idx, tld)) { - // out of regions or memory - return NULL; - } - } - - // ------------------------------------------------ - // found a region and claimed `blocks` at `bit_idx`, initialize them now - mi_assert_internal(region != NULL); - mi_assert_internal(_mi_bitmap_is_claimed(®ion->in_use, 1, blocks, bit_idx)); - - mi_region_info_t info; - info.value = mi_atomic_load_acquire(®ion->info); - uint8_t* start = (uint8_t*)mi_atomic_load_ptr_acquire(uint8_t,®ion->start); - mi_assert_internal(!(info.x.is_large && !*large)); - mi_assert_internal(start != NULL); - - *is_zero = _mi_bitmap_claim(®ion->dirty, 1, blocks, bit_idx, NULL); - *large = info.x.is_large; - *is_pinned = info.x.is_pinned; - *memid = mi_memid_create(region, bit_idx); - void* p = start + (mi_bitmap_index_bit_in_field(bit_idx) * MI_SEGMENT_SIZE); - - // commit - if (*commit) { - // ensure commit - bool any_uncommitted; - _mi_bitmap_claim(®ion->commit, 1, blocks, bit_idx, &any_uncommitted); - if (any_uncommitted) { - mi_assert_internal(!info.x.is_large && !info.x.is_pinned); - bool commit_zero = false; - if (!_mi_mem_commit(p, blocks * MI_SEGMENT_SIZE, &commit_zero, tld)) { - // failed to commit! unclaim and return - mi_bitmap_unclaim(®ion->in_use, 1, blocks, bit_idx); - return NULL; - } - if (commit_zero) *is_zero = true; - } - } - else { - // no need to commit, but check if already fully committed - *commit = _mi_bitmap_is_claimed(®ion->commit, 1, blocks, bit_idx); - } - mi_assert_internal(!*commit || _mi_bitmap_is_claimed(®ion->commit, 1, blocks, bit_idx)); - - // unreset reset blocks - if (_mi_bitmap_is_any_claimed(®ion->reset, 1, blocks, bit_idx)) { - // some blocks are still reset - mi_assert_internal(!info.x.is_large && !info.x.is_pinned); - mi_assert_internal(!mi_option_is_enabled(mi_option_eager_commit) || *commit || mi_option_get(mi_option_eager_commit_delay) > 0); - mi_bitmap_unclaim(®ion->reset, 1, blocks, bit_idx); - if (*commit || !mi_option_is_enabled(mi_option_reset_decommits)) { // only if needed - bool reset_zero = false; - _mi_mem_unreset(p, blocks * MI_SEGMENT_SIZE, &reset_zero, tld); - if (reset_zero) *is_zero = true; - } - } - mi_assert_internal(!_mi_bitmap_is_any_claimed(®ion->reset, 1, blocks, bit_idx)); - - #if (MI_DEBUG>=2) && !MI_TRACK_ENABLED - if (*commit) { ((uint8_t*)p)[0] = 0; } - #endif - - // and return the allocation - mi_assert_internal(p != NULL); - return p; -} - - -/* ---------------------------------------------------------------------------- - Allocation ------------------------------------------------------------------------------*/ - -// Allocate `size` memory aligned at `alignment`. Return non NULL on success, with a given memory `id`. -// (`id` is abstract, but `id = idx*MI_REGION_MAP_BITS + bitidx`) -void* _mi_mem_alloc_aligned(size_t size, size_t alignment, bool* commit, bool* large, bool* is_pinned, bool* is_zero, size_t* memid, mi_os_tld_t* tld) -{ - mi_assert_internal(memid != NULL && tld != NULL); - mi_assert_internal(size > 0); - *memid = 0; - *is_zero = false; - *is_pinned = false; - bool default_large = false; - if (large==NULL) large = &default_large; // ensure `large != NULL` - if (size == 0) return NULL; - size = _mi_align_up(size, _mi_os_page_size()); - - // allocate from regions if possible - void* p = NULL; - size_t arena_memid; - const size_t blocks = mi_region_block_count(size); - if (blocks <= MI_REGION_MAX_OBJ_BLOCKS && alignment <= MI_SEGMENT_ALIGN) { - p = mi_region_try_alloc(blocks, commit, large, is_pinned, is_zero, memid, tld); - if (p == NULL) { - _mi_warning_message("unable to allocate from region: size %zu\n", size); - } - } - if (p == NULL) { - // and otherwise fall back to the OS - p = _mi_arena_alloc_aligned(size, alignment, commit, large, is_pinned, is_zero, _mi_arena_id_none(), & arena_memid, tld); - *memid = mi_memid_create_from_arena(arena_memid); - } - - if (p != NULL) { - mi_assert_internal((uintptr_t)p % alignment == 0); - #if (MI_DEBUG>=2) && !MI_TRACK_ENABLED - if (*commit) { ((uint8_t*)p)[0] = 0; } // ensure the memory is committed - #endif - } - return p; -} - - - -/* ---------------------------------------------------------------------------- -Free ------------------------------------------------------------------------------*/ - -// Free previously allocated memory with a given id. -void _mi_mem_free(void* p, size_t size, size_t id, bool full_commit, bool any_reset, mi_os_tld_t* tld) { - mi_assert_internal(size > 0 && tld != NULL); - if (p==NULL) return; - if (size==0) return; - size = _mi_align_up(size, _mi_os_page_size()); - - size_t arena_memid = 0; - mi_bitmap_index_t bit_idx; - mem_region_t* region; - if (mi_memid_is_arena(id,®ion,&bit_idx,&arena_memid)) { - // was a direct arena allocation, pass through - _mi_arena_free(p, size, arena_memid, full_commit, tld->stats); - } - else { - // allocated in a region - mi_assert_internal(size <= MI_REGION_MAX_OBJ_SIZE); if (size > MI_REGION_MAX_OBJ_SIZE) return; - const size_t blocks = mi_region_block_count(size); - mi_assert_internal(blocks + bit_idx <= MI_BITMAP_FIELD_BITS); - mi_region_info_t info; - info.value = mi_atomic_load_acquire(®ion->info); - mi_assert_internal(info.value != 0); - void* blocks_start = mi_region_blocks_start(region, bit_idx); - mi_assert_internal(blocks_start == p); // not a pointer in our area? - mi_assert_internal(bit_idx + blocks <= MI_BITMAP_FIELD_BITS); - if (blocks_start != p || bit_idx + blocks > MI_BITMAP_FIELD_BITS) return; // or `abort`? - - // committed? - if (full_commit && (size % MI_SEGMENT_SIZE) == 0) { - _mi_bitmap_claim(®ion->commit, 1, blocks, bit_idx, NULL); - } - - if (any_reset) { - // set the is_reset bits if any pages were reset - _mi_bitmap_claim(®ion->reset, 1, blocks, bit_idx, NULL); - } - - // reset the blocks to reduce the working set. - if (!info.x.is_large && !info.x.is_pinned && mi_option_is_enabled(mi_option_segment_reset) - && (mi_option_is_enabled(mi_option_eager_commit) || - mi_option_is_enabled(mi_option_reset_decommits))) // cannot reset halfway committed segments, use only `option_page_reset` instead - { - bool any_unreset; - _mi_bitmap_claim(®ion->reset, 1, blocks, bit_idx, &any_unreset); - if (any_unreset) { - _mi_abandoned_await_readers(); // ensure no more pending write (in case reset = decommit) - _mi_mem_reset(p, blocks * MI_SEGMENT_SIZE, tld); - } - } - - // and unclaim - bool all_unclaimed = mi_bitmap_unclaim(®ion->in_use, 1, blocks, bit_idx); - mi_assert_internal(all_unclaimed); MI_UNUSED(all_unclaimed); - } -} - - -/* ---------------------------------------------------------------------------- - collection ------------------------------------------------------------------------------*/ -void _mi_mem_collect(mi_os_tld_t* tld) { - // free every region that has no segments in use. - size_t rcount = mi_atomic_load_relaxed(®ions_count); - for (size_t i = 0; i < rcount; i++) { - mem_region_t* region = ®ions[i]; - if (mi_atomic_load_relaxed(®ion->info) != 0) { - // if no segments used, try to claim the whole region - size_t m = mi_atomic_load_relaxed(®ion->in_use); - while (m == 0 && !mi_atomic_cas_weak_release(®ion->in_use, &m, MI_BITMAP_FIELD_FULL)) { /* nothing */ }; - if (m == 0) { - // on success, free the whole region - uint8_t* start = (uint8_t*)mi_atomic_load_ptr_acquire(uint8_t,®ions[i].start); - size_t arena_memid = mi_atomic_load_relaxed(®ions[i].arena_memid); - size_t commit = mi_atomic_load_relaxed(®ions[i].commit); - memset((void*)®ions[i], 0, sizeof(mem_region_t)); // cast to void* to avoid atomic warning - // and release the whole region - mi_atomic_store_release(®ion->info, (size_t)0); - if (start != NULL) { // && !_mi_os_is_huge_reserved(start)) { - _mi_abandoned_await_readers(); // ensure no pending reads - _mi_arena_free(start, MI_REGION_SIZE, arena_memid, (~commit == 0), tld->stats); - } - } - } - } -} - - -/* ---------------------------------------------------------------------------- - Other ------------------------------------------------------------------------------*/ - -bool _mi_mem_reset(void* p, size_t size, mi_os_tld_t* tld) { - return _mi_os_reset(p, size, tld->stats); -} - -bool _mi_mem_unreset(void* p, size_t size, bool* is_zero, mi_os_tld_t* tld) { - return _mi_os_unreset(p, size, is_zero, tld->stats); -} - -bool _mi_mem_commit(void* p, size_t size, bool* is_zero, mi_os_tld_t* tld) { - return _mi_os_commit(p, size, is_zero, tld->stats); -} - -bool _mi_mem_decommit(void* p, size_t size, mi_os_tld_t* tld) { - return _mi_os_decommit(p, size, tld->stats); -} - -bool _mi_mem_protect(void* p, size_t size) { - return _mi_os_protect(p, size); -} - -bool _mi_mem_unprotect(void* p, size_t size) { - return _mi_os_unprotect(p, size); -} diff --git a/src/dashbls/depends/mimalloc/src/segment-cache.c b/src/dashbls/depends/mimalloc/src/segment-cache.c deleted file mode 100644 index da726716a574..000000000000 --- a/src/dashbls/depends/mimalloc/src/segment-cache.c +++ /dev/null @@ -1,368 +0,0 @@ -/* ---------------------------------------------------------------------------- -Copyright (c) 2020, Microsoft Research, Daan Leijen -This is free software; you can redistribute it and/or modify it under the -terms of the MIT license. A copy of the license can be found in the file -"LICENSE" at the root of this distribution. ------------------------------------------------------------------------------*/ - -/* ---------------------------------------------------------------------------- - Implements a cache of segments to avoid expensive OS calls and to reuse - the commit_mask to optimize the commit/decommit calls. - The full memory map of all segments is also implemented here. ------------------------------------------------------------------------------*/ -#include "mimalloc.h" -#include "mimalloc-internal.h" -#include "mimalloc-atomic.h" - -#include "bitmap.h" // atomic bitmap - -//#define MI_CACHE_DISABLE 1 // define to completely disable the segment cache - -#define MI_CACHE_FIELDS (16) -#define MI_CACHE_MAX (MI_BITMAP_FIELD_BITS*MI_CACHE_FIELDS) // 1024 on 64-bit - -#define BITS_SET() MI_ATOMIC_VAR_INIT(UINTPTR_MAX) -#define MI_CACHE_BITS_SET MI_INIT16(BITS_SET) // note: update if MI_CACHE_FIELDS changes - -typedef struct mi_cache_slot_s { - void* p; - size_t memid; - bool is_pinned; - mi_commit_mask_t commit_mask; - mi_commit_mask_t decommit_mask; - _Atomic(mi_msecs_t) expire; -} mi_cache_slot_t; - -static mi_decl_cache_align mi_cache_slot_t cache[MI_CACHE_MAX]; // = 0 - -static mi_decl_cache_align mi_bitmap_field_t cache_available[MI_CACHE_FIELDS] = { MI_CACHE_BITS_SET }; // zero bit = available! -static mi_decl_cache_align mi_bitmap_field_t cache_available_large[MI_CACHE_FIELDS] = { MI_CACHE_BITS_SET }; -static mi_decl_cache_align mi_bitmap_field_t cache_inuse[MI_CACHE_FIELDS]; // zero bit = free - -static bool mi_cdecl mi_segment_cache_is_suitable(mi_bitmap_index_t bitidx, void* arg) { - mi_arena_id_t req_arena_id = *((mi_arena_id_t*)arg); - mi_cache_slot_t* slot = &cache[mi_bitmap_index_bit(bitidx)]; - return _mi_arena_memid_is_suitable(slot->memid, req_arena_id); -} - -mi_decl_noinline void* _mi_segment_cache_pop(size_t size, mi_commit_mask_t* commit_mask, mi_commit_mask_t* decommit_mask, bool* large, bool* is_pinned, bool* is_zero, mi_arena_id_t _req_arena_id, size_t* memid, mi_os_tld_t* tld) -{ -#ifdef MI_CACHE_DISABLE - return NULL; -#else - - // only segment blocks - if (size != MI_SEGMENT_SIZE) return NULL; - - // numa node determines start field - const int numa_node = _mi_os_numa_node(tld); - size_t start_field = 0; - if (numa_node > 0) { - start_field = (MI_CACHE_FIELDS / _mi_os_numa_node_count())*numa_node; - if (start_field >= MI_CACHE_FIELDS) start_field = 0; - } - - // find an available slot - mi_bitmap_index_t bitidx = 0; - bool claimed = false; - mi_arena_id_t req_arena_id = _req_arena_id; - mi_bitmap_pred_fun_t pred_fun = &mi_segment_cache_is_suitable; // cannot pass NULL as the arena may be exclusive itself; todo: do not put exclusive arenas in the cache? - - if (*large) { // large allowed? - claimed = _mi_bitmap_try_find_from_claim_pred(cache_available_large, MI_CACHE_FIELDS, start_field, 1, pred_fun, &req_arena_id, &bitidx); - if (claimed) *large = true; - } - if (!claimed) { - claimed = _mi_bitmap_try_find_from_claim_pred (cache_available, MI_CACHE_FIELDS, start_field, 1, pred_fun, &req_arena_id, &bitidx); - if (claimed) *large = false; - } - - if (!claimed) return NULL; - - // found a slot - mi_cache_slot_t* slot = &cache[mi_bitmap_index_bit(bitidx)]; - void* p = slot->p; - *memid = slot->memid; - *is_pinned = slot->is_pinned; - *is_zero = false; - *commit_mask = slot->commit_mask; - *decommit_mask = slot->decommit_mask; - slot->p = NULL; - mi_atomic_storei64_release(&slot->expire,(mi_msecs_t)0); - - // mark the slot as free again - mi_assert_internal(_mi_bitmap_is_claimed(cache_inuse, MI_CACHE_FIELDS, 1, bitidx)); - _mi_bitmap_unclaim(cache_inuse, MI_CACHE_FIELDS, 1, bitidx); - return p; -#endif -} - -static mi_decl_noinline void mi_commit_mask_decommit(mi_commit_mask_t* cmask, void* p, size_t total, mi_stats_t* stats) -{ - if (mi_commit_mask_is_empty(cmask)) { - // nothing - } - else if (mi_commit_mask_is_full(cmask)) { - _mi_os_decommit(p, total, stats); - } - else { - // todo: one call to decommit the whole at once? - mi_assert_internal((total%MI_COMMIT_MASK_BITS)==0); - size_t part = total/MI_COMMIT_MASK_BITS; - size_t idx; - size_t count; - mi_commit_mask_foreach(cmask, idx, count) { - void* start = (uint8_t*)p + (idx*part); - size_t size = count*part; - _mi_os_decommit(start, size, stats); - } - mi_commit_mask_foreach_end() - } - mi_commit_mask_create_empty(cmask); -} - -#define MI_MAX_PURGE_PER_PUSH (4) - -static mi_decl_noinline void mi_segment_cache_purge(bool force, mi_os_tld_t* tld) -{ - MI_UNUSED(tld); - if (!mi_option_is_enabled(mi_option_allow_decommit)) return; - mi_msecs_t now = _mi_clock_now(); - size_t purged = 0; - const size_t max_visits = (force ? MI_CACHE_MAX /* visit all */ : MI_CACHE_FIELDS /* probe at most N (=16) slots */); - size_t idx = (force ? 0 : _mi_random_shuffle((uintptr_t)now) % MI_CACHE_MAX /* random start */ ); - for (size_t visited = 0; visited < max_visits; visited++,idx++) { // visit N slots - if (idx >= MI_CACHE_MAX) idx = 0; // wrap - mi_cache_slot_t* slot = &cache[idx]; - mi_msecs_t expire = mi_atomic_loadi64_relaxed(&slot->expire); - if (expire != 0 && (force || now >= expire)) { // racy read - // seems expired, first claim it from available - purged++; - mi_bitmap_index_t bitidx = mi_bitmap_index_create_from_bit(idx); - if (_mi_bitmap_claim(cache_available, MI_CACHE_FIELDS, 1, bitidx, NULL)) { - // was available, we claimed it - expire = mi_atomic_loadi64_acquire(&slot->expire); - if (expire != 0 && (force || now >= expire)) { // safe read - // still expired, decommit it - mi_atomic_storei64_relaxed(&slot->expire,(mi_msecs_t)0); - mi_assert_internal(!mi_commit_mask_is_empty(&slot->commit_mask) && _mi_bitmap_is_claimed(cache_available_large, MI_CACHE_FIELDS, 1, bitidx)); - _mi_abandoned_await_readers(); // wait until safe to decommit - // decommit committed parts - // TODO: instead of decommit, we could also free to the OS? - mi_commit_mask_decommit(&slot->commit_mask, slot->p, MI_SEGMENT_SIZE, tld->stats); - mi_commit_mask_create_empty(&slot->decommit_mask); - } - _mi_bitmap_unclaim(cache_available, MI_CACHE_FIELDS, 1, bitidx); // make it available again for a pop - } - if (!force && purged > MI_MAX_PURGE_PER_PUSH) break; // bound to no more than N purge tries per push - } - } -} - -void _mi_segment_cache_collect(bool force, mi_os_tld_t* tld) { - mi_segment_cache_purge(force, tld ); -} - -mi_decl_noinline bool _mi_segment_cache_push(void* start, size_t size, size_t memid, const mi_commit_mask_t* commit_mask, const mi_commit_mask_t* decommit_mask, bool is_large, bool is_pinned, mi_os_tld_t* tld) -{ -#ifdef MI_CACHE_DISABLE - return false; -#else - - // only for normal segment blocks - if (size != MI_SEGMENT_SIZE || ((uintptr_t)start % MI_SEGMENT_ALIGN) != 0) return false; - - // numa node determines start field - int numa_node = _mi_os_numa_node(NULL); - size_t start_field = 0; - if (numa_node > 0) { - start_field = (MI_CACHE_FIELDS / _mi_os_numa_node_count())*numa_node; - if (start_field >= MI_CACHE_FIELDS) start_field = 0; - } - - // purge expired entries - mi_segment_cache_purge(false /* force? */, tld); - - // find an available slot - mi_bitmap_index_t bitidx; - bool claimed = _mi_bitmap_try_find_from_claim(cache_inuse, MI_CACHE_FIELDS, start_field, 1, &bitidx); - if (!claimed) return false; - - mi_assert_internal(_mi_bitmap_is_claimed(cache_available, MI_CACHE_FIELDS, 1, bitidx)); - mi_assert_internal(_mi_bitmap_is_claimed(cache_available_large, MI_CACHE_FIELDS, 1, bitidx)); -#if MI_DEBUG>1 - if (is_pinned || is_large) { - mi_assert_internal(mi_commit_mask_is_full(commit_mask)); - } -#endif - - // set the slot - mi_cache_slot_t* slot = &cache[mi_bitmap_index_bit(bitidx)]; - slot->p = start; - slot->memid = memid; - slot->is_pinned = is_pinned; - mi_atomic_storei64_relaxed(&slot->expire,(mi_msecs_t)0); - slot->commit_mask = *commit_mask; - slot->decommit_mask = *decommit_mask; - if (!mi_commit_mask_is_empty(commit_mask) && !is_large && !is_pinned && mi_option_is_enabled(mi_option_allow_decommit)) { - long delay = mi_option_get(mi_option_segment_decommit_delay); - if (delay == 0) { - _mi_abandoned_await_readers(); // wait until safe to decommit - mi_commit_mask_decommit(&slot->commit_mask, start, MI_SEGMENT_SIZE, tld->stats); - mi_commit_mask_create_empty(&slot->decommit_mask); - } - else { - mi_atomic_storei64_release(&slot->expire, _mi_clock_now() + delay); - } - } - - // make it available - _mi_bitmap_unclaim((is_large ? cache_available_large : cache_available), MI_CACHE_FIELDS, 1, bitidx); - return true; -#endif -} - - -/* ----------------------------------------------------------- - The following functions are to reliably find the segment or - block that encompasses any pointer p (or NULL if it is not - in any of our segments). - We maintain a bitmap of all memory with 1 bit per MI_SEGMENT_SIZE (64MiB) - set to 1 if it contains the segment meta data. ------------------------------------------------------------ */ - - -#if (MI_INTPTR_SIZE==8) -#define MI_MAX_ADDRESS ((size_t)20 << 40) // 20TB -#else -#define MI_MAX_ADDRESS ((size_t)2 << 30) // 2Gb -#endif - -#define MI_SEGMENT_MAP_BITS (MI_MAX_ADDRESS / MI_SEGMENT_SIZE) -#define MI_SEGMENT_MAP_SIZE (MI_SEGMENT_MAP_BITS / 8) -#define MI_SEGMENT_MAP_WSIZE (MI_SEGMENT_MAP_SIZE / MI_INTPTR_SIZE) - -static _Atomic(uintptr_t) mi_segment_map[MI_SEGMENT_MAP_WSIZE + 1]; // 2KiB per TB with 64MiB segments - -static size_t mi_segment_map_index_of(const mi_segment_t* segment, size_t* bitidx) { - mi_assert_internal(_mi_ptr_segment(segment) == segment); // is it aligned on MI_SEGMENT_SIZE? - if ((uintptr_t)segment >= MI_MAX_ADDRESS) { - *bitidx = 0; - return MI_SEGMENT_MAP_WSIZE; - } - else { - const uintptr_t segindex = ((uintptr_t)segment) / MI_SEGMENT_SIZE; - *bitidx = segindex % MI_INTPTR_BITS; - const size_t mapindex = segindex / MI_INTPTR_BITS; - mi_assert_internal(mapindex < MI_SEGMENT_MAP_WSIZE); - return mapindex; - } -} - -void _mi_segment_map_allocated_at(const mi_segment_t* segment) { - size_t bitidx; - size_t index = mi_segment_map_index_of(segment, &bitidx); - mi_assert_internal(index <= MI_SEGMENT_MAP_WSIZE); - if (index==MI_SEGMENT_MAP_WSIZE) return; - uintptr_t mask = mi_atomic_load_relaxed(&mi_segment_map[index]); - uintptr_t newmask; - do { - newmask = (mask | ((uintptr_t)1 << bitidx)); - } while (!mi_atomic_cas_weak_release(&mi_segment_map[index], &mask, newmask)); -} - -void _mi_segment_map_freed_at(const mi_segment_t* segment) { - size_t bitidx; - size_t index = mi_segment_map_index_of(segment, &bitidx); - mi_assert_internal(index <= MI_SEGMENT_MAP_WSIZE); - if (index == MI_SEGMENT_MAP_WSIZE) return; - uintptr_t mask = mi_atomic_load_relaxed(&mi_segment_map[index]); - uintptr_t newmask; - do { - newmask = (mask & ~((uintptr_t)1 << bitidx)); - } while (!mi_atomic_cas_weak_release(&mi_segment_map[index], &mask, newmask)); -} - -// Determine the segment belonging to a pointer or NULL if it is not in a valid segment. -static mi_segment_t* _mi_segment_of(const void* p) { - mi_segment_t* segment = _mi_ptr_segment(p); - if (segment == NULL) return NULL; - size_t bitidx; - size_t index = mi_segment_map_index_of(segment, &bitidx); - // fast path: for any pointer to valid small/medium/large object or first MI_SEGMENT_SIZE in huge - const uintptr_t mask = mi_atomic_load_relaxed(&mi_segment_map[index]); - if mi_likely((mask & ((uintptr_t)1 << bitidx)) != 0) { - return segment; // yes, allocated by us - } - if (index==MI_SEGMENT_MAP_WSIZE) return NULL; - - // TODO: maintain max/min allocated range for efficiency for more efficient rejection of invalid pointers? - - // search downwards for the first segment in case it is an interior pointer - // could be slow but searches in MI_INTPTR_SIZE * MI_SEGMENT_SIZE (512MiB) steps trough - // valid huge objects - // note: we could maintain a lowest index to speed up the path for invalid pointers? - size_t lobitidx; - size_t loindex; - uintptr_t lobits = mask & (((uintptr_t)1 << bitidx) - 1); - if (lobits != 0) { - loindex = index; - lobitidx = mi_bsr(lobits); // lobits != 0 - } - else if (index == 0) { - return NULL; - } - else { - mi_assert_internal(index > 0); - uintptr_t lomask = mask; - loindex = index; - do { - loindex--; - lomask = mi_atomic_load_relaxed(&mi_segment_map[loindex]); - } while (lomask != 0 && loindex > 0); - if (lomask == 0) return NULL; - lobitidx = mi_bsr(lomask); // lomask != 0 - } - mi_assert_internal(loindex < MI_SEGMENT_MAP_WSIZE); - // take difference as the addresses could be larger than the MAX_ADDRESS space. - size_t diff = (((index - loindex) * (8*MI_INTPTR_SIZE)) + bitidx - lobitidx) * MI_SEGMENT_SIZE; - segment = (mi_segment_t*)((uint8_t*)segment - diff); - - if (segment == NULL) return NULL; - mi_assert_internal((void*)segment < p); - bool cookie_ok = (_mi_ptr_cookie(segment) == segment->cookie); - mi_assert_internal(cookie_ok); - if mi_unlikely(!cookie_ok) return NULL; - if (((uint8_t*)segment + mi_segment_size(segment)) <= (uint8_t*)p) return NULL; // outside the range - mi_assert_internal(p >= (void*)segment && (uint8_t*)p < (uint8_t*)segment + mi_segment_size(segment)); - return segment; -} - -// Is this a valid pointer in our heap? -static bool mi_is_valid_pointer(const void* p) { - return (_mi_segment_of(p) != NULL); -} - -mi_decl_nodiscard mi_decl_export bool mi_is_in_heap_region(const void* p) mi_attr_noexcept { - return mi_is_valid_pointer(p); -} - -/* -// Return the full segment range belonging to a pointer -static void* mi_segment_range_of(const void* p, size_t* size) { - mi_segment_t* segment = _mi_segment_of(p); - if (segment == NULL) { - if (size != NULL) *size = 0; - return NULL; - } - else { - if (size != NULL) *size = segment->segment_size; - return segment; - } - mi_assert_expensive(page == NULL || mi_segment_is_valid(_mi_page_segment(page),tld)); - mi_assert_internal(page == NULL || (mi_segment_page_size(_mi_page_segment(page)) - (MI_SECURE == 0 ? 0 : _mi_os_page_size())) >= block_size); - mi_reset_delayed(tld); - mi_assert_internal(page == NULL || mi_page_not_in_queue(page, tld)); - return page; -} -*/ diff --git a/src/dashbls/depends/mimalloc/src/segment.c b/src/dashbls/depends/mimalloc/src/segment.c deleted file mode 100644 index 2ae591fde880..000000000000 --- a/src/dashbls/depends/mimalloc/src/segment.c +++ /dev/null @@ -1,1553 +0,0 @@ -/* ---------------------------------------------------------------------------- -Copyright (c) 2018-2020, Microsoft Research, Daan Leijen -This is free software; you can redistribute it and/or modify it under the -terms of the MIT license. A copy of the license can be found in the file -"LICENSE" at the root of this distribution. ------------------------------------------------------------------------------*/ -#include "mimalloc.h" -#include "mimalloc-internal.h" -#include "mimalloc-atomic.h" - -#include // memset -#include - -#define MI_PAGE_HUGE_ALIGN (256*1024) - -static void mi_segment_delayed_decommit(mi_segment_t* segment, bool force, mi_stats_t* stats); - - -// ------------------------------------------------------------------- -// commit mask -// ------------------------------------------------------------------- - -static bool mi_commit_mask_all_set(const mi_commit_mask_t* commit, const mi_commit_mask_t* cm) { - for (size_t i = 0; i < MI_COMMIT_MASK_FIELD_COUNT; i++) { - if ((commit->mask[i] & cm->mask[i]) != cm->mask[i]) return false; - } - return true; -} - -static bool mi_commit_mask_any_set(const mi_commit_mask_t* commit, const mi_commit_mask_t* cm) { - for (size_t i = 0; i < MI_COMMIT_MASK_FIELD_COUNT; i++) { - if ((commit->mask[i] & cm->mask[i]) != 0) return true; - } - return false; -} - -static void mi_commit_mask_create_intersect(const mi_commit_mask_t* commit, const mi_commit_mask_t* cm, mi_commit_mask_t* res) { - for (size_t i = 0; i < MI_COMMIT_MASK_FIELD_COUNT; i++) { - res->mask[i] = (commit->mask[i] & cm->mask[i]); - } -} - -static void mi_commit_mask_clear(mi_commit_mask_t* res, const mi_commit_mask_t* cm) { - for (size_t i = 0; i < MI_COMMIT_MASK_FIELD_COUNT; i++) { - res->mask[i] &= ~(cm->mask[i]); - } -} - -static void mi_commit_mask_set(mi_commit_mask_t* res, const mi_commit_mask_t* cm) { - for (size_t i = 0; i < MI_COMMIT_MASK_FIELD_COUNT; i++) { - res->mask[i] |= cm->mask[i]; - } -} - -static void mi_commit_mask_create(size_t bitidx, size_t bitcount, mi_commit_mask_t* cm) { - mi_assert_internal(bitidx < MI_COMMIT_MASK_BITS); - mi_assert_internal((bitidx + bitcount) <= MI_COMMIT_MASK_BITS); - if (bitcount == MI_COMMIT_MASK_BITS) { - mi_assert_internal(bitidx==0); - mi_commit_mask_create_full(cm); - } - else if (bitcount == 0) { - mi_commit_mask_create_empty(cm); - } - else { - mi_commit_mask_create_empty(cm); - size_t i = bitidx / MI_COMMIT_MASK_FIELD_BITS; - size_t ofs = bitidx % MI_COMMIT_MASK_FIELD_BITS; - while (bitcount > 0) { - mi_assert_internal(i < MI_COMMIT_MASK_FIELD_COUNT); - size_t avail = MI_COMMIT_MASK_FIELD_BITS - ofs; - size_t count = (bitcount > avail ? avail : bitcount); - size_t mask = (count >= MI_COMMIT_MASK_FIELD_BITS ? ~((size_t)0) : (((size_t)1 << count) - 1) << ofs); - cm->mask[i] = mask; - bitcount -= count; - ofs = 0; - i++; - } - } -} - -size_t _mi_commit_mask_committed_size(const mi_commit_mask_t* cm, size_t total) { - mi_assert_internal((total%MI_COMMIT_MASK_BITS)==0); - size_t count = 0; - for (size_t i = 0; i < MI_COMMIT_MASK_FIELD_COUNT; i++) { - size_t mask = cm->mask[i]; - if (~mask == 0) { - count += MI_COMMIT_MASK_FIELD_BITS; - } - else { - for (; mask != 0; mask >>= 1) { // todo: use popcount - if ((mask&1)!=0) count++; - } - } - } - // we use total since for huge segments each commit bit may represent a larger size - return ((total / MI_COMMIT_MASK_BITS) * count); -} - - -size_t _mi_commit_mask_next_run(const mi_commit_mask_t* cm, size_t* idx) { - size_t i = (*idx) / MI_COMMIT_MASK_FIELD_BITS; - size_t ofs = (*idx) % MI_COMMIT_MASK_FIELD_BITS; - size_t mask = 0; - // find first ones - while (i < MI_COMMIT_MASK_FIELD_COUNT) { - mask = cm->mask[i]; - mask >>= ofs; - if (mask != 0) { - while ((mask&1) == 0) { - mask >>= 1; - ofs++; - } - break; - } - i++; - ofs = 0; - } - if (i >= MI_COMMIT_MASK_FIELD_COUNT) { - // not found - *idx = MI_COMMIT_MASK_BITS; - return 0; - } - else { - // found, count ones - size_t count = 0; - *idx = (i*MI_COMMIT_MASK_FIELD_BITS) + ofs; - do { - mi_assert_internal(ofs < MI_COMMIT_MASK_FIELD_BITS && (mask&1) == 1); - do { - count++; - mask >>= 1; - } while ((mask&1) == 1); - if ((((*idx + count) % MI_COMMIT_MASK_FIELD_BITS) == 0)) { - i++; - if (i >= MI_COMMIT_MASK_FIELD_COUNT) break; - mask = cm->mask[i]; - ofs = 0; - } - } while ((mask&1) == 1); - mi_assert_internal(count > 0); - return count; - } -} - - -/* -------------------------------------------------------------------------------- - Segment allocation - - If a thread ends, it "abandons" pages with used blocks - and there is an abandoned segment list whose segments can - be reclaimed by still running threads, much like work-stealing. --------------------------------------------------------------------------------- */ - - -/* ----------------------------------------------------------- - Slices ------------------------------------------------------------ */ - - -static const mi_slice_t* mi_segment_slices_end(const mi_segment_t* segment) { - return &segment->slices[segment->slice_entries]; -} - -static uint8_t* mi_slice_start(const mi_slice_t* slice) { - mi_segment_t* segment = _mi_ptr_segment(slice); - mi_assert_internal(slice >= segment->slices && slice < mi_segment_slices_end(segment)); - return ((uint8_t*)segment + ((slice - segment->slices)*MI_SEGMENT_SLICE_SIZE)); -} - - -/* ----------------------------------------------------------- - Bins ------------------------------------------------------------ */ -// Use bit scan forward to quickly find the first zero bit if it is available - -static inline size_t mi_slice_bin8(size_t slice_count) { - if (slice_count<=1) return slice_count; - mi_assert_internal(slice_count <= MI_SLICES_PER_SEGMENT); - slice_count--; - size_t s = mi_bsr(slice_count); // slice_count > 1 - if (s <= 2) return slice_count + 1; - size_t bin = ((s << 2) | ((slice_count >> (s - 2))&0x03)) - 4; - return bin; -} - -static inline size_t mi_slice_bin(size_t slice_count) { - mi_assert_internal(slice_count*MI_SEGMENT_SLICE_SIZE <= MI_SEGMENT_SIZE); - mi_assert_internal(mi_slice_bin8(MI_SLICES_PER_SEGMENT) <= MI_SEGMENT_BIN_MAX); - size_t bin = mi_slice_bin8(slice_count); - mi_assert_internal(bin <= MI_SEGMENT_BIN_MAX); - return bin; -} - -static inline size_t mi_slice_index(const mi_slice_t* slice) { - mi_segment_t* segment = _mi_ptr_segment(slice); - ptrdiff_t index = slice - segment->slices; - mi_assert_internal(index >= 0 && index < (ptrdiff_t)segment->slice_entries); - return index; -} - - -/* ----------------------------------------------------------- - Slice span queues ------------------------------------------------------------ */ - -static void mi_span_queue_push(mi_span_queue_t* sq, mi_slice_t* slice) { - // todo: or push to the end? - mi_assert_internal(slice->prev == NULL && slice->next==NULL); - slice->prev = NULL; // paranoia - slice->next = sq->first; - sq->first = slice; - if (slice->next != NULL) slice->next->prev = slice; - else sq->last = slice; - slice->xblock_size = 0; // free -} - -static mi_span_queue_t* mi_span_queue_for(size_t slice_count, mi_segments_tld_t* tld) { - size_t bin = mi_slice_bin(slice_count); - mi_span_queue_t* sq = &tld->spans[bin]; - mi_assert_internal(sq->slice_count >= slice_count); - return sq; -} - -static void mi_span_queue_delete(mi_span_queue_t* sq, mi_slice_t* slice) { - mi_assert_internal(slice->xblock_size==0 && slice->slice_count>0 && slice->slice_offset==0); - // should work too if the queue does not contain slice (which can happen during reclaim) - if (slice->prev != NULL) slice->prev->next = slice->next; - if (slice == sq->first) sq->first = slice->next; - if (slice->next != NULL) slice->next->prev = slice->prev; - if (slice == sq->last) sq->last = slice->prev; - slice->prev = NULL; - slice->next = NULL; - slice->xblock_size = 1; // no more free -} - - -/* ----------------------------------------------------------- - Invariant checking ------------------------------------------------------------ */ - -static bool mi_slice_is_used(const mi_slice_t* slice) { - return (slice->xblock_size > 0); -} - - -#if (MI_DEBUG>=3) -static bool mi_span_queue_contains(mi_span_queue_t* sq, mi_slice_t* slice) { - for (mi_slice_t* s = sq->first; s != NULL; s = s->next) { - if (s==slice) return true; - } - return false; -} - -static bool mi_segment_is_valid(mi_segment_t* segment, mi_segments_tld_t* tld) { - mi_assert_internal(segment != NULL); - mi_assert_internal(_mi_ptr_cookie(segment) == segment->cookie); - mi_assert_internal(segment->abandoned <= segment->used); - mi_assert_internal(segment->thread_id == 0 || segment->thread_id == _mi_thread_id()); - mi_assert_internal(mi_commit_mask_all_set(&segment->commit_mask, &segment->decommit_mask)); // can only decommit committed blocks - //mi_assert_internal(segment->segment_info_size % MI_SEGMENT_SLICE_SIZE == 0); - mi_slice_t* slice = &segment->slices[0]; - const mi_slice_t* end = mi_segment_slices_end(segment); - size_t used_count = 0; - mi_span_queue_t* sq; - while(slice < end) { - mi_assert_internal(slice->slice_count > 0); - mi_assert_internal(slice->slice_offset == 0); - size_t index = mi_slice_index(slice); - size_t maxindex = (index + slice->slice_count >= segment->slice_entries ? segment->slice_entries : index + slice->slice_count) - 1; - if (mi_slice_is_used(slice)) { // a page in use, we need at least MAX_SLICE_OFFSET valid back offsets - used_count++; - for (size_t i = 0; i <= MI_MAX_SLICE_OFFSET && index + i <= maxindex; i++) { - mi_assert_internal(segment->slices[index + i].slice_offset == i*sizeof(mi_slice_t)); - mi_assert_internal(i==0 || segment->slices[index + i].slice_count == 0); - mi_assert_internal(i==0 || segment->slices[index + i].xblock_size == 1); - } - // and the last entry as well (for coalescing) - const mi_slice_t* last = slice + slice->slice_count - 1; - if (last > slice && last < mi_segment_slices_end(segment)) { - mi_assert_internal(last->slice_offset == (slice->slice_count-1)*sizeof(mi_slice_t)); - mi_assert_internal(last->slice_count == 0); - mi_assert_internal(last->xblock_size == 1); - } - } - else { // free range of slices; only last slice needs a valid back offset - mi_slice_t* last = &segment->slices[maxindex]; - if (segment->kind != MI_SEGMENT_HUGE || slice->slice_count <= (segment->slice_entries - segment->segment_info_slices)) { - mi_assert_internal((uint8_t*)slice == (uint8_t*)last - last->slice_offset); - } - mi_assert_internal(slice == last || last->slice_count == 0 ); - mi_assert_internal(last->xblock_size == 0 || (segment->kind==MI_SEGMENT_HUGE && last->xblock_size==1)); - if (segment->kind != MI_SEGMENT_HUGE && segment->thread_id != 0) { // segment is not huge or abandoned - sq = mi_span_queue_for(slice->slice_count,tld); - mi_assert_internal(mi_span_queue_contains(sq,slice)); - } - } - slice = &segment->slices[maxindex+1]; - } - mi_assert_internal(slice == end); - mi_assert_internal(used_count == segment->used + 1); - return true; -} -#endif - -/* ----------------------------------------------------------- - Segment size calculations ------------------------------------------------------------ */ - -static size_t mi_segment_info_size(mi_segment_t* segment) { - return segment->segment_info_slices * MI_SEGMENT_SLICE_SIZE; -} - -static uint8_t* _mi_segment_page_start_from_slice(const mi_segment_t* segment, const mi_slice_t* slice, size_t xblock_size, size_t* page_size) -{ - ptrdiff_t idx = slice - segment->slices; - size_t psize = (size_t)slice->slice_count * MI_SEGMENT_SLICE_SIZE; - // make the start not OS page aligned for smaller blocks to avoid page/cache effects - size_t start_offset = (xblock_size >= MI_INTPTR_SIZE && xblock_size <= 1024 ? MI_MAX_ALIGN_GUARANTEE : 0); - if (page_size != NULL) { *page_size = psize - start_offset; } - return (uint8_t*)segment + ((idx*MI_SEGMENT_SLICE_SIZE) + start_offset); -} - -// Start of the page available memory; can be used on uninitialized pages -uint8_t* _mi_segment_page_start(const mi_segment_t* segment, const mi_page_t* page, size_t* page_size) -{ - const mi_slice_t* slice = mi_page_to_slice((mi_page_t*)page); - uint8_t* p = _mi_segment_page_start_from_slice(segment, slice, page->xblock_size, page_size); - mi_assert_internal(page->xblock_size > 0 || _mi_ptr_page(p) == page); - mi_assert_internal(_mi_ptr_segment(p) == segment); - return p; -} - - -static size_t mi_segment_calculate_slices(size_t required, size_t* pre_size, size_t* info_slices) { - size_t page_size = _mi_os_page_size(); - size_t isize = _mi_align_up(sizeof(mi_segment_t), page_size); - size_t guardsize = 0; - - if (MI_SECURE>0) { - // in secure mode, we set up a protected page in between the segment info - // and the page data (and one at the end of the segment) - guardsize = page_size; - required = _mi_align_up(required, page_size); - } - - if (pre_size != NULL) *pre_size = isize; - isize = _mi_align_up(isize + guardsize, MI_SEGMENT_SLICE_SIZE); - if (info_slices != NULL) *info_slices = isize / MI_SEGMENT_SLICE_SIZE; - size_t segment_size = (required==0 ? MI_SEGMENT_SIZE : _mi_align_up( required + isize + guardsize, MI_SEGMENT_SLICE_SIZE) ); - mi_assert_internal(segment_size % MI_SEGMENT_SLICE_SIZE == 0); - return (segment_size / MI_SEGMENT_SLICE_SIZE); -} - - -/* ---------------------------------------------------------------------------- -Segment caches -We keep a small segment cache per thread to increase local -reuse and avoid setting/clearing guard pages in secure mode. -------------------------------------------------------------------------------- */ - -static void mi_segments_track_size(long segment_size, mi_segments_tld_t* tld) { - if (segment_size>=0) _mi_stat_increase(&tld->stats->segments,1); - else _mi_stat_decrease(&tld->stats->segments,1); - tld->count += (segment_size >= 0 ? 1 : -1); - if (tld->count > tld->peak_count) tld->peak_count = tld->count; - tld->current_size += segment_size; - if (tld->current_size > tld->peak_size) tld->peak_size = tld->current_size; -} - -static void mi_segment_os_free(mi_segment_t* segment, mi_segments_tld_t* tld) { - segment->thread_id = 0; - _mi_segment_map_freed_at(segment); - mi_segments_track_size(-((long)mi_segment_size(segment)),tld); - if (MI_SECURE>0) { - // _mi_os_unprotect(segment, mi_segment_size(segment)); // ensure no more guard pages are set - // unprotect the guard pages; we cannot just unprotect the whole segment size as part may be decommitted - size_t os_pagesize = _mi_os_page_size(); - _mi_os_unprotect((uint8_t*)segment + mi_segment_info_size(segment) - os_pagesize, os_pagesize); - uint8_t* end = (uint8_t*)segment + mi_segment_size(segment) - os_pagesize; - _mi_os_unprotect(end, os_pagesize); - } - - // purge delayed decommits now? (no, leave it to the cache) - // mi_segment_delayed_decommit(segment,true,tld->stats); - - // _mi_os_free(segment, mi_segment_size(segment), /*segment->memid,*/ tld->stats); - const size_t size = mi_segment_size(segment); - if (size != MI_SEGMENT_SIZE || !_mi_segment_cache_push(segment, size, segment->memid, &segment->commit_mask, &segment->decommit_mask, segment->mem_is_large, segment->mem_is_pinned, tld->os)) { - const size_t csize = _mi_commit_mask_committed_size(&segment->commit_mask, size); - if (csize > 0 && !segment->mem_is_pinned) _mi_stat_decrease(&_mi_stats_main.committed, csize); - _mi_abandoned_await_readers(); // wait until safe to free - _mi_arena_free(segment, mi_segment_size(segment), segment->memid, segment->mem_is_pinned /* pretend not committed to not double count decommits */, tld->os); - } -} - -// called by threads that are terminating -void _mi_segment_thread_collect(mi_segments_tld_t* tld) { - MI_UNUSED(tld); - // nothing to do -} - - -/* ----------------------------------------------------------- - Span management ------------------------------------------------------------ */ - -static void mi_segment_commit_mask(mi_segment_t* segment, bool conservative, uint8_t* p, size_t size, uint8_t** start_p, size_t* full_size, mi_commit_mask_t* cm) { - mi_assert_internal(_mi_ptr_segment(p) == segment); - mi_assert_internal(segment->kind != MI_SEGMENT_HUGE); - mi_commit_mask_create_empty(cm); - if (size == 0 || size > MI_SEGMENT_SIZE || segment->kind == MI_SEGMENT_HUGE) return; - const size_t segstart = mi_segment_info_size(segment); - const size_t segsize = mi_segment_size(segment); - if (p >= (uint8_t*)segment + segsize) return; - - size_t pstart = (p - (uint8_t*)segment); - mi_assert_internal(pstart + size <= segsize); - - size_t start; - size_t end; - if (conservative) { - // decommit conservative - start = _mi_align_up(pstart, MI_COMMIT_SIZE); - end = _mi_align_down(pstart + size, MI_COMMIT_SIZE); - mi_assert_internal(start >= segstart); - mi_assert_internal(end <= segsize); - } - else { - // commit liberal - start = _mi_align_down(pstart, MI_MINIMAL_COMMIT_SIZE); - end = _mi_align_up(pstart + size, MI_MINIMAL_COMMIT_SIZE); - } - if (pstart >= segstart && start < segstart) { // note: the mask is also calculated for an initial commit of the info area - start = segstart; - } - if (end > segsize) { - end = segsize; - } - - mi_assert_internal(start <= pstart && (pstart + size) <= end); - mi_assert_internal(start % MI_COMMIT_SIZE==0 && end % MI_COMMIT_SIZE == 0); - *start_p = (uint8_t*)segment + start; - *full_size = (end > start ? end - start : 0); - if (*full_size == 0) return; - - size_t bitidx = start / MI_COMMIT_SIZE; - mi_assert_internal(bitidx < MI_COMMIT_MASK_BITS); - - size_t bitcount = *full_size / MI_COMMIT_SIZE; // can be 0 - if (bitidx + bitcount > MI_COMMIT_MASK_BITS) { - _mi_warning_message("commit mask overflow: idx=%zu count=%zu start=%zx end=%zx p=0x%p size=%zu fullsize=%zu\n", bitidx, bitcount, start, end, p, size, *full_size); - } - mi_assert_internal((bitidx + bitcount) <= MI_COMMIT_MASK_BITS); - mi_commit_mask_create(bitidx, bitcount, cm); -} - - -static bool mi_segment_commitx(mi_segment_t* segment, bool commit, uint8_t* p, size_t size, mi_stats_t* stats) { - mi_assert_internal(mi_commit_mask_all_set(&segment->commit_mask, &segment->decommit_mask)); - - // try to commit in at least MI_MINIMAL_COMMIT_SIZE sizes. - /* - if (commit && size > 0) { - const size_t csize = _mi_align_up(size, MI_MINIMAL_COMMIT_SIZE); - if (p + csize <= mi_segment_end(segment)) { - size = csize; - } - } - */ - // commit liberal, but decommit conservative - uint8_t* start = NULL; - size_t full_size = 0; - mi_commit_mask_t mask; - mi_segment_commit_mask(segment, !commit/*conservative*/, p, size, &start, &full_size, &mask); - if (mi_commit_mask_is_empty(&mask) || full_size==0) return true; - - if (commit && !mi_commit_mask_all_set(&segment->commit_mask, &mask)) { - bool is_zero = false; - mi_commit_mask_t cmask; - mi_commit_mask_create_intersect(&segment->commit_mask, &mask, &cmask); - _mi_stat_decrease(&_mi_stats_main.committed, _mi_commit_mask_committed_size(&cmask, MI_SEGMENT_SIZE)); // adjust for overlap - if (!_mi_os_commit(start,full_size,&is_zero,stats)) return false; - mi_commit_mask_set(&segment->commit_mask, &mask); - } - else if (!commit && mi_commit_mask_any_set(&segment->commit_mask, &mask)) { - mi_assert_internal((void*)start != (void*)segment); - //mi_assert_internal(mi_commit_mask_all_set(&segment->commit_mask, &mask)); - - mi_commit_mask_t cmask; - mi_commit_mask_create_intersect(&segment->commit_mask, &mask, &cmask); - _mi_stat_increase(&_mi_stats_main.committed, full_size - _mi_commit_mask_committed_size(&cmask, MI_SEGMENT_SIZE)); // adjust for overlap - if (segment->allow_decommit) { - _mi_os_decommit(start, full_size, stats); // ok if this fails - } - mi_commit_mask_clear(&segment->commit_mask, &mask); - } - // increase expiration of reusing part of the delayed decommit - if (commit && mi_commit_mask_any_set(&segment->decommit_mask, &mask)) { - segment->decommit_expire = _mi_clock_now() + mi_option_get(mi_option_decommit_delay); - } - // always undo delayed decommits - mi_commit_mask_clear(&segment->decommit_mask, &mask); - return true; -} - -static bool mi_segment_ensure_committed(mi_segment_t* segment, uint8_t* p, size_t size, mi_stats_t* stats) { - mi_assert_internal(mi_commit_mask_all_set(&segment->commit_mask, &segment->decommit_mask)); - // note: assumes commit_mask is always full for huge segments as otherwise the commit mask bits can overflow - if (mi_commit_mask_is_full(&segment->commit_mask) && mi_commit_mask_is_empty(&segment->decommit_mask)) return true; // fully committed - return mi_segment_commitx(segment,true,p,size,stats); -} - -static void mi_segment_perhaps_decommit(mi_segment_t* segment, uint8_t* p, size_t size, mi_stats_t* stats) { - if (!segment->allow_decommit) return; - if (mi_option_get(mi_option_decommit_delay) == 0) { - mi_segment_commitx(segment, false, p, size, stats); - } - else { - // register for future decommit in the decommit mask - uint8_t* start = NULL; - size_t full_size = 0; - mi_commit_mask_t mask; - mi_segment_commit_mask(segment, true /*conservative*/, p, size, &start, &full_size, &mask); - if (mi_commit_mask_is_empty(&mask) || full_size==0) return; - - // update delayed commit - mi_assert_internal(segment->decommit_expire > 0 || mi_commit_mask_is_empty(&segment->decommit_mask)); - mi_commit_mask_t cmask; - mi_commit_mask_create_intersect(&segment->commit_mask, &mask, &cmask); // only decommit what is committed; span_free may try to decommit more - mi_commit_mask_set(&segment->decommit_mask, &cmask); - mi_msecs_t now = _mi_clock_now(); - if (segment->decommit_expire == 0) { - // no previous decommits, initialize now - segment->decommit_expire = now + mi_option_get(mi_option_decommit_delay); - } - else if (segment->decommit_expire <= now) { - // previous decommit mask already expired - // mi_segment_delayed_decommit(segment, true, stats); - segment->decommit_expire = now + mi_option_get(mi_option_decommit_extend_delay); // (mi_option_get(mi_option_decommit_delay) / 8); // wait a tiny bit longer in case there is a series of free's - } - else { - // previous decommit mask is not yet expired, increase the expiration by a bit. - segment->decommit_expire += mi_option_get(mi_option_decommit_extend_delay); - } - } -} - -static void mi_segment_delayed_decommit(mi_segment_t* segment, bool force, mi_stats_t* stats) { - if (!segment->allow_decommit || mi_commit_mask_is_empty(&segment->decommit_mask)) return; - mi_msecs_t now = _mi_clock_now(); - if (!force && now < segment->decommit_expire) return; - - mi_commit_mask_t mask = segment->decommit_mask; - segment->decommit_expire = 0; - mi_commit_mask_create_empty(&segment->decommit_mask); - - size_t idx; - size_t count; - mi_commit_mask_foreach(&mask, idx, count) { - // if found, decommit that sequence - if (count > 0) { - uint8_t* p = (uint8_t*)segment + (idx*MI_COMMIT_SIZE); - size_t size = count * MI_COMMIT_SIZE; - mi_segment_commitx(segment, false, p, size, stats); - } - } - mi_commit_mask_foreach_end() - mi_assert_internal(mi_commit_mask_is_empty(&segment->decommit_mask)); -} - - -static bool mi_segment_is_abandoned(mi_segment_t* segment) { - return (segment->thread_id == 0); -} - -// note: can be called on abandoned segments -static void mi_segment_span_free(mi_segment_t* segment, size_t slice_index, size_t slice_count, mi_segments_tld_t* tld) { - mi_assert_internal(slice_index < segment->slice_entries); - mi_span_queue_t* sq = (segment->kind == MI_SEGMENT_HUGE || mi_segment_is_abandoned(segment) - ? NULL : mi_span_queue_for(slice_count,tld)); - if (slice_count==0) slice_count = 1; - mi_assert_internal(slice_index + slice_count - 1 < segment->slice_entries); - - // set first and last slice (the intermediates can be undetermined) - mi_slice_t* slice = &segment->slices[slice_index]; - slice->slice_count = (uint32_t)slice_count; - mi_assert_internal(slice->slice_count == slice_count); // no overflow? - slice->slice_offset = 0; - if (slice_count > 1) { - mi_slice_t* last = &segment->slices[slice_index + slice_count - 1]; - last->slice_count = 0; - last->slice_offset = (uint32_t)(sizeof(mi_page_t)*(slice_count - 1)); - last->xblock_size = 0; - } - - // perhaps decommit - mi_segment_perhaps_decommit(segment,mi_slice_start(slice),slice_count*MI_SEGMENT_SLICE_SIZE,tld->stats); - - // and push it on the free page queue (if it was not a huge page) - if (sq != NULL) mi_span_queue_push( sq, slice ); - else slice->xblock_size = 0; // mark huge page as free anyways -} - -/* -// called from reclaim to add existing free spans -static void mi_segment_span_add_free(mi_slice_t* slice, mi_segments_tld_t* tld) { - mi_segment_t* segment = _mi_ptr_segment(slice); - mi_assert_internal(slice->xblock_size==0 && slice->slice_count>0 && slice->slice_offset==0); - size_t slice_index = mi_slice_index(slice); - mi_segment_span_free(segment,slice_index,slice->slice_count,tld); -} -*/ - -static void mi_segment_span_remove_from_queue(mi_slice_t* slice, mi_segments_tld_t* tld) { - mi_assert_internal(slice->slice_count > 0 && slice->slice_offset==0 && slice->xblock_size==0); - mi_assert_internal(_mi_ptr_segment(slice)->kind != MI_SEGMENT_HUGE); - mi_span_queue_t* sq = mi_span_queue_for(slice->slice_count, tld); - mi_span_queue_delete(sq, slice); -} - -// note: can be called on abandoned segments -static mi_slice_t* mi_segment_span_free_coalesce(mi_slice_t* slice, mi_segments_tld_t* tld) { - mi_assert_internal(slice != NULL && slice->slice_count > 0 && slice->slice_offset == 0); - mi_segment_t* segment = _mi_ptr_segment(slice); - bool is_abandoned = mi_segment_is_abandoned(segment); - - // for huge pages, just mark as free but don't add to the queues - if (segment->kind == MI_SEGMENT_HUGE) { - mi_assert_internal(segment->used == 1); // decreased right after this call in `mi_segment_page_clear` - slice->xblock_size = 0; // mark as free anyways - // we should mark the last slice `xblock_size=0` now to maintain invariants but we skip it to - // avoid a possible cache miss (and the segment is about to be freed) - return slice; - } - - // otherwise coalesce the span and add to the free span queues - size_t slice_count = slice->slice_count; - mi_slice_t* next = slice + slice->slice_count; - mi_assert_internal(next <= mi_segment_slices_end(segment)); - if (next < mi_segment_slices_end(segment) && next->xblock_size==0) { - // free next block -- remove it from free and merge - mi_assert_internal(next->slice_count > 0 && next->slice_offset==0); - slice_count += next->slice_count; // extend - if (!is_abandoned) { mi_segment_span_remove_from_queue(next, tld); } - } - if (slice > segment->slices) { - mi_slice_t* prev = mi_slice_first(slice - 1); - mi_assert_internal(prev >= segment->slices); - if (prev->xblock_size==0) { - // free previous slice -- remove it from free and merge - mi_assert_internal(prev->slice_count > 0 && prev->slice_offset==0); - slice_count += prev->slice_count; - if (!is_abandoned) { mi_segment_span_remove_from_queue(prev, tld); } - slice = prev; - } - } - - // and add the new free page - mi_segment_span_free(segment, mi_slice_index(slice), slice_count, tld); - return slice; -} - - -static void mi_segment_slice_split(mi_segment_t* segment, mi_slice_t* slice, size_t slice_count, mi_segments_tld_t* tld) { - mi_assert_internal(_mi_ptr_segment(slice)==segment); - mi_assert_internal(slice->slice_count >= slice_count); - mi_assert_internal(slice->xblock_size > 0); // no more in free queue - if (slice->slice_count <= slice_count) return; - mi_assert_internal(segment->kind != MI_SEGMENT_HUGE); - size_t next_index = mi_slice_index(slice) + slice_count; - size_t next_count = slice->slice_count - slice_count; - mi_segment_span_free(segment, next_index, next_count, tld); - slice->slice_count = (uint32_t)slice_count; -} - -// Note: may still return NULL if committing the memory failed -static mi_page_t* mi_segment_span_allocate(mi_segment_t* segment, size_t slice_index, size_t slice_count, mi_segments_tld_t* tld) { - mi_assert_internal(slice_index < segment->slice_entries); - mi_slice_t* slice = &segment->slices[slice_index]; - mi_assert_internal(slice->xblock_size==0 || slice->xblock_size==1); - - // commit before changing the slice data - if (!mi_segment_ensure_committed(segment, _mi_segment_page_start_from_slice(segment, slice, 0, NULL), slice_count * MI_SEGMENT_SLICE_SIZE, tld->stats)) { - return NULL; // commit failed! - } - - // convert the slices to a page - slice->slice_offset = 0; - slice->slice_count = (uint32_t)slice_count; - mi_assert_internal(slice->slice_count == slice_count); - const size_t bsize = slice_count * MI_SEGMENT_SLICE_SIZE; - slice->xblock_size = (uint32_t)(bsize >= MI_HUGE_BLOCK_SIZE ? MI_HUGE_BLOCK_SIZE : bsize); - mi_page_t* page = mi_slice_to_page(slice); - mi_assert_internal(mi_page_block_size(page) == bsize); - - // set slice back pointers for the first MI_MAX_SLICE_OFFSET entries - size_t extra = slice_count-1; - if (extra > MI_MAX_SLICE_OFFSET) extra = MI_MAX_SLICE_OFFSET; - if (slice_index + extra >= segment->slice_entries) extra = segment->slice_entries - slice_index - 1; // huge objects may have more slices than avaiable entries in the segment->slices - slice++; - for (size_t i = 1; i <= extra; i++, slice++) { - slice->slice_offset = (uint32_t)(sizeof(mi_slice_t)*i); - slice->slice_count = 0; - slice->xblock_size = 1; - } - - // and also for the last one (if not set already) (the last one is needed for coalescing) - // note: the cast is needed for ubsan since the index can be larger than MI_SLICES_PER_SEGMENT for huge allocations (see #543) - mi_slice_t* last = &((mi_slice_t*)segment->slices)[slice_index + slice_count - 1]; - if (last < mi_segment_slices_end(segment) && last >= slice) { - last->slice_offset = (uint32_t)(sizeof(mi_slice_t)*(slice_count-1)); - last->slice_count = 0; - last->xblock_size = 1; - } - - // and initialize the page - page->is_reset = false; - page->is_committed = true; - segment->used++; - return page; -} - -static mi_page_t* mi_segments_page_find_and_allocate(size_t slice_count, mi_arena_id_t req_arena_id, mi_segments_tld_t* tld) { - mi_assert_internal(slice_count*MI_SEGMENT_SLICE_SIZE <= MI_LARGE_OBJ_SIZE_MAX); - // search from best fit up - mi_span_queue_t* sq = mi_span_queue_for(slice_count, tld); - if (slice_count == 0) slice_count = 1; - while (sq <= &tld->spans[MI_SEGMENT_BIN_MAX]) { - for (mi_slice_t* slice = sq->first; slice != NULL; slice = slice->next) { - if (slice->slice_count >= slice_count) { - // found one - mi_segment_t* segment = _mi_ptr_segment(slice); - if (_mi_arena_memid_is_suitable(segment->memid, req_arena_id)) { - // found a suitable page span - mi_span_queue_delete(sq, slice); - - if (slice->slice_count > slice_count) { - mi_segment_slice_split(segment, slice, slice_count, tld); - } - mi_assert_internal(slice != NULL && slice->slice_count == slice_count && slice->xblock_size > 0); - mi_page_t* page = mi_segment_span_allocate(segment, mi_slice_index(slice), slice->slice_count, tld); - if (page == NULL) { - // commit failed; return NULL but first restore the slice - mi_segment_span_free_coalesce(slice, tld); - return NULL; - } - return page; - } - } - } - sq++; - } - // could not find a page.. - return NULL; -} - - -/* ----------------------------------------------------------- - Segment allocation ------------------------------------------------------------ */ - -// Allocate a segment from the OS aligned to `MI_SEGMENT_SIZE` . -static mi_segment_t* mi_segment_init(mi_segment_t* segment, size_t required, mi_arena_id_t req_arena_id, mi_segments_tld_t* tld, mi_os_tld_t* os_tld, mi_page_t** huge_page) -{ - mi_assert_internal((required==0 && huge_page==NULL) || (required>0 && huge_page != NULL)); - mi_assert_internal((segment==NULL) || (segment!=NULL && required==0)); - // calculate needed sizes first - size_t info_slices; - size_t pre_size; - const size_t segment_slices = mi_segment_calculate_slices(required, &pre_size, &info_slices); - const size_t slice_entries = (segment_slices > MI_SLICES_PER_SEGMENT ? MI_SLICES_PER_SEGMENT : segment_slices); - const size_t segment_size = segment_slices * MI_SEGMENT_SLICE_SIZE; - - // Commit eagerly only if not the first N lazy segments (to reduce impact of many threads that allocate just a little) - const bool eager_delay = (// !_mi_os_has_overcommit() && // never delay on overcommit systems - _mi_current_thread_count() > 1 && // do not delay for the first N threads - tld->count < (size_t)mi_option_get(mi_option_eager_commit_delay)); - const bool eager = !eager_delay && mi_option_is_enabled(mi_option_eager_commit); - bool commit = eager || (required > 0); - - // Try to get from our cache first - bool is_zero = false; - const bool commit_info_still_good = (segment != NULL); - mi_commit_mask_t commit_mask; - mi_commit_mask_t decommit_mask; - if (segment != NULL) { - commit_mask = segment->commit_mask; - decommit_mask = segment->decommit_mask; - } - else { - mi_commit_mask_create_empty(&commit_mask); - mi_commit_mask_create_empty(&decommit_mask); - } - if (segment==NULL) { - // Allocate the segment from the OS - bool mem_large = (!eager_delay && (MI_SECURE==0)); // only allow large OS pages once we are no longer lazy - bool is_pinned = false; - size_t memid = 0; - segment = (mi_segment_t*)_mi_segment_cache_pop(segment_size, &commit_mask, &decommit_mask, &mem_large, &is_pinned, &is_zero, req_arena_id, &memid, os_tld); - if (segment==NULL) { - segment = (mi_segment_t*)_mi_arena_alloc_aligned(segment_size, MI_SEGMENT_SIZE, &commit, &mem_large, &is_pinned, &is_zero, req_arena_id, &memid, os_tld); - if (segment == NULL) return NULL; // failed to allocate - if (commit) { - mi_commit_mask_create_full(&commit_mask); - } - else { - mi_commit_mask_create_empty(&commit_mask); - } - } - mi_assert_internal(segment != NULL && (uintptr_t)segment % MI_SEGMENT_SIZE == 0); - - const size_t commit_needed = _mi_divide_up(info_slices*MI_SEGMENT_SLICE_SIZE, MI_COMMIT_SIZE); - mi_assert_internal(commit_needed>0); - mi_commit_mask_t commit_needed_mask; - mi_commit_mask_create(0, commit_needed, &commit_needed_mask); - if (!mi_commit_mask_all_set(&commit_mask, &commit_needed_mask)) { - // at least commit the info slices - mi_assert_internal(commit_needed*MI_COMMIT_SIZE >= info_slices*MI_SEGMENT_SLICE_SIZE); - bool ok = _mi_os_commit(segment, commit_needed*MI_COMMIT_SIZE, &is_zero, tld->stats); - if (!ok) return NULL; // failed to commit - mi_commit_mask_set(&commit_mask, &commit_needed_mask); - } - mi_track_mem_undefined(segment,commit_needed); - segment->memid = memid; - segment->mem_is_pinned = is_pinned; - segment->mem_is_large = mem_large; - segment->mem_is_committed = mi_commit_mask_is_full(&commit_mask); - mi_segments_track_size((long)(segment_size), tld); - _mi_segment_map_allocated_at(segment); - } - - // zero the segment info? -- not always needed as it is zero initialized from the OS - mi_atomic_store_ptr_release(mi_segment_t, &segment->abandoned_next, NULL); // tsan - if (!is_zero) { - ptrdiff_t ofs = offsetof(mi_segment_t, next); - size_t prefix = offsetof(mi_segment_t, slices) - ofs; - memset((uint8_t*)segment+ofs, 0, prefix + sizeof(mi_slice_t)*segment_slices); - } - - if (!commit_info_still_good) { - segment->commit_mask = commit_mask; // on lazy commit, the initial part is always committed - segment->allow_decommit = (mi_option_is_enabled(mi_option_allow_decommit) && !segment->mem_is_pinned && !segment->mem_is_large); - if (segment->allow_decommit) { - segment->decommit_expire = _mi_clock_now() + mi_option_get(mi_option_decommit_delay); - segment->decommit_mask = decommit_mask; - mi_assert_internal(mi_commit_mask_all_set(&segment->commit_mask, &segment->decommit_mask)); - #if MI_DEBUG>2 - const size_t commit_needed = _mi_divide_up(info_slices*MI_SEGMENT_SLICE_SIZE, MI_COMMIT_SIZE); - mi_commit_mask_t commit_needed_mask; - mi_commit_mask_create(0, commit_needed, &commit_needed_mask); - mi_assert_internal(!mi_commit_mask_any_set(&segment->decommit_mask, &commit_needed_mask)); - #endif - } - else { - mi_assert_internal(mi_commit_mask_is_empty(&decommit_mask)); - segment->decommit_expire = 0; - mi_commit_mask_create_empty( &segment->decommit_mask ); - mi_assert_internal(mi_commit_mask_is_empty(&segment->decommit_mask)); - } - } - - - // initialize segment info - segment->segment_slices = segment_slices; - segment->segment_info_slices = info_slices; - segment->thread_id = _mi_thread_id(); - segment->cookie = _mi_ptr_cookie(segment); - segment->slice_entries = slice_entries; - segment->kind = (required == 0 ? MI_SEGMENT_NORMAL : MI_SEGMENT_HUGE); - - // memset(segment->slices, 0, sizeof(mi_slice_t)*(info_slices+1)); - _mi_stat_increase(&tld->stats->page_committed, mi_segment_info_size(segment)); - - // set up guard pages - size_t guard_slices = 0; - if (MI_SECURE>0) { - // in secure mode, we set up a protected page in between the segment info - // and the page data, and at the end of the segment. - size_t os_pagesize = _mi_os_page_size(); - mi_assert_internal(mi_segment_info_size(segment) - os_pagesize >= pre_size); - _mi_os_protect((uint8_t*)segment + mi_segment_info_size(segment) - os_pagesize, os_pagesize); - uint8_t* end = (uint8_t*)segment + mi_segment_size(segment) - os_pagesize; - mi_segment_ensure_committed(segment, end, os_pagesize, tld->stats); - _mi_os_protect(end, os_pagesize); - if (slice_entries == segment_slices) segment->slice_entries--; // don't use the last slice :-( - guard_slices = 1; - } - - // reserve first slices for segment info - mi_page_t* page0 = mi_segment_span_allocate(segment, 0, info_slices, tld); - mi_assert_internal(page0!=NULL); if (page0==NULL) return NULL; // cannot fail as we always commit in advance - mi_assert_internal(segment->used == 1); - segment->used = 0; // don't count our internal slices towards usage - - // initialize initial free pages - if (segment->kind == MI_SEGMENT_NORMAL) { // not a huge page - mi_assert_internal(huge_page==NULL); - mi_segment_span_free(segment, info_slices, segment->slice_entries - info_slices, tld); - } - else { - mi_assert_internal(huge_page!=NULL); - mi_assert_internal(mi_commit_mask_is_empty(&segment->decommit_mask)); - mi_assert_internal(mi_commit_mask_is_full(&segment->commit_mask)); - *huge_page = mi_segment_span_allocate(segment, info_slices, segment_slices - info_slices - guard_slices, tld); - mi_assert_internal(*huge_page != NULL); // cannot fail as we commit in advance - } - - mi_assert_expensive(mi_segment_is_valid(segment,tld)); - return segment; -} - - -// Allocate a segment from the OS aligned to `MI_SEGMENT_SIZE` . -static mi_segment_t* mi_segment_alloc(size_t required, mi_arena_id_t req_arena_id, mi_segments_tld_t* tld, mi_os_tld_t* os_tld, mi_page_t** huge_page) { - return mi_segment_init(NULL, required, req_arena_id, tld, os_tld, huge_page); -} - - -static void mi_segment_free(mi_segment_t* segment, bool force, mi_segments_tld_t* tld) { - MI_UNUSED(force); - mi_assert_internal(segment != NULL); - mi_assert_internal(segment->next == NULL); - mi_assert_internal(segment->used == 0); - - // Remove the free pages - mi_slice_t* slice = &segment->slices[0]; - const mi_slice_t* end = mi_segment_slices_end(segment); - size_t page_count = 0; - while (slice < end) { - mi_assert_internal(slice->slice_count > 0); - mi_assert_internal(slice->slice_offset == 0); - mi_assert_internal(mi_slice_index(slice)==0 || slice->xblock_size == 0); // no more used pages .. - if (slice->xblock_size == 0 && segment->kind != MI_SEGMENT_HUGE) { - mi_segment_span_remove_from_queue(slice, tld); - } - page_count++; - slice = slice + slice->slice_count; - } - mi_assert_internal(page_count == 2); // first page is allocated by the segment itself - - // stats - _mi_stat_decrease(&tld->stats->page_committed, mi_segment_info_size(segment)); - - // return it to the OS - mi_segment_os_free(segment, tld); -} - - -/* ----------------------------------------------------------- - Page Free ------------------------------------------------------------ */ - -static void mi_segment_abandon(mi_segment_t* segment, mi_segments_tld_t* tld); - -// note: can be called on abandoned pages -static mi_slice_t* mi_segment_page_clear(mi_page_t* page, mi_segments_tld_t* tld) { - mi_assert_internal(page->xblock_size > 0); - mi_assert_internal(mi_page_all_free(page)); - mi_segment_t* segment = _mi_ptr_segment(page); - mi_assert_internal(segment->used > 0); - - size_t inuse = page->capacity * mi_page_block_size(page); - _mi_stat_decrease(&tld->stats->page_committed, inuse); - _mi_stat_decrease(&tld->stats->pages, 1); - - // reset the page memory to reduce memory pressure? - if (!segment->mem_is_pinned && !page->is_reset && mi_option_is_enabled(mi_option_page_reset)) { - size_t psize; - uint8_t* start = _mi_page_start(segment, page, &psize); - page->is_reset = true; - _mi_os_reset(start, psize, tld->stats); - } - - // zero the page data, but not the segment fields - page->is_zero_init = false; - ptrdiff_t ofs = offsetof(mi_page_t, capacity); - memset((uint8_t*)page + ofs, 0, sizeof(*page) - ofs); - page->xblock_size = 1; - - // and free it - mi_slice_t* slice = mi_segment_span_free_coalesce(mi_page_to_slice(page), tld); - segment->used--; - // cannot assert segment valid as it is called during reclaim - // mi_assert_expensive(mi_segment_is_valid(segment, tld)); - return slice; -} - -void _mi_segment_page_free(mi_page_t* page, bool force, mi_segments_tld_t* tld) -{ - mi_assert(page != NULL); - - mi_segment_t* segment = _mi_page_segment(page); - mi_assert_expensive(mi_segment_is_valid(segment,tld)); - - // mark it as free now - mi_segment_page_clear(page, tld); - mi_assert_expensive(mi_segment_is_valid(segment, tld)); - - if (segment->used == 0) { - // no more used pages; remove from the free list and free the segment - mi_segment_free(segment, force, tld); - } - else if (segment->used == segment->abandoned) { - // only abandoned pages; remove from free list and abandon - mi_segment_abandon(segment,tld); - } -} - - -/* ----------------------------------------------------------- -Abandonment - -When threads terminate, they can leave segments with -live blocks (reachable through other threads). Such segments -are "abandoned" and will be reclaimed by other threads to -reuse their pages and/or free them eventually - -We maintain a global list of abandoned segments that are -reclaimed on demand. Since this is shared among threads -the implementation needs to avoid the A-B-A problem on -popping abandoned segments: -We use tagged pointers to avoid accidentially identifying -reused segments, much like stamped references in Java. -Secondly, we maintain a reader counter to avoid resetting -or decommitting segments that have a pending read operation. - -Note: the current implementation is one possible design; -another way might be to keep track of abandoned segments -in the arenas/segment_cache's. This would have the advantage of keeping -all concurrent code in one place and not needing to deal -with ABA issues. The drawback is that it is unclear how to -scan abandoned segments efficiently in that case as they -would be spread among all other segments in the arenas. ------------------------------------------------------------ */ - -// Use the bottom 20-bits (on 64-bit) of the aligned segment pointers -// to put in a tag that increments on update to avoid the A-B-A problem. -#define MI_TAGGED_MASK MI_SEGMENT_MASK -typedef uintptr_t mi_tagged_segment_t; - -static mi_segment_t* mi_tagged_segment_ptr(mi_tagged_segment_t ts) { - return (mi_segment_t*)(ts & ~MI_TAGGED_MASK); -} - -static mi_tagged_segment_t mi_tagged_segment(mi_segment_t* segment, mi_tagged_segment_t ts) { - mi_assert_internal(((uintptr_t)segment & MI_TAGGED_MASK) == 0); - uintptr_t tag = ((ts & MI_TAGGED_MASK) + 1) & MI_TAGGED_MASK; - return ((uintptr_t)segment | tag); -} - -// This is a list of visited abandoned pages that were full at the time. -// this list migrates to `abandoned` when that becomes NULL. The use of -// this list reduces contention and the rate at which segments are visited. -static mi_decl_cache_align _Atomic(mi_segment_t*) abandoned_visited; // = NULL - -// The abandoned page list (tagged as it supports pop) -static mi_decl_cache_align _Atomic(mi_tagged_segment_t) abandoned; // = NULL - -// Maintain these for debug purposes (these counts may be a bit off) -static mi_decl_cache_align _Atomic(size_t) abandoned_count; -static mi_decl_cache_align _Atomic(size_t) abandoned_visited_count; - -// We also maintain a count of current readers of the abandoned list -// in order to prevent resetting/decommitting segment memory if it might -// still be read. -static mi_decl_cache_align _Atomic(size_t) abandoned_readers; // = 0 - -// Push on the visited list -static void mi_abandoned_visited_push(mi_segment_t* segment) { - mi_assert_internal(segment->thread_id == 0); - mi_assert_internal(mi_atomic_load_ptr_relaxed(mi_segment_t,&segment->abandoned_next) == NULL); - mi_assert_internal(segment->next == NULL); - mi_assert_internal(segment->used > 0); - mi_segment_t* anext = mi_atomic_load_ptr_relaxed(mi_segment_t, &abandoned_visited); - do { - mi_atomic_store_ptr_release(mi_segment_t, &segment->abandoned_next, anext); - } while (!mi_atomic_cas_ptr_weak_release(mi_segment_t, &abandoned_visited, &anext, segment)); - mi_atomic_increment_relaxed(&abandoned_visited_count); -} - -// Move the visited list to the abandoned list. -static bool mi_abandoned_visited_revisit(void) -{ - // quick check if the visited list is empty - if (mi_atomic_load_ptr_relaxed(mi_segment_t, &abandoned_visited) == NULL) return false; - - // grab the whole visited list - mi_segment_t* first = mi_atomic_exchange_ptr_acq_rel(mi_segment_t, &abandoned_visited, NULL); - if (first == NULL) return false; - - // first try to swap directly if the abandoned list happens to be NULL - mi_tagged_segment_t afirst; - mi_tagged_segment_t ts = mi_atomic_load_relaxed(&abandoned); - if (mi_tagged_segment_ptr(ts)==NULL) { - size_t count = mi_atomic_load_relaxed(&abandoned_visited_count); - afirst = mi_tagged_segment(first, ts); - if (mi_atomic_cas_strong_acq_rel(&abandoned, &ts, afirst)) { - mi_atomic_add_relaxed(&abandoned_count, count); - mi_atomic_sub_relaxed(&abandoned_visited_count, count); - return true; - } - } - - // find the last element of the visited list: O(n) - mi_segment_t* last = first; - mi_segment_t* next; - while ((next = mi_atomic_load_ptr_relaxed(mi_segment_t, &last->abandoned_next)) != NULL) { - last = next; - } - - // and atomically prepend to the abandoned list - // (no need to increase the readers as we don't access the abandoned segments) - mi_tagged_segment_t anext = mi_atomic_load_relaxed(&abandoned); - size_t count; - do { - count = mi_atomic_load_relaxed(&abandoned_visited_count); - mi_atomic_store_ptr_release(mi_segment_t, &last->abandoned_next, mi_tagged_segment_ptr(anext)); - afirst = mi_tagged_segment(first, anext); - } while (!mi_atomic_cas_weak_release(&abandoned, &anext, afirst)); - mi_atomic_add_relaxed(&abandoned_count, count); - mi_atomic_sub_relaxed(&abandoned_visited_count, count); - return true; -} - -// Push on the abandoned list. -static void mi_abandoned_push(mi_segment_t* segment) { - mi_assert_internal(segment->thread_id == 0); - mi_assert_internal(mi_atomic_load_ptr_relaxed(mi_segment_t, &segment->abandoned_next) == NULL); - mi_assert_internal(segment->next == NULL); - mi_assert_internal(segment->used > 0); - mi_tagged_segment_t next; - mi_tagged_segment_t ts = mi_atomic_load_relaxed(&abandoned); - do { - mi_atomic_store_ptr_release(mi_segment_t, &segment->abandoned_next, mi_tagged_segment_ptr(ts)); - next = mi_tagged_segment(segment, ts); - } while (!mi_atomic_cas_weak_release(&abandoned, &ts, next)); - mi_atomic_increment_relaxed(&abandoned_count); -} - -// Wait until there are no more pending reads on segments that used to be in the abandoned list -// called for example from `arena.c` before decommitting -void _mi_abandoned_await_readers(void) { - size_t n; - do { - n = mi_atomic_load_acquire(&abandoned_readers); - if (n != 0) mi_atomic_yield(); - } while (n != 0); -} - -// Pop from the abandoned list -static mi_segment_t* mi_abandoned_pop(void) { - mi_segment_t* segment; - // Check efficiently if it is empty (or if the visited list needs to be moved) - mi_tagged_segment_t ts = mi_atomic_load_relaxed(&abandoned); - segment = mi_tagged_segment_ptr(ts); - if mi_likely(segment == NULL) { - if mi_likely(!mi_abandoned_visited_revisit()) { // try to swap in the visited list on NULL - return NULL; - } - } - - // Do a pop. We use a reader count to prevent - // a segment to be decommitted while a read is still pending, - // and a tagged pointer to prevent A-B-A link corruption. - // (this is called from `region.c:_mi_mem_free` for example) - mi_atomic_increment_relaxed(&abandoned_readers); // ensure no segment gets decommitted - mi_tagged_segment_t next = 0; - ts = mi_atomic_load_acquire(&abandoned); - do { - segment = mi_tagged_segment_ptr(ts); - if (segment != NULL) { - mi_segment_t* anext = mi_atomic_load_ptr_relaxed(mi_segment_t, &segment->abandoned_next); - next = mi_tagged_segment(anext, ts); // note: reads the segment's `abandoned_next` field so should not be decommitted - } - } while (segment != NULL && !mi_atomic_cas_weak_acq_rel(&abandoned, &ts, next)); - mi_atomic_decrement_relaxed(&abandoned_readers); // release reader lock - if (segment != NULL) { - mi_atomic_store_ptr_release(mi_segment_t, &segment->abandoned_next, NULL); - mi_atomic_decrement_relaxed(&abandoned_count); - } - return segment; -} - -/* ----------------------------------------------------------- - Abandon segment/page ------------------------------------------------------------ */ - -static void mi_segment_abandon(mi_segment_t* segment, mi_segments_tld_t* tld) { - mi_assert_internal(segment->used == segment->abandoned); - mi_assert_internal(segment->used > 0); - mi_assert_internal(mi_atomic_load_ptr_relaxed(mi_segment_t, &segment->abandoned_next) == NULL); - mi_assert_internal(segment->abandoned_visits == 0); - mi_assert_expensive(mi_segment_is_valid(segment,tld)); - - // remove the free pages from the free page queues - mi_slice_t* slice = &segment->slices[0]; - const mi_slice_t* end = mi_segment_slices_end(segment); - while (slice < end) { - mi_assert_internal(slice->slice_count > 0); - mi_assert_internal(slice->slice_offset == 0); - if (slice->xblock_size == 0) { // a free page - mi_segment_span_remove_from_queue(slice,tld); - slice->xblock_size = 0; // but keep it free - } - slice = slice + slice->slice_count; - } - - // perform delayed decommits - mi_segment_delayed_decommit(segment, mi_option_is_enabled(mi_option_abandoned_page_decommit) /* force? */, tld->stats); - - // all pages in the segment are abandoned; add it to the abandoned list - _mi_stat_increase(&tld->stats->segments_abandoned, 1); - mi_segments_track_size(-((long)mi_segment_size(segment)), tld); - segment->thread_id = 0; - mi_atomic_store_ptr_release(mi_segment_t, &segment->abandoned_next, NULL); - segment->abandoned_visits = 1; // from 0 to 1 to signify it is abandoned - mi_abandoned_push(segment); -} - -void _mi_segment_page_abandon(mi_page_t* page, mi_segments_tld_t* tld) { - mi_assert(page != NULL); - mi_assert_internal(mi_page_thread_free_flag(page)==MI_NEVER_DELAYED_FREE); - mi_assert_internal(mi_page_heap(page) == NULL); - mi_segment_t* segment = _mi_page_segment(page); - - mi_assert_expensive(mi_segment_is_valid(segment,tld)); - segment->abandoned++; - - _mi_stat_increase(&tld->stats->pages_abandoned, 1); - mi_assert_internal(segment->abandoned <= segment->used); - if (segment->used == segment->abandoned) { - // all pages are abandoned, abandon the entire segment - mi_segment_abandon(segment, tld); - } -} - -/* ----------------------------------------------------------- - Reclaim abandoned pages ------------------------------------------------------------ */ - -static mi_slice_t* mi_slices_start_iterate(mi_segment_t* segment, const mi_slice_t** end) { - mi_slice_t* slice = &segment->slices[0]; - *end = mi_segment_slices_end(segment); - mi_assert_internal(slice->slice_count>0 && slice->xblock_size>0); // segment allocated page - slice = slice + slice->slice_count; // skip the first segment allocated page - return slice; -} - -// Possibly free pages and check if free space is available -static bool mi_segment_check_free(mi_segment_t* segment, size_t slices_needed, size_t block_size, mi_segments_tld_t* tld) -{ - mi_assert_internal(block_size < MI_HUGE_BLOCK_SIZE); - mi_assert_internal(mi_segment_is_abandoned(segment)); - bool has_page = false; - - // for all slices - const mi_slice_t* end; - mi_slice_t* slice = mi_slices_start_iterate(segment, &end); - while (slice < end) { - mi_assert_internal(slice->slice_count > 0); - mi_assert_internal(slice->slice_offset == 0); - if (mi_slice_is_used(slice)) { // used page - // ensure used count is up to date and collect potential concurrent frees - mi_page_t* const page = mi_slice_to_page(slice); - _mi_page_free_collect(page, false); - if (mi_page_all_free(page)) { - // if this page is all free now, free it without adding to any queues (yet) - mi_assert_internal(page->next == NULL && page->prev==NULL); - _mi_stat_decrease(&tld->stats->pages_abandoned, 1); - segment->abandoned--; - slice = mi_segment_page_clear(page, tld); // re-assign slice due to coalesce! - mi_assert_internal(!mi_slice_is_used(slice)); - if (slice->slice_count >= slices_needed) { - has_page = true; - } - } - else { - if (page->xblock_size == block_size && mi_page_has_any_available(page)) { - // a page has available free blocks of the right size - has_page = true; - } - } - } - else { - // empty span - if (slice->slice_count >= slices_needed) { - has_page = true; - } - } - slice = slice + slice->slice_count; - } - return has_page; -} - -// Reclaim an abandoned segment; returns NULL if the segment was freed -// set `right_page_reclaimed` to `true` if it reclaimed a page of the right `block_size` that was not full. -static mi_segment_t* mi_segment_reclaim(mi_segment_t* segment, mi_heap_t* heap, size_t requested_block_size, bool* right_page_reclaimed, mi_segments_tld_t* tld) { - mi_assert_internal(mi_atomic_load_ptr_relaxed(mi_segment_t, &segment->abandoned_next) == NULL); - mi_assert_expensive(mi_segment_is_valid(segment, tld)); - if (right_page_reclaimed != NULL) { *right_page_reclaimed = false; } - - segment->thread_id = _mi_thread_id(); - segment->abandoned_visits = 0; - mi_segments_track_size((long)mi_segment_size(segment), tld); - mi_assert_internal(segment->next == NULL); - _mi_stat_decrease(&tld->stats->segments_abandoned, 1); - - // for all slices - const mi_slice_t* end; - mi_slice_t* slice = mi_slices_start_iterate(segment, &end); - while (slice < end) { - mi_assert_internal(slice->slice_count > 0); - mi_assert_internal(slice->slice_offset == 0); - if (mi_slice_is_used(slice)) { - // in use: reclaim the page in our heap - mi_page_t* page = mi_slice_to_page(slice); - mi_assert_internal(!page->is_reset); - mi_assert_internal(page->is_committed); - mi_assert_internal(mi_page_thread_free_flag(page)==MI_NEVER_DELAYED_FREE); - mi_assert_internal(mi_page_heap(page) == NULL); - mi_assert_internal(page->next == NULL && page->prev==NULL); - _mi_stat_decrease(&tld->stats->pages_abandoned, 1); - segment->abandoned--; - // set the heap again and allow delayed free again - mi_page_set_heap(page, heap); - _mi_page_use_delayed_free(page, MI_USE_DELAYED_FREE, true); // override never (after heap is set) - _mi_page_free_collect(page, false); // ensure used count is up to date - if (mi_page_all_free(page)) { - // if everything free by now, free the page - slice = mi_segment_page_clear(page, tld); // set slice again due to coalesceing - } - else { - // otherwise reclaim it into the heap - _mi_page_reclaim(heap, page); - if (requested_block_size == page->xblock_size && mi_page_has_any_available(page)) { - if (right_page_reclaimed != NULL) { *right_page_reclaimed = true; } - } - } - } - else { - // the span is free, add it to our page queues - slice = mi_segment_span_free_coalesce(slice, tld); // set slice again due to coalesceing - } - mi_assert_internal(slice->slice_count>0 && slice->slice_offset==0); - slice = slice + slice->slice_count; - } - - mi_assert(segment->abandoned == 0); - if (segment->used == 0) { // due to page_clear - mi_assert_internal(right_page_reclaimed == NULL || !(*right_page_reclaimed)); - mi_segment_free(segment, false, tld); - return NULL; - } - else { - return segment; - } -} - - -void _mi_abandoned_reclaim_all(mi_heap_t* heap, mi_segments_tld_t* tld) { - mi_segment_t* segment; - while ((segment = mi_abandoned_pop()) != NULL) { - mi_segment_reclaim(segment, heap, 0, NULL, tld); - } -} - -static mi_segment_t* mi_segment_try_reclaim(mi_heap_t* heap, size_t needed_slices, size_t block_size, bool* reclaimed, mi_segments_tld_t* tld) -{ - *reclaimed = false; - mi_segment_t* segment; - long max_tries = mi_option_get_clamp(mi_option_max_segment_reclaim, 8, 1024); // limit the work to bound allocation times - while ((max_tries-- > 0) && ((segment = mi_abandoned_pop()) != NULL)) { - segment->abandoned_visits++; - // todo: an arena exclusive heap will potentially visit many abandoned unsuitable segments - // and push them into the visited list and use many tries. Perhaps we can skip non-suitable ones in a better way? - bool is_suitable = _mi_heap_memid_is_suitable(heap, segment->memid); - bool has_page = mi_segment_check_free(segment,needed_slices,block_size,tld); // try to free up pages (due to concurrent frees) - if (segment->used == 0) { - // free the segment (by forced reclaim) to make it available to other threads. - // note1: we prefer to free a segment as that might lead to reclaiming another - // segment that is still partially used. - // note2: we could in principle optimize this by skipping reclaim and directly - // freeing but that would violate some invariants temporarily) - mi_segment_reclaim(segment, heap, 0, NULL, tld); - } - else if (has_page && is_suitable) { - // found a large enough free span, or a page of the right block_size with free space - // we return the result of reclaim (which is usually `segment`) as it might free - // the segment due to concurrent frees (in which case `NULL` is returned). - return mi_segment_reclaim(segment, heap, block_size, reclaimed, tld); - } - else if (segment->abandoned_visits > 3 && is_suitable) { - // always reclaim on 3rd visit to limit the abandoned queue length. - mi_segment_reclaim(segment, heap, 0, NULL, tld); - } - else { - // otherwise, push on the visited list so it gets not looked at too quickly again - mi_segment_delayed_decommit(segment, true /* force? */, tld->stats); // forced decommit if needed as we may not visit soon again - mi_abandoned_visited_push(segment); - } - } - return NULL; -} - - -void _mi_abandoned_collect(mi_heap_t* heap, bool force, mi_segments_tld_t* tld) -{ - mi_segment_t* segment; - int max_tries = (force ? 16*1024 : 1024); // limit latency - if (force) { - mi_abandoned_visited_revisit(); - } - while ((max_tries-- > 0) && ((segment = mi_abandoned_pop()) != NULL)) { - mi_segment_check_free(segment,0,0,tld); // try to free up pages (due to concurrent frees) - if (segment->used == 0) { - // free the segment (by forced reclaim) to make it available to other threads. - // note: we could in principle optimize this by skipping reclaim and directly - // freeing but that would violate some invariants temporarily) - mi_segment_reclaim(segment, heap, 0, NULL, tld); - } - else { - // otherwise, decommit if needed and push on the visited list - // note: forced decommit can be expensive if many threads are destroyed/created as in mstress. - mi_segment_delayed_decommit(segment, force, tld->stats); - mi_abandoned_visited_push(segment); - } - } -} - -/* ----------------------------------------------------------- - Reclaim or allocate ------------------------------------------------------------ */ - -static mi_segment_t* mi_segment_reclaim_or_alloc(mi_heap_t* heap, size_t needed_slices, size_t block_size, mi_segments_tld_t* tld, mi_os_tld_t* os_tld) -{ - mi_assert_internal(block_size < MI_HUGE_BLOCK_SIZE); - mi_assert_internal(block_size <= MI_LARGE_OBJ_SIZE_MAX); - - // 1. try to reclaim an abandoned segment - bool reclaimed; - mi_segment_t* segment = mi_segment_try_reclaim(heap, needed_slices, block_size, &reclaimed, tld); - if (reclaimed) { - // reclaimed the right page right into the heap - mi_assert_internal(segment != NULL); - return NULL; // pretend out-of-memory as the page will be in the page queue of the heap with available blocks - } - else if (segment != NULL) { - // reclaimed a segment with a large enough empty span in it - return segment; - } - // 2. otherwise allocate a fresh segment - return mi_segment_alloc(0, heap->arena_id, tld, os_tld, NULL); -} - - -/* ----------------------------------------------------------- - Page allocation ------------------------------------------------------------ */ - -static mi_page_t* mi_segments_page_alloc(mi_heap_t* heap, mi_page_kind_t page_kind, size_t required, size_t block_size, mi_segments_tld_t* tld, mi_os_tld_t* os_tld) -{ - mi_assert_internal(required <= MI_LARGE_OBJ_SIZE_MAX && page_kind <= MI_PAGE_LARGE); - - // find a free page - size_t page_size = _mi_align_up(required, (required > MI_MEDIUM_PAGE_SIZE ? MI_MEDIUM_PAGE_SIZE : MI_SEGMENT_SLICE_SIZE)); - size_t slices_needed = page_size / MI_SEGMENT_SLICE_SIZE; - mi_assert_internal(slices_needed * MI_SEGMENT_SLICE_SIZE == page_size); - mi_page_t* page = mi_segments_page_find_and_allocate(slices_needed, heap->arena_id, tld); //(required <= MI_SMALL_SIZE_MAX ? 0 : slices_needed), tld); - if (page==NULL) { - // no free page, allocate a new segment and try again - if (mi_segment_reclaim_or_alloc(heap, slices_needed, block_size, tld, os_tld) == NULL) { - // OOM or reclaimed a good page in the heap - return NULL; - } - else { - // otherwise try again - return mi_segments_page_alloc(heap, page_kind, required, block_size, tld, os_tld); - } - } - mi_assert_internal(page != NULL && page->slice_count*MI_SEGMENT_SLICE_SIZE == page_size); - mi_assert_internal(_mi_ptr_segment(page)->thread_id == _mi_thread_id()); - mi_segment_delayed_decommit(_mi_ptr_segment(page), false, tld->stats); - return page; -} - - - -/* ----------------------------------------------------------- - Huge page allocation ------------------------------------------------------------ */ - -static mi_page_t* mi_segment_huge_page_alloc(size_t size, mi_arena_id_t req_arena_id, mi_segments_tld_t* tld, mi_os_tld_t* os_tld) -{ - mi_page_t* page = NULL; - mi_segment_t* segment = mi_segment_alloc(size,req_arena_id,tld,os_tld,&page); - if (segment == NULL || page==NULL) return NULL; - mi_assert_internal(segment->used==1); - mi_assert_internal(mi_page_block_size(page) >= size); - segment->thread_id = 0; // huge segments are immediately abandoned - return page; -} - -// free huge block from another thread -void _mi_segment_huge_page_free(mi_segment_t* segment, mi_page_t* page, mi_block_t* block) { - // huge page segments are always abandoned and can be freed immediately by any thread - mi_assert_internal(segment->kind==MI_SEGMENT_HUGE); - mi_assert_internal(segment == _mi_page_segment(page)); - mi_assert_internal(mi_atomic_load_relaxed(&segment->thread_id)==0); - - // claim it and free - mi_heap_t* heap = mi_heap_get_default(); // issue #221; don't use the internal get_default_heap as we need to ensure the thread is initialized. - // paranoia: if this it the last reference, the cas should always succeed - size_t expected_tid = 0; - if (mi_atomic_cas_strong_acq_rel(&segment->thread_id, &expected_tid, heap->thread_id)) { - mi_block_set_next(page, block, page->free); - page->free = block; - page->used--; - page->is_zero = false; - mi_assert(page->used == 0); - mi_tld_t* tld = heap->tld; - _mi_segment_page_free(page, true, &tld->segments); - } -#if (MI_DEBUG!=0) - else { - mi_assert_internal(false); - } -#endif -} - -/* ----------------------------------------------------------- - Page allocation and free ------------------------------------------------------------ */ -mi_page_t* _mi_segment_page_alloc(mi_heap_t* heap, size_t block_size, mi_segments_tld_t* tld, mi_os_tld_t* os_tld) { - mi_page_t* page; - if (block_size <= MI_SMALL_OBJ_SIZE_MAX) { - page = mi_segments_page_alloc(heap,MI_PAGE_SMALL,block_size,block_size,tld,os_tld); - } - else if (block_size <= MI_MEDIUM_OBJ_SIZE_MAX) { - page = mi_segments_page_alloc(heap,MI_PAGE_MEDIUM,MI_MEDIUM_PAGE_SIZE,block_size,tld, os_tld); - } - else if (block_size <= MI_LARGE_OBJ_SIZE_MAX) { - page = mi_segments_page_alloc(heap,MI_PAGE_LARGE,block_size,block_size,tld, os_tld); - } - else { - page = mi_segment_huge_page_alloc(block_size,heap->arena_id,tld,os_tld); - } - mi_assert_internal(page == NULL || _mi_heap_memid_is_suitable(heap, _mi_page_segment(page)->memid)); - mi_assert_expensive(page == NULL || mi_segment_is_valid(_mi_page_segment(page),tld)); - return page; -} - - diff --git a/src/dashbls/depends/mimalloc/src/static.c b/src/dashbls/depends/mimalloc/src/static.c index 5b34ddbb6ce0..dd874f1697c6 100644 --- a/src/dashbls/depends/mimalloc/src/static.c +++ b/src/dashbls/depends/mimalloc/src/static.c @@ -14,26 +14,28 @@ terms of the MIT license. A copy of the license can be found in the file #endif #include "mimalloc.h" -#include "mimalloc-internal.h" +#include "mimalloc/internal.h" // For a static override we create a single object file // containing the whole library. If it is linked first // it will override all the standard library allocation // functions (on Unix's). -#include "stats.c" -#include "random.c" -#include "os.c" -#include "bitmap.c" -#include "arena.c" -#include "segment-cache.c" -#include "segment.c" -#include "page.c" -#include "heap.c" -#include "alloc.c" +#include "alloc.c" // includes alloc-override.c and free.c #include "alloc-aligned.c" #include "alloc-posix.c" -#if MI_OSX_ZONE -#include "alloc-override-osx.c" -#endif +#include "arena.c" +#include "arena-meta.c" +#include "bitmap.c" +#include "heap.c" #include "init.c" +#include "libc.c" #include "options.c" +#include "os.c" +#include "page.c" // includes page-queue.c +#include "page-map.c" +#include "random.c" +#include "stats.c" +#include "prim/prim.c" +#if MI_OSX_ZONE +#include "prim/osx/alloc-override-zone.c" +#endif diff --git a/src/dashbls/depends/mimalloc/src/stats.c b/src/dashbls/depends/mimalloc/src/stats.c index f82c7c67f227..4eba519a44e3 100644 --- a/src/dashbls/depends/mimalloc/src/stats.c +++ b/src/dashbls/depends/mimalloc/src/stats.c @@ -5,10 +5,10 @@ terms of the MIT license. A copy of the license can be found in the file "LICENSE" at the root of this distribution. -----------------------------------------------------------------------------*/ #include "mimalloc.h" -#include "mimalloc-internal.h" -#include "mimalloc-atomic.h" +#include "mimalloc/internal.h" +#include "mimalloc/atomic.h" +#include "mimalloc/prim.h" -#include // fputs, stderr #include // memset #if defined(_MSC_VER) && (_MSC_VER < 1920) @@ -19,121 +19,126 @@ terms of the MIT license. A copy of the license can be found in the file Statistics operations ----------------------------------------------------------- */ -static bool mi_is_in_main(void* stat) { - return ((uint8_t*)stat >= (uint8_t*)&_mi_stats_main - && (uint8_t*)stat < ((uint8_t*)&_mi_stats_main + sizeof(mi_stats_t))); +static void mi_stat_update_mt(mi_stat_count_t* stat, int64_t amount) { + if (amount == 0) return; + // add atomically + int64_t current = mi_atomic_addi64_relaxed(&stat->current, amount); + mi_atomic_maxi64_relaxed(&stat->peak, current + amount); + if (amount > 0) { + mi_atomic_addi64_relaxed(&stat->total, amount); + } } static void mi_stat_update(mi_stat_count_t* stat, int64_t amount) { if (amount == 0) return; - if (mi_is_in_main(stat)) - { - // add atomically (for abandoned pages) - int64_t current = mi_atomic_addi64_relaxed(&stat->current, amount); - mi_atomic_maxi64_relaxed(&stat->peak, current + amount); - if (amount > 0) { - mi_atomic_addi64_relaxed(&stat->allocated,amount); - } - else { - mi_atomic_addi64_relaxed(&stat->freed, -amount); - } - } - else { - // add thread local - stat->current += amount; - if (stat->current > stat->peak) stat->peak = stat->current; - if (amount > 0) { - stat->allocated += amount; - } - else { - stat->freed += -amount; - } - } + // add thread local + stat->current += amount; + if (stat->current > stat->peak) { stat->peak = stat->current; } + if (amount > 0) { stat->total += amount; } } -void _mi_stat_counter_increase(mi_stat_counter_t* stat, size_t amount) { - if (mi_is_in_main(stat)) { - mi_atomic_addi64_relaxed( &stat->count, 1 ); - mi_atomic_addi64_relaxed( &stat->total, (int64_t)amount ); - } - else { - stat->count++; - stat->total += amount; - } + +void __mi_stat_counter_increase_mt(mi_stat_counter_t* stat, size_t amount) { + mi_atomic_addi64_relaxed(&stat->total, (int64_t)amount); +} + +void __mi_stat_counter_increase(mi_stat_counter_t* stat, size_t amount) { + stat->total += amount; } -void _mi_stat_increase(mi_stat_count_t* stat, size_t amount) { +void __mi_stat_increase_mt(mi_stat_count_t* stat, size_t amount) { + mi_stat_update_mt(stat, (int64_t)amount); +} +void __mi_stat_increase(mi_stat_count_t* stat, size_t amount) { mi_stat_update(stat, (int64_t)amount); } -void _mi_stat_decrease(mi_stat_count_t* stat, size_t amount) { +void __mi_stat_decrease_mt(mi_stat_count_t* stat, size_t amount) { + mi_stat_update_mt(stat, -((int64_t)amount)); +} +void __mi_stat_decrease(mi_stat_count_t* stat, size_t amount) { mi_stat_update(stat, -((int64_t)amount)); } + +// Adjust stats to compensate; for example before committing a range, +// first adjust downwards with parts that were already committed so +// we avoid double counting. +static void mi_stat_adjust_mt(mi_stat_count_t* stat, int64_t amount) { + if (amount == 0) return; + // adjust atomically + mi_atomic_addi64_relaxed(&stat->current, amount); + mi_atomic_addi64_relaxed(&stat->total, amount); +} + +static void mi_stat_adjust(mi_stat_count_t* stat, int64_t amount) { + if (amount == 0) return; + stat->current += amount; + stat->total += amount; +} + +void __mi_stat_adjust_increase_mt(mi_stat_count_t* stat, size_t amount) { + mi_stat_adjust_mt(stat, (int64_t)amount); +} +void __mi_stat_adjust_increase(mi_stat_count_t* stat, size_t amount) { + mi_stat_adjust(stat, (int64_t)amount); +} +void __mi_stat_adjust_decrease_mt(mi_stat_count_t* stat, size_t amount) { + mi_stat_adjust_mt(stat, -((int64_t)amount)); +} +void __mi_stat_adjust_decrease(mi_stat_count_t* stat, size_t amount) { + mi_stat_adjust(stat, -((int64_t)amount)); +} + + // must be thread safe as it is called from stats_merge -static void mi_stat_add(mi_stat_count_t* stat, const mi_stat_count_t* src, int64_t unit) { +static void mi_stat_count_add_mt(mi_stat_count_t* stat, const mi_stat_count_t* src) { if (stat==src) return; - if (src->allocated==0 && src->freed==0) return; - mi_atomic_addi64_relaxed( &stat->allocated, src->allocated * unit); - mi_atomic_addi64_relaxed( &stat->current, src->current * unit); - mi_atomic_addi64_relaxed( &stat->freed, src->freed * unit); - // peak scores do not work across threads.. - mi_atomic_addi64_relaxed( &stat->peak, src->peak * unit); + mi_atomic_void_addi64_relaxed(&stat->total, &src->total); + mi_atomic_void_addi64_relaxed(&stat->current, &src->current); + // peak scores do really not work across threads .. we just add them + mi_atomic_void_addi64_relaxed( &stat->peak, &src->peak); + // or, take the max? + // mi_atomic_maxi64_relaxed(&stat->peak, src->peak); } -static void mi_stat_counter_add(mi_stat_counter_t* stat, const mi_stat_counter_t* src, int64_t unit) { +static void mi_stat_counter_add_mt(mi_stat_counter_t* stat, const mi_stat_counter_t* src) { if (stat==src) return; - mi_atomic_addi64_relaxed( &stat->total, src->total * unit); - mi_atomic_addi64_relaxed( &stat->count, src->count * unit); + mi_atomic_void_addi64_relaxed(&stat->total, &src->total); } +#define MI_STAT_COUNT(stat) mi_stat_count_add_mt(&stats->stat, &src->stat); +#define MI_STAT_COUNTER(stat) mi_stat_counter_add_mt(&stats->stat, &src->stat); + // must be thread safe as it is called from stats_merge static void mi_stats_add(mi_stats_t* stats, const mi_stats_t* src) { if (stats==src) return; - mi_stat_add(&stats->segments, &src->segments,1); - mi_stat_add(&stats->pages, &src->pages,1); - mi_stat_add(&stats->reserved, &src->reserved, 1); - mi_stat_add(&stats->committed, &src->committed, 1); - mi_stat_add(&stats->reset, &src->reset, 1); - mi_stat_add(&stats->page_committed, &src->page_committed, 1); - - mi_stat_add(&stats->pages_abandoned, &src->pages_abandoned, 1); - mi_stat_add(&stats->segments_abandoned, &src->segments_abandoned, 1); - mi_stat_add(&stats->threads, &src->threads, 1); - - mi_stat_add(&stats->malloc, &src->malloc, 1); - mi_stat_add(&stats->segments_cache, &src->segments_cache, 1); - mi_stat_add(&stats->normal, &src->normal, 1); - mi_stat_add(&stats->huge, &src->huge, 1); - mi_stat_add(&stats->large, &src->large, 1); - - mi_stat_counter_add(&stats->pages_extended, &src->pages_extended, 1); - mi_stat_counter_add(&stats->mmap_calls, &src->mmap_calls, 1); - mi_stat_counter_add(&stats->commit_calls, &src->commit_calls, 1); - - mi_stat_counter_add(&stats->page_no_retire, &src->page_no_retire, 1); - mi_stat_counter_add(&stats->searches, &src->searches, 1); - mi_stat_counter_add(&stats->normal_count, &src->normal_count, 1); - mi_stat_counter_add(&stats->huge_count, &src->huge_count, 1); - mi_stat_counter_add(&stats->large_count, &src->large_count, 1); -#if MI_STAT>1 + + // copy all fields + MI_STAT_FIELDS() + + #if MI_STAT>1 for (size_t i = 0; i <= MI_BIN_HUGE; i++) { - if (src->normal_bins[i].allocated > 0 || src->normal_bins[i].freed > 0) { - mi_stat_add(&stats->normal_bins[i], &src->normal_bins[i], 1); - } + mi_stat_count_add_mt(&stats->malloc_bins[i], &src->malloc_bins[i]); + } + #endif + for (size_t i = 0; i <= MI_BIN_HUGE; i++) { + mi_stat_count_add_mt(&stats->page_bins[i], &src->page_bins[i]); } -#endif } +#undef MI_STAT_COUNT +#undef MI_STAT_COUNTER + /* ----------------------------------------------------------- Display statistics ----------------------------------------------------------- */ -// unit > 0 : size in binary bytes +// unit > 0 : size in binary bytes // unit == 0: count as decimal // unit < 0 : count in binary static void mi_printf_amount(int64_t n, int64_t unit, mi_output_fun* out, void* arg, const char* fmt) { - char buf[32]; buf[0] = 0; + char buf[32]; _mi_memzero_var(buf); int len = 32; const char* suffix = (unit <= 0 ? " " : "B"); const int64_t base = (unit == 0 ? 1000 : 1024); @@ -142,11 +147,11 @@ static void mi_printf_amount(int64_t n, int64_t unit, mi_output_fun* out, void* const int64_t pos = (n < 0 ? -n : n); if (pos < base) { if (n!=1 || suffix[0] != 'B') { // skip printing 1 B for the unit column - snprintf(buf, len, "%d %-3s", (int)n, (n==0 ? "" : suffix)); + _mi_snprintf(buf, len, "%lld %-3s", (long long)n, (n==0 ? "" : suffix)); } } else { - int64_t divider = base; + int64_t divider = base; const char* magnitude = "K"; if (pos >= divider*base) { divider *= base; magnitude = "M"; } if (pos >= divider*base) { divider *= base; magnitude = "G"; } @@ -154,10 +159,10 @@ static void mi_printf_amount(int64_t n, int64_t unit, mi_output_fun* out, void* const long whole = (long)(tens/10); const long frac1 = (long)(tens%10); char unitdesc[8]; - snprintf(unitdesc, 8, "%s%s%s", magnitude, (base==1024 ? "i" : ""), suffix); - snprintf(buf, len, "%ld.%ld %-3s", whole, (frac1 < 0 ? -frac1 : frac1), unitdesc); + _mi_snprintf(unitdesc, 8, "%s%s%s", magnitude, (base==1024 ? "i" : ""), suffix); + _mi_snprintf(buf, len, "%ld.%ld %-3s", whole, (frac1 < 0 ? -frac1 : frac1), unitdesc); } - _mi_fprintf(out, arg, (fmt==NULL ? "%11s" : fmt), buf); + _mi_fprintf(out, arg, (fmt==NULL ? "%12s" : fmt), buf); } @@ -166,58 +171,80 @@ static void mi_print_amount(int64_t n, int64_t unit, mi_output_fun* out, void* a } static void mi_print_count(int64_t n, int64_t unit, mi_output_fun* out, void* arg) { - if (unit==1) _mi_fprintf(out, arg, "%11s"," "); + if (unit==1) _mi_fprintf(out, arg, "%12s"," "); else mi_print_amount(n,0,out,arg); } -static void mi_stat_print(const mi_stat_count_t* stat, const char* msg, int64_t unit, mi_output_fun* out, void* arg ) { +static void mi_stat_print_ex(const mi_stat_count_t* stat, const char* msg, int64_t unit, mi_output_fun* out, void* arg, const char* notok ) { _mi_fprintf(out, arg,"%10s:", msg); - if (unit>0) { - mi_print_amount(stat->peak, unit, out, arg); - mi_print_amount(stat->allocated, unit, out, arg); - mi_print_amount(stat->freed, unit, out, arg); - mi_print_amount(stat->current, unit, out, arg); - mi_print_amount(unit, 1, out, arg); - mi_print_count(stat->allocated, unit, out, arg); - if (stat->allocated > stat->freed) - _mi_fprintf(out, arg, " not all freed!\n"); - else - _mi_fprintf(out, arg, " ok\n"); - } - else if (unit<0) { - mi_print_amount(stat->peak, -1, out, arg); - mi_print_amount(stat->allocated, -1, out, arg); - mi_print_amount(stat->freed, -1, out, arg); - mi_print_amount(stat->current, -1, out, arg); - if (unit==-1) { - _mi_fprintf(out, arg, "%22s", ""); + if (unit != 0) { + if (unit > 0) { + mi_print_amount(stat->peak, unit, out, arg); + mi_print_amount(stat->total, unit, out, arg); + // mi_print_amount(stat->freed, unit, out, arg); + mi_print_amount(stat->current, unit, out, arg); + mi_print_amount(unit, 1, out, arg); + mi_print_count(stat->total, unit, out, arg); } else { - mi_print_amount(-unit, 1, out, arg); - mi_print_count((stat->allocated / -unit), 0, out, arg); + mi_print_amount(stat->peak, -1, out, arg); + mi_print_amount(stat->total, -1, out, arg); + // mi_print_amount(stat->freed, -1, out, arg); + mi_print_amount(stat->current, -1, out, arg); + if (unit == -1) { + _mi_fprintf(out, arg, "%24s", ""); + } + else { + mi_print_amount(-unit, 1, out, arg); + mi_print_count((stat->total / -unit), 0, out, arg); + } } - if (stat->allocated > stat->freed) - _mi_fprintf(out, arg, " not all freed!\n"); - else + if (stat->current != 0) { + _mi_fprintf(out, arg, " "); + _mi_fprintf(out, arg, (notok == NULL ? "not all freed" : notok)); + _mi_fprintf(out, arg, "\n"); + } + else { _mi_fprintf(out, arg, " ok\n"); + } } else { mi_print_amount(stat->peak, 1, out, arg); - mi_print_amount(stat->allocated, 1, out, arg); - _mi_fprintf(out, arg, "%11s", " "); // no freed + mi_print_amount(stat->total, 1, out, arg); + _mi_fprintf(out, arg, "%11s", " "); // no freed mi_print_amount(stat->current, 1, out, arg); _mi_fprintf(out, arg, "\n"); } } +static void mi_stat_print(const mi_stat_count_t* stat, const char* msg, int64_t unit, mi_output_fun* out, void* arg) { + mi_stat_print_ex(stat, msg, unit, out, arg, NULL); +} + +static void mi_stat_peak_print(const mi_stat_count_t* stat, const char* msg, int64_t unit, mi_output_fun* out, void* arg) { + _mi_fprintf(out, arg, "%10s:", msg); + mi_print_amount(stat->peak, unit, out, arg); + _mi_fprintf(out, arg, "\n"); +} + +#if MI_STAT>1 +static void mi_stat_total_print(const mi_stat_count_t* stat, const char* msg, int64_t unit, mi_output_fun* out, void* arg) { + _mi_fprintf(out, arg, "%10s:", msg); + _mi_fprintf(out, arg, "%12s", " "); // no peak + mi_print_amount(stat->total, unit, out, arg); + _mi_fprintf(out, arg, "\n"); +} +#endif + static void mi_stat_counter_print(const mi_stat_counter_t* stat, const char* msg, mi_output_fun* out, void* arg ) { _mi_fprintf(out, arg, "%10s:", msg); mi_print_amount(stat->total, -1, out, arg); _mi_fprintf(out, arg, "\n"); } + static void mi_stat_counter_print_avg(const mi_stat_counter_t* stat, const char* msg, mi_output_fun* out, void* arg) { - const int64_t avg_tens = (stat->count == 0 ? 0 : (stat->total*10 / stat->count)); + const int64_t avg_tens = (stat->total == 0 ? 0 : (stat->total*10 / stat->total)); const long avg_whole = (long)(avg_tens/10); const long avg_frac1 = (long)(avg_tens%10); _mi_fprintf(out, arg, "%10s: %5ld.%ld avg\n", msg, avg_whole, avg_frac1); @@ -225,7 +252,7 @@ static void mi_stat_counter_print_avg(const mi_stat_counter_t* stat, const char* static void mi_print_header(mi_output_fun* out, void* arg ) { - _mi_fprintf(out, arg, "%10s: %10s %10s %10s %10s %10s %10s\n", "heap stats", "peak ", "total ", "freed ", "current ", "unit ", "count "); + _mi_fprintf(out, arg, "%10s: %11s %11s %11s %11s %11s\n", "heap stats", "peak ", "total ", "current ", "block ", "total# "); } #if MI_STAT>1 @@ -233,10 +260,10 @@ static void mi_stats_print_bins(const mi_stat_count_t* bins, size_t max, const c bool found = false; char buf[64]; for (size_t i = 0; i <= max; i++) { - if (bins[i].allocated > 0) { + if (bins[i].total > 0) { found = true; int64_t unit = _mi_bin_size((uint8_t)i); - snprintf(buf, 64, "%s %3lu", fmt, (long)i); + _mi_snprintf(buf, 64, "%s %3lu", fmt, (long)i); mi_stat_print(&bins[i], buf, unit, out, arg); } } @@ -257,7 +284,7 @@ typedef struct buffered_s { mi_output_fun* out; // original output function void* arg; // and state char* buf; // local buffer of at least size `count+1` - size_t used; // currently used chars `used <= count` + size_t used; // currently used chars `used <= count` size_t count; // total chars available for output } buffered_t; @@ -283,11 +310,9 @@ static void mi_cdecl mi_buffered_out(const char* msg, void* arg) { // Print statistics //------------------------------------------------------------ -static void mi_stat_process_info(mi_msecs_t* elapsed, mi_msecs_t* utime, mi_msecs_t* stime, size_t* current_rss, size_t* peak_rss, size_t* current_commit, size_t* peak_commit, size_t* page_faults); - -static void _mi_stats_print(mi_stats_t* stats, mi_output_fun* out0, void* arg0) mi_attr_noexcept { +void _mi_stats_print(mi_stats_t* stats, mi_output_fun* out0, void* arg0) mi_attr_noexcept { // wrap the output function to be line buffered - char buf[256]; + char buf[256]; _mi_memzero_var(buf); buffered_t buffer = { out0, arg0, NULL, 0, 255 }; buffer.buf = buf; mi_output_fun* out = &mi_buffered_out; @@ -296,91 +321,115 @@ static void _mi_stats_print(mi_stats_t* stats, mi_output_fun* out0, void* arg0) // and print using that mi_print_header(out,arg); #if MI_STAT>1 - mi_stats_print_bins(stats->normal_bins, MI_BIN_HUGE, "normal",out,arg); + mi_stats_print_bins(stats->malloc_bins, MI_BIN_HUGE, "bin",out,arg); #endif #if MI_STAT - mi_stat_print(&stats->normal, "normal", (stats->normal_count.count == 0 ? 1 : -(stats->normal.allocated / stats->normal_count.count)), out, arg); - mi_stat_print(&stats->large, "large", (stats->large_count.count == 0 ? 1 : -(stats->large.allocated / stats->large_count.count)), out, arg); - mi_stat_print(&stats->huge, "huge", (stats->huge_count.count == 0 ? 1 : -(stats->huge.allocated / stats->huge_count.count)), out, arg); - mi_stat_count_t total = { 0,0,0,0 }; - mi_stat_add(&total, &stats->normal, 1); - mi_stat_add(&total, &stats->large, 1); - mi_stat_add(&total, &stats->huge, 1); - mi_stat_print(&total, "total", 1, out, arg); + mi_stat_print(&stats->malloc_normal, "binned", (stats->malloc_normal_count.total == 0 ? 1 : -1), out, arg); + mi_stat_print(&stats->malloc_huge, "huge", (stats->malloc_huge_count.total == 0 ? 1 : -1), out, arg); + mi_stat_count_t total = { 0,0,0 }; + mi_stat_count_add_mt(&total, &stats->malloc_normal); + mi_stat_count_add_mt(&total, &stats->malloc_huge); + mi_stat_print_ex(&total, "total", 1, out, arg, ""); #endif #if MI_STAT>1 - mi_stat_print(&stats->malloc, "malloc req", 1, out, arg); + mi_stat_total_print(&stats->malloc_requested, "malloc req", 1, out, arg); _mi_fprintf(out, arg, "\n"); #endif - mi_stat_print(&stats->reserved, "reserved", 1, out, arg); - mi_stat_print(&stats->committed, "committed", 1, out, arg); - mi_stat_print(&stats->reset, "reset", 1, out, arg); - mi_stat_print(&stats->page_committed, "touched", 1, out, arg); - mi_stat_print(&stats->segments, "segments", -1, out, arg); - mi_stat_print(&stats->segments_abandoned, "-abandoned", -1, out, arg); - mi_stat_print(&stats->segments_cache, "-cached", -1, out, arg); + mi_stat_print_ex(&stats->reserved, "reserved", 1, out, arg, ""); + mi_stat_print_ex(&stats->committed, "committed", 1, out, arg, ""); + mi_stat_peak_print(&stats->reset, "reset", 1, out, arg ); + mi_stat_peak_print(&stats->purged, "purged", 1, out, arg ); + mi_stat_print_ex(&stats->page_committed, "touched", 1, out, arg, ""); + // mi_stat_print(&stats->segments, "segments", -1, out, arg); + // mi_stat_print(&stats->segments_abandoned, "-abandoned", -1, out, arg); + // mi_stat_print(&stats->segments_cache, "-cached", -1, out, arg); mi_stat_print(&stats->pages, "pages", -1, out, arg); mi_stat_print(&stats->pages_abandoned, "-abandoned", -1, out, arg); + mi_stat_counter_print(&stats->pages_reclaim_on_alloc, "-reclaima", out, arg); + mi_stat_counter_print(&stats->pages_reclaim_on_free, "-reclaimf", out, arg); + mi_stat_counter_print(&stats->pages_reabandon_full, "-reabandon", out, arg); + mi_stat_counter_print(&stats->pages_unabandon_busy_wait, "-waits", out, arg); mi_stat_counter_print(&stats->pages_extended, "-extended", out, arg); - mi_stat_counter_print(&stats->page_no_retire, "-noretire", out, arg); + mi_stat_counter_print(&stats->pages_retire, "-retire", out, arg); + mi_stat_counter_print(&stats->arena_count, "arenas", out, arg); + // mi_stat_counter_print(&stats->arena_crossover_count, "-crossover", out, arg); + // mi_stat_counter_print(&stats->arena_purges, "-purges", out, arg); + mi_stat_counter_print(&stats->arena_rollback_count, "-rollback", out, arg); mi_stat_counter_print(&stats->mmap_calls, "mmaps", out, arg); mi_stat_counter_print(&stats->commit_calls, "commits", out, arg); + mi_stat_counter_print(&stats->reset_calls, "resets", out, arg); + mi_stat_counter_print(&stats->purge_calls, "purges", out, arg); + mi_stat_counter_print(&stats->malloc_guarded_count, "guarded", out, arg); mi_stat_print(&stats->threads, "threads", -1, out, arg); - mi_stat_counter_print_avg(&stats->searches, "searches", out, arg); - _mi_fprintf(out, arg, "%10s: %7zu\n", "numa nodes", _mi_os_numa_node_count()); - - mi_msecs_t elapsed; - mi_msecs_t user_time; - mi_msecs_t sys_time; + mi_stat_counter_print_avg(&stats->page_searches, "searches", out, arg); + _mi_fprintf(out, arg, "%10s: %5i\n", "numa nodes", _mi_os_numa_node_count()); + + size_t elapsed; + size_t user_time; + size_t sys_time; size_t current_rss; size_t peak_rss; size_t current_commit; size_t peak_commit; size_t page_faults; - mi_stat_process_info(&elapsed, &user_time, &sys_time, ¤t_rss, &peak_rss, ¤t_commit, &peak_commit, &page_faults); - _mi_fprintf(out, arg, "%10s: %7ld.%03ld s\n", "elapsed", elapsed/1000, elapsed%1000); - _mi_fprintf(out, arg, "%10s: user: %ld.%03ld s, system: %ld.%03ld s, faults: %lu, rss: ", "process", - user_time/1000, user_time%1000, sys_time/1000, sys_time%1000, (unsigned long)page_faults ); + mi_process_info(&elapsed, &user_time, &sys_time, ¤t_rss, &peak_rss, ¤t_commit, &peak_commit, &page_faults); + _mi_fprintf(out, arg, "%10s: %5zu.%03zu s\n", "elapsed", elapsed/1000, elapsed%1000); + _mi_fprintf(out, arg, "%10s: user: %zu.%03zu s, system: %zu.%03zu s, faults: %zu, rss: ", "process", + user_time/1000, user_time%1000, sys_time/1000, sys_time%1000, page_faults ); mi_printf_amount((int64_t)peak_rss, 1, out, arg, "%s"); if (peak_commit > 0) { _mi_fprintf(out, arg, ", commit: "); mi_printf_amount((int64_t)peak_commit, 1, out, arg, "%s"); } - _mi_fprintf(out, arg, "\n"); + _mi_fprintf(out, arg, "\n"); } static mi_msecs_t mi_process_start; // = 0 -static mi_stats_t* mi_stats_get_default(void) { - mi_heap_t* heap = mi_heap_get_default(); - return &heap->tld->stats; +// called on process init +void _mi_stats_init(void) { + if (mi_process_start == 0) { mi_process_start = _mi_clock_start(); }; } -static void mi_stats_merge_from(mi_stats_t* stats) { - if (stats != &_mi_stats_main) { - mi_stats_add(&_mi_stats_main, stats); - memset(stats, 0, sizeof(mi_stats_t)); - } + +// return thread local stats +static mi_stats_t* mi_get_tld_stats(void) { + return &_mi_thread_tld()->stats; } void mi_stats_reset(void) mi_attr_noexcept { - mi_stats_t* stats = mi_stats_get_default(); - if (stats != &_mi_stats_main) { memset(stats, 0, sizeof(mi_stats_t)); } - memset(&_mi_stats_main, 0, sizeof(mi_stats_t)); - if (mi_process_start == 0) { mi_process_start = _mi_clock_start(); }; + mi_stats_t* stats = mi_get_tld_stats(); + mi_subproc_t* subproc = _mi_subproc(); + if (stats != &subproc->stats) { _mi_memzero(stats, sizeof(mi_stats_t)); } + _mi_memzero(&subproc->stats, sizeof(mi_stats_t)); + _mi_stats_init(); } -void mi_stats_merge(void) mi_attr_noexcept { - mi_stats_merge_from( mi_stats_get_default() ); + +void _mi_stats_merge_from(mi_stats_t* to, mi_stats_t* from) { + mi_assert_internal(to != NULL && from != NULL); + if (to != from) { + mi_stats_add(to, from); + _mi_memzero(from, sizeof(mi_stats_t)); + } } void _mi_stats_done(mi_stats_t* stats) { // called from `mi_thread_done` - mi_stats_merge_from(stats); + _mi_stats_merge_from(&_mi_subproc()->stats, stats); +} + +void _mi_stats_merge_thread(mi_tld_t* tld) { + mi_assert_internal(tld != NULL && tld->subproc != NULL); + _mi_stats_merge_from( &tld->subproc->stats, &tld->stats ); +} + +void mi_stats_merge(void) mi_attr_noexcept { + _mi_stats_merge_thread( _mi_thread_tld() ); } void mi_stats_print_out(mi_output_fun* out, void* arg) mi_attr_noexcept { - mi_stats_merge_from(mi_stats_get_default()); - _mi_stats_print(&_mi_stats_main, out, arg); + mi_stats_merge(); + _mi_stats_print(&_mi_subproc()->stats, out, arg); } void mi_stats_print(void* out) mi_attr_noexcept { @@ -389,53 +438,19 @@ void mi_stats_print(void* out) mi_attr_noexcept { } void mi_thread_stats_print_out(mi_output_fun* out, void* arg) mi_attr_noexcept { - _mi_stats_print(mi_stats_get_default(), out, arg); + _mi_stats_print(mi_get_tld_stats(), out, arg); } // ---------------------------------------------------------------- // Basic timer for convenience; use milli-seconds to avoid doubles // ---------------------------------------------------------------- -#ifdef _WIN32 -#include -static mi_msecs_t mi_to_msecs(LARGE_INTEGER t) { - static LARGE_INTEGER mfreq; // = 0 - if (mfreq.QuadPart == 0LL) { - LARGE_INTEGER f; - QueryPerformanceFrequency(&f); - mfreq.QuadPart = f.QuadPart/1000LL; - if (mfreq.QuadPart == 0) mfreq.QuadPart = 1; - } - return (mi_msecs_t)(t.QuadPart / mfreq.QuadPart); -} + +static mi_msecs_t mi_clock_diff; mi_msecs_t _mi_clock_now(void) { - LARGE_INTEGER t; - QueryPerformanceCounter(&t); - return mi_to_msecs(t); -} -#else -#include -#if defined(CLOCK_REALTIME) || defined(CLOCK_MONOTONIC) -mi_msecs_t _mi_clock_now(void) { - struct timespec t; - #ifdef CLOCK_MONOTONIC - clock_gettime(CLOCK_MONOTONIC, &t); - #else - clock_gettime(CLOCK_REALTIME, &t); - #endif - return ((mi_msecs_t)t.tv_sec * 1000) + ((mi_msecs_t)t.tv_nsec / 1000000); -} -#else -// low resolution timer -mi_msecs_t _mi_clock_now(void) { - return ((mi_msecs_t)clock() / ((mi_msecs_t)CLOCKS_PER_SEC / 1000)); + return _mi_prim_clock_now(); } -#endif -#endif - - -static mi_msecs_t mi_clock_diff; mi_msecs_t _mi_clock_start(void) { if (mi_clock_diff == 0.0) { @@ -455,130 +470,210 @@ mi_msecs_t _mi_clock_end(mi_msecs_t start) { // Basic process statistics // -------------------------------------------------------- -#if defined(_WIN32) -#include -#include -#pragma comment(lib,"psapi.lib") - -static mi_msecs_t filetime_msecs(const FILETIME* ftime) { - ULARGE_INTEGER i; - i.LowPart = ftime->dwLowDateTime; - i.HighPart = ftime->dwHighDateTime; - mi_msecs_t msecs = (i.QuadPart / 10000); // FILETIME is in 100 nano seconds - return msecs; +mi_decl_export void mi_process_info(size_t* elapsed_msecs, size_t* user_msecs, size_t* system_msecs, size_t* current_rss, size_t* peak_rss, size_t* current_commit, size_t* peak_commit, size_t* page_faults) mi_attr_noexcept +{ + mi_subproc_t* subproc = _mi_subproc(); + mi_process_info_t pinfo; + _mi_memzero_var(pinfo); + pinfo.elapsed = _mi_clock_end(mi_process_start); + pinfo.current_commit = (size_t)(mi_atomic_loadi64_relaxed((_Atomic(int64_t)*)(&subproc->stats.committed.current))); + pinfo.peak_commit = (size_t)(mi_atomic_loadi64_relaxed((_Atomic(int64_t)*)(&subproc->stats.committed.peak))); + pinfo.current_rss = pinfo.current_commit; + pinfo.peak_rss = pinfo.peak_commit; + pinfo.utime = 0; + pinfo.stime = 0; + pinfo.page_faults = 0; + + _mi_prim_process_info(&pinfo); + + if (elapsed_msecs!=NULL) *elapsed_msecs = (pinfo.elapsed < 0 ? 0 : (pinfo.elapsed < (mi_msecs_t)PTRDIFF_MAX ? (size_t)pinfo.elapsed : PTRDIFF_MAX)); + if (user_msecs!=NULL) *user_msecs = (pinfo.utime < 0 ? 0 : (pinfo.utime < (mi_msecs_t)PTRDIFF_MAX ? (size_t)pinfo.utime : PTRDIFF_MAX)); + if (system_msecs!=NULL) *system_msecs = (pinfo.stime < 0 ? 0 : (pinfo.stime < (mi_msecs_t)PTRDIFF_MAX ? (size_t)pinfo.stime : PTRDIFF_MAX)); + if (current_rss!=NULL) *current_rss = pinfo.current_rss; + if (peak_rss!=NULL) *peak_rss = pinfo.peak_rss; + if (current_commit!=NULL) *current_commit = pinfo.current_commit; + if (peak_commit!=NULL) *peak_commit = pinfo.peak_commit; + if (page_faults!=NULL) *page_faults = pinfo.page_faults; } -static void mi_stat_process_info(mi_msecs_t* elapsed, mi_msecs_t* utime, mi_msecs_t* stime, size_t* current_rss, size_t* peak_rss, size_t* current_commit, size_t* peak_commit, size_t* page_faults) -{ - *elapsed = _mi_clock_end(mi_process_start); - FILETIME ct; - FILETIME ut; - FILETIME st; - FILETIME et; - GetProcessTimes(GetCurrentProcess(), &ct, &et, &st, &ut); - *utime = filetime_msecs(&ut); - *stime = filetime_msecs(&st); - PROCESS_MEMORY_COUNTERS info; - GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info)); - *current_rss = (size_t)info.WorkingSetSize; - *peak_rss = (size_t)info.PeakWorkingSetSize; - *current_commit = (size_t)info.PagefileUsage; - *peak_commit = (size_t)info.PeakPagefileUsage; - *page_faults = (size_t)info.PageFaultCount; -} - -#elif !defined(__wasi__) && (defined(__unix__) || defined(__unix) || defined(unix) || defined(__APPLE__) || defined(__HAIKU__)) -#include -#include -#include - -#if defined(__APPLE__) -#include -#endif -#if defined(__HAIKU__) -#include -#endif +// -------------------------------------------------------- +// Return statistics +// -------------------------------------------------------- -static mi_msecs_t timeval_secs(const struct timeval* tv) { - return ((mi_msecs_t)tv->tv_sec * 1000L) + ((mi_msecs_t)tv->tv_usec / 1000L); +size_t mi_stats_get_bin_size(size_t bin) mi_attr_noexcept { + if (bin > MI_BIN_HUGE) return 0; + return _mi_bin_size(bin); } -static void mi_stat_process_info(mi_msecs_t* elapsed, mi_msecs_t* utime, mi_msecs_t* stime, size_t* current_rss, size_t* peak_rss, size_t* current_commit, size_t* peak_commit, size_t* page_faults) -{ - *elapsed = _mi_clock_end(mi_process_start); - struct rusage rusage; - getrusage(RUSAGE_SELF, &rusage); - *utime = timeval_secs(&rusage.ru_utime); - *stime = timeval_secs(&rusage.ru_stime); -#if !defined(__HAIKU__) - *page_faults = rusage.ru_majflt; -#endif - // estimate commit using our stats - *peak_commit = (size_t)(mi_atomic_loadi64_relaxed((_Atomic(int64_t)*)&_mi_stats_main.committed.peak)); - *current_commit = (size_t)(mi_atomic_loadi64_relaxed((_Atomic(int64_t)*)&_mi_stats_main.committed.current)); - *current_rss = *current_commit; // estimate -#if defined(__HAIKU__) - // Haiku does not have (yet?) a way to - // get these stats per process - thread_info tid; - area_info mem; - ssize_t c; - get_thread_info(find_thread(0), &tid); - while (get_next_area_info(tid.team, &c, &mem) == B_OK) { - *peak_rss += mem.ram_size; +void mi_stats_get(size_t stats_size, mi_stats_t* stats) mi_attr_noexcept { + if (stats == NULL || stats_size == 0) return; + _mi_memzero(stats, stats_size); + const size_t size = (stats_size > sizeof(mi_stats_t) ? sizeof(mi_stats_t) : stats_size); + _mi_memcpy(stats, &_mi_subproc()->stats, size); + stats->version = MI_STAT_VERSION; +} + + +// -------------------------------------------------------- +// Statics in json format +// -------------------------------------------------------- + +typedef struct mi_heap_buf_s { + char* buf; + size_t size; + size_t used; + bool can_realloc; +} mi_heap_buf_t; + +static bool mi_heap_buf_expand(mi_heap_buf_t* hbuf) { + if (hbuf==NULL) return false; + if (hbuf->buf != NULL && hbuf->size>0) { + hbuf->buf[hbuf->size-1] = 0; + } + if (hbuf->size > SIZE_MAX/2 || !hbuf->can_realloc) return false; + const size_t newsize = (hbuf->size == 0 ? mi_good_size(12*MI_KiB) : 2*hbuf->size); + char* const newbuf = (char*)mi_rezalloc(hbuf->buf, newsize); + if (newbuf == NULL) return false; + hbuf->buf = newbuf; + hbuf->size = newsize; + return true; +} + +static void mi_heap_buf_print(mi_heap_buf_t* hbuf, const char* msg) { + if (msg==NULL || hbuf==NULL) return; + if (hbuf->used + 1 >= hbuf->size && !hbuf->can_realloc) return; + for (const char* src = msg; *src != 0; src++) { + char c = *src; + if (hbuf->used + 1 >= hbuf->size) { + if (!mi_heap_buf_expand(hbuf)) return; + } + mi_assert_internal(hbuf->used < hbuf->size); + hbuf->buf[hbuf->used++] = c; } - *page_faults = 0; -#elif defined(__APPLE__) - *peak_rss = rusage.ru_maxrss; // BSD reports in bytes - struct mach_task_basic_info info; - mach_msg_type_number_t infoCount = MACH_TASK_BASIC_INFO_COUNT; - if (task_info(mach_task_self(), MACH_TASK_BASIC_INFO, (task_info_t)&info, &infoCount) == KERN_SUCCESS) { - *current_rss = (size_t)info.resident_size; + mi_assert_internal(hbuf->used < hbuf->size); + hbuf->buf[hbuf->used] = 0; +} + +static void mi_heap_buf_print_count_bin(mi_heap_buf_t* hbuf, const char* prefix, mi_stat_count_t* stat, size_t bin, bool add_comma) { + const size_t binsize = mi_stats_get_bin_size(bin); + const size_t pagesize = (binsize <= MI_SMALL_MAX_OBJ_SIZE ? MI_SMALL_PAGE_SIZE : + (binsize <= MI_MEDIUM_MAX_OBJ_SIZE ? MI_MEDIUM_PAGE_SIZE : + (binsize <= MI_LARGE_MAX_OBJ_SIZE ? MI_LARGE_PAGE_SIZE : 0))); + char buf[128]; + _mi_snprintf(buf, 128, "%s{ \"total\": %lld, \"peak\": %lld, \"current\": %lld, \"block_size\": %zu, \"page_size\": %zu }%s\n", prefix, stat->total, stat->peak, stat->current, binsize, pagesize, (add_comma ? "," : "")); + buf[127] = 0; + mi_heap_buf_print(hbuf, buf); +} + +static void mi_heap_buf_print_count_cbin(mi_heap_buf_t* hbuf, const char* prefix, mi_stat_count_t* stat, mi_chunkbin_t bin, bool add_comma) { + const char* cbin = " "; + switch(bin) { + case MI_CBIN_SMALL: cbin = "S"; break; + case MI_CBIN_MEDIUM: cbin = "M"; break; + case MI_CBIN_LARGE: cbin = "L"; break; + case MI_CBIN_OTHER: cbin = "X"; break; + default: cbin = " "; break; } -#else - *peak_rss = rusage.ru_maxrss * 1024; // Linux reports in KiB -#endif + char buf[128]; + _mi_snprintf(buf, 128, "%s{ \"total\": %lld, \"peak\": %lld, \"current\": %lld, \"bin\": \"%s\" }%s\n", prefix, stat->total, stat->peak, stat->current, cbin, (add_comma ? "," : "")); + buf[127] = 0; + mi_heap_buf_print(hbuf, buf); } -#else -#ifndef __wasi__ -// WebAssembly instances are not processes -#pragma message("define a way to get process info") -#endif +static void mi_heap_buf_print_count(mi_heap_buf_t* hbuf, const char* prefix, mi_stat_count_t* stat, bool add_comma) { + char buf[128]; + _mi_snprintf(buf, 128, "%s{ \"total\": %lld, \"peak\": %lld, \"current\": %lld }%s\n", prefix, stat->total, stat->peak, stat->current, (add_comma ? "," : "")); + buf[127] = 0; + mi_heap_buf_print(hbuf, buf); +} -static void mi_stat_process_info(mi_msecs_t* elapsed, mi_msecs_t* utime, mi_msecs_t* stime, size_t* current_rss, size_t* peak_rss, size_t* current_commit, size_t* peak_commit, size_t* page_faults) -{ - *elapsed = _mi_clock_end(mi_process_start); - *peak_commit = (size_t)(mi_atomic_loadi64_relaxed((_Atomic(int64_t)*)&_mi_stats_main.committed.peak)); - *current_commit = (size_t)(mi_atomic_loadi64_relaxed((_Atomic(int64_t)*)&_mi_stats_main.committed.current)); - *peak_rss = *peak_commit; - *current_rss = *current_commit; - *page_faults = 0; - *utime = 0; - *stime = 0; +static void mi_heap_buf_print_count_value(mi_heap_buf_t* hbuf, const char* name, mi_stat_count_t* stat) { + char buf[128]; + _mi_snprintf(buf, 128, " \"%s\": ", name); + buf[127] = 0; + mi_heap_buf_print(hbuf, buf); + mi_heap_buf_print_count(hbuf, "", stat, true); } -#endif +static void mi_heap_buf_print_value(mi_heap_buf_t* hbuf, const char* name, int64_t val) { + char buf[128]; + _mi_snprintf(buf, 128, " \"%s\": %lld,\n", name, val); + buf[127] = 0; + mi_heap_buf_print(hbuf, buf); +} -mi_decl_export void mi_process_info(size_t* elapsed_msecs, size_t* user_msecs, size_t* system_msecs, size_t* current_rss, size_t* peak_rss, size_t* current_commit, size_t* peak_commit, size_t* page_faults) mi_attr_noexcept -{ - mi_msecs_t elapsed = 0; - mi_msecs_t utime = 0; - mi_msecs_t stime = 0; - size_t current_rss0 = 0; - size_t peak_rss0 = 0; - size_t current_commit0 = 0; - size_t peak_commit0 = 0; - size_t page_faults0 = 0; - mi_stat_process_info(&elapsed,&utime, &stime, ¤t_rss0, &peak_rss0, ¤t_commit0, &peak_commit0, &page_faults0); - if (elapsed_msecs!=NULL) *elapsed_msecs = (elapsed < 0 ? 0 : (elapsed < (mi_msecs_t)PTRDIFF_MAX ? (size_t)elapsed : PTRDIFF_MAX)); - if (user_msecs!=NULL) *user_msecs = (utime < 0 ? 0 : (utime < (mi_msecs_t)PTRDIFF_MAX ? (size_t)utime : PTRDIFF_MAX)); - if (system_msecs!=NULL) *system_msecs = (stime < 0 ? 0 : (stime < (mi_msecs_t)PTRDIFF_MAX ? (size_t)stime : PTRDIFF_MAX)); - if (current_rss!=NULL) *current_rss = current_rss0; - if (peak_rss!=NULL) *peak_rss = peak_rss0; - if (current_commit!=NULL) *current_commit = current_commit0; - if (peak_commit!=NULL) *peak_commit = peak_commit0; - if (page_faults!=NULL) *page_faults = page_faults0; +static void mi_heap_buf_print_size(mi_heap_buf_t* hbuf, const char* name, size_t val, bool add_comma) { + char buf[128]; + _mi_snprintf(buf, 128, " \"%s\": %zu%s\n", name, val, (add_comma ? "," : "")); + buf[127] = 0; + mi_heap_buf_print(hbuf, buf); } +static void mi_heap_buf_print_counter_value(mi_heap_buf_t* hbuf, const char* name, mi_stat_counter_t* stat) { + mi_heap_buf_print_value(hbuf, name, stat->total); +} + +#define MI_STAT_COUNT(stat) mi_heap_buf_print_count_value(&hbuf, #stat, &stats->stat); +#define MI_STAT_COUNTER(stat) mi_heap_buf_print_counter_value(&hbuf, #stat, &stats->stat); + +char* mi_stats_get_json(size_t output_size, char* output_buf) mi_attr_noexcept { + mi_stats_merge(); + mi_heap_buf_t hbuf = { NULL, 0, 0, true }; + if (output_size > 0 && output_buf != NULL) { + _mi_memzero(output_buf, output_size); + hbuf.buf = output_buf; + hbuf.size = output_size; + hbuf.can_realloc = false; + } + else { + if (!mi_heap_buf_expand(&hbuf)) return NULL; + } + mi_heap_buf_print(&hbuf, "{\n"); + mi_heap_buf_print_value(&hbuf, "version", MI_STAT_VERSION); + mi_heap_buf_print_value(&hbuf, "mimalloc_version", MI_MALLOC_VERSION); + + // process info + mi_heap_buf_print(&hbuf, " \"process\": {\n"); + size_t elapsed; + size_t user_time; + size_t sys_time; + size_t current_rss; + size_t peak_rss; + size_t current_commit; + size_t peak_commit; + size_t page_faults; + mi_process_info(&elapsed, &user_time, &sys_time, ¤t_rss, &peak_rss, ¤t_commit, &peak_commit, &page_faults); + mi_heap_buf_print_size(&hbuf, "elapsed_msecs", elapsed, true); + mi_heap_buf_print_size(&hbuf, "user_msecs", user_time, true); + mi_heap_buf_print_size(&hbuf, "system_msecs", sys_time, true); + mi_heap_buf_print_size(&hbuf, "page_faults", page_faults, true); + mi_heap_buf_print_size(&hbuf, "rss_current", current_rss, true); + mi_heap_buf_print_size(&hbuf, "rss_peak", peak_rss, true); + mi_heap_buf_print_size(&hbuf, "commit_current", current_commit, true); + mi_heap_buf_print_size(&hbuf, "commit_peak", peak_commit, false); + mi_heap_buf_print(&hbuf, " },\n"); + + // statistics + mi_stats_t* stats = &_mi_subproc()->stats; + MI_STAT_FIELDS() + + // size bins + mi_heap_buf_print(&hbuf, " \"malloc_bins\": [\n"); + for (size_t i = 0; i <= MI_BIN_HUGE; i++) { + mi_heap_buf_print_count_bin(&hbuf, " ", &stats->malloc_bins[i], i, i!=MI_BIN_HUGE); + } + mi_heap_buf_print(&hbuf, " ],\n"); + mi_heap_buf_print(&hbuf, " \"page_bins\": [\n"); + for (size_t i = 0; i <= MI_BIN_HUGE; i++) { + mi_heap_buf_print_count_bin(&hbuf, " ", &stats->page_bins[i], i, i!=MI_BIN_HUGE); + } + mi_heap_buf_print(&hbuf, " ],\n"); + mi_heap_buf_print(&hbuf, " \"chunk_bins\": [\n"); + for (size_t i = 0; i < MI_CBIN_COUNT; i++) { + mi_heap_buf_print_count_cbin(&hbuf, " ", &stats->chunk_bins[i], (mi_chunkbin_t)i, i!=MI_CBIN_COUNT-1); + } + mi_heap_buf_print(&hbuf, " ]\n"); + mi_heap_buf_print(&hbuf, "}\n"); + return hbuf.buf; +} diff --git a/src/dashbls/depends/mimalloc/test/CMakeLists.txt b/src/dashbls/depends/mimalloc/test/CMakeLists.txt index e76ffa64fcd5..5905613c9717 100644 --- a/src/dashbls/depends/mimalloc/test/CMakeLists.txt +++ b/src/dashbls/depends/mimalloc/test/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.0) +cmake_minimum_required(VERSION 3.18) project(mimalloc-test C CXX) set(CMAKE_C_STANDARD 11) @@ -16,10 +16,12 @@ if (NOT CMAKE_BUILD_TYPE) endif() # Import mimalloc (if installed) -find_package(mimalloc 2.0 REQUIRED NO_SYSTEM_ENVIRONMENT_PATH) +find_package(mimalloc 1.9 CONFIG REQUIRED) message(STATUS "Found mimalloc installed at: ${MIMALLOC_LIBRARY_DIR} (${MIMALLOC_VERSION_DIR})") -# overriding with a dynamic library + +# link with a dynamic shared library +# use `LD_PRELOAD` to actually override malloc/free at runtime with mimalloc add_executable(dynamic-override main-override.c) target_link_libraries(dynamic-override PUBLIC mimalloc) @@ -29,9 +31,9 @@ target_link_libraries(dynamic-override-cxx PUBLIC mimalloc) # overriding with a static object file works reliable as the symbols in the # object file have priority over those in library files -add_executable(static-override-obj main-override.c ${MIMALLOC_OBJECT_DIR}/mimalloc.o) +add_executable(static-override-obj main-override.c ${MIMALLOC_OBJECT_DIR}/mimalloc${CMAKE_C_OUTPUT_EXTENSION}) target_include_directories(static-override-obj PUBLIC ${MIMALLOC_INCLUDE_DIR}) -target_link_libraries(static-override-obj PUBLIC pthread) +target_link_libraries(static-override-obj PUBLIC mimalloc-static) # overriding with a static library works too if using the `mimalloc-override.h` diff --git a/src/dashbls/depends/mimalloc/test/main-override-dep.cpp b/src/dashbls/depends/mimalloc/test/main-override-dep.cpp new file mode 100644 index 000000000000..4f293e7b73be --- /dev/null +++ b/src/dashbls/depends/mimalloc/test/main-override-dep.cpp @@ -0,0 +1,60 @@ +// Issue #981: test overriding allocation in a DLL that is compiled independent of mimalloc. +// This is imported by the `mimalloc-test-override` project. +#include +#include +#include "main-override-dep.h" + +std::string TestAllocInDll::GetString() +{ + char* test = new char[128]; + memset(test, 0, 128); + const char* t = "test"; + memcpy(test, t, 4); + std::string r = test; + std::cout << "override-dep: GetString: " << r << "\n"; + delete[] test; + return r; +} + +#include + +void TestAllocInDll::TestHeapAlloc() +{ + HANDLE heap = GetProcessHeap(); + int* p = (int*)HeapAlloc(heap, 0, sizeof(int)); + *p = 42; + HeapFree(heap, 0, p); +} + +class Static { +private: + void* p; +public: + Static() { + printf("override-dep: static constructor\n"); + p = malloc(64); + return; + } + ~Static() { + free(p); + printf("override-dep: static destructor\n"); + return; + } +}; + +static Static s = Static(); + + +#include + +BOOL WINAPI DllMain(HINSTANCE module, DWORD reason, LPVOID reserved) { + (void)(reserved); + (void)(module); + if (reason==DLL_PROCESS_ATTACH) { + printf("override-dep: dll attach\n"); + } + else if (reason==DLL_PROCESS_DETACH) { + printf("override-dep: dll detach\n"); + } + return TRUE; +} diff --git a/src/dashbls/depends/mimalloc/test/main-override-dep.h b/src/dashbls/depends/mimalloc/test/main-override-dep.h new file mode 100644 index 000000000000..9d4aabfdb649 --- /dev/null +++ b/src/dashbls/depends/mimalloc/test/main-override-dep.h @@ -0,0 +1,12 @@ +#pragma once +// Issue #981: test overriding allocation in a DLL that is compiled independent of mimalloc. +// This is imported by the `mimalloc-test-override` project. + +#include + +class TestAllocInDll +{ +public: + __declspec(dllexport) std::string GetString(); + __declspec(dllexport) void TestHeapAlloc(); +}; diff --git a/src/dashbls/depends/mimalloc/test/main-override-static.c b/src/dashbls/depends/mimalloc/test/main-override-static.c index 70b6293ccc53..3e47874ecc36 100644 --- a/src/dashbls/depends/mimalloc/test/main-override-static.c +++ b/src/dashbls/depends/mimalloc/test/main-override-static.c @@ -1,3 +1,6 @@ +#if _WIN32 +#include +#endif #include #include #include @@ -7,11 +10,13 @@ #include #include // redefines malloc etc. +static void mi_bins(void); static void double_free1(); static void double_free2(); static void corrupt_free(); static void block_overflow1(); +static void block_overflow2(); static void invalid_free(); static void test_aslr(void); static void test_process_info(void); @@ -19,53 +24,67 @@ static void test_reserved(void); static void negative_stat(void); static void alloc_huge(void); static void test_heap_walk(void); -static void test_heap_arena(void); +static void test_canary_leak(void); +static void test_manage_os_memory(void); +// static void test_large_pages(void); + int main() { mi_version(); mi_stats_reset(); + + // mi_bins(); + + // test_manage_os_memory(); + // test_large_pages(); // detect double frees and heap corruption // double_free1(); // double_free2(); // corrupt_free(); // block_overflow1(); + // block_overflow2(); + test_canary_leak(); // test_aslr(); // invalid_free(); // test_reserved(); // negative_stat(); - // alloc_huge(); // test_heap_walk(); - test_heap_arena(); - + // alloc_huge(); + + void* p1 = malloc(78); void* p2 = malloc(24); free(p1); p1 = mi_malloc(8); char* s = strdup("hello\n"); free(p2); - + + mi_heap_t* h = mi_heap_new(); + mi_heap_set_default(h); + p2 = malloc(16); p1 = realloc(p1, 32); free(p1); free(p2); free(s); - + /* now test if override worked by allocating/freeing across the api's*/ //p1 = mi_malloc(32); //free(p1); //p2 = malloc(32); //mi_free(p2); - + //mi_collect(true); //mi_stats_print(NULL); - + // test_process_info(); + return 0; } static void invalid_free() { free((void*)0xBADBEEF); - realloc((void*)0xBADBEEF,10); + realloc((void*)0xBADBEEF, 10); } static void block_overflow1() { @@ -74,6 +93,12 @@ static void block_overflow1() { free(p); } +static void block_overflow2() { + uint8_t* p = (uint8_t*)mi_malloc(16); + p[17] = 0; + free(p); +} + // The double free samples come ArcHeap [1] by Insu Yun (issue #161) // [1]: https://arxiv.org/pdf/1903.00503.pdf @@ -155,9 +180,9 @@ static void test_process_info(void) { size_t peak_rss = 0; size_t current_commit = 0; size_t peak_commit = 0; - size_t page_faults = 0; + size_t page_faults = 0; for (int i = 0; i < 100000; i++) { - void* p = calloc(100,10); + void* p = calloc(100, 10); free(p); } mi_process_info(&elapsed, &user_msecs, &system_msecs, ¤t_rss, &peak_rss, ¤t_commit, &peak_commit, &page_faults); @@ -168,7 +193,7 @@ static void test_reserved(void) { #define KiB 1024ULL #define MiB (KiB*KiB) #define GiB (MiB*KiB) - mi_reserve_os_memory(4*GiB, false, true); + mi_reserve_os_memory(3*GiB, false, true); void* p1 = malloc(100); void* p2 = malloc(100000); void* p3 = malloc(2*GiB); @@ -187,7 +212,7 @@ static void negative_stat(void) { mi_stats_print_out(NULL, NULL); *p = 100; mi_free(p); - mi_stats_print_out(NULL, NULL); + mi_stats_print_out(NULL, NULL); } static void alloc_huge(void) { @@ -207,27 +232,85 @@ static bool test_visit(const mi_heap_t* heap, const mi_heap_area_t* area, void* static void test_heap_walk(void) { mi_heap_t* heap = mi_heap_new(); - //mi_heap_malloc(heap, 2097152); + mi_heap_malloc(heap, 16*2097152); mi_heap_malloc(heap, 2067152); mi_heap_malloc(heap, 2097160); mi_heap_malloc(heap, 24576); mi_heap_visit_blocks(heap, true, &test_visit, NULL); } -static void test_heap_arena(void) { +static void test_canary_leak(void) { + char* p = mi_mallocn_tp(char, 22); + for (int i = 0; i < 22; i++) { + p[i] = '0'+i; + } + puts(p); + free(p); +} + +#if _WIN32 +static void test_manage_os_memory(void) { + size_t size = 256 * 1024 * 1024; + void* ptr = VirtualAlloc(NULL, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); mi_arena_id_t arena_id; - int err = mi_reserve_os_memory_ex(100 * 1024 * 1024, false /* commit */, false /* allow large */, true /* exclusive */, &arena_id); - if (err) abort(); - mi_heap_t* heap = mi_heap_new_in_arena(arena_id); - for (int i = 0; i < 500000; i++) { - void* p = mi_heap_malloc(heap, 1024); - if (p == NULL) { - printf("out of memory after %d kb (expecting about 100_000kb)\n", i); - break; - } + mi_manage_os_memory_ex(ptr, size, true /* committed */, true /* pinned */, false /* is zero */, -1 /* numa node */, true /* exclusive */, &arena_id); + mi_heap_t* cuda_heap = mi_heap_new_in_arena(arena_id); // you can do this in any thread + + // now allocate only in the cuda arena + void* p1 = mi_heap_malloc(cuda_heap, 8); + int* p2 = mi_heap_malloc_tp(cuda_heap, int); + *p2 = 42; + + // and maybe set the cuda heap as the default heap? (but careful as now `malloc` will allocate in the cuda heap as well) + { + mi_heap_t* prev_default_heap = mi_heap_set_default(cuda_heap); + void* p3 = mi_malloc(8); // allocate in the cuda heap + mi_free(p3); } + mi_free(p1); + mi_free(p2); +} +#else +static void test_manage_os_memory(void) { + // empty +} +#endif + +// Experiment with huge OS pages +#if 0 + +#include +#include +#include +#include + +static void test_large_pages(void) { + mi_memid_t memid; + +#if 0 + size_t pages_reserved; + size_t page_size; + uint8_t* p = (uint8_t*)_mi_os_alloc_huge_os_pages(1, -1, 30000, &pages_reserved, &page_size, &memid); + const size_t req_size = pages_reserved * page_size; +#else + const size_t req_size = 64*MI_MiB; + uint8_t* p = (uint8_t*)_mi_os_alloc(req_size, &memid, NULL); +#endif + + p[0] = 1; + + //_mi_os_protect(p, _mi_os_page_size()); + //_mi_os_unprotect(p, _mi_os_page_size()); + //_mi_os_decommit(p, _mi_os_page_size(), NULL); + if (madvise(p, req_size, MADV_HUGEPAGE) == 0) { + printf("advised huge pages\n"); + _mi_os_decommit(p, _mi_os_page_size(), NULL); + }; + _mi_os_free(p, req_size, memid, NULL); } +#endif + // ---------------------------- // bin size experiments // ------------------------------ @@ -235,8 +318,8 @@ static void test_heap_arena(void) { #if 0 #include #include +#include -#define MI_INTPTR_SIZE 8 #define MI_LARGE_WSIZE_MAX (4*1024*1024 / MI_INTPTR_SIZE) #define MI_BIN_HUGE 100 @@ -246,11 +329,11 @@ static void test_heap_arena(void) { static inline uint8_t mi_bsr32(uint32_t x); #if defined(_MSC_VER) -#include +//#include #include static inline uint8_t mi_bsr32(uint32_t x) { uint32_t idx; - _BitScanReverse((DWORD*)&idx, x); + _BitScanReverse(&idx, x); return idx; } #elif defined(__GNUC__) || defined(__clang__) @@ -274,7 +357,7 @@ static inline uint8_t mi_bsr32(uint32_t x) { } #endif -/* + // Bit scan reverse: return the index of the highest bit. uint8_t _mi_bsr(uintptr_t x) { if (x == 0) return 0; @@ -287,38 +370,39 @@ uint8_t _mi_bsr(uintptr_t x) { # error "define bsr for non-32 or 64-bit platforms" #endif } -*/ - static inline size_t _mi_wsize_from_size(size_t size) { return (size + sizeof(uintptr_t) - 1) / sizeof(uintptr_t); } +// #define MI_ALIGN2W + // Return the bin for a given field size. // Returns MI_BIN_HUGE if the size is too large. // We use `wsize` for the size in "machine word sizes", // i.e. byte size == `wsize*sizeof(void*)`. -extern inline uint8_t _mi_bin8(size_t size) { - size_t wsize = _mi_wsize_from_size(size); - uint8_t bin; - if (wsize <= 1) { +static inline size_t mi_bin(size_t wsize) { + // size_t wsize = _mi_wsize_from_size(size); + // size_t bin; + /*if (wsize <= 1) { bin = 1; } + */ #if defined(MI_ALIGN4W) - else if (wsize <= 4) { - bin = (uint8_t)((wsize+1)&~1); // round to double word sizes + if (wsize <= 4) { + return (wsize <= 1 ? 1 : (wsize+1)&~1); // round to double word sizes } #elif defined(MI_ALIGN2W) - else if (wsize <= 8) { - bin = (uint8_t)((wsize+1)&~1); // round to double word sizes + if (wsize <= 8) { + return (wsize <= 1 ? 1 : (wsize+1)&~1); // round to double word sizes } #else - else if (wsize <= 8) { - bin = (uint8_t)wsize; + if (wsize <= 8) { + return (wsize == 0 ? 1 : wsize); } #endif else if (wsize > MI_LARGE_WSIZE_MAX) { - bin = MI_BIN_HUGE; + return MI_BIN_HUGE; } else { #if defined(MI_ALIGN4W) @@ -326,15 +410,19 @@ extern inline uint8_t _mi_bin8(size_t size) { #endif wsize--; // find the highest bit - uint8_t b = mi_bsr32((uint32_t)wsize); + size_t idx; + mi_bsr(wsize, &idx); + uint8_t b = (uint8_t)idx; // and use the top 3 bits to determine the bin (~12.5% worst internal fragmentation). // - adjust with 3 because we use do not round the first 8 sizes // which each get an exact bin - bin = ((b << 2) + (uint8_t)((wsize >> (b - 2)) & 0x03)) - 3; + const size_t bin = ((b << 2) + ((wsize >> (b - 2)) & 0x03)) - 3; + assert(bin > 0 && bin < MI_BIN_HUGE); + return bin; } - return bin; } + static inline uint8_t _mi_bin4(size_t size) { size_t wsize = _mi_wsize_from_size(size); uint8_t bin; @@ -358,44 +446,79 @@ static inline uint8_t _mi_bin4(size_t size) { bin = MI_BIN_HUGE; } else { - uint8_t b = mi_bsr32((uint32_t)wsize); + size_t idx; + mi_bsr(wsize, &idx); + uint8_t b = (uint8_t)idx; bin = ((b << 1) + (uint8_t)((wsize >> (b - 1)) & 0x01)) + 3; } return bin; } -static size_t _mi_binx4(size_t bsize) { - if (bsize==0) return 0; - uint8_t b = mi_bsr32((uint32_t)bsize); - if (b <= 1) return bsize; - size_t bin = ((b << 1) | (bsize >> (b - 1))&0x01); +static size_t _mi_binx4(size_t wsize) { + size_t bin; + if (wsize <= 1) { + bin = 1; + } + else if (wsize <= 8) { + // bin = (wsize+1)&~1; // round to double word sizes + bin = (uint8_t)wsize; + } + else { + size_t idx; + mi_bsr(wsize, &idx); + uint8_t b = (uint8_t)idx; + if (b <= 1) return wsize; + bin = ((b << 1) | (wsize >> (b - 1))&0x01) + 3; + } return bin; } static size_t _mi_binx8(size_t bsize) { if (bsize<=1) return bsize; - uint8_t b = mi_bsr32((uint32_t)bsize); + size_t idx; + mi_bsr(bsize, &idx); + uint8_t b = (uint8_t)idx; if (b <= 2) return bsize; size_t bin = ((b << 2) | (bsize >> (b - 2))&0x03) - 5; return bin; } + +static inline size_t mi_binx(size_t wsize) { + uint8_t bin; + if (wsize <= 1) { + bin = 1; + } + else if (wsize <= 8) { + // bin = (wsize+1)&~1; // round to double word sizes + bin = (uint8_t)wsize; + } + else { + wsize--; + assert(wsize>0); + // find the highest bit + uint8_t b = (uint8_t)(MI_SIZE_BITS - 1 - mi_clz(wsize)); + + // and use the top 3 bits to determine the bin (~12.5% worst internal fragmentation). + // - adjust with 3 because we use do not round the first 8 sizes + // which each get an exact bin + bin = ((b << 2) + (uint8_t)((wsize >> (b - 2)) & 0x03)) - 3; + } + return bin; +} + + static void mi_bins(void) { //printf(" QNULL(1), /* 0 */ \\\n "); size_t last_bin = 0; - size_t min_bsize = 0; - size_t last_bsize = 0; - for (size_t bsize = 1; bsize < 2*1024; bsize++) { - size_t size = bsize * 64 * 1024; - size_t bin = _mi_binx8(bsize); + for (size_t wsize = 1; wsize <= (4*1024*1024) / 8 + 1024; wsize++) { + size_t bin = mi_bin(wsize); if (bin != last_bin) { - printf("min bsize: %6zd, max bsize: %6zd, bin: %6zd\n", min_bsize, last_bsize, last_bin); - //printf("QNULL(%6zd), ", wsize); - //if (last_bin%8 == 0) printf("/* %i */ \\\n ", last_bin); + //printf("min bsize: %6zd, max bsize: %6zd, bin: %6zd\n", min_wsize, last_wsize, last_bin); + printf("QNULL(%6zd), ", wsize-1); + if (last_bin%8 == 0) printf("/* %zu */ \\\n ", last_bin); last_bin = bin; - min_bsize = bsize; } - last_bsize = bsize; } } #endif diff --git a/src/dashbls/depends/mimalloc/test/main-override.cpp b/src/dashbls/depends/mimalloc/test/main-override.cpp index e0dba5a3d77f..408b5ee8f9e7 100644 --- a/src/dashbls/depends/mimalloc/test/main-override.cpp +++ b/src/dashbls/depends/mimalloc/test/main-override.cpp @@ -9,17 +9,12 @@ #include #include #include - #include -#include #include #ifdef _WIN32 #include -#endif - -#ifdef _WIN32 -#include +#include static void msleep(unsigned long msecs) { Sleep(msecs); } #else #include @@ -32,27 +27,47 @@ static void heap_late_free(); // issue #204 static void padding_shrink(); // issue #209 static void various_tests(); static void test_mt_shutdown(); -static void large_alloc(void); // issue #363 static void fail_aslr(); // issue #372 static void tsan_numa_test(); // issue #414 -static void strdup_test(); // issue #445 -static void bench_alloc_large(void); // issue #xxx +static void strdup_test(); // issue #445 +static void heap_thread_free_huge(); +static void test_std_string(); // issue #697 +static void test_thread_local(); // issue #944 +// static void test_mixed0(); // issue #942 +static void test_mixed1(); // issue #942 +static void test_stl_allocators(); + +#if _WIN32 +#include "main-override-dep.h" +static void test_dep(); // issue #981: test overriding in another DLL +#else +static void test_dep() { }; +#endif int main() { mi_stats_reset(); // ignore earlier allocations - - heap_thread_free_large(); - heap_no_delete(); - heap_late_free(); - padding_shrink(); - various_tests(); - large_alloc(); - tsan_numa_test(); - strdup_test(); - + //various_tests(); + //test_mixed1(); + + test_dep(); + + //test_std_string(); + //test_thread_local(); + // heap_thread_free_huge(); + /* + heap_thread_free_large(); + heap_no_delete(); + heap_late_free(); + padding_shrink(); + + tsan_numa_test(); + */ + /* + strdup_test(); + test_stl_allocators(); test_mt_shutdown(); + */ //fail_aslr(); - bench_alloc_large(); mi_stats_print(NULL); return 0; } @@ -92,6 +107,15 @@ static void various_tests() { delete t; t = new (std::nothrow) Test(42); delete t; + auto tbuf = new unsigned char[sizeof(Test)]; + t = new (tbuf) Test(42); + t->~Test(); + delete[] tbuf; + + #if _WIN32 + const char* ptr = ::_Getdays(); // test _base overrid + free((void*)ptr); + #endif } class Static { @@ -120,6 +144,18 @@ static bool test_stl_allocator1() { struct some_struct { int i; int j; double z; }; + +#if _WIN32 +static void test_dep() +{ + TestAllocInDll t; + std::string s = t.GetString(); + std::cout << "test_dep GetString: " << s << "\n"; + t.TestHeapAlloc(); +} +#endif + + static bool test_stl_allocator2() { std::vector > vec; vec.push_back(some_struct()); @@ -127,6 +163,130 @@ static bool test_stl_allocator2() { return vec.size() == 0; } +#if MI_HAS_HEAP_STL_ALLOCATOR +static bool test_stl_allocator3() { + std::vector > vec; + vec.push_back(1); + vec.pop_back(); + return vec.size() == 0; +} + +static bool test_stl_allocator4() { + std::vector > vec; + vec.push_back(some_struct()); + vec.pop_back(); + return vec.size() == 0; +} + +static bool test_stl_allocator5() { + std::vector > vec; + vec.push_back(1); + vec.pop_back(); + return vec.size() == 0; +} + +static bool test_stl_allocator6() { + std::vector > vec; + vec.push_back(some_struct()); + vec.pop_back(); + return vec.size() == 0; +} +#endif + +static void test_stl_allocators() { + test_stl_allocator1(); + test_stl_allocator2(); +#if MI_HAS_HEAP_STL_ALLOCATOR + test_stl_allocator3(); + test_stl_allocator4(); + test_stl_allocator5(); + test_stl_allocator6(); +#endif +} + +#if 0 +#include +#include +#include +#include +#include +#include + +static void test_mixed0() { + std::vector> numbers(1024 * 1024 * 100); + std::vector threads(1); + + std::atomic index{}; + + auto start = std::chrono::system_clock::now(); + + for (auto& thread : threads) { + thread = std::thread{[&index, &numbers]() { + while (true) { + auto i = index.fetch_add(1, std::memory_order_relaxed); + if (i >= numbers.size()) return; + + numbers[i] = std::make_unique(i); + } + }}; + } + + for (auto& thread : threads) thread.join(); + + auto end = std::chrono::system_clock::now(); + + auto duration = + std::chrono::duration_cast(end - start); + std::cout << "Running on " << threads.size() << " threads took " << duration + << std::endl; +} +#endif + +void asd() { + void* p = malloc(128); + free(p); +} +static void test_mixed1() { + std::thread thread(asd); + thread.join(); +} + +#if 0 +// issue #691 +static char* cptr; + +static void* thread1_allocate() +{ + cptr = mi_calloc_tp(char,22085632); + return NULL; +} + +static void* thread2_free() +{ + assert(cptr); + mi_free(cptr); + cptr = NULL; + return NULL; +} + +static void test_large_migrate(void) { + auto t1 = std::thread(thread1_allocate); + t1.join(); + auto t2 = std::thread(thread2_free); + t2.join(); + /* + pthread_t thread1, thread2; + + pthread_create(&thread1, NULL, &thread1_allocate, NULL); + pthread_join(thread1, NULL); + + pthread_create(&thread2, NULL, &thread2_free, NULL); + pthread_join(thread2, NULL); + */ + return; +} +#endif + // issue 445 static void strdup_test() { #ifdef _MSC_VER @@ -142,7 +302,7 @@ static void strdup_test() { // Issue #202 static void heap_no_delete_worker() { mi_heap_t* heap = mi_heap_new(); - void* q = mi_heap_malloc(heap, 1024); + void* q = mi_heap_malloc(heap, 1024); (void)(q); // mi_heap_delete(heap); // uncomment to prevent assertion } @@ -152,6 +312,13 @@ static void heap_no_delete() { } +// Issue #697 +static void test_std_string() { + std::string path = "/Users/xxxx/Library/Developer/Xcode/DerivedData/xxxxxxxxxx/Build/Intermediates.noindex/xxxxxxxxxxx/arm64/XX_lto.o/0.arm64.lto.o"; + std::string path1 = "/Users/xxxx/Library/Developer/Xcode/DerivedData/xxxxxxxxxx/Build/Intermediates.noindex/xxxxxxxxxxx/arm64/XX_lto.o/1.arm64.lto.o"; + std::cout << path + "\n>>> " + path1 + "\n>>> " << std::endl; +} + // Issue #204 static volatile void* global_p; @@ -193,12 +360,23 @@ static void heap_thread_free_large_worker() { static void heap_thread_free_large() { for (int i = 0; i < 100; i++) { - shared_p = mi_malloc_aligned(2 * 1024 * 1024 + 1, 8); + shared_p = mi_malloc_aligned(2*1024*1024 + 1, 8); auto t1 = std::thread(heap_thread_free_large_worker); t1.join(); } } +static void heap_thread_free_huge_worker() { + mi_free(shared_p); +} + +static void heap_thread_free_huge() { + for (int i = 0; i < 10; i++) { + shared_p = mi_malloc(1024 * 1024 * 1024); + auto t1 = std::thread(heap_thread_free_huge_worker); + t1.join(); + } +} static void test_mt_shutdown() @@ -225,21 +403,9 @@ static void test_mt_shutdown() std::cout << "done" << std::endl; } -// issue #363 -using namespace std; - -void large_alloc(void) -{ - char* a = new char[1ull << 25]; - thread th([&] { - delete[] a; - }); - th.join(); -} - // issue #372 static void fail_aslr() { - size_t sz = (4ULL << 40); // 4TiB + size_t sz = (size_t)(4ULL << 40); // 4TiB void* p = malloc(sz); printf("pointer p: %p: area up to %p\n", p, (uint8_t*)p + sz); *(int*)0x5FFFFFFF000 = 0; // should segfault @@ -257,33 +423,30 @@ static void tsan_numa_test() { t1.join(); } -// issue #? -#include -#include -#include -static void bench_alloc_large(void) { - static constexpr int kNumBuffers = 20; - static constexpr size_t kMinBufferSize = 5 * 1024 * 1024; - static constexpr size_t kMaxBufferSize = 25 * 1024 * 1024; - std::unique_ptr buffers[kNumBuffers]; - - std::random_device rd; - std::mt19937 gen(42); //rd()); - std::uniform_int_distribution<> size_distribution(kMinBufferSize, kMaxBufferSize); - std::uniform_int_distribution<> buf_number_distribution(0, kNumBuffers - 1); - - static constexpr int kNumIterations = 2000; - const auto start = std::chrono::steady_clock::now(); - for (int i = 0; i < kNumIterations; ++i) { - int buffer_idx = buf_number_distribution(gen); - size_t new_size = size_distribution(gen); - buffers[buffer_idx] = std::make_unique(new_size); - } - const auto end = std::chrono::steady_clock::now(); - const auto num_ms = std::chrono::duration_cast(end - start).count(); - const auto us_per_allocation = std::chrono::duration_cast(end - start).count() / kNumIterations; - std::cout << kNumIterations << " allocations Done in " << num_ms << "ms." << std::endl; - std::cout << "Avg " << us_per_allocation << " us per allocation" << std::endl; +class MTest +{ + char *data; +public: + MTest() { data = (char*)malloc(1024); } + ~MTest() { free(data); }; +}; + +thread_local MTest tlVariable; + +void threadFun( int i ) +{ + printf( "Thread %d\n", i ); + std::this_thread::sleep_for( std::chrono::milliseconds(100) ); } +void test_thread_local() +{ + for( int i=1; i < 100; ++i ) + { + std::thread t( threadFun, i ); + t.join(); + mi_stats_print(NULL); + } + return; +} \ No newline at end of file diff --git a/src/dashbls/depends/mimalloc/test/test-api-fill.c b/src/dashbls/depends/mimalloc/test/test-api-fill.c index c205637c359c..eebbd394ef83 100644 --- a/src/dashbls/depends/mimalloc/test/test-api-fill.c +++ b/src/dashbls/depends/mimalloc/test/test-api-fill.c @@ -5,7 +5,7 @@ terms of the MIT license. A copy of the license can be found in the file "LICENSE" at the root of this distribution. -----------------------------------------------------------------------------*/ #include "mimalloc.h" -#include "mimalloc-types.h" +#include "mimalloc/types.h" #include "testhelper.h" @@ -164,7 +164,7 @@ int main(void) { mi_free(p); }; -#if MI_DEBUG >= 2 +#if (MI_DEBUG >= 2) && !MI_TSAN // --------------------------------------------------- // Debug filling // --------------------------------------------------- @@ -271,7 +271,7 @@ int main(void) { mi_free(p); }; - + #if !(MI_TRACK_VALGRIND || MI_TRACK_ASAN || MI_GUARDED) CHECK_BODY("fill-freed-small") { size_t malloc_size = MI_SMALL_SIZE_MAX / 2; uint8_t* p = (uint8_t*)mi_malloc(malloc_size); @@ -286,6 +286,7 @@ int main(void) { // First sizeof(void*) bytes will contain housekeeping data, skip these result = check_debug_fill_freed(p + sizeof(void*), malloc_size - sizeof(void*)); }; + #endif #endif // --------------------------------------------------- @@ -309,7 +310,7 @@ bool check_zero_init(uint8_t* p, size_t size) { #if MI_DEBUG >= 2 bool check_debug_fill_uninit(uint8_t* p, size_t size) { -#if MI_VALGRIND +#if MI_TRACK_VALGRIND || MI_TRACK_ASAN (void)p; (void)size; return true; // when compiled with valgrind we don't init on purpose #else @@ -325,10 +326,10 @@ bool check_debug_fill_uninit(uint8_t* p, size_t size) { } bool check_debug_fill_freed(uint8_t* p, size_t size) { -#if MI_VALGRIND +#if MI_TRACK_VALGRIND (void)p; (void)size; return true; // when compiled with valgrind we don't fill on purpose -#else +#else if(!p) return false; @@ -337,6 +338,6 @@ bool check_debug_fill_freed(uint8_t* p, size_t size) { result &= p[i] == MI_DEBUG_FREED; } return result; -#endif +#endif } #endif diff --git a/src/dashbls/depends/mimalloc/test/test-api.c b/src/dashbls/depends/mimalloc/test/test-api.c index 3c2ef7e43fdf..fa8fc3cd5271 100644 --- a/src/dashbls/depends/mimalloc/test/test-api.c +++ b/src/dashbls/depends/mimalloc/test/test-api.c @@ -33,8 +33,8 @@ we therefore test the API over various inputs. Please add more tests :-) #endif #include "mimalloc.h" -// #include "mimalloc-internal.h" -#include "mimalloc-types.h" // for MI_DEBUG +// #include "mimalloc/internal.h" +#include "mimalloc/types.h" // for MI_DEBUG and MI_PAGE_MAX_OVERALLOC_ALIGN #include "testhelper.h" @@ -46,27 +46,54 @@ bool test_heap2(void); bool test_stl_allocator1(void); bool test_stl_allocator2(void); +bool test_stl_heap_allocator1(void); +bool test_stl_heap_allocator2(void); +bool test_stl_heap_allocator3(void); +bool test_stl_heap_allocator4(void); + +bool mem_is_zero(uint8_t* p, size_t size) { + if (p==NULL) return false; + for (size_t i = 0; i < size; ++i) { + if (p[i] != 0) return false; + } + return true; +} + // --------------------------------------------------------------------------- // Main testing // --------------------------------------------------------------------------- int main(void) { mi_option_disable(mi_option_verbose); + CHECK_BODY("malloc-aligned9a") { // test large alignments + void* p = mi_zalloc_aligned(1024 * 1024, 2); + mi_free(p); + p = mi_zalloc_aligned(1024 * 1024, 2); + mi_free(p); + result = true; + }; + + // --------------------------------------------------- // Malloc // --------------------------------------------------- CHECK_BODY("malloc-zero") { - void* p = mi_malloc(0); + void* p = mi_malloc(0); result = (p != NULL); mi_free(p); }; CHECK_BODY("malloc-nomem1") { result = (mi_malloc((size_t)PTRDIFF_MAX + (size_t)1) == NULL); }; - CHECK_BODY("malloc-null") { + CHECK_BODY("malloc-free-null") { mi_free(NULL); }; + #if MI_INTPTR_BITS > 32 + CHECK_BODY("malloc-free-invalid-low") { + mi_free((void*)(MI_ZU(0x0000000003990080))); // issue #1087 + }; + #endif CHECK_BODY("calloc-overflow") { // use (size_t)&mi_calloc to get some number without triggering compiler warnings result = (mi_calloc((size_t)&mi_calloc,SIZE_MAX/1000) == NULL); @@ -83,7 +110,7 @@ int main(void) { // --------------------------------------------------- // Extended - // --------------------------------------------------- + // --------------------------------------------------- CHECK_BODY("posix_memalign1") { void* p = &p; int err = mi_posix_memalign(&p, sizeof(void*), 32); @@ -122,7 +149,7 @@ int main(void) { void* p = mi_malloc_aligned(48,32); result = (p != NULL && (uintptr_t)(p) % 32 == 0); mi_free(p); }; CHECK_BODY("malloc-aligned3") { - void* p1 = mi_malloc_aligned(48,32); bool result1 = (p1 != NULL && (uintptr_t)(p1) % 32 == 0); + void* p1 = mi_malloc_aligned(48,32); bool result1 = (p1 != NULL && (uintptr_t)(p1) % 32 == 0); void* p2 = mi_malloc_aligned(48,32); bool result2 = (p2 != NULL && (uintptr_t)(p2) % 32 == 0); mi_free(p2); mi_free(p1); @@ -138,18 +165,20 @@ int main(void) { result = ok; }; CHECK_BODY("malloc-aligned5") { - void* p = mi_malloc_aligned(4097,4096); - size_t usable = mi_usable_size(p); - result = (usable >= 4097 && usable < 16000); - printf("malloc_aligned5: usable size: %zi\n", usable); + void* p = mi_malloc_aligned(4097,4096); + size_t usable = mi_usable_size(p); + result = (usable >= 4097 && usable < 16000); + fprintf(stderr, "malloc_aligned5: usable size: %zi. ", usable); mi_free(p); }; + /* CHECK_BODY("malloc-aligned6") { bool ok = true; - for (size_t align = 1; align <= MI_ALIGNMENT_MAX && ok; align *= 2) { + for (size_t align = 1; align <= MI_PAGE_MAX_OVERALLOC_ALIGN && ok; align *= 2) { void* ps[8]; for (int i = 0; i < 8 && ok; i++) { - ps[i] = mi_malloc_aligned(align*13 /*size*/, align); + ps[i] = mi_malloc_aligned(align*13 // size + , align); if (ps[i] == NULL || (uintptr_t)(ps[i]) % align != 0) { ok = false; } @@ -160,18 +189,98 @@ int main(void) { } result = ok; }; + */ CHECK_BODY("malloc-aligned7") { - void* p = mi_malloc_aligned(1024,MI_ALIGNMENT_MAX); mi_free(p); - }; + void* p = mi_malloc_aligned(1024,MI_PAGE_MAX_OVERALLOC_ALIGN); + mi_free(p); + result = ((uintptr_t)p % MI_PAGE_MAX_OVERALLOC_ALIGN) == 0; + }; CHECK_BODY("malloc-aligned8") { - void* p = mi_malloc_aligned(1024,2*MI_ALIGNMENT_MAX); mi_free(p); + bool ok = true; + for (int i = 0; i < 5 && ok; i++) { + int n = (1 << i); + void* p = mi_malloc_aligned(1024, n * MI_PAGE_MAX_OVERALLOC_ALIGN); + ok = ((uintptr_t)p % (n*MI_PAGE_MAX_OVERALLOC_ALIGN)) == 0; + mi_free(p); + } + result = ok; + }; + CHECK_BODY("malloc-aligned9") { // test large alignments + bool ok = true; + void* p[8]; + const int max_align_shift = + #if SIZE_MAX > UINT32_MAX + 28 + #else + 20 + #endif + ; + size_t sizes[8] = { 8, 512, 1024 * 1024, MI_PAGE_MAX_OVERALLOC_ALIGN, MI_PAGE_MAX_OVERALLOC_ALIGN + 1, 2 * MI_PAGE_MAX_OVERALLOC_ALIGN, 8 * MI_PAGE_MAX_OVERALLOC_ALIGN, 0 }; + for (int i = 0; i < max_align_shift && ok; i++) { + int align = (1 << i); + for (int j = 0; j < 8 && ok; j++) { + p[j] = mi_zalloc_aligned(sizes[j], align); + ok = ((uintptr_t)p[j] % align) == 0; + } + for (int j = 0; j < 8; j++) { + mi_free(p[j]); + } + } + result = ok; }; + CHECK_BODY("malloc-aligned10") { + bool ok = true; + void* p[10+1]; + int align; + int j; + for(j = 0, align = 1; j <= 10 && ok; align *= 2, j++ ) { + p[j] = mi_malloc_aligned(43 + align, align); + ok = ((uintptr_t)p[j] % align) == 0; + } + for ( ; j > 0; j--) { + mi_free(p[j-1]); + } + result = ok; + } + CHECK_BODY("malloc_aligned11") { + mi_heap_t* heap = mi_heap_new(); + void* p = mi_heap_malloc_aligned(heap, 33554426, 8); + result = mi_heap_contains_block(heap, p); + mi_heap_destroy(heap); + } + CHECK_BODY("mimalloc-aligned12") { + void* p = mi_malloc_aligned(0x100, 0x100); + result = (((uintptr_t)p % 0x100) == 0); // #602 + mi_free(p); + } + CHECK_BODY("mimalloc-aligned13") { + bool ok = true; + for( size_t size = 1; size <= (MI_SMALL_SIZE_MAX * 2) && ok; size++ ) { + for(size_t align = 1; align <= size && ok; align *= 2 ) { + void* p[10]; + for(int i = 0; i < 10 && ok; i++) { + p[i] = mi_malloc_aligned(size,align);; + ok = (p[i] != NULL && ((uintptr_t)(p[i]) % align) == 0); + } + for(int i = 0; i < 10 && ok; i++) { + mi_free(p[i]); + } + /* + if (ok && align <= size && ((size + MI_PADDING_SIZE) & (align-1)) == 0) { + size_t bsize = mi_good_size(size); + ok = (align <= bsize && (bsize & (align-1)) == 0); + } + */ + } + } + result = ok; + } CHECK_BODY("malloc-aligned-at1") { void* p = mi_malloc_aligned_at(48,32,0); result = (p != NULL && ((uintptr_t)(p) + 0) % 32 == 0); mi_free(p); }; CHECK_BODY("malloc-aligned-at2") { void* p = mi_malloc_aligned_at(50,32,8); result = (p != NULL && ((uintptr_t)(p) + 8) % 32 == 0); mi_free(p); - }; + }; CHECK_BODY("memalign1") { void* p; bool ok = true; @@ -181,7 +290,22 @@ int main(void) { } result = ok; }; - + CHECK_BODY("zalloc-aligned-small1") { + size_t zalloc_size = MI_SMALL_SIZE_MAX / 2; + uint8_t* p = (uint8_t*)mi_zalloc_aligned(zalloc_size, MI_MAX_ALIGN_SIZE * 2); + result = mem_is_zero(p, zalloc_size); + mi_free(p); + }; + CHECK_BODY("rezalloc_aligned-small1") { + size_t zalloc_size = MI_SMALL_SIZE_MAX / 2; + uint8_t* p = (uint8_t*)mi_zalloc_aligned(zalloc_size, MI_MAX_ALIGN_SIZE * 2); + result = mem_is_zero(p, zalloc_size); + zalloc_size *= 3; + p = (uint8_t*)mi_rezalloc_aligned(p, zalloc_size, MI_MAX_ALIGN_SIZE * 2); + result = result && mem_is_zero(p, zalloc_size); + mi_free(p); + }; + // --------------------------------------------------- // Reallocation // --------------------------------------------------- @@ -221,15 +345,22 @@ int main(void) { // --------------------------------------------------- // various // --------------------------------------------------- + #if !defined(MI_TRACK_ASAN) // realpath may leak with ASAN enabled (as the ASAN allocator intercepts it) CHECK_BODY("realpath") { char* s = mi_realpath( ".", NULL ); // printf("realpath: %s\n",s); mi_free(s); }; + #endif CHECK("stl_allocator1", test_stl_allocator1()); CHECK("stl_allocator2", test_stl_allocator2()); + CHECK("stl_heap_allocator1", test_stl_heap_allocator1()); + CHECK("stl_heap_allocator2", test_stl_heap_allocator2()); + CHECK("stl_heap_allocator3", test_stl_heap_allocator3()); + CHECK("stl_heap_allocator4", test_stl_heap_allocator4()); + // --------------------------------------------------- // Done // ---------------------------------------------------[] @@ -240,7 +371,7 @@ int main(void) { // Larger test functions // --------------------------------------------------- -bool test_heap1() { +bool test_heap1(void) { mi_heap_t* heap = mi_heap_new(); int* p1 = mi_heap_malloc_tp(heap,int); int* p2 = mi_heap_malloc_tp(heap,int); @@ -249,7 +380,7 @@ bool test_heap1() { return true; } -bool test_heap2() { +bool test_heap2(void) { mi_heap_t* heap = mi_heap_new(); int* p1 = mi_heap_malloc_tp(heap,int); int* p2 = mi_heap_malloc_tp(heap,int); @@ -260,7 +391,7 @@ bool test_heap2() { return true; } -bool test_stl_allocator1() { +bool test_stl_allocator1(void) { #ifdef __cplusplus std::vector > vec; vec.push_back(1); @@ -273,7 +404,7 @@ bool test_stl_allocator1() { struct some_struct { int i; int j; double z; }; -bool test_stl_allocator2() { +bool test_stl_allocator2(void) { #ifdef __cplusplus std::vector > vec; vec.push_back(some_struct()); @@ -283,3 +414,61 @@ bool test_stl_allocator2() { return true; #endif } + +bool test_stl_heap_allocator1(void) { +#ifdef __cplusplus + std::vector > vec; + vec.push_back(some_struct()); + vec.pop_back(); + return vec.size() == 0; +#else + return true; +#endif +} + +bool test_stl_heap_allocator2(void) { +#ifdef __cplusplus + std::vector > vec; + vec.push_back(some_struct()); + vec.pop_back(); + return vec.size() == 0; +#else + return true; +#endif +} + +bool test_stl_heap_allocator3(void) { +#ifdef __cplusplus + mi_heap_t* heap = mi_heap_new(); + bool good = false; + { + mi_heap_stl_allocator myAlloc(heap); + std::vector > vec(myAlloc); + vec.push_back(some_struct()); + vec.pop_back(); + good = vec.size() == 0; + } + mi_heap_delete(heap); + return good; +#else + return true; +#endif +} + +bool test_stl_heap_allocator4(void) { +#ifdef __cplusplus + mi_heap_t* heap = mi_heap_new(); + bool good = false; + { + mi_heap_destroy_stl_allocator myAlloc(heap); + std::vector > vec(myAlloc); + vec.push_back(some_struct()); + vec.pop_back(); + good = vec.size() == 0; + } + mi_heap_destroy(heap); + return good; +#else + return true; +#endif +} diff --git a/src/dashbls/depends/mimalloc/test/test-stress.c b/src/dashbls/depends/mimalloc/test/test-stress.c index 61171d0389b7..a2e2b3776f35 100644 --- a/src/dashbls/depends/mimalloc/test/test-stress.c +++ b/src/dashbls/depends/mimalloc/test/test-stress.c @@ -7,7 +7,7 @@ terms of the MIT license. /* This is a stress test for the allocator, using multiple threads and transferring objects between threads. It tries to reflect real-world workloads: - allocation size is distributed linearly in powers of two - - with some fraction extra large (and some extra extra large) + - with some fraction extra large (and some very large) - the allocations are initialized and read again at free - pointers transfer between threads - threads are terminated and recreated with some objects surviving in between @@ -20,33 +20,73 @@ terms of the MIT license. #include #include #include +#include + +// #define MI_GUARDED +// #define USE_STD_MALLOC // > mimalloc-test-stress [THREADS] [SCALE] [ITER] // // argument defaults +#if defined(MI_TSAN) // with thread-sanitizer reduce the threads to test within the azure pipeline limits +static int THREADS = 8; +static int SCALE = 25; +static int ITER = 400; +#elif defined(MI_UBSAN) // with undefined behavious sanitizer reduce parameters to stay within the azure pipeline limits +static int THREADS = 8; +static int SCALE = 25; +static int ITER = 20; +#elif defined(MI_GUARDED) // with debug guard pages reduce parameters to stay within the azure pipeline limits +static int THREADS = 8; +static int SCALE = 10; +static int ITER = 10; +#elif 0 +static int THREADS = 4; +static int SCALE = 10; +static int ITER = 20; +#elif 0 +static int THREADS = 32; +static int SCALE = 50; +static int ITER = 50; +#elif 0 +static int THREADS = 32; +static int SCALE = 25; +static int ITER = 50; +#define ALLOW_LARGE true +#else static int THREADS = 32; // more repeatable if THREADS <= #processors -static int SCALE = 25; // scaling factor +static int SCALE = 50; // scaling factor static int ITER = 50; // N full iterations destructing and re-creating all threads +#endif -// static int THREADS = 8; // more repeatable if THREADS <= #processors -// static int SCALE = 100; // scaling factor -#define STRESS // undefine for leak test -static bool allow_large_objects = true; // allow very large objects? -static size_t use_one_size = 0; // use single object size of `N * sizeof(uintptr_t)`? +#define STRESS // undefine for leak test +#ifndef ALLOW_LARGE +#define ALLOW_LARGE false +#endif + +static bool allow_large_objects = ALLOW_LARGE; // allow very large objects? (set to `true` if SCALE>100) + +static size_t use_one_size = 0; // use single object size of `N * sizeof(uintptr_t)`? + +static bool main_participates = false; // main thread participates as a worker too -// #define USE_STD_MALLOC #ifdef USE_STD_MALLOC -#define custom_calloc(n,s) malloc(n*s) +#define custom_calloc(n,s) calloc(n,s) #define custom_realloc(p,s) realloc(p,s) #define custom_free(p) free(p) #else #include -#define custom_calloc(n,s) mi_malloc(n*s) +#include +#define custom_calloc(n,s) mi_calloc(n,s) #define custom_realloc(p,s) mi_realloc(p,s) #define custom_free(p) mi_free(p) + +#ifndef NDEBUG +#define xHEAP_WALK // walk the heap objects? +#endif #endif // transfer pointer between threads @@ -95,12 +135,13 @@ static void* alloc_items(size_t items, random_t r) { else if (chance(10, r) && allow_large_objects) items *= 1000; // 0.1% huge else items *= 100; // 1% large objects; } - if (items == 40) items++; // pthreads uses that size for stack increases + if (items>=32 && items<=40) items*=2; // pthreads uses 320b allocations (this shows that more clearly in the stats) if (use_one_size > 0) items = (use_one_size / sizeof(uintptr_t)); if (items==0) items = 1; uintptr_t* p = (uintptr_t*)custom_calloc(items,sizeof(uintptr_t)); if (p != NULL) { for (uintptr_t i = 0; i < items; i++) { + assert(p[i] == 0); p[i] = (items - i) ^ cookie; } } @@ -121,6 +162,16 @@ static void free_items(void* p) { custom_free(p); } +#ifdef HEAP_WALK +static bool visit_blocks(const mi_heap_t* heap, const mi_heap_area_t* area, void* block, size_t block_size, void* arg) { + (void)(heap); (void)(area); + size_t* total = (size_t*)arg; + if (block != NULL) { + *total += block_size; + } + return true; +} +#endif static void stress(intptr_t tid) { //bench_start_thread(); @@ -165,6 +216,13 @@ static void stress(intptr_t tid) { data[data_idx] = q; } } + + #ifdef HEAP_WALK + // walk the heap + size_t total = 0; + mi_heap_visit_blocks(mi_heap_get_default(), true, visit_blocks, &total); + #endif + // free everything that is left for (size_t i = 0; i < retain_top; i++) { free_items(retained[i]); @@ -182,7 +240,15 @@ static void run_os_threads(size_t nthreads, void (*entry)(intptr_t tid)); static void test_stress(void) { uintptr_t r = rand(); for (int n = 0; n < ITER; n++) { - run_os_threads(THREADS, &stress); + run_os_threads(THREADS, &stress); + #if !defined(NDEBUG) && !defined(USE_STD_MALLOC) + // switch between arena and OS allocation for testing + // mi_option_set_enabled(mi_option_disallow_arena_alloc, (n%2)==1); + #endif + #ifdef HEAP_WALK + size_t total = 0; + mi_abandoned_visit_blocks(mi_subproc_main(), -1, true, visit_blocks, &total); + #endif for (int i = 0; i < TRANSFERS; i++) { if (chance(50, &r) || n + 1 == ITER) { // free all on last run, otherwise free half of the transfers void* p = atomic_exchange_ptr(&transfer[i], NULL); @@ -191,12 +257,26 @@ static void test_stress(void) { } #ifndef NDEBUG //mi_collect(false); - //mi_debug_show_arenas(); - #endif + //mi_debug_show_arenas(true); + #endif #if !defined(NDEBUG) || defined(MI_TSAN) - if ((n + 1) % 10 == 0) { printf("- iterations left: %3d\n", ITER - (n + 1)); } + if ((n + 1) % 10 == 0) { + printf("- iterations left: %3d\n", ITER - (n + 1)); + #ifndef USE_STD_MALLOC + mi_debug_show_arenas(); + #endif + //mi_collect(true); + //mi_debug_show_arenas(); + } #endif } + // clean up + for (int i = 0; i < TRANSFERS; i++) { + void* p = atomic_exchange_ptr(&transfer[i], NULL); + if (p != NULL) { + free_items(p); + } + } } #ifndef STRESS @@ -221,7 +301,29 @@ static void test_leak(void) { } #endif -int main(int argc, char** argv) { +#if defined(USE_STD_MALLOC) && defined(MI_LINK_VERSION) +#ifdef __cplusplus +extern "C" +#endif +int mi_version(void); +#endif + +int main(int argc, char** argv) { + #ifdef MI_LINK_VERSION + mi_version(); + #endif + #ifdef HEAP_WALK + mi_option_enable(mi_option_visit_abandoned); + #endif + #if !defined(NDEBUG) && !defined(USE_STD_MALLOC) + // mi_option_set(mi_option_arena_reserve, 32 * 1024 /* in kib = 32MiB */); + // mi_option_set(mi_option_purge_delay,1); + #endif + #if defined(NDEBUG) && !defined(USE_STD_MALLOC) + // mi_option_set(mi_option_purge_delay,-1); + mi_option_set(mi_option_page_reclaim_on_free, 0); + #endif + // > mimalloc-test-stress [THREADS] [SCALE] [ITER] if (argc >= 2) { char* end; @@ -238,7 +340,15 @@ int main(int argc, char** argv) { long n = (strtol(argv[3], &end, 10)); if (n > 0) ITER = n; } - printf("Using %d threads with a %d%% load-per-thread and %d iterations\n", THREADS, SCALE, ITER); + if (SCALE > 100) { + allow_large_objects = true; + } + printf("Using %d threads with a %d%% load-per-thread and %d iterations %s\n", THREADS, SCALE, ITER, (allow_large_objects ? "(allow large objects)" : "")); + + #if !defined(NDEBUG) && !defined(USE_STD_MALLOC) + mi_stats_reset(); + #endif + //mi_reserve_os_memory(1024*1024*1024ULL, false, true); //int res = mi_reserve_huge_os_pages(4,1); //printf("(reserve huge: %i\n)", res); @@ -247,26 +357,26 @@ int main(int argc, char** argv) { // Run ITER full iterations where half the objects in the transfer buffer survive to the next round. srand(0x7feb352d); - - //mi_reserve_os_memory(512ULL << 20, true, true); - -#if !defined(NDEBUG) && !defined(USE_STD_MALLOC) - mi_stats_reset(); -#endif - + // mi_stats_reset(); #ifdef STRESS - test_stress(); + test_stress(); #else - test_leak(); + test_leak(); #endif #ifndef USE_STD_MALLOC #ifndef NDEBUG + mi_debug_show_arenas(); mi_collect(true); - //mi_debug_show_arenas(); + char* json = mi_stats_get_json(0, NULL); + if (json != NULL) { + fputs(json,stderr); + mi_free(json); + } #endif + mi_collect(true); mi_stats_print(NULL); -#endif +#endif //bench_end_program(); return 0; } @@ -276,7 +386,7 @@ static void (*thread_entry_fun)(intptr_t) = &stress; #ifdef _WIN32 -#include +#include static DWORD WINAPI thread_entry(LPVOID param) { thread_entry_fun((intptr_t)param); @@ -287,13 +397,16 @@ static void run_os_threads(size_t nthreads, void (*fun)(intptr_t)) { thread_entry_fun = fun; DWORD* tids = (DWORD*)custom_calloc(nthreads,sizeof(DWORD)); HANDLE* thandles = (HANDLE*)custom_calloc(nthreads,sizeof(HANDLE)); - for (uintptr_t i = 0; i < nthreads; i++) { - thandles[i] = CreateThread(0, 8*1024, &thread_entry, (void*)(i), 0, &tids[i]); + thandles[0] = GetCurrentThread(); // avoid lint warning + const size_t start = (main_participates ? 1 : 0); + for (size_t i = start; i < nthreads; i++) { + thandles[i] = CreateThread(0, 8*1024L, &thread_entry, (void*)(i), 0, &tids[i]); } - for (size_t i = 0; i < nthreads; i++) { + if (main_participates) fun(0); // run the main thread as well + for (size_t i = start; i < nthreads; i++) { WaitForSingleObject(thandles[i], INFINITE); } - for (size_t i = 0; i < nthreads; i++) { + for (size_t i = start; i < nthreads; i++) { CloseHandle(thandles[i]); } custom_free(tids); @@ -320,11 +433,13 @@ static void run_os_threads(size_t nthreads, void (*fun)(intptr_t)) { thread_entry_fun = fun; pthread_t* threads = (pthread_t*)custom_calloc(nthreads,sizeof(pthread_t)); memset(threads, 0, sizeof(pthread_t) * nthreads); + const size_t start = (main_participates ? 1 : 0); //pthread_setconcurrency(nthreads); - for (size_t i = 0; i < nthreads; i++) { + for (size_t i = start; i < nthreads; i++) { pthread_create(&threads[i], NULL, &thread_entry, (void*)i); } - for (size_t i = 0; i < nthreads; i++) { + if (main_participates) fun(0); // run the main thread as well + for (size_t i = start; i < nthreads; i++) { pthread_join(threads[i], NULL); } custom_free(threads); diff --git a/src/dashbls/depends/mimalloc/test/test-wrong.c b/src/dashbls/depends/mimalloc/test/test-wrong.c index 8bf7767edb4d..56a2339a7554 100644 --- a/src/dashbls/depends/mimalloc/test/test-wrong.c +++ b/src/dashbls/depends/mimalloc/test/test-wrong.c @@ -5,20 +5,42 @@ terms of the MIT license. A copy of the license can be found in the file "LICENSE" at the root of this distribution. -----------------------------------------------------------------------------*/ -/* test file for valgrind support. +/* test file for valgrind/asan support. + + VALGRIND: + ---------- Compile in an "out/debug" folder: > cd out/debug - > cmake ../.. -DMI_VALGRIND=1 + > cmake ../.. -DMI_TRACK_VALGRIND=1 > make -j8 - and then compile this file as: + and then compile this file as: > gcc -g -o test-wrong -I../../include ../../test/test-wrong.c libmimalloc-valgrind-debug.a -lpthread and test as: > valgrind ./test-wrong + + + ASAN + ---------- + Compile in an "out/debug" folder: + + > cd out/debug + > cmake ../.. -DMI_TRACK_ASAN=1 + > make -j8 + + and then compile this file as: + + > clang -g -o test-wrong -I../../include ../../test/test-wrong.c libmimalloc-asan-debug.a -lpthread -fsanitize=address -fsanitize-recover=address + + and test as: + + > ASAN_OPTIONS=verbosity=1:halt_on_error=0 ./test-wrong + + */ #include #include @@ -31,9 +53,9 @@ terms of the MIT license. A copy of the license can be found in the file #endif int main(int argc, char** argv) { - int* p = mi(malloc)(3*sizeof(int)); - - int* r = mi_malloc_aligned(8,16); + int* p = (int*)mi(malloc)(3*sizeof(int)); + + int* r = (int*)mi_malloc_aligned(8,16); mi_free(r); // illegal byte wise read @@ -42,12 +64,12 @@ int main(int argc, char** argv) { mi(free)(c); // undefined access - int* q = mi(malloc)(sizeof(int)); + int* q = (int*)mi(malloc)(sizeof(int)); printf("undefined: %d\n", *q); // illegal int read printf("invalid: over: %d, under: %d\n", q[1], q[-1]); - + *q = 42; // buffer overflow @@ -55,7 +77,7 @@ int main(int argc, char** argv) { // buffer underflow q[-1] = 44; - + mi(free)(q); // double free @@ -66,5 +88,5 @@ int main(int argc, char** argv) { // leak p // mi_free(p) - return 0; + return 0; } \ No newline at end of file diff --git a/src/dashbls/depends/mimalloc/test/testhelper.h b/src/dashbls/depends/mimalloc/test/testhelper.h index 44776b74b337..a97275841177 100644 --- a/src/dashbls/depends/mimalloc/test/testhelper.h +++ b/src/dashbls/depends/mimalloc/test/testhelper.h @@ -19,12 +19,12 @@ static int failed = 0; static bool check_result(bool result, const char* testname, const char* fname, long lineno) { if (!(result)) { - failed++; + failed++; fprintf(stderr,"\n FAILED: %s: %s:%ld\n", testname, fname, lineno); - /* exit(1); */ - } - else { - ok++; + /* exit(1); */ + } + else { + ok++; fprintf(stderr, "ok.\n"); } return true; diff --git a/src/dashbls/depends/relic/CMakeLists.txt b/src/dashbls/depends/relic/CMakeLists.txt index db5a62507468..db36c9bb7d46 100644 --- a/src/dashbls/depends/relic/CMakeLists.txt +++ b/src/dashbls/depends/relic/CMakeLists.txt @@ -1,7 +1,5 @@ -cmake_minimum_required(VERSION 3.1) -if(NOT ${CMAKE_VERSION} VERSION_LESS "3.1") - cmake_policy(SET CMP0054 NEW) -endif() +cmake_minimum_required(VERSION 3.18) +cmake_policy(SET CMP0054 NEW) project(RELIC C CXX) set(PROJECT_VERSION_MAJOR "0") diff --git a/src/dashbls/go-bindings/Makefile b/src/dashbls/go-bindings/Makefile index c7a57e7307d7..dcea3f24f2d3 100644 --- a/src/dashbls/go-bindings/Makefile +++ b/src/dashbls/go-bindings/Makefile @@ -1,29 +1,59 @@ -SRC_DIR=$(PWD)/../src -BUILD_DIR=$(PWD)/../build +export CGO_ENABLED := 1 +GO=go -GO="go" -COVERAGE_OUTPUT ?= coverage.out - -.PHONY: default vet test clean +OS := $(shell uname -s) +ARCH := $(shell uname -m) -default: prepare vet test clean +COVERAGE_OUTPUT ?= coverage.out MAKEFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) + +BUILD_DIR=$(CURDIR)/../build CURR_DIR := $(dir $(MAKEFILE_PATH)) +SRC_DIR=$(CURDIR)/../src -CGO_ENABLED := 1 +GMP_PREFIX := /usr/local -CGO_LDFLAGS ?= "\ --L$(CURR_DIR)../build/depends/mimalloc \ --L$(CURR_DIR)../build/depends/relic/lib \ --L$(CURR_DIR)../build/src \ --ldashbls -lrelic_s -lmimalloc-secure -lgmp" +ifeq ("$(OS)", "Darwin") + ifneq ($(wildcard /opt/local/bin/port),) + GMP_PREFIX := /opt/local + endif + ifeq ("$(ARCH)", "arm64") + ifneq ($(wildcard /opt/homebrew/bin/brew),) + GMP_PREFIX := /opt/homebrew + endif + endif +else ifeq ("$(OS)", "Linux") + ifneq ($(wildcard /home/linuxbrew/.linuxbrew/bin/brew),) + GMP_PREFIX := /home/linuxbrew/.linuxbrew + endif +endif + +MIMALLOC_LIB := mimalloc-secure +MIMALLOC_LIB_PATH := $(CURR_DIR)../build/depends/mimalloc + +ifneq ($(wildcard $(MIMALLOC_LIB_PATH)/libmimalloc-secure-debug.a),) + MIMALLOC_LIB := mimalloc-secure-debug +endif CGO_CXXFLAGS ?= "\ -I$(CURR_DIR)../build/depends/relic/include \ -I$(CURR_DIR)../depends/mimalloc/include \ -I$(CURR_DIR)../depends/relic/include \ --I$(CURR_DIR)../include" +-I$(CURR_DIR)../include \ +-I$(GMP_PREFIX)/include" + +CGO_LDFLAGS ?= "\ +-L$(CURR_DIR)../build/src -ldashbls \ +-L$(MIMALLOC_LIB_PATH) -l$(MIMALLOC_LIB) \ +-L$(CURR_DIR)../build/depends/relic/lib -lrelic_s \ +-L$(GMP_PREFIX)/lib -lgmp" + +.PHONY: default prepare fmt test cover vet help clean config + +all: default + +default: prepare vet test clean prepare: @mkdir -p ../build/src/dashbls @@ -42,7 +72,7 @@ cover: ## Run tests and generate test coverage file, output coverage results an rm -f $(COVERAGE_OUTPUT) vet: ## Go vet all project code - CGO_CXXFLAGS=$(CGO_CXXFLAGS) CGO_LDFLAGS=$(CGO_LDFLAGS) go vet ./... + CGO_CXXFLAGS=$(CGO_CXXFLAGS) CGO_LDFLAGS=$(CGO_LDFLAGS) $(GO) vet ./... help: ## Show This Help @for line in $$(cat Makefile | grep "##" | grep -v "grep" | sed "s/:.*##/:/g" | sed "s/\ /!/g"); do verb=$$(echo $$line | cut -d ":" -f 1); desc=$$(echo $$line | cut -d ":" -f 2 | sed "s/!/\ /g"); printf "%-30s--%s\n" "$$verb" "$$desc"; done @@ -50,3 +80,18 @@ help: ## Show This Help clean: ## Clean up transient (generated) files $(GO) clean rm -f $(COVERAGE_OUTPUT) + +config: ## Display build configuration + @echo "" + @echo "OS: $(OS)" + @echo "ARCH: $(ARCH)" + @echo "" + @echo "CC: $${CC:-}" + @echo "CXX: $${CXX:-}" + @echo "GO: $(GO)" + @echo "" + @echo "GOROOT: $${GOROOT:-}" + @echo "" + @echo "CGO_CXXFLAGS: $(CGO_CXXFLAGS)" + @echo "CGO_LDFLAGS: $(CGO_LDFLAGS)" + @echo "" diff --git a/src/dashbls/go-bindings/elements.cpp b/src/dashbls/go-bindings/elements.cpp index fda47b2e6237..eb30fcec88ec 100644 --- a/src/dashbls/go-bindings/elements.cpp +++ b/src/dashbls/go-bindings/elements.cpp @@ -23,11 +23,11 @@ int CG1ElementSize() { return bls::G1Element::SIZE; } -CG1Element CG1ElementFromBytes(const void* data, bool* didErr) { +CG1Element CG1ElementFromBytes(const void* data, size_t len, bool* didErr) { bls::G1Element* el = nullptr; try { el = new bls::G1Element( - bls::G1Element::FromBytes(bls::Bytes((uint8_t*)(data), bls::G1Element::SIZE)) + bls::G1Element::FromBytes(bls::Bytes((uint8_t*)data, len)) ); } catch(const std::exception& ex) { gErrMsg = ex.what(); @@ -93,11 +93,11 @@ int CG2ElementSize() { return bls::G2Element::SIZE; } -CG2Element CG2ElementFromBytes(const void* data, bool* didErr) { +CG2Element CG2ElementFromBytes(const void* data, size_t len, bool* didErr) { bls::G2Element* el = nullptr; try { el = new bls::G2Element( - bls::G2Element::FromBytes(bls::Bytes((uint8_t*)data, bls::G2Element::SIZE)) + bls::G2Element::FromBytes(bls::Bytes((uint8_t*)data, len)) ); *didErr = false; } catch(const std::exception& ex) { diff --git a/src/dashbls/go-bindings/elements.go b/src/dashbls/go-bindings/elements.go index 013127677c7f..84548c17e1dd 100644 --- a/src/dashbls/go-bindings/elements.go +++ b/src/dashbls/go-bindings/elements.go @@ -14,8 +14,6 @@ package blschia -// #cgo LDFLAGS: -ldashbls -lrelic_s -lmimalloc-secure -lgmp -// #cgo CXXFLAGS: -std=c++14 // #include // #include // #include "elements.h" @@ -40,7 +38,7 @@ func G1ElementFromBytes(data []byte) (*G1Element, error) { defer C.free(cBytesPtr) var cDidErr C.bool el := G1Element{ - val: C.CG1ElementFromBytes(cBytesPtr, &cDidErr), + val: C.CG1ElementFromBytes(cBytesPtr, C.size_t(len(data)), &cDidErr), } if bool(cDidErr) { return nil, errFromC() @@ -131,7 +129,7 @@ func G2ElementFromBytes(data []byte) (*G2Element, error) { defer C.free(cBytesPtr) var cDidErr C.bool el := G2Element{ - val: C.CG2ElementFromBytes(cBytesPtr, &cDidErr), + val: C.CG2ElementFromBytes(cBytesPtr, C.size_t(len(data)), &cDidErr), } if bool(cDidErr) { return nil, errFromC() diff --git a/src/dashbls/go-bindings/elements.h b/src/dashbls/go-bindings/elements.h index 2a4c6e544b8d..a391534dc55d 100644 --- a/src/dashbls/go-bindings/elements.h +++ b/src/dashbls/go-bindings/elements.h @@ -27,7 +27,7 @@ typedef void* CPrivateKey; // G1Element int CG1ElementSize(); -CG1Element CG1ElementFromBytes(const void* data, bool* didErr); +CG1Element CG1ElementFromBytes(const void* data, size_t len, bool* didErr); CG1Element CG1ElementGenerator(); bool CG1ElementIsValid(const CG1Element el); uint32_t CG1ElementGetFingerprint(const CG1Element el); @@ -40,7 +40,7 @@ void CG1ElementFree(const CG1Element el); // G2Element int CG2ElementSize(); -CG2Element CG2ElementFromBytes(const void* data, bool* didErr); +CG2Element CG2ElementFromBytes(const void* data, size_t len, bool* didErr); CG2Element CG2ElementGenerator(); bool CG2ElementIsValid(const CG2Element el); bool CG2ElementIsEqual(const CG2Element el1, const CG2Element el2); diff --git a/src/dashbls/go-bindings/privatekey.cpp b/src/dashbls/go-bindings/privatekey.cpp index cbe5fddf3a74..90b7f0aab696 100644 --- a/src/dashbls/go-bindings/privatekey.cpp +++ b/src/dashbls/go-bindings/privatekey.cpp @@ -20,12 +20,12 @@ #include "utils.hpp" // private key bindings implementation -CPrivateKey CPrivateKeyFromBytes(const void* data, const bool modOrder, bool* didErr) { +CPrivateKey CPrivateKeyFromBytes(const void* data, size_t len, const bool modOrder, bool* didErr) { bls::PrivateKey* skPtr = nullptr; try { skPtr = new bls::PrivateKey( bls::PrivateKey::FromBytes( - bls::Bytes((uint8_t*)data, bls::PrivateKey::PRIVATE_KEY_SIZE), + bls::Bytes((uint8_t*)data, len), modOrder ) ); diff --git a/src/dashbls/go-bindings/privatekey.go b/src/dashbls/go-bindings/privatekey.go index 1a47454b26e0..155338e834cb 100644 --- a/src/dashbls/go-bindings/privatekey.go +++ b/src/dashbls/go-bindings/privatekey.go @@ -14,8 +14,6 @@ package blschia -// #cgo LDFLAGS: -ldashbls -lrelic_s -lmimalloc-secure -lgmp -// #cgo CXXFLAGS: -std=c++14 // #include // #include // #include "privatekey.h" @@ -38,7 +36,7 @@ func PrivateKeyFromBytes(data []byte, modOrder bool) (*PrivateKey, error) { defer C.SecFree(cBytesPtr) var cDidErr C.bool sk := PrivateKey{ - val: C.CPrivateKeyFromBytes(cBytesPtr, C.bool(modOrder), &cDidErr), + val: C.CPrivateKeyFromBytes(cBytesPtr, C.size_t(len(data)), C.bool(modOrder), &cDidErr), } if bool(cDidErr) { return nil, errFromC() diff --git a/src/dashbls/go-bindings/privatekey.h b/src/dashbls/go-bindings/privatekey.h index 55d1c86ea852..13f3c5d3dd14 100644 --- a/src/dashbls/go-bindings/privatekey.h +++ b/src/dashbls/go-bindings/privatekey.h @@ -23,7 +23,7 @@ extern "C" { typedef void* CPrivateKey; -CPrivateKey CPrivateKeyFromBytes(const void* data, const bool modOrder, bool* didErr); +CPrivateKey CPrivateKeyFromBytes(const void* data, size_t len, const bool modOrder, bool* didErr); CPrivateKey CPrivateKeyAggregate(void** sks, const size_t len); CG1Element CPrivateKeyGetG1Element(const CPrivateKey sk, bool* didErr); CG2Element CPrivateKeyGetG2Element(const CPrivateKey sk, bool* didErr); diff --git a/src/dashbls/go-bindings/schemes.go b/src/dashbls/go-bindings/schemes.go index 21126f91258a..2289b212bd7d 100644 --- a/src/dashbls/go-bindings/schemes.go +++ b/src/dashbls/go-bindings/schemes.go @@ -14,8 +14,6 @@ package blschia -// #cgo LDFLAGS: -ldashbls -lrelic_s -lmimalloc-secure -lgmp -// #cgo CXXFLAGS: -std=c++14 // #include // #include // #include "schemes.h" diff --git a/src/dashbls/go-bindings/threshold.go b/src/dashbls/go-bindings/threshold.go index 5d59b1743e4c..5f484cee8dc3 100644 --- a/src/dashbls/go-bindings/threshold.go +++ b/src/dashbls/go-bindings/threshold.go @@ -14,8 +14,6 @@ package blschia -// #cgo LDFLAGS: -ldashbls -lrelic_s -lmimalloc-secure -lgmp -// #cgo CXXFLAGS: -std=c++14 // #include // #include "threshold.h" // #include "blschia.h" diff --git a/src/dashbls/go-bindings/util.go b/src/dashbls/go-bindings/util.go index 39b91513c1b5..fbea18895a76 100644 --- a/src/dashbls/go-bindings/util.go +++ b/src/dashbls/go-bindings/util.go @@ -14,8 +14,6 @@ package blschia -// #cgo LDFLAGS: -ldashbls -lrelic_s -lmimalloc-secure -lgmp -// #cgo CXXFLAGS: -std=c++14 // #include "blschia.h" // #include import "C" diff --git a/src/dashbls/include/dashbls/schemes.hpp b/src/dashbls/include/dashbls/schemes.hpp index 31e6b1a1b704..1aee61dd346d 100644 --- a/src/dashbls/include/dashbls/schemes.hpp +++ b/src/dashbls/include/dashbls/schemes.hpp @@ -15,6 +15,7 @@ #ifndef SRC_BLSSCHEMES_HPP_ #define SRC_BLSSCHEMES_HPP_ +#include #include #include @@ -65,8 +66,8 @@ class CoreMPL { virtual bool Verify(const G1Element& pubkey, const Bytes& message, const G2Element& signature); - virtual vector Aggregate(const vector> &signatures); - virtual vector Aggregate(const vector& signatures); + virtual std::array Aggregate(const vector> &signatures); + virtual std::array Aggregate(const vector& signatures); virtual G2Element Aggregate(const vector &signatures); @@ -243,7 +244,7 @@ class LegacySchemeMPL final : public CoreMPL { bool Verify(const Bytes& pubkey, const Bytes& message, const Bytes& signature) final { throw std::runtime_error("Not supported in LegacySchemeMPL"); } bool Verify(const G1Element &pubkey, const Bytes& message, const G2Element &signature) final; - vector Aggregate(const vector> &signatures) final { throw std::runtime_error("Not supported in LegacySchemeMPL"); } + std::array Aggregate(const vector> &signatures) final { throw std::runtime_error("Not supported in LegacySchemeMPL"); } G2Element AggregateSecure(const std::vector& vecPublicKeys, const std::vector& vecSignatures, diff --git a/src/dashbls/js-bindings/CMakeLists.txt b/src/dashbls/js-bindings/CMakeLists.txt index 03da706af724..f053eb2ea05e 100644 --- a/src/dashbls/js-bindings/CMakeLists.txt +++ b/src/dashbls/js-bindings/CMakeLists.txt @@ -20,6 +20,20 @@ add_custom_target(install_npm_dependencies npm ci) add_dependencies(blsjstmp install_npm_dependencies) target_link_libraries(blsjstmp PRIVATE dashbls) +target_link_options(blsjstmp PRIVATE + "SHELL:--bind" + "SHELL:-Oz" + "SHELL:--closure 1" + "SHELL:-s MODULARIZE=1" + "SHELL:-s MALLOC=emmalloc" + "SHELL:-s ALLOW_MEMORY_GROWTH=1" + "SHELL:-s INITIAL_MEMORY=134217728" +) + +if(CMAKE_BUILD_TYPE MATCHES "Debug") + target_link_options(blsjstmp PRIVATE "SHELL:-s ASSERTIONS=2") +endif() + # Copy necessary files for the npm package configure_file(${CMAKE_CURRENT_SOURCE_DIR}/package.json package.json COPYONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/package-lock.json package-lock.json COPYONLY) @@ -34,5 +48,4 @@ foreach(file ${JS_BINDINGS_TESTS}) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/tests/${file} tests/${file} COPYONLY) endforeach() -set_target_properties(blsjstmp PROPERTIES LINK_FLAGS "--bind -Oz --closure 1 -s MODULARIZE=1") add_custom_command(TARGET blsjstmp POST_BUILD COMMAND npm run build:web) diff --git a/src/dashbls/python-bindings/pythonbindings.cpp b/src/dashbls/python-bindings/pythonbindings.cpp index 419588c24eb8..4ba2acb83a67 100644 --- a/src/dashbls/python-bindings/pythonbindings.cpp +++ b/src/dashbls/python-bindings/pythonbindings.cpp @@ -25,6 +25,16 @@ namespace py = pybind11; using namespace bls; +namespace { +inline int PyLong_AsByteArray(PyLongObject* obj, uint8_t* buf, Py_ssize_t size, bool is_le, bool is_signed) +{ + return _PyLong_AsByteArray(obj, buf, size, is_le, is_signed +#if PY_VERSION_HEX >= 0x030d0000 + , /*with_exceptions=*/true +#endif // PY_VERSION_HEX >= 0x030d0000 + ); +} +} // anonymous namespace PYBIND11_MODULE(blspy, m) { @@ -46,7 +56,7 @@ PYBIND11_MODULE(blspy, m) } auto data_ptr = reinterpret_cast(info.ptr); std::array data; - std::copy(data_ptr, data_ptr + PrivateKey::PRIVATE_KEY_SIZE, data.data()); + std::copy(data_ptr, data_ptr + data.size(), data.data()); py::gil_scoped_release release; return PrivateKey::FromBytes(data); }) @@ -357,10 +367,10 @@ PYBIND11_MODULE(blspy, m) .def(py::init(&G1Element::FromByteVector), py::call_guard()) .def(py::init([](py::int_ pyint) { std::array buffer{}; - if (_PyLong_AsByteArray( + if (PyLong_AsByteArray( (PyLongObject *)pyint.ptr(), buffer.data(), - G1Element::SIZE, + buffer.size(), 0, 0) < 0) { throw std::invalid_argument("Failed to cast int to G1Element"); @@ -380,7 +390,7 @@ PYBIND11_MODULE(blspy, m) } auto data_ptr = static_cast(info.ptr); std::array data; - std::copy(data_ptr, data_ptr + G1Element::SIZE, data.data()); + std::copy(data_ptr, data_ptr + data.size(), data.data()); py::gil_scoped_release release; return G1Element::FromBytes(data); })) @@ -398,7 +408,7 @@ PYBIND11_MODULE(blspy, m) } auto data_ptr = reinterpret_cast(info.ptr); std::array data; - std::copy(data_ptr, data_ptr + G1Element::SIZE, data.data()); + std::copy(data_ptr, data_ptr + data.size(), data.data()); py::gil_scoped_release release; return G1Element::FromBytes(data); }) @@ -509,16 +519,16 @@ PYBIND11_MODULE(blspy, m) } auto data_ptr = static_cast(info.ptr); std::array data; - std::copy(data_ptr, data_ptr + G2Element::SIZE, data.data()); + std::copy(data_ptr, data_ptr + data.size(), data.data()); py::gil_scoped_release release; return G2Element::FromBytes(data); })) .def(py::init([](py::int_ pyint) { std::array buffer{}; - if (_PyLong_AsByteArray( + if (PyLong_AsByteArray( (PyLongObject *)pyint.ptr(), buffer.data(), - G2Element::SIZE, + buffer.size(), 0, 0) < 0) { throw std::invalid_argument("Failed to cast int to G2Element"); @@ -540,7 +550,7 @@ PYBIND11_MODULE(blspy, m) } auto data_ptr = reinterpret_cast(info.ptr); std::array data; - std::copy(data_ptr, data_ptr + G2Element::SIZE, data.data()); + std::copy(data_ptr, data_ptr + data.size(), data.data()); py::gil_scoped_release release; return G2Element::FromBytes(data); }) @@ -637,20 +647,20 @@ PYBIND11_MODULE(blspy, m) if ((int)info.size != GTElement::SIZE) { throw std::invalid_argument( - "Length of bytes object not equal to G2Element::SIZE"); + "Length of bytes object not equal to GTElement::SIZE"); } auto data_ptr = static_cast(info.ptr); std::array data; - std::copy(data_ptr, data_ptr + GTElement::SIZE, data.data()); + std::copy(data_ptr, data_ptr + data.size(), data.data()); py::gil_scoped_release release; return GTElement::FromBytes(data); })) .def(py::init([](py::int_ pyint) { - std::array buffer{}; - if (_PyLong_AsByteArray( + std::array buffer{}; + if (PyLong_AsByteArray( (PyLongObject *)pyint.ptr(), buffer.data(), - GTElement::SIZE, + buffer.size(), 0, 0) < 0) { throw std::invalid_argument("Failed to cast int to GTElement"); @@ -672,7 +682,7 @@ PYBIND11_MODULE(blspy, m) } auto data_ptr = reinterpret_cast(info.ptr); std::array data; - std::copy(data_ptr, data_ptr + GTElement::SIZE, data.data()); + std::copy(data_ptr, data_ptr + data.size(), data.data()); py::gil_scoped_release release; return GTElement::FromBytes(data); }) @@ -690,7 +700,7 @@ PYBIND11_MODULE(blspy, m) } auto data_ptr = reinterpret_cast(info.ptr); std::array data; - std::copy(data_ptr, data_ptr + GTElement::SIZE, data.data()); + std::copy(data_ptr, data_ptr + data.size(), data.data()); py::gil_scoped_release release; return GTElement::FromBytesUnchecked(data); }) diff --git a/src/dashbls/rust-bindings/bls-dash-sys/bindings.rs b/src/dashbls/rust-bindings/bls-dash-sys/bindings.rs index b90527e85fa2..6d570a7f9321 100644 --- a/src/dashbls/rust-bindings/bls-dash-sys/bindings.rs +++ b/src/dashbls/rust-bindings/bls-dash-sys/bindings.rs @@ -15,6 +15,7 @@ extern "C" { pub fn G1ElementFromBytes( data: *const ::std::os::raw::c_void, + len: usize, legacy: bool, didErr: *mut bool, ) -> G1Element; @@ -43,6 +44,7 @@ extern "C" { pub fn G2ElementFromBytes( data: *const ::std::os::raw::c_void, + len: usize, legacy: bool, didErr: *mut bool, ) -> G2Element; @@ -67,6 +69,7 @@ extern "C" { pub fn PrivateKeyFromBytes( data: *const ::std::os::raw::c_void, + len: usize, modOrder: bool, didErr: *mut bool, ) -> PrivateKey; @@ -355,6 +358,7 @@ extern "C" { pub fn BIP32ExtendedPublicKeyFromBytes( data: *const ::std::os::raw::c_void, + len: usize, legacy: bool, didErr: *mut bool, ) -> BIP32ExtendedPublicKey; @@ -385,6 +389,7 @@ extern "C" { pub fn BIP32ExtendedPrivateKeyFromBytes( data: *const ::std::os::raw::c_void, + len: usize, didErr: *mut bool, ) -> BIP32ExtendedPrivateKey; diff --git a/src/dashbls/rust-bindings/bls-dash-sys/build.rs b/src/dashbls/rust-bindings/bls-dash-sys/build.rs index c5245e6c25a9..0570baaa89b0 100644 --- a/src/dashbls/rust-bindings/bls-dash-sys/build.rs +++ b/src/dashbls/rust-bindings/bls-dash-sys/build.rs @@ -201,12 +201,14 @@ fn main() { println!("cargo:rustc-link-lib=static=relic_s"); - println!( - "cargo:rustc-link-search={}", - root_path.join("build/depends/mimalloc").display() - ); - - println!("cargo:rustc-link-lib=static=mimalloc-secure"); + let mimalloc_dir = root_path.join("build/depends/mimalloc"); + println!("cargo:rustc-link-search={}", mimalloc_dir.display()); + let mimalloc_lib = if mimalloc_dir.join("libmimalloc-secure-debug.a").exists() { + "mimalloc-secure-debug" + } else { + "mimalloc-secure" + }; + println!("cargo:rustc-link-lib=static={}", mimalloc_lib); println!( "cargo:rustc-link-search={}", diff --git a/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/bip32/extendedprivatekey.cpp b/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/bip32/extendedprivatekey.cpp index 541f5f992cf1..5e9efb8d81e2 100644 --- a/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/bip32/extendedprivatekey.cpp +++ b/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/bip32/extendedprivatekey.cpp @@ -6,12 +6,12 @@ #include "../error.h" #include "bls.hpp" -BIP32ExtendedPrivateKey BIP32ExtendedPrivateKeyFromBytes(const void* data, bool* didErr) +BIP32ExtendedPrivateKey BIP32ExtendedPrivateKeyFromBytes(const void* data, size_t len, bool* didErr) { bls::ExtendedPrivateKey* el = nullptr; try { el = new bls::ExtendedPrivateKey(bls::ExtendedPrivateKey::FromBytes( - bls::Bytes((uint8_t*)(data), bls::ExtendedPrivateKey::SIZE))); + bls::Bytes((uint8_t*)data, len))); } catch (const std::exception& ex) { gErrMsg = ex.what(); *didErr = true; @@ -26,7 +26,7 @@ BIP32ExtendedPrivateKey BIP32ExtendedPrivateKeyFromSeed(const void* data, const bls::ExtendedPrivateKey* el = nullptr; try { el = new bls::ExtendedPrivateKey(bls::ExtendedPrivateKey::FromSeed( - bls::Bytes((uint8_t*)(data), len))); + bls::Bytes((uint8_t*)data, len))); } catch (const std::exception& ex) { gErrMsg = ex.what(); *didErr = true; diff --git a/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/bip32/extendedprivatekey.h b/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/bip32/extendedprivatekey.h index 18ca3c28f301..8741737215d0 100644 --- a/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/bip32/extendedprivatekey.h +++ b/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/bip32/extendedprivatekey.h @@ -18,6 +18,7 @@ typedef void* BIP32ExtendedPrivateKey; // ExtendedPrivateKey BIP32ExtendedPrivateKey BIP32ExtendedPrivateKeyFromBytes( const void* data, + size_t len, bool* didErr); BIP32ExtendedPrivateKey BIP32ExtendedPrivateKeyFromSeed(const void* data, const size_t len, bool* didErr); BIP32ExtendedPrivateKey BIP32ExtendedPrivateKeyPrivateChild( diff --git a/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/bip32/extendedpublickey.cpp b/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/bip32/extendedpublickey.cpp index 703c32e0216f..a52bcabe5605 100644 --- a/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/bip32/extendedpublickey.cpp +++ b/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/bip32/extendedpublickey.cpp @@ -8,13 +8,14 @@ BIP32ExtendedPublicKey BIP32ExtendedPublicKeyFromBytes( const void* data, + size_t len, const bool legacy, bool* didErr) { bls::ExtendedPublicKey* el = nullptr; try { el = new bls::ExtendedPublicKey(bls::ExtendedPublicKey::FromBytes( - bls::Bytes((uint8_t*)(data), bls::ExtendedPublicKey::SIZE), + bls::Bytes((uint8_t*)data, len), legacy)); } catch (const std::exception& ex) { gErrMsg = ex.what(); diff --git a/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/bip32/extendedpublickey.h b/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/bip32/extendedpublickey.h index 51465cae039c..420da3156001 100644 --- a/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/bip32/extendedpublickey.h +++ b/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/bip32/extendedpublickey.h @@ -16,6 +16,7 @@ typedef void* BIP32ExtendedPublicKey; // ExtendedPublicKey BIP32ExtendedPublicKey BIP32ExtendedPublicKeyFromBytes( const void* data, + size_t len, const bool legacy, bool* didErr); BIP32ExtendedPublicKey BIP32ExtendedPublicKeyPublicChild( diff --git a/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/elements.cpp b/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/elements.cpp index 5214bc4fc931..486ee32f4781 100644 --- a/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/elements.cpp +++ b/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/elements.cpp @@ -23,11 +23,11 @@ int G1ElementSize() { return bls::G1Element::SIZE; } -G1Element G1ElementFromBytes(const void* data, bool legacy, bool* didErr) { +G1Element G1ElementFromBytes(const void* data, size_t len, bool legacy, bool* didErr) { bls::G1Element* el = nullptr; try { el = new bls::G1Element( - bls::G1Element::FromBytes(bls::Bytes((uint8_t*)(data), bls::G1Element::SIZE), legacy) + bls::G1Element::FromBytes(bls::Bytes((uint8_t*)data, len), legacy) ); } catch(const std::exception& ex) { gErrMsg = ex.what(); @@ -97,11 +97,11 @@ int G2ElementSize() { return bls::G2Element::SIZE; } -G2Element G2ElementFromBytes(const void* data, const bool legacy, bool* didErr) { +G2Element G2ElementFromBytes(const void* data, size_t len, const bool legacy, bool* didErr) { bls::G2Element* el = nullptr; try { el = new bls::G2Element( - bls::G2Element::FromBytes(bls::Bytes((uint8_t*)data, bls::G2Element::SIZE), legacy) + bls::G2Element::FromBytes(bls::Bytes((uint8_t*)data, len), legacy) ); *didErr = false; } catch(const std::exception& ex) { diff --git a/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/elements.h b/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/elements.h index fa1b5ae58117..e6912125375a 100644 --- a/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/elements.h +++ b/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/elements.h @@ -27,7 +27,7 @@ typedef void* PrivateKey; // G1Element int G1ElementSize(); -G1Element G1ElementFromBytes(const void* data, const bool legacy, bool* didErr); +G1Element G1ElementFromBytes(const void* data, size_t len, const bool legacy, bool* didErr); G1Element G1ElementGenerator(); bool G1ElementIsValid(const G1Element el); uint32_t G1ElementGetFingerprint(const G1Element el, const bool legacy); @@ -41,7 +41,7 @@ void G1ElementFree(const G1Element el); // G2Element int G2ElementSize(); -G2Element G2ElementFromBytes(const void* data, const bool legacy, bool* didErr); +G2Element G2ElementFromBytes(const void* data, size_t len, const bool legacy, bool* didErr); G2Element G2ElementGenerator(); bool G2ElementIsValid(const G2Element el); bool G2ElementIsEqual(const G2Element el1, const G2Element el2); diff --git a/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/privatekey.cpp b/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/privatekey.cpp index 4e1d0df34661..ca1b2bcde719 100644 --- a/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/privatekey.cpp +++ b/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/privatekey.cpp @@ -20,12 +20,12 @@ #include "utils.hpp" // private key bindings implementation -PrivateKey PrivateKeyFromBytes(const void* data, const bool modOrder, bool* didErr) { +PrivateKey PrivateKeyFromBytes(const void* data, size_t len, const bool modOrder, bool* didErr) { bls::PrivateKey* skPtr = nullptr; try { skPtr = new bls::PrivateKey( bls::PrivateKey::FromBytes( - bls::Bytes((uint8_t*)data, bls::PrivateKey::PRIVATE_KEY_SIZE), + bls::Bytes((uint8_t*)data, len), modOrder ) ); diff --git a/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/privatekey.h b/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/privatekey.h index 147e1a618f21..bba2837a1753 100644 --- a/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/privatekey.h +++ b/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/privatekey.h @@ -23,7 +23,7 @@ extern "C" { typedef void* PrivateKey; -PrivateKey PrivateKeyFromBytes(const void* data, const bool modOrder, bool* didErr); +PrivateKey PrivateKeyFromBytes(const void* data, size_t len, const bool modOrder, bool* didErr); PrivateKey PrivateKeyFromSeedBIP32(const void* data, const size_t len); PrivateKey PrivateKeyAggregate(void** sks, const size_t len); G1Element PrivateKeyGetG1Element(const PrivateKey sk, bool* didErr); diff --git a/src/dashbls/rust-bindings/bls-signatures/src/bip32/private_key.rs b/src/dashbls/rust-bindings/bls-signatures/src/bip32/private_key.rs index af4394f17979..08c217c2a881 100644 --- a/src/dashbls/rust-bindings/bls-signatures/src/bip32/private_key.rs +++ b/src/dashbls/rust-bindings/bls-signatures/src/bip32/private_key.rs @@ -47,7 +47,7 @@ impl ExtendedPrivateKey { } Ok(ExtendedPrivateKey { c_extended_private_key: c_err_to_result(|did_err| unsafe { - BIP32ExtendedPrivateKeyFromBytes(bytes.as_ptr() as *const _, did_err) + BIP32ExtendedPrivateKeyFromBytes(bytes.as_ptr() as *const _, bytes.len(), did_err) })?, }) } diff --git a/src/dashbls/rust-bindings/bls-signatures/src/bip32/public_key.rs b/src/dashbls/rust-bindings/bls-signatures/src/bip32/public_key.rs index 43fa484f0cc2..38265939dca1 100644 --- a/src/dashbls/rust-bindings/bls-signatures/src/bip32/public_key.rs +++ b/src/dashbls/rust-bindings/bls-signatures/src/bip32/public_key.rs @@ -42,7 +42,7 @@ impl ExtendedPublicKey { } Ok(ExtendedPublicKey { c_extended_public_key: c_err_to_result(|did_err| unsafe { - BIP32ExtendedPublicKeyFromBytes(bytes.as_ptr() as *const _, legacy, did_err) + BIP32ExtendedPublicKeyFromBytes(bytes.as_ptr() as *const _, bytes.len(), legacy, did_err) })?, }) } diff --git a/src/dashbls/rust-bindings/bls-signatures/src/elements.rs b/src/dashbls/rust-bindings/bls-signatures/src/elements.rs index b671bdf6b5c5..76de9a6e7bdf 100644 --- a/src/dashbls/rust-bindings/bls-signatures/src/elements.rs +++ b/src/dashbls/rust-bindings/bls-signatures/src/elements.rs @@ -75,7 +75,7 @@ impl G1Element { } Ok(G1Element { c_element: c_err_to_result(|did_err| unsafe { - G1ElementFromBytes(bytes.as_ptr() as *const _, legacy, did_err) + G1ElementFromBytes(bytes.as_ptr() as *const _, bytes.len(), legacy, did_err) })?, }) } @@ -234,7 +234,7 @@ impl G2Element { } Ok(G2Element { c_element: c_err_to_result(|did_err| unsafe { - G2ElementFromBytes(bytes.as_ptr() as *const _, legacy, did_err) + G2ElementFromBytes(bytes.as_ptr() as *const _, bytes.len(), legacy, did_err) })?, }) } diff --git a/src/dashbls/rust-bindings/bls-signatures/src/private_key.rs b/src/dashbls/rust-bindings/bls-signatures/src/private_key.rs index ab129856cdd5..556c968ed2a7 100755 --- a/src/dashbls/rust-bindings/bls-signatures/src/private_key.rs +++ b/src/dashbls/rust-bindings/bls-signatures/src/private_key.rs @@ -137,7 +137,7 @@ impl PrivateKey { } let c_private_key = c_err_to_result(|did_err| unsafe { - PrivateKeyFromBytes(bytes.as_ptr() as *const c_void, mod_order, did_err) + PrivateKeyFromBytes(bytes.as_ptr() as *const c_void, bytes.len(), mod_order, did_err) })?; Ok(PrivateKey { c_private_key }) diff --git a/src/dashbls/src/CMakeLists.txt b/src/dashbls/src/CMakeLists.txt index c3c1abd7593d..5802843a61ed 100644 --- a/src/dashbls/src/CMakeLists.txt +++ b/src/dashbls/src/CMakeLists.txt @@ -46,9 +46,23 @@ if(BUILD_BLS_TESTS) target_link_libraries(runtest PRIVATE dashbls PRIVATE catch2) + + if(EMSCRIPTEN) + target_link_options(runtest PRIVATE "SHELL:-s MALLOC=emmalloc") + if(CMAKE_BUILD_TYPE MATCHES "Debug") + target_link_options(runtest PRIVATE "SHELL:-s ASSERTIONS=2") + endif() + endif() endif() if(BUILD_BLS_BENCHMARKS) add_executable(runbench test-bench.cpp) target_link_libraries(runbench PRIVATE dashbls) + + if(EMSCRIPTEN) + target_link_options(runbench PRIVATE "SHELL:-s MALLOC=emmalloc") + if(CMAKE_BUILD_TYPE MATCHES "Debug") + target_link_options(runbench PRIVATE "SHELL:-s ASSERTIONS=2") + endif() + endif() endif() diff --git a/src/dashbls/src/privatekey.cpp b/src/dashbls/src/privatekey.cpp index d4dd32d11677..d07246d8575e 100644 --- a/src/dashbls/src/privatekey.cpp +++ b/src/dashbls/src/privatekey.cpp @@ -300,7 +300,9 @@ G2Element PrivateKey::SignG2( { CheckKeyData(); - g2_st* pt = Util::SecAlloc(1); + g2_t pt; + g2_null(pt); + g2_new(pt); if (fLegacy) { ep2_map_legacy(pt, msg, BLS::MESSAGE_HASH_LEN); @@ -310,7 +312,7 @@ G2Element PrivateKey::SignG2( g2_mul(pt, pt, keydata); G2Element ret = G2Element::FromNative(pt); - Util::SecFree(pt); + g2_free(pt); return ret; } diff --git a/src/dashbls/src/schemes.cpp b/src/dashbls/src/schemes.cpp index 003a44a46707..c0d7ad294c64 100644 --- a/src/dashbls/src/schemes.cpp +++ b/src/dashbls/src/schemes.cpp @@ -13,6 +13,7 @@ // limitations under the License. #include +#include #include #include @@ -26,21 +27,23 @@ using std::vector; namespace bls { -static void HashPubKeys(bn_t* computedTs, std::vector vecPubKeyBytes) +template +static void HashPubKeys(bn_t* computedTs, size_t nPubKeys, GetBytesFn getBytes) { bn_t order; bn_new(order); g2_get_ord(order); - std::vector vecBuffer(vecPubKeyBytes.size() * G1Element::SIZE); + std::vector vecBuffer(nPubKeys * G1Element::SIZE); - for (size_t i = 0; i < vecPubKeyBytes.size(); i++) { - memcpy(vecBuffer.data() + i * G1Element::SIZE, vecPubKeyBytes[i].begin(), G1Element::SIZE); + for (size_t i = 0; i < nPubKeys; i++) { + const uint8_t* pkBytes = getBytes(i); + memcpy(vecBuffer.data() + i * G1Element::SIZE, pkBytes, G1Element::SIZE); } uint8_t pkHash[32]; - Util::Hash256(pkHash, vecBuffer.data(), vecPubKeyBytes.size() * G1Element::SIZE); - for (size_t i = 0; i < vecPubKeyBytes.size(); ++i) { + Util::Hash256(pkHash, vecBuffer.data(), nPubKeys * G1Element::SIZE); + for (size_t i = 0; i < nPubKeys; ++i) { uint8_t hash[32]; uint8_t buffer[4 + 32]; memset(buffer, 0, 4); @@ -53,6 +56,7 @@ static void HashPubKeys(bn_t* computedTs, std::vector vecPubKeyBytes) bn_read_bin(computedTs[i], hash, 32); bn_mod_basic(computedTs[i], computedTs[i], order); } + bn_free(order); } enum InvariantResult { BAD=false, GOOD=true, CONTINUE }; @@ -133,39 +137,41 @@ bool CoreMPL::Verify(const G1Element& pubkey, const Bytes& message, const G2Elem { const G2Element hashedPoint = G2Element::FromMessage(message, (const uint8_t*)strCiphersuiteId.c_str(), strCiphersuiteId.length()); - std::vector vecG1(2); - std::vector vecG2(2); + std::array g1s; + std::array g2s; - G1Element::Generator().Negate().ToNative(&vecG1[0]); + G1Element::Generator().Negate().ToNative(g1s[0]); if (!pubkey.IsValid()) { return false; } if (!signature.IsValid()) { return false; } - pubkey.ToNative(&vecG1[1]); - signature.ToNative(&vecG2[0]); - hashedPoint.ToNative(&vecG2[1]); + pubkey.ToNative(g1s[1]); + signature.ToNative(g2s[0]); + hashedPoint.ToNative(g2s[1]); - return CoreMPL::NativeVerify((g1_t*)vecG1.data(), (g2_t*)vecG2.data(), 2); + return CoreMPL::NativeVerify(g1s.data(), g2s.data(), 2); } -vector CoreMPL::Aggregate(const vector> &signatures) +std::array CoreMPL::Aggregate(const vector> &signatures) { vector elements; + elements.reserve(signatures.size()); for (const vector& signature : signatures) { elements.push_back(G2Element::FromByteVector(signature)); } - return CoreMPL::Aggregate(elements).Serialize(); + return CoreMPL::Aggregate(elements).SerializeToArray(); } -vector CoreMPL::Aggregate(const vector& signatures) +std::array CoreMPL::Aggregate(const vector& signatures) { vector elements; + elements.reserve(signatures.size()); for (const Bytes& signature : signatures) { elements.push_back(G2Element::FromBytes(signature)); } - return CoreMPL::Aggregate(elements).Serialize(); + return CoreMPL::Aggregate(elements).SerializeToArray(); } G2Element CoreMPL::Aggregate(const vector &signatures) @@ -195,22 +201,17 @@ G2Element CoreMPL::AggregateSecure(std::vector const &vecPublicKeys, } bn_t* computedTs = new bn_t[vecPublicKeys.size()]; - std::vector, const G2Element*>> vecSorted(vecPublicKeys.size()); + std::vector, const G2Element*>> vecSorted(vecPublicKeys.size()); for (size_t i = 0; i < vecPublicKeys.size(); i++) { bn_new(computedTs[i]); - vecSorted[i] = std::make_pair(vecPublicKeys[i].Serialize(fLegacy), &vecSignatures[i]); + vecSorted[i] = std::make_pair(vecPublicKeys[i].SerializeToArray(fLegacy), &vecSignatures[i]); } std::sort(vecSorted.begin(), vecSorted.end(), [](const auto& a, const auto& b) { return std::memcmp(a.first.data(), b.first.data(), G1Element::SIZE) < 0; }); - std::vector vecPublicKeyBytes; - vecPublicKeyBytes.reserve(vecPublicKeys.size()); - for (const auto& it : vecSorted) { - vecPublicKeyBytes.push_back(Bytes{it.first}); - } - - HashPubKeys(computedTs, vecPublicKeyBytes); + HashPubKeys(computedTs, vecSorted.size(), + [&](size_t i) { return vecSorted[i].first.data(); }); // Raise all signatures to power of the corresponding t's and aggregate the results into aggSig // Also accumulates aggregation info for each signature @@ -222,6 +223,9 @@ G2Element CoreMPL::AggregateSecure(std::vector const &vecPublicKeys, G2Element aggSig = CoreMPL::Aggregate(expSigs); + for (size_t i = 0; i < vecPublicKeys.size(); i++) { + bn_free(computedTs[i]); + } delete[] computedTs; return aggSig; @@ -237,30 +241,28 @@ bool CoreMPL::VerifySecure(const std::vector& vecPublicKeys, const G2Element& signature, const Bytes& message, const bool fLegacy) { - bn_t one; - bn_new(one); - bn_zero(one); - bn_set_dig(one, 1); - bn_t* computedTs = new bn_t[vecPublicKeys.size()]; - std::vector> vecSorted(vecPublicKeys.size()); + std::vector> vecSorted(vecPublicKeys.size()); for (size_t i = 0; i < vecPublicKeys.size(); i++) { bn_new(computedTs[i]); - vecSorted[i] = vecPublicKeys[i].Serialize(fLegacy); + vecSorted[i] = vecPublicKeys[i].SerializeToArray(fLegacy); } std::sort(vecSorted.begin(), vecSorted.end(), [](const auto& a, const auto& b) -> bool { return std::memcmp(a.data(), b.data(), G1Element::SIZE) < 0; }); - HashPubKeys(computedTs, {vecSorted.begin(), vecSorted.end()}); + HashPubKeys(computedTs, vecSorted.size(), + [&](size_t i) { return vecSorted[i].data(); }); G1Element publicKey; for (size_t i = 0; i < vecSorted.size(); ++i) { G1Element g1 = G1Element::FromBytes(Bytes(vecSorted[i]), fLegacy); - publicKey = CoreMPL::Aggregate({publicKey, g1 * computedTs[i]}); + publicKey += g1 * computedTs[i]; } - bn_free(one); + for (size_t i = 0; i < vecPublicKeys.size(); i++) { + bn_free(computedTs[i]); + } delete[] computedTs; return AggregateVerify({publicKey}, {message}, {signature}); @@ -293,6 +295,7 @@ bool CoreMPL::AggregateVerify(const vector& pubkeys, } vector pubkeyElements; + pubkeyElements.reserve(nPubKeys); for (size_t i = 0; i < nPubKeys; ++i) { pubkeyElements.push_back(G1Element::FromBytes(pubkeys[i])); } @@ -573,14 +576,14 @@ bool AugSchemeMPL::AggregateVerify(const vector& pubkeys, G2Element PopSchemeMPL::PopProve(const PrivateKey &seckey) { const G1Element& pk = seckey.GetG1Element(); - const G2Element hashedKey = G2Element::FromMessage(pk.Serialize(), (const uint8_t *)POP_CIPHERSUITE_ID.c_str(), POP_CIPHERSUITE_ID.length()); + const G2Element hashedKey = G2Element::FromMessage(pk.SerializeToArray(), (const uint8_t *)POP_CIPHERSUITE_ID.c_str(), POP_CIPHERSUITE_ID.length()); return seckey.GetG2Power(hashedKey); } bool PopSchemeMPL::PopVerify(const G1Element &pubkey, const G2Element &signature_proof) { - const G2Element hashedPoint = G2Element::FromMessage(pubkey.Serialize(), (const uint8_t*)POP_CIPHERSUITE_ID.c_str(), POP_CIPHERSUITE_ID.length()); + const G2Element hashedPoint = G2Element::FromMessage(pubkey.SerializeToArray(), (const uint8_t*)POP_CIPHERSUITE_ID.c_str(), POP_CIPHERSUITE_ID.length()); g1_t g1s[2]; g2_t g2s[2]; diff --git a/src/dashbls/src/test.cpp b/src/dashbls/src/test.cpp index 51d84706a83c..7e9d5280b3b5 100644 --- a/src/dashbls/src/test.cpp +++ b/src/dashbls/src/test.cpp @@ -1010,8 +1010,8 @@ TEST_CASE("Advanced") { vector> vecG2Vector = {g2BasicSignVector1.Serialize(), g2BasicSign3.Serialize()}; vector> vecHashes = {vecHash, vecG2Element}; - vector aggVector = BasicSchemeMPL().Aggregate(vecG2Vector); - vector aggBytes = BasicSchemeMPL().Aggregate(vector{vecG2Vector.begin(), vecG2Vector.end()}); + auto aggVector = BasicSchemeMPL().Aggregate(vecG2Vector); + auto aggBytes = BasicSchemeMPL().Aggregate(vector{vecG2Vector.begin(), vecG2Vector.end()}); REQUIRE(aggVector == aggBytes); REQUIRE(BasicSchemeMPL().AggregateVerify(vector{vecG1Vector.begin(), vecG1Vector.end()}, @@ -1019,7 +1019,7 @@ TEST_CASE("Advanced") { Bytes(aggVector))); REQUIRE(BasicSchemeMPL().AggregateVerify({g1_1, g1_3}, vector{vecHashes.begin(), vecHashes.end()}, - G2Element::FromByteVector(aggVector))); + G2Element::FromBytes(aggVector))); G2Element g2AugSignVector1 = AugSchemeMPL().Sign(pk1, vecHash); G2Element g2AugSignBytes1 = AugSchemeMPL().Sign(pk1, Bytes(vecHash)); @@ -1033,8 +1033,8 @@ TEST_CASE("Advanced") { vector> vecG1AugVector = {g1_1.Serialize(), g1_2.Serialize()}; vector> vecG2AugVector = {g2AugSignVector1.Serialize(), g2AugSign2.Serialize()}; - vector aggAugVector = AugSchemeMPL().Aggregate(vecG2AugVector); - vector aggAugBytes = AugSchemeMPL().Aggregate(vector{vecG2AugVector.begin(), vecG2AugVector.end()}); + auto aggAugVector = AugSchemeMPL().Aggregate(vecG2AugVector); + auto aggAugBytes = AugSchemeMPL().Aggregate(vector{vecG2AugVector.begin(), vecG2AugVector.end()}); REQUIRE(aggAugVector == aggAugBytes); REQUIRE(AugSchemeMPL().AggregateVerify(vector{vecG1AugVector.begin(), vecG1AugVector.end()}, @@ -1042,7 +1042,7 @@ TEST_CASE("Advanced") { Bytes(aggAugVector))); REQUIRE(AugSchemeMPL().AggregateVerify({g1_1, g1_2}, vector{vecHashes.begin(), vecHashes.end()}, - G2Element::FromByteVector(aggAugVector))); + G2Element::FromBytes(aggAugVector))); G2Element proof = PopSchemeMPL().PopProve(pk1); REQUIRE(PopSchemeMPL().PopVerify(g1_1, proof)); @@ -1063,9 +1063,9 @@ TEST_CASE("Schemes") { SECTION("Basic Scheme") { vector seed1(32, 0x04); vector seed2(32, 0x05); - vector msg1 = {7, 8, 9}; - vector msg2 = {10, 11, 12}; - vector> msgs = {msg1, msg2}; + std::array msg1 = {7, 8, 9}; + std::array msg2 = {10, 11, 12}; + vector msgs = {Bytes{msg1}, Bytes{msg2}}; PrivateKey sk1 = BasicSchemeMPL().KeyGen(seed1); G1Element pk1 = BasicSchemeMPL().SkToG1(sk1); @@ -1093,7 +1093,7 @@ TEST_CASE("Schemes") { REQUIRE(BasicSchemeMPL().Verify(pk2v, msg1, sig1v) == false); G2Element aggsig = BasicSchemeMPL().Aggregate({sig1, sig2}); - vector aggsigv = BasicSchemeMPL().Aggregate(vector>{sig1v, sig2v}); + auto aggsigv = BasicSchemeMPL().Aggregate(vector>{sig1v, sig2v}); REQUIRE(BasicSchemeMPL().AggregateVerify({pk1, pk2}, msgs, aggsig)); REQUIRE(BasicSchemeMPL().AggregateVerify({pk1v, pk2v}, msgs, aggsigv)); } @@ -1102,9 +1102,9 @@ TEST_CASE("Schemes") { { vector seed1(32, 0x04); vector seed2(32, 0x05); - vector msg1 = {7, 8, 9}; - vector msg2 = {10, 11, 12}; - vector> msgs = {msg1, msg2}; + std::array msg1 = {7, 8, 9}; + std::array msg2 = {10, 11, 12}; + vector msgs = {Bytes{msg1}, Bytes{msg2}}; PrivateKey sk1 = AugSchemeMPL().KeyGen(seed1); G1Element pk1 = AugSchemeMPL().SkToG1(sk1); @@ -1132,18 +1132,18 @@ TEST_CASE("Schemes") { REQUIRE(AugSchemeMPL().Verify(pk2v, msg1, sig1v) == false); G2Element aggsig = AugSchemeMPL().Aggregate({sig1, sig2}); - vector aggsigv = AugSchemeMPL().Aggregate(vector>{sig1v, sig2v}); + auto aggsigv = AugSchemeMPL().Aggregate(vector>{sig1v, sig2v}); REQUIRE(AugSchemeMPL().AggregateVerify({pk1, pk2}, msgs, aggsig)); - REQUIRE(AugSchemeMPL().AggregateVerify({pk1v, pk2v}, msgs, aggsigv)); + REQUIRE(AugSchemeMPL().AggregateVerify({pk1v, pk2v}, msgs, Bytes(aggsigv.data(), aggsigv.size()))); } SECTION("Pop Scheme") { vector seed1(32, 0x06); vector seed2(32, 0x07); - vector msg1 = {7, 8, 9}; - vector msg2 = {10, 11, 12}; - vector> msgs = {msg1, msg2}; + std::array msg1 = {7, 8, 9}; + std::array msg2 = {10, 11, 12}; + vector msgs = {Bytes{msg1}, Bytes{msg2}}; PrivateKey sk1 = PopSchemeMPL().KeyGen(seed1); G1Element pk1 = PopSchemeMPL().SkToG1(sk1); @@ -1171,9 +1171,9 @@ TEST_CASE("Schemes") { REQUIRE(PopSchemeMPL().Verify(pk2v, msg1, sig1v) == false); G2Element aggsig = PopSchemeMPL().Aggregate({sig1, sig2}); - vector aggsigv = PopSchemeMPL().Aggregate(vector>{sig1v, sig2v}); + auto aggsigv = PopSchemeMPL().Aggregate(vector>{sig1v, sig2v}); REQUIRE(PopSchemeMPL().AggregateVerify({pk1, pk2}, msgs, aggsig)); - REQUIRE(PopSchemeMPL().AggregateVerify({pk1v, pk2v}, msgs, aggsigv)); + REQUIRE(PopSchemeMPL().AggregateVerify({pk1v, pk2v}, msgs, Bytes(aggsigv.data(), aggsigv.size()))); // PopVerify G2Element proof1 = PopSchemeMPL().PopProve(sk1); @@ -1186,7 +1186,7 @@ TEST_CASE("Schemes") { G2Element sig2_same = PopSchemeMPL().Sign(sk2, msg1); vector sig2v_same = PopSchemeMPL().Sign(sk2, msg1).Serialize(); G2Element aggsig_same = PopSchemeMPL().Aggregate({sig1, sig2_same}); - vector aggsigv_same = + auto aggsigv_same = PopSchemeMPL().Aggregate(vector>{sig1v, sig2v_same}); REQUIRE( PopSchemeMPL().FastAggregateVerify({pk1, pk2}, msg1, aggsig_same)); diff --git a/src/dashbls/src/threshold.cpp b/src/dashbls/src/threshold.cpp index 723b24410168..73a3023b28da 100644 --- a/src/dashbls/src/threshold.cpp +++ b/src/dashbls/src/threshold.cpp @@ -92,10 +92,17 @@ namespace bls { struct PolyOpsBase { bn_t order; + bn_t iv; PolyOpsBase() { bn_new(order); gt_get_ord(order); + bn_new(iv); + } + + ~PolyOpsBase() { + bn_free(iv); + bn_free(order); } void MulFP(bn_t& r, const bn_t& a, const bn_t& b) { @@ -114,8 +121,6 @@ namespace bls { } void DivFP(bn_t& r, const bn_t& a, const bn_t& b) { - bn_t iv; - bn_new(iv); fp_inv_exgcd_bn(iv, b, order); bn_mul(r, a, iv); ModOrder(r); @@ -143,7 +148,7 @@ namespace bls { template<> struct PolyOps : PolyOpsBase { G1Element Add(const G1Element& a, const G1Element& b) { - return pThresholdScheme->Aggregate({a, b}); + return a + b; } G1Element Mul(const G1Element& a, const bn_t& b) { @@ -154,7 +159,7 @@ namespace bls { template<> struct PolyOps : PolyOpsBase { G2Element Add(const G2Element& a, const G2Element& b) { - return pThresholdScheme->Aggregate({a, b}); + return a + b; } G2Element Mul(const G2Element& a, bn_t& b) { diff --git a/src/dbwrapper.cpp b/src/dbwrapper.cpp index 87adcb254418..c4d9cf615faa 100644 --- a/src/dbwrapper.cpp +++ b/src/dbwrapper.cpp @@ -4,15 +4,26 @@ #include -#include +#include +#include #include +#include +#include +#include +#include +#include +#include +#include #include +#include #include #include #include -#include -#include +#include +#include +#include +#include #include class CBitcoinLevelDBLogger : public leveldb::Logger { diff --git a/src/dbwrapper.h b/src/dbwrapper.h index 91f5bae74fc1..bd6e847180a6 100644 --- a/src/dbwrapper.h +++ b/src/dbwrapper.h @@ -5,18 +5,38 @@ #ifndef BITCOIN_DBWRAPPER_H #define BITCOIN_DBWRAPPER_H +#include #include #include +#include #include #include #include -#include -#include -#include +#include +#include +#include +#include +#include #include +#include +#include +#include +#include #include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace leveldb { +class Env; +} static const size_t DBWRAPPER_PREALLOC_KEY_SIZE = 64; static const size_t DBWRAPPER_PREALLOC_VALUE_SIZE = 1024; @@ -689,4 +709,19 @@ class CDBTransaction { } }; +namespace util { +struct DbWrapperParams +{ + const fs::path path{""}; + const bool memory{false}; + const bool wipe{false}; + const size_t cache_size{1 << 20}; +}; + +static inline std::unique_ptr MakeDbWrapper(const DbWrapperParams& params) +{ + return std::make_unique(params.path, params.cache_size, params.memory, params.wipe); +} +} // namespace util + #endif // BITCOIN_DBWRAPPER_H diff --git a/src/deploymentinfo.cpp b/src/deploymentinfo.cpp index cc84c2777761..856403e32889 100644 --- a/src/deploymentinfo.cpp +++ b/src/deploymentinfo.cpp @@ -12,7 +12,7 @@ const struct VBDeploymentInfo VersionBitsDeploymentInfo[Consensus::MAX_VERSION_B /*.gbt_force =*/ true, }, { - /*.name =*/"v23", + /*.name =*/"v24", /*.gbt_force =*/true, }, }; diff --git a/src/dsnotificationinterface.cpp b/src/dsnotificationinterface.cpp index 95066be54658..830da58fb847 100644 --- a/src/dsnotificationinterface.cpp +++ b/src/dsnotificationinterface.cpp @@ -2,43 +2,42 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include -#ifdef ENABLE_WALLET -#include -#endif // ENABLE_WALLET -#include + #include -#include -#include + +#include #include #include +#include #include #include +#include #include #include #include #include #include +#include CDSNotificationInterface::CDSNotificationInterface(CConnman& connman, + CDSTXManager& dstxman, CMasternodeSync& mn_sync, CGovernanceManager& govman, - PeerManager& peerman, const ChainstateManager& chainman, - const CActiveMasternodeManager* const mn_activeman, const std::unique_ptr& dmnman, - const std::unique_ptr& llmq_ctx, - const std::unique_ptr& cj_ctx) - : m_connman(connman), - m_mn_sync(mn_sync), - m_govman(govman), - m_peerman(peerman), - m_chainman(chainman), - m_mn_activeman(mn_activeman), - m_dmnman(dmnman), - m_llmq_ctx(llmq_ctx), - m_cj_ctx(cj_ctx) {} + const std::unique_ptr& llmq_ctx) : + m_connman{connman}, + m_dstxman{dstxman}, + m_mn_sync{mn_sync}, + m_govman{govman}, + m_chainman{chainman}, + m_dmnman{dmnman}, + m_llmq_ctx{llmq_ctx} +{ +} + +CDSNotificationInterface::~CDSNotificationInterface() = default; void CDSNotificationInterface::InitializeCurrentBlockTip() { @@ -48,9 +47,7 @@ void CDSNotificationInterface::InitializeCurrentBlockTip() void CDSNotificationInterface::AcceptedBlockHeader(const CBlockIndex *pindexNew) { - assert(m_llmq_ctx); - - m_llmq_ctx->clhandler->AcceptedBlockHeader(pindexNew); + Assert(m_llmq_ctx)->clhandler->AcceptedBlockHeader(pindexNew); m_mn_sync.AcceptedBlockHeader(pindexNew); } @@ -61,18 +58,14 @@ void CDSNotificationInterface::NotifyHeaderTip(const CBlockIndex *pindexNew, boo void CDSNotificationInterface::SynchronousUpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) { - assert(m_dmnman); - if (pindexNew == pindexFork) // blocks were disconnected without any new ones return; - m_dmnman->UpdatedBlockTip(pindexNew); + Assert(m_dmnman)->UpdatedBlockTip(pindexNew); } void CDSNotificationInterface::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) { - assert(m_cj_ctx && m_llmq_ctx); - if (pindexNew == pindexFork) // blocks were disconnected without any new ones return; @@ -81,57 +74,44 @@ void CDSNotificationInterface::UpdatedBlockTip(const CBlockIndex *pindexNew, con if (fInitialDownload) return; - m_cj_ctx->dstxman->UpdatedBlockTip(pindexNew, *m_llmq_ctx->clhandler, m_mn_sync); -#ifdef ENABLE_WALLET - m_cj_ctx->walletman->ForEachCJClientMan( - [&pindexNew](std::unique_ptr& clientman) { clientman->UpdatedBlockTip(pindexNew); }); -#endif // ENABLE_WALLET + m_dstxman.UpdatedBlockTip(pindexNew, *Assert(m_llmq_ctx)->clhandler, m_mn_sync); m_llmq_ctx->isman->UpdatedBlockTip(pindexNew); m_llmq_ctx->clhandler->UpdatedBlockTip(*m_llmq_ctx->isman); - - m_llmq_ctx->qman->UpdatedBlockTip(pindexNew, m_connman, fInitialDownload); m_llmq_ctx->qdkgsman->UpdatedBlockTip(pindexNew, fInitialDownload); + m_llmq_ctx->qman->UpdatedBlockTip(pindexNew, m_connman, fInitialDownload); if (m_govman.IsValid()) { - m_govman.UpdatedBlockTip(pindexNew, m_connman, m_peerman, m_mn_activeman); + m_govman.UpdatedBlockTip(pindexNew); } } void CDSNotificationInterface::TransactionAddedToMempool(const CTransactionRef& ptx, int64_t nAcceptTime, uint64_t mempool_sequence) { - assert(m_cj_ctx && m_llmq_ctx); - - m_llmq_ctx->isman->TransactionAddedToMempool(ptx); + Assert(m_llmq_ctx)->isman->TransactionAddedToMempool(ptx); m_llmq_ctx->clhandler->TransactionAddedToMempool(ptx, nAcceptTime); - m_cj_ctx->dstxman->TransactionAddedToMempool(ptx); + m_dstxman.TransactionAddedToMempool(ptx); } void CDSNotificationInterface::TransactionRemovedFromMempool(const CTransactionRef& ptx, MemPoolRemovalReason reason, uint64_t mempool_sequence) { - assert(m_llmq_ctx); - - m_llmq_ctx->isman->TransactionRemovedFromMempool(ptx); + Assert(m_llmq_ctx)->isman->TransactionRemovedFromMempool(ptx); } void CDSNotificationInterface::BlockConnected(const std::shared_ptr& pblock, const CBlockIndex* pindex) { - assert(m_cj_ctx && m_llmq_ctx); - - m_llmq_ctx->isman->BlockConnected(pblock, pindex); + Assert(m_llmq_ctx)->isman->BlockConnected(pblock, pindex); m_llmq_ctx->clhandler->BlockConnected(pblock, pindex); - m_cj_ctx->dstxman->BlockConnected(pblock, pindex); + m_dstxman.BlockConnected(pblock, pindex); } void CDSNotificationInterface::BlockDisconnected(const std::shared_ptr& pblock, const CBlockIndex* pindexDisconnected) { - assert(m_cj_ctx && m_llmq_ctx); - - m_llmq_ctx->isman->BlockDisconnected(pblock, pindexDisconnected); + Assert(m_llmq_ctx)->isman->BlockDisconnected(pblock, pindexDisconnected); m_llmq_ctx->clhandler->BlockDisconnected(pblock, pindexDisconnected); - m_cj_ctx->dstxman->BlockDisconnected(pblock, pindexDisconnected); + m_dstxman.BlockDisconnected(pblock, pindexDisconnected); } void CDSNotificationInterface::NotifyMasternodeListChanged(bool undo, const CDeterministicMNList& oldMNList, const CDeterministicMNListDiff& diff) @@ -145,10 +125,8 @@ void CDSNotificationInterface::NotifyMasternodeListChanged(bool undo, const CDet void CDSNotificationInterface::NotifyChainLock(const CBlockIndex* pindex, const std::shared_ptr& clsig) { - assert(m_cj_ctx && m_llmq_ctx); - - m_llmq_ctx->isman->NotifyChainLock(pindex); - m_cj_ctx->dstxman->NotifyChainLock(pindex, *m_llmq_ctx->clhandler, m_mn_sync); + Assert(m_llmq_ctx)->isman->NotifyChainLock(pindex); + m_dstxman.NotifyChainLock(pindex, *m_llmq_ctx->clhandler, m_mn_sync); } std::unique_ptr g_ds_notification_interface; diff --git a/src/dsnotificationinterface.h b/src/dsnotificationinterface.h index 6ca8634e2cc1..7c33a3462adb 100644 --- a/src/dsnotificationinterface.h +++ b/src/dsnotificationinterface.h @@ -7,29 +7,28 @@ #include -class CActiveMasternodeManager; class CConnman; +class CDSTXManager; class CDeterministicMNManager; class CGovernanceManager; class ChainstateManager; class CMasternodeSync; -class PeerManager; -struct CJContext; struct LLMQContext; class CDSNotificationInterface : public CValidationInterface { public: + CDSNotificationInterface() = delete; + CDSNotificationInterface(const CDSNotificationInterface&) = delete; + CDSNotificationInterface& operator=(const CDSNotificationInterface&) = delete; explicit CDSNotificationInterface(CConnman& connman, + CDSTXManager& dstxman, CMasternodeSync& mn_sync, CGovernanceManager& govman, - PeerManager& peerman, const ChainstateManager& chainman, - const CActiveMasternodeManager* const mn_activeman, const std::unique_ptr& dmnman, - const std::unique_ptr& llmq_ctx, - const std::unique_ptr& cj_ctx); - virtual ~CDSNotificationInterface() = default; + const std::unique_ptr& llmq_ctx); + virtual ~CDSNotificationInterface(); // a small helper to initialize current block height in sub-modules on startup void InitializeCurrentBlockTip(); @@ -50,14 +49,12 @@ class CDSNotificationInterface : public CValidationInterface private: CConnman& m_connman; + CDSTXManager& m_dstxman; CMasternodeSync& m_mn_sync; CGovernanceManager& m_govman; - PeerManager& m_peerman; const ChainstateManager& m_chainman; - const CActiveMasternodeManager* const m_mn_activeman; const std::unique_ptr& m_dmnman; const std::unique_ptr& m_llmq_ctx; - const std::unique_ptr& m_cj_ctx; }; extern std::unique_ptr g_ds_notification_interface; diff --git a/src/dummywallet.cpp b/src/dummywallet.cpp index e02c4b505149..5ad3b2ee23ee 100644 --- a/src/dummywallet.cpp +++ b/src/dummywallet.cpp @@ -51,6 +51,7 @@ void DummyWalletInit::AddWalletOptions(ArgsManager& argsman) const "-maxtxfee=", "-rescan=", "-salvagewallet", + "-signer=", "-spendzeroconfchange", "-wallet=", "-walletbackupsdir=", diff --git a/src/evo/assetlocktx.h b/src/evo/assetlocktx.h index 2fc44643fa8f..433dd098ee47 100644 --- a/src/evo/assetlocktx.h +++ b/src/evo/assetlocktx.h @@ -17,6 +17,7 @@ class CBlockIndex; class CRangesSet; class TxValidationState; +struct RPCResult; namespace llmq { class CQuorumManager; } // namespace llmq @@ -51,6 +52,7 @@ class CAssetLockPayload std::string ToString() const; + [[nodiscard]] static RPCResult GetJsonHelp(const std::string& key, bool optional); [[nodiscard]] UniValue ToJson() const; // getters @@ -108,6 +110,7 @@ class CAssetUnlockPayload std::string ToString() const; + [[nodiscard]] static RPCResult GetJsonHelp(const std::string& key, bool optional); [[nodiscard]] UniValue ToJson() const; bool VerifySig(const llmq::CQuorumManager& qman, const uint256& msgHash, gsl::not_null pindexTip, TxValidationState& state) const; diff --git a/src/evo/cbtx.h b/src/evo/cbtx.h index 482d880dd522..da6d92f802a8 100644 --- a/src/evo/cbtx.h +++ b/src/evo/cbtx.h @@ -6,16 +6,20 @@ #define BITCOIN_EVO_CBTX_H #include + #include + #include #include +#include class BlockValidationState; class CBlock; class CBlockIndex; class CDeterministicMNList; class TxValidationState; +struct RPCResult; namespace llmq { class CQuorumBlockProcessor; @@ -57,6 +61,7 @@ class CCbTx } + [[nodiscard]] static RPCResult GetJsonHelp(const std::string& key, bool optional); std::string ToString() const; [[nodiscard]] UniValue ToJson() const; diff --git a/src/evo/chainhelper.cpp b/src/evo/chainhelper.cpp index d4661d71b724..9c11fc4e6a3c 100644 --- a/src/evo/chainhelper.cpp +++ b/src/evo/chainhelper.cpp @@ -38,7 +38,7 @@ bool CChainstateHelper::HasChainLock(int nHeight, const uint256& blockHash) cons return clhandler.HasChainLock(nHeight, blockHash); } -int32_t CChainstateHelper::GetBestChainLockHeight() const { return clhandler.GetBestChainLock().getHeight(); } +int32_t CChainstateHelper::GetBestChainLockHeight() const { return clhandler.GetBestChainLockHeight(); } /** Passthrough functions to CInstantSendManager */ std::optional> CChainstateHelper::ConflictingISLockIfAny( diff --git a/src/evo/chainhelper.h b/src/evo/chainhelper.h index 6dd94bf1941f..66bee994652f 100644 --- a/src/evo/chainhelper.h +++ b/src/evo/chainhelper.h @@ -36,6 +36,9 @@ class CChainstateHelper const llmq::CChainLocksHandler& clhandler; public: + CChainstateHelper() = delete; + CChainstateHelper(const CChainstateHelper&) = delete; + CChainstateHelper& operator=(const CChainstateHelper&) = delete; explicit CChainstateHelper(CCreditPoolManager& cpoolman, CDeterministicMNManager& dmnman, CMNHFManager& mnhfman, CGovernanceManager& govman, llmq::CInstantSendManager& isman, llmq::CQuorumBlockProcessor& qblockman, llmq::CQuorumSnapshotManager& qsnapman, @@ -44,9 +47,6 @@ class CChainstateHelper const llmq::CChainLocksHandler& clhandler, const llmq::CQuorumManager& qman); ~CChainstateHelper(); - CChainstateHelper() = delete; - CChainstateHelper(const CChainstateHelper&) = delete; - /** Passthrough functions to CChainLocksHandler */ bool HasConflictingChainLock(int nHeight, const uint256& blockHash) const; bool HasChainLock(int nHeight, const uint256& blockHash) const; diff --git a/src/evo/core_write.cpp b/src/evo/core_write.cpp index 574910214294..0779abe51893 100644 --- a/src/evo/core_write.cpp +++ b/src/evo/core_write.cpp @@ -2,11 +2,10 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include -#include - #include #include +#include +#include #include #include #include @@ -15,9 +14,91 @@ #include #include +#include +#include +#include +#include + #include -[[nodiscard]] UniValue CAssetLockPayload::ToJson() const +#include +#include + +namespace { +#define RESULT_MAP_ENTRY(name, type, desc) {name, {type, name, desc}} +const std::map RPCRESULT_MAP{{ + {"addresses", + {RPCResult::Type::OBJ, "addresses", "Network addresses of the masternode", + { + {RPCResult::Type::ARR, "core_p2p", /*optional=*/true, "Addresses used for protocol P2P", + {{RPCResult::Type::STR, "address", ""}}}, + {RPCResult::Type::ARR, "platform_p2p", /*optional=*/true, "Addresses used for Platform P2P", + {{RPCResult::Type::STR, "address", ""}}}, + {RPCResult::Type::ARR, "platform_https", /*optional=*/true, "Addresses used for Platform HTTPS API", + {{RPCResult::Type::STR, "address", ""}}}, + }}}, + RESULT_MAP_ENTRY("collateralHash", RPCResult::Type::STR_HEX, "Collateral transaction hash"), + RESULT_MAP_ENTRY("collateralIndex", RPCResult::Type::NUM, "Collateral transaction output index"), + RESULT_MAP_ENTRY("consecutivePayments", RPCResult::Type::NUM, "Consecutive payments masternode has received in payment cycle"), + RESULT_MAP_ENTRY("height", RPCResult::Type::NUM, "Block height"), + RESULT_MAP_ENTRY("inputsHash", RPCResult::Type::STR_HEX, "Hash of all the outpoints of the transaction inputs"), + RESULT_MAP_ENTRY("lastPaidHeight", RPCResult::Type::NUM, "Height masternode was last paid"), + RESULT_MAP_ENTRY("llmqType", RPCResult::Type::NUM, "Quorum type"), + RESULT_MAP_ENTRY("merkleRootMNList", RPCResult::Type::STR_HEX, "Merkle root of the masternode list"), + RESULT_MAP_ENTRY("merkleRootQuorums", RPCResult::Type::STR_HEX, "Merkle root of the quorum list"), + RESULT_MAP_ENTRY("operatorPayoutAddress", RPCResult::Type::STR, "Dash address used for operator reward payments"), + RESULT_MAP_ENTRY("operatorReward", RPCResult::Type::NUM, "Fraction in %% of reward shared with the operator between 0 and 10000"), + RESULT_MAP_ENTRY("ownerAddress", RPCResult::Type::STR, "Dash address used for payee updates and proposal voting"), + RESULT_MAP_ENTRY("payoutAddress", RPCResult::Type::STR, "Dash address used for masternode reward payments"), + RESULT_MAP_ENTRY("platformHTTPPort", RPCResult::Type::NUM, "(DEPRECATED) TCP port of Platform HTTP API"), + RESULT_MAP_ENTRY("platformNodeID", RPCResult::Type::STR_HEX, "Node ID derived from P2P public key for Platform P2P"), + RESULT_MAP_ENTRY("platformP2PPort", RPCResult::Type::NUM, "(DEPRECATED) TCP port of Platform P2P"), + RESULT_MAP_ENTRY("PoSeBanHeight", RPCResult::Type::NUM, "Height masternode was banned for Proof of Service violations"), + RESULT_MAP_ENTRY("PoSePenalty", RPCResult::Type::NUM, "Proof of Service penalty score"), + RESULT_MAP_ENTRY("PoSeRevivedHeight", RPCResult::Type::NUM, "Height masternode recovered from Proof of Service violations"), + RESULT_MAP_ENTRY("proTxHash", RPCResult::Type::STR_HEX, "Hash of the masternode's initial ProRegTx"), + RESULT_MAP_ENTRY("pubKeyOperator", RPCResult::Type::STR, "BLS public key used for operator signing"), + RESULT_MAP_ENTRY("quorumIndex", RPCResult::Type::NUM, "Quorum index. Relevant for rotation quorums only, 0 for non-rotating quorums"), + RESULT_MAP_ENTRY("quorumHash", RPCResult::Type::STR_HEX, "Hash of the quorum"), + RESULT_MAP_ENTRY("quorumSig", RPCResult::Type::STR_HEX, "BLS recovered threshold signature of quorum"), + RESULT_MAP_ENTRY("registeredHeight", RPCResult::Type::NUM, "Height masternode was registered"), + RESULT_MAP_ENTRY("revocationReason", RPCResult::Type::NUM, "Reason for ProUpRegTx revocation"), + RESULT_MAP_ENTRY("service", RPCResult::Type::STR, "(DEPRECATED) IP address and port of the masternode"), + RESULT_MAP_ENTRY("type", RPCResult::Type::NUM, "Masternode type"), + RESULT_MAP_ENTRY("version", RPCResult::Type::NUM, "Special transaction version"), + RESULT_MAP_ENTRY("votingAddress", RPCResult::Type::STR, "Dash address used for voting"), +}}; +#undef RESULT_MAP_ENTRY +} // anonymous namespace + +RPCResult GetRpcResult(const std::string& key, bool optional) +{ + if (const auto it = RPCRESULT_MAP.find(key); it != RPCRESULT_MAP.end()) { + const auto& ret{it->second}; + return RPCResult{ret.m_type, ret.m_key_name, optional, ret.m_description, ret.m_inner}; + } + throw NonFatalCheckError(strprintf("Requested invalid RPCResult for nonexistent key \"%s\"", key).c_str(), + __FILE__, __LINE__, __func__); +} + +RPCResult CAssetLockPayload::GetJsonHelp(const std::string& key, bool optional) +{ + return {RPCResult::Type::OBJ, key, optional, key.empty() ? "" : "The asset lock special transaction", + { + GetRpcResult("version"), + {RPCResult::Type::ARR, "creditOutputs", "", { + {RPCResult::Type::OBJ, "", "", { + {RPCResult::Type::NUM, "value", "The value in Dash"}, + {RPCResult::Type::NUM, "valueSat", "The value in duffs"}, + {RPCResult::Type::OBJ, "scriptPubKey", "", { + {RPCResult::Type::STR, "asm", "The asm"}, + {RPCResult::Type::STR_HEX, "hex", "The hex"}, + {RPCResult::Type::STR, "type", "The type, eg 'pubkeyhash'"}, + }}}}}} + }}; +} + +UniValue CAssetLockPayload::ToJson() const { UniValue outputs(UniValue::VARR); for (const CTxOut& credit_output : creditOutputs) { @@ -36,7 +117,20 @@ return ret; } -[[nodiscard]] UniValue CAssetUnlockPayload::ToJson() const +RPCResult CAssetUnlockPayload::GetJsonHelp(const std::string& key, bool optional) +{ + return {RPCResult::Type::OBJ, key, optional, key.empty() ? "" : "The asset unlock special transaction", + { + GetRpcResult("version"), + {RPCResult::Type::NUM, "index", "Index of the transaction"}, + {RPCResult::Type::NUM, "fee", "Transaction fee in duffs awarded to the miner"}, + {RPCResult::Type::NUM, "requestedHeight", "Payment chain block height known by Platform when signing the withdrawal"}, + GetRpcResult("quorumHash"), + GetRpcResult("quorumSig"), + }}; +} + +UniValue CAssetUnlockPayload::ToJson() const { UniValue ret(UniValue::VOBJ); ret.pushKV("version", nVersion); @@ -48,7 +142,21 @@ return ret; } -[[nodiscard]] UniValue CCbTx::ToJson() const +RPCResult CCbTx::GetJsonHelp(const std::string& key, bool optional) +{ + return {RPCResult::Type::OBJ, key, optional, key.empty() ? "" : "The coinbase special transaction", + { + GetRpcResult("version"), + GetRpcResult("height"), + GetRpcResult("merkleRootMNList"), + GetRpcResult("merkleRootQuorums", /*optional=*/true), + {RPCResult::Type::NUM, "bestCLHeightDiff", /*optional=*/true, "Blocks between the current block and the last known block with a ChainLock"}, + {RPCResult::Type::STR_HEX, "bestCLSignature", /*optional=*/true, "Best ChainLock signature known by the miner"}, + {RPCResult::Type::NUM, "creditPoolBalance", /*optional=*/true, "Balance in the Platform credit pool"}, + }}; +} + +UniValue CCbTx::ToJson() const { UniValue ret(UniValue::VOBJ); ret.pushKV("version", ToUnderlying(nVersion)); @@ -65,7 +173,127 @@ return ret; } -[[nodiscard]] UniValue CProRegTx::ToJson() const +// CDeterministicMN::ToJson() defined in evo/deterministicmns.cpp +RPCResult CDeterministicMN::GetJsonHelp(const std::string& key, bool optional) +{ + return {RPCResult::Type::OBJ, key, optional, key.empty() ? "" : "The masternode's details", + { + {RPCResult::Type::STR, "type", "Masternode type"}, + GetRpcResult("proTxHash"), + GetRpcResult("collateralHash"), + GetRpcResult("collateralIndex"), + {RPCResult::Type::STR, "collateralAddress", /*optional=*/true, "Dash address used for collateral"}, + GetRpcResult("operatorReward"), + CDeterministicMNState::GetJsonHelp(/*key=*/"state", /*optional=*/false), + }}; +} + +RPCResult CDeterministicMNState::GetJsonHelp(const std::string& key, bool optional) +{ + return {RPCResult::Type::OBJ, key, optional, key.empty() ? "" : "The masternode state", + { + {RPCResult::Type::NUM, "version", "Version of the masternode state"}, + GetRpcResult("service"), + GetRpcResult("addresses"), + GetRpcResult("registeredHeight"), + GetRpcResult("lastPaidHeight"), + GetRpcResult("consecutivePayments"), + GetRpcResult("PoSePenalty"), + GetRpcResult("PoSeRevivedHeight"), + GetRpcResult("PoSeBanHeight"), + GetRpcResult("revocationReason"), + GetRpcResult("ownerAddress"), + GetRpcResult("votingAddress"), + GetRpcResult("platformNodeID", /*optional=*/true), + GetRpcResult("platformP2PPort", /*optional=*/true), + GetRpcResult("platformHTTPPort", /*optional=*/true), + GetRpcResult("payoutAddress", /*optional=*/true), + GetRpcResult("pubKeyOperator"), + GetRpcResult("operatorPayoutAddress", /*optional=*/true), + }}; +} + +UniValue CDeterministicMNState::ToJson(MnType nType) const +{ + UniValue obj(UniValue::VOBJ); + obj.pushKV("version", nVersion); + obj.pushKV("service", netInfo->GetPrimary().ToStringAddrPort()); + obj.pushKV("addresses", GetNetInfoWithLegacyFields(*this, nType)); + obj.pushKV("registeredHeight", nRegisteredHeight); + obj.pushKV("lastPaidHeight", nLastPaidHeight); + obj.pushKV("consecutivePayments", nConsecutivePayments); + obj.pushKV("PoSePenalty", nPoSePenalty); + obj.pushKV("PoSeRevivedHeight", nPoSeRevivedHeight); + obj.pushKV("PoSeBanHeight", nPoSeBanHeight); + obj.pushKV("revocationReason", nRevocationReason); + obj.pushKV("ownerAddress", EncodeDestination(PKHash(keyIDOwner))); + obj.pushKV("votingAddress", EncodeDestination(PKHash(keyIDVoting))); + if (nType == MnType::Evo) { + obj.pushKV("platformNodeID", platformNodeID.ToString()); + obj.pushKV("platformP2PPort", GetPlatformPort(*this)); + obj.pushKV("platformHTTPPort", GetPlatformPort(*this)); + } + + CTxDestination dest; + if (ExtractDestination(scriptPayout, dest)) { + obj.pushKV("payoutAddress", EncodeDestination(dest)); + } + obj.pushKV("pubKeyOperator", pubKeyOperator.ToString()); + if (ExtractDestination(scriptOperatorPayout, dest)) { + obj.pushKV("operatorPayoutAddress", EncodeDestination(dest)); + } + return obj; +} + +// CDeterministicMNStateDiff::ToJson() defined in evo/dmnstate.cpp +RPCResult CDeterministicMNStateDiff::GetJsonHelp(const std::string& key, bool optional) +{ + return {RPCResult::Type::OBJ, key, optional, key.empty() ? "" : "The masternode state diff", + { + {RPCResult::Type::NUM, "version", "Version of the masternode state diff"}, + GetRpcResult("service", /*optional=*/true), + GetRpcResult("registeredHeight", /*optional=*/true), + GetRpcResult("lastPaidHeight", /*optional=*/true), + GetRpcResult("consecutivePayments", /*optional=*/true), + GetRpcResult("PoSePenalty", /*optional=*/true), + GetRpcResult("PoSeRevivedHeight", /*optional=*/true), + GetRpcResult("PoSeBanHeight", /*optional=*/true), + GetRpcResult("revocationReason", /*optional=*/true), + GetRpcResult("ownerAddress", /*optional=*/true), + GetRpcResult("votingAddress", /*optional=*/true), + GetRpcResult("payoutAddress", /*optional=*/true), + GetRpcResult("operatorPayoutAddress", /*optional=*/true), + GetRpcResult("pubKeyOperator", /*optional=*/true), + GetRpcResult("platformNodeID", /*optional=*/true), + GetRpcResult("platformP2PPort", /*optional=*/true), + GetRpcResult("platformHTTPPort", /*optional=*/true), + GetRpcResult("addresses", /*optional=*/true), + }}; +} + +RPCResult CProRegTx::GetJsonHelp(const std::string& key, bool optional) +{ + return {RPCResult::Type::OBJ, key, optional, key.empty() ? "" : "The masternode registration special transaction", + { + GetRpcResult("version"), + GetRpcResult("type"), + GetRpcResult("collateralHash"), + GetRpcResult("collateralIndex"), + GetRpcResult("service"), + GetRpcResult("addresses"), + GetRpcResult("ownerAddress"), + GetRpcResult("votingAddress"), + GetRpcResult("payoutAddress", /*optional=*/true), + GetRpcResult("pubKeyOperator"), + GetRpcResult("operatorReward"), + GetRpcResult("platformNodeID", /*optional=*/true), + GetRpcResult("platformP2PPort", /*optional=*/true), + GetRpcResult("platformHTTPPort", /*optional=*/true), + GetRpcResult("inputsHash"), + }}; +} + +UniValue CProRegTx::ToJson() const { UniValue ret(UniValue::VOBJ); ret.pushKV("version", nVersion); @@ -90,7 +318,20 @@ return ret; } -[[nodiscard]] UniValue CProUpRegTx::ToJson() const +RPCResult CProUpRegTx::GetJsonHelp(const std::string& key, bool optional) +{ + return {RPCResult::Type::OBJ, key, optional, key.empty() ? "" : "The masternode update registrar special transaction", + { + GetRpcResult("version"), + GetRpcResult("proTxHash"), + GetRpcResult("votingAddress"), + GetRpcResult("payoutAddress", /*optional=*/true), + GetRpcResult("pubKeyOperator"), + GetRpcResult("inputsHash"), + }}; +} + +UniValue CProUpRegTx::ToJson() const { UniValue ret(UniValue::VOBJ); ret.pushKV("version", nVersion); @@ -104,7 +345,18 @@ return ret; } -[[nodiscard]] UniValue CProUpRevTx::ToJson() const +RPCResult CProUpRevTx::GetJsonHelp(const std::string& key, bool optional) +{ + return {RPCResult::Type::OBJ, key, optional, key.empty() ? "" : "The masternode operator revocation special transaction", + { + GetRpcResult("version"), + GetRpcResult("proTxHash"), + {RPCResult::Type::NUM, "reason", "Reason for masternode service revocation"}, + GetRpcResult("inputsHash", /*optional=*/true), + }}; +} + +UniValue CProUpRevTx::ToJson() const { UniValue ret(UniValue::VOBJ); ret.pushKV("version", nVersion); @@ -114,7 +366,24 @@ return ret; } -[[nodiscard]] UniValue CProUpServTx::ToJson() const +RPCResult CProUpServTx::GetJsonHelp(const std::string& key, bool optional) +{ + return {RPCResult::Type::OBJ, key, optional, key.empty() ? "" : "The masternode update service special transaction", + { + GetRpcResult("version"), + GetRpcResult("type"), + GetRpcResult("proTxHash"), + GetRpcResult("service"), + GetRpcResult("addresses"), + GetRpcResult("operatorPayoutAddress", /*optional=*/true), + GetRpcResult("platformNodeID", /*optional=*/true), + GetRpcResult("platformP2PPort", /*optional=*/true), + GetRpcResult("platformHTTPPort", /*optional=*/true), + GetRpcResult("inputsHash"), + }}; +} + +UniValue CProUpServTx::ToJson() const { UniValue ret(UniValue::VOBJ); ret.pushKV("version", nVersion); @@ -134,53 +403,37 @@ return ret; } -[[nodiscard]] UniValue MNHFTxPayload::ToJson() const -{ - UniValue ret(UniValue::VOBJ); - ret.pushKV("version", nVersion); - ret.pushKV("signal", signal.ToJson()); - return ret; -} - -[[nodiscard]] UniValue llmq::CFinalCommitmentTxPayload::ToJson() const +RPCResult CSimplifiedMNListDiff::GetJsonHelp(const std::string& key, bool optional) { - UniValue ret(UniValue::VOBJ); - ret.pushKV("version", nVersion); - ret.pushKV("height", nHeight); - ret.pushKV("commitment", commitment.ToJson()); - return ret; -} - -[[nodiscard]] UniValue CSimplifiedMNListEntry::ToJson(bool extended) const -{ - UniValue obj(UniValue::VOBJ); - obj.pushKV("nVersion", nVersion); - obj.pushKV("nType", ToUnderlying(nType)); - obj.pushKV("proRegTxHash", proRegTxHash.ToString()); - obj.pushKV("confirmedHash", confirmedHash.ToString()); - obj.pushKV("service", netInfo->GetPrimary().ToStringAddrPort()); - obj.pushKV("addresses", GetNetInfoWithLegacyFields(*this, nType)); - obj.pushKV("pubKeyOperator", pubKeyOperator.ToString()); - obj.pushKV("votingAddress", EncodeDestination(PKHash(keyIDVoting))); - obj.pushKV("isValid", isValid); - if (nType == MnType::Evo) { - obj.pushKV("platformHTTPPort", GetPlatformPort(*this)); - obj.pushKV("platformNodeID", platformNodeID.ToString()); - } - - if (extended) { - CTxDestination dest; - if (ExtractDestination(scriptPayout, dest)) { - obj.pushKV("payoutAddress", EncodeDestination(dest)); - } - if (ExtractDestination(scriptOperatorPayout, dest)) { - obj.pushKV("operatorPayoutAddress", EncodeDestination(dest)); - } - } - return obj; + return {RPCResult::Type::OBJ, key, optional, key.empty() ? "" : "The simplified masternode list diff", + { + {RPCResult::Type::NUM, "nVersion", "Version of the diff"}, + {RPCResult::Type::STR_HEX, "baseBlockHash", "Hash of the base block"}, + {RPCResult::Type::STR_HEX, "blockHash", "Hash of the ending block"}, + {RPCResult::Type::STR_HEX, "cbTxMerkleTree", "Coinbase transaction merkle tree"}, + {RPCResult::Type::STR_HEX, "cbTx", "Coinbase raw transaction"}, + {RPCResult::Type::ARR, "deletedMNs", "ProRegTx hashes of deleted masternodes", + {{RPCResult::Type::STR_HEX, "hash", ""}}}, + {RPCResult::Type::ARR, "mnList", "Masternode list details", + {CSimplifiedMNListEntry::GetJsonHelp(/*key=*/"", /*optional=*/false)}}, + {RPCResult::Type::ARR, "deletedQuorums", "Deleted quorums", + {{RPCResult::Type::OBJ, "", "", { + GetRpcResult("llmqType"), + GetRpcResult("quorumHash"), + }}}}, + {RPCResult::Type::ARR, "newQuorums", "New quorums", + {llmq::CFinalCommitment::GetJsonHelp(/*key=*/"", /*optional=*/false)}}, + GetRpcResult("merkleRootMNList", /*optional=*/true), + GetRpcResult("merkleRootQuorums", /*optional=*/true), + {RPCResult::Type::ARR, "quorumsCLSigs", "ChainLock signature details", { + {RPCResult::Type::OBJ, "", "", { + {RPCResult::Type::ARR, "", "Array of quorum indices, keyed by BLS signature", { + {RPCResult::Type::NUM, "", "Quorum index"} + }}}}}}, + }}; } -[[nodiscard]] UniValue CSimplifiedMNListDiff::ToJson(bool extended) const +UniValue CSimplifiedMNListDiff::ToJson(bool extended) const { UniValue obj(UniValue::VOBJ); @@ -242,3 +495,88 @@ obj.pushKV("quorumsCLSigs", quorumsCLSigsArr); return obj; } + +RPCResult CSimplifiedMNListEntry::GetJsonHelp(const std::string& key, bool optional) +{ + return {RPCResult::Type::OBJ, key, optional, key.empty() ? "" : "The simplified masternode list entry", + { + {RPCResult::Type::NUM, "nVersion", "Version of the entry"}, + {RPCResult::Type::NUM, "nType", "Masternode type"}, + {RPCResult::Type::STR_HEX, "proRegTxHash", "Hash of the ProRegTx identifying the masternode"}, + {RPCResult::Type::STR_HEX, "confirmedHash", "Hash of the block where the masternode was confirmed"}, + GetRpcResult("service"), + GetRpcResult("addresses"), + GetRpcResult("pubKeyOperator"), + GetRpcResult("votingAddress"), + {RPCResult::Type::BOOL, "isValid", "Returns true if the masternode is not Proof-of-Service banned"}, + GetRpcResult("platformHTTPPort", /*optional=*/true), + GetRpcResult("platformNodeID", /*optional=*/true), + GetRpcResult("payoutAddress", /*optional=*/true), + GetRpcResult("operatorPayoutAddress", /*optional=*/true), + }}; +} + +UniValue CSimplifiedMNListEntry::ToJson(bool extended) const +{ + UniValue obj(UniValue::VOBJ); + obj.pushKV("nVersion", nVersion); + obj.pushKV("nType", ToUnderlying(nType)); + obj.pushKV("proRegTxHash", proRegTxHash.ToString()); + obj.pushKV("confirmedHash", confirmedHash.ToString()); + obj.pushKV("service", netInfo->GetPrimary().ToStringAddrPort()); + obj.pushKV("addresses", GetNetInfoWithLegacyFields(*this, nType)); + obj.pushKV("pubKeyOperator", pubKeyOperator.ToString()); + obj.pushKV("votingAddress", EncodeDestination(PKHash(keyIDVoting))); + obj.pushKV("isValid", isValid); + if (nType == MnType::Evo) { + obj.pushKV("platformHTTPPort", GetPlatformPort(*this)); + obj.pushKV("platformNodeID", platformNodeID.ToString()); + } + + if (extended) { + CTxDestination dest; + if (ExtractDestination(scriptPayout, dest)) { + obj.pushKV("payoutAddress", EncodeDestination(dest)); + } + if (ExtractDestination(scriptOperatorPayout, dest)) { + obj.pushKV("operatorPayoutAddress", EncodeDestination(dest)); + } + } + return obj; +} + +RPCResult MNHFTx::GetJsonHelp(const std::string& key, bool optional) +{ + return {RPCResult::Type::OBJ, key, optional, key.empty() ? "" : "The masternode hard fork payload", + { + {RPCResult::Type::NUM, "versionBit", "Version bit associated with the hard fork"}, + GetRpcResult("quorumHash"), + {RPCResult::Type::STR_HEX, "sig", "BLS signature by a quorum public key"}, + }}; +} + +UniValue MNHFTx::ToJson() const +{ + UniValue obj(UniValue::VOBJ); + obj.pushKV("versionBit", versionBit); + obj.pushKV("quorumHash", quorumHash.ToString()); + obj.pushKV("sig", sig.ToString()); + return obj; +} + +RPCResult MNHFTxPayload::GetJsonHelp(const std::string& key, bool optional) +{ + return {RPCResult::Type::OBJ, key, optional, key.empty() ? "" : "The masternode hard fork signal special transaction", + { + GetRpcResult("version"), + MNHFTx::GetJsonHelp(/*key=*/"signal", /*optional=*/false), + }}; +} + +UniValue MNHFTxPayload::ToJson() const +{ + UniValue ret(UniValue::VOBJ); + ret.pushKV("version", nVersion); + ret.pushKV("signal", signal.ToJson()); + return ret; +} diff --git a/src/evo/creditpool.cpp b/src/evo/creditpool.cpp index 20ae214d32ff..772ac70630ac 100644 --- a/src/evo/creditpool.cpp +++ b/src/evo/creditpool.cpp @@ -91,7 +91,7 @@ static std::optional GetCreditDataFromBlock(const gsl::n LogPrintf("%s: WARNING: No valid CbTx at height=%d\n", __func__, block_index->nHeight); return std::nullopt; } - for (CTransactionRef tx : block.vtx) { + for (const CTransactionRef& tx : block.vtx) { if (!tx->IsSpecialTxVersion() || tx->nType != TRANSACTION_ASSET_UNLOCK) continue; CAmount unlocked{0}; @@ -189,8 +189,8 @@ CCreditPool CCreditPoolManager::ConstructCreditPool(const gsl::not_null GetFromCache(const CBlockIndex& block_index); - void AddToCache(const uint256& block_hash, int height, const CCreditPool& pool); + std::optional GetFromCache(const CBlockIndex& block_index) EXCLUSIVE_LOCKS_REQUIRED(!cache_mutex); + void AddToCache(const uint256& block_hash, int height, const CCreditPool& pool) EXCLUSIVE_LOCKS_REQUIRED(!cache_mutex); CCreditPool ConstructCreditPool(const gsl::not_null block_index, CCreditPool prev, - const Consensus::Params& consensusParams); + const Consensus::Params& consensusParams) EXCLUSIVE_LOCKS_REQUIRED(!cache_mutex); }; std::optional GetCreditPoolDiffForBlock(CCreditPoolManager& cpoolman, const node::BlockManager& blockman, const llmq::CQuorumManager& qman, diff --git a/src/evo/deterministicmns.cpp b/src/evo/deterministicmns.cpp index ec00139807f6..8ac189b8a612 100644 --- a/src/evo/deterministicmns.cpp +++ b/src/evo/deterministicmns.cpp @@ -25,6 +25,7 @@ #include #include +#include #include #include @@ -440,6 +441,12 @@ void CDeterministicMNList::AddMN(const CDeterministicMNCPtr& dmn, bool fBumpTota throw std::runtime_error(strprintf("%s: Can't add a masternode %s with a duplicate address=%s", __func__, dmn->proTxHash.ToString(), service_opt->ToStringAddrPort())); } + } else if (const auto domain_opt{entry.GetDomainPort()}) { + if (!AddUniqueProperty(*dmn, *domain_opt)) { + mnUniquePropertyMap = mnUniquePropertyMapSaved; + throw std::runtime_error(strprintf("%s: Can't add a masternode %s with a duplicate address=%s", + __func__, dmn->proTxHash.ToString(), domain_opt->ToStringAddrPort())); + } } else { mnUniquePropertyMap = mnUniquePropertyMapSaved; throw std::runtime_error( @@ -494,6 +501,10 @@ void CDeterministicMNList::UpdateMN(const CDeterministicMN& oldDmn, const std::s if (!DeleteUniqueProperty(dmn, *service_opt)) { return "internal error"; // This shouldn't be possible } + } else if (const auto domain_opt{old_entry.GetDomainPort()}) { + if (!DeleteUniqueProperty(dmn, *domain_opt)) { + return "internal error"; // This shouldn't be possible + } } else { return "invalid address"; } @@ -503,6 +514,10 @@ void CDeterministicMNList::UpdateMN(const CDeterministicMN& oldDmn, const std::s if (!AddUniqueProperty(dmn, *service_opt)) { return strprintf("duplicate (%s)", service_opt->ToStringAddrPort()); } + } else if (const auto domain_opt{new_entry.GetDomainPort()}) { + if (!AddUniqueProperty(dmn, *domain_opt)) { + return strprintf("duplicate (%s)", domain_opt->ToStringAddrPort()); + } } else { return "invalid address"; } @@ -583,6 +598,12 @@ void CDeterministicMNList::RemoveMN(const uint256& proTxHash) throw std::runtime_error(strprintf("%s: Can't delete a masternode %s with an address=%s", __func__, proTxHash.ToString(), service_opt->ToStringAddrPort())); } + } else if (const auto domain_opt{entry.GetDomainPort()}) { + if (!DeleteUniqueProperty(*dmn, *domain_opt)) { + mnUniquePropertyMap = mnUniquePropertyMapSaved; + throw std::runtime_error(strprintf("%s: Can't delete a masternode %s with an address=%s", __func__, + proTxHash.ToString(), domain_opt->ToStringAddrPort())); + } } else { mnUniquePropertyMap = mnUniquePropertyMapSaved; throw std::runtime_error(strprintf("%s: Can't delete a masternode %s with invalid address", __func__, @@ -614,6 +635,14 @@ void CDeterministicMNList::RemoveMN(const uint256& proTxHash) InvalidateSMLCache(); } +CDeterministicMNManager::CDeterministicMNManager(CEvoDB& evoDb, CMasternodeMetaMan& mn_metaman) : + m_evoDb{evoDb}, + m_mn_metaman{mn_metaman} +{ +} + +CDeterministicMNManager::~CDeterministicMNManager() = default; + bool CDeterministicMNManager::ProcessBlock(const CBlock& block, gsl::not_null pindex, BlockValidationState& state, const CDeterministicMNList& newList, std::optional& updatesRet) @@ -648,8 +677,7 @@ bool CDeterministicMNManager::ProcessBlock(const CBlock& block, gsl::not_null(tx); if (!opt_proTx) continue; // should not happen but does not matter - if (auto meta_info = m_mn_metaman.GetMetaInfo(opt_proTx->proTxHash, false); - !meta_info || !meta_info->SetPlatformBan(false, nHeight)) { + if (!m_mn_metaman.ResetPlatformBan(opt_proTx->proTxHash, nHeight)) { LogPrint(BCLog::LLMQ, "%s -- MN %s is failed to Platform revived at height %d\n", __func__, opt_proTx->proTxHash.ToString(), nHeight); } @@ -694,8 +722,10 @@ bool CDeterministicMNManager::ProcessBlock(const CBlock& block, gsl::not_null to_cleanup) to_cleanup = nHeight; - + int current = to_cleanup.load(); + while (nHeight > current && !to_cleanup.compare_exchange_weak(current, nHeight)) { + // Loop continues if compare_exchange_weak failed (another thread changed it) (current is updated to the new value in to_cleanup) + } return true; } @@ -1026,18 +1056,18 @@ static std::optional GetValidatedPayload(const CTransaction& tx, gsl::not /** * Validates potential changes to masternode state version by ProTx transaction version - * @param[in] pindexPrev Previous block index to validate DEPLOYMENT_V23 activation + * @param[in] pindexPrev Previous block index to validate DEPLOYMENT_V24 activation * @param[in] tx_type Special transaction type * @param[in] state_version Current masternode state version * @param[in] tx_version Proposed transaction version * @param[out] state This may be set to an Error state if any error occurred processing them - * @returns true if version change is valid or DEPLOYMENT_V23 is not active + * @returns true if version change is valid or DEPLOYMENT_V24 is not active */ bool IsVersionChangeValid(gsl::not_null pindexPrev, const uint16_t tx_type, const uint16_t state_version, const uint16_t tx_version, TxValidationState& state) { - if (!DeploymentActiveAfter(pindexPrev, Params().GetConsensus(), Consensus::DEPLOYMENT_V23)) { - // New restrictions only apply after v23 deployment + if (!DeploymentActiveAfter(pindexPrev, Params().GetConsensus(), Consensus::DEPLOYMENT_V24)) { + // New restrictions only apply after v24 deployment return true; } @@ -1067,10 +1097,10 @@ bool CheckProRegTx(CDeterministicMNManager& dmnman, const CTransaction& tx, gsl: return false; } - const bool is_v23_active{DeploymentActiveAfter(pindexPrev, Params().GetConsensus(), Consensus::DEPLOYMENT_V23)}; + const bool is_v24_active{DeploymentActiveAfter(pindexPrev, Params().GetConsensus(), Consensus::DEPLOYMENT_V24)}; // No longer allow legacy scheme masternode registration - if (is_v23_active && opt_ptx->nVersion < ProTxVersion::BasicBLS) { + if (is_v24_active && opt_ptx->nVersion < ProTxVersion::BasicBLS) { return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-version-disallowed"); } @@ -1142,6 +1172,11 @@ bool CheckProRegTx(CDeterministicMNManager& dmnman, const CTransaction& tx, gsl: mnList.GetUniquePropertyMN(*service_opt)->collateralOutpoint != collateralOutpoint) { return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-dup-netinfo-entry"); } + } else if (const auto domain_opt{entry.GetDomainPort()}) { + if (mnList.HasUniqueProperty(*domain_opt) && + mnList.GetUniquePropertyMN(*domain_opt)->collateralOutpoint != collateralOutpoint) { + return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-dup-netinfo-entry"); + } } else { return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-netinfo-entry"); } @@ -1224,6 +1259,10 @@ bool CheckProUpServTx(CDeterministicMNManager& dmnman, const CTransaction& tx, g mnList.GetUniquePropertyMN(*service_opt)->proTxHash != opt_ptx->proTxHash) { return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-dup-netinfo-entry"); } + } else if (const auto domain_opt{entry.GetDomainPort()}) { + if (mnList.HasUniqueProperty(*domain_opt) && mnList.GetUniquePropertyMN(*domain_opt)->proTxHash != opt_ptx->proTxHash) { + return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-dup-netinfo-entry"); + } } else { return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-netinfo-entry"); } @@ -1459,9 +1498,9 @@ bool CDeterministicMNManager::MigrateLegacyDiffs(const CBlockIndex* const tip_in stateDiff.fields |= CDeterministicMNStateDiff::Field_nVersion; stateDiff.state.nVersion = dmn->pdmnState->nVersion; } - if (stateDiff.fields & CDeterministicMNStateDiff::Field_pubKeyOperator) { - stateDiff.state.pubKeyOperator.SetLegacy(stateDiff.state.nVersion == ProTxVersion::LegacyBLS); - } + } + if (stateDiff.fields & CDeterministicMNStateDiff::Field_pubKeyOperator) { + stateDiff.state.pubKeyOperator.SetLegacy(stateDiff.state.nVersion == ProTxVersion::LegacyBLS); } convertedDiff.updatedMNs.emplace(internalId, stateDiff); } @@ -1541,3 +1580,328 @@ bool CDeterministicMNManager::MigrateLegacyDiffs(const CBlockIndex* const tip_in return true; } + +CDeterministicMNManager::RecalcDiffsResult CDeterministicMNManager::RecalculateAndRepairDiffs( + const CBlockIndex* start_index, const CBlockIndex* stop_index, ChainstateManager& chainman, + BuildListFromBlockFunc build_list_func, bool repair) +{ + RecalcDiffsResult result; + result.start_height = start_index->nHeight; + result.stop_height = stop_index->nHeight; + + const auto& consensus_params = Params().GetConsensus(); + + // Clamp start height to DIP0003 activation (no snapshots/diffs exist before this) + if (start_index->nHeight < consensus_params.DIP0003Height) { + start_index = stop_index->GetAncestor(consensus_params.DIP0003Height); + if (!start_index) { + result.verification_errors.push_back(strprintf("Stop height %d is below DIP0003 activation height %d", + stop_index->nHeight, consensus_params.DIP0003Height)); + return result; + } + LogPrintf("CDeterministicMNManager::%s -- Clamped start height from %d to DIP0003 activation height %d\n", + __func__, result.start_height, consensus_params.DIP0003Height); + // Update result to reflect the clamped start height + result.start_height = start_index->nHeight; + } + + // Collect all snapshot blocks in the range + std::vector snapshot_blocks = CollectSnapshotBlocks(start_index, stop_index, consensus_params); + + if (snapshot_blocks.empty()) { + result.verification_errors.push_back("Could not find starting snapshot"); + return result; + } + + if (snapshot_blocks.size() < 2) { + result.verification_errors.push_back(strprintf("Need at least 2 snapshots, found %d", snapshot_blocks.size())); + return result; + } + + LogPrintf("CDeterministicMNManager::%s -- Processing %d snapshot pairs between heights %d and %d\n", __func__, + snapshot_blocks.size() - 1, result.start_height, result.stop_height); + + // Storage for recalculated diffs if we plan to repair + std::vector> recalculated_diffs; + + // Process each pair of consecutive snapshots + for (size_t i = 0; i < snapshot_blocks.size() - 1; ++i) { + const CBlockIndex* from_index = snapshot_blocks[i]; + const CBlockIndex* to_index = snapshot_blocks[i + 1]; + + // Load the snapshots from disk + CDeterministicMNList from_snapshot; + CDeterministicMNList to_snapshot; + + bool has_from_snapshot = m_evoDb.Read(std::make_pair(DB_LIST_SNAPSHOT, from_index->GetBlockHash()), from_snapshot); + bool has_to_snapshot = m_evoDb.Read(std::make_pair(DB_LIST_SNAPSHOT, to_index->GetBlockHash()), to_snapshot); + + // Handle missing snapshots + if (!has_from_snapshot) { + // The initial snapshot at DIP0003 activation might not exist in the database on nodes + // that synced before the fix to explicitly write it. This is the only acceptable case. + if (from_index->nHeight == consensus_params.DIP0003Height) { + // Create an empty initial snapshot (matching what GetListForBlockInternal does) + from_snapshot = CDeterministicMNList(from_index->GetBlockHash(), from_index->nHeight, 0); + LogPrintf("CDeterministicMNManager::%s -- Using empty initial snapshot at DIP0003 height %d\n", + __func__, from_index->nHeight); + } else { + // Any other missing snapshot is critical corruption beyond our repair capability + result.verification_errors.push_back(strprintf("CRITICAL: Snapshot missing at height %d. " + "This cannot be repaired by this tool - full reindex required.", from_index->nHeight)); + return result; + } + } + + if (!has_to_snapshot) { + // Missing target snapshot is always critical - we cannot repair snapshots, only diffs + result.verification_errors.push_back(strprintf("CRITICAL: Snapshot missing at height %d. " + "This cannot be repaired by this tool - full reindex required.", to_index->nHeight)); + return result; + } + + // Log progress periodically (every 100 snapshot pairs) to avoid spam + if (i % 100 == 0) { + LogPrintf("CDeterministicMNManager::%s -- Progress: verifying snapshot pair %d/%d (heights %d-%d)\n", + __func__, i + 1, snapshot_blocks.size() - 1, from_index->nHeight, to_index->nHeight); + } + + // Verify this snapshot pair + bool is_snapshot_pair_valid = VerifySnapshotPair(from_index, to_index, from_snapshot, to_snapshot, result); + + // If repair mode is enabled and verification failed, recalculate diffs from blockchain + if (repair && !is_snapshot_pair_valid) { + auto temp_diffs = RepairSnapshotPair(from_index, to_index, from_snapshot, to_snapshot, build_list_func, result); + if (temp_diffs.empty()) { + // RepairSnapshotPair failed - this is a critical error, cannot continue + return result; + } + // Only commit diffs if recalculation verification passed + recalculated_diffs.insert(recalculated_diffs.end(), temp_diffs.begin(), temp_diffs.end()); + result.diffs_recalculated += temp_diffs.size(); + } + } + + // Write repaired diffs to database + if (repair) { + WriteRepairedDiffs(recalculated_diffs, result); + } + + return result; +} + +std::vector CDeterministicMNManager::CollectSnapshotBlocks( + const CBlockIndex* start_index, const CBlockIndex* stop_index, const Consensus::Params& consensus_params) +{ + std::vector snapshot_blocks; + + // Add the starting snapshot (find the snapshot at or before start) + // Walk backwards to find a snapshot block (divisible by DISK_SNAPSHOT_PERIOD) + // or the initial snapshot at DIP0003 activation height + const CBlockIndex* snapshot_start_index = start_index; + while (snapshot_start_index && snapshot_start_index->nHeight > consensus_params.DIP0003Height && + (snapshot_start_index->nHeight % DISK_SNAPSHOT_PERIOD) != 0) { + snapshot_start_index = snapshot_start_index->pprev; + } + + if (!snapshot_start_index) { + return snapshot_blocks; // Empty vector indicates error + } + + // Collect all snapshot blocks up to and including the stop block + snapshot_blocks.push_back(snapshot_start_index); + + // Find all subsequent snapshot heights + int current_snapshot_height = snapshot_start_index->nHeight; + while (true) { + // Calculate next snapshot height + int next_snapshot_height; + if (current_snapshot_height == consensus_params.DIP0003Height) { + // If we're at DIP0003 activation (initial snapshot), next is at first regular interval + next_snapshot_height = ((consensus_params.DIP0003Height / DISK_SNAPSHOT_PERIOD) + 1) * DISK_SNAPSHOT_PERIOD; + } else { + // Otherwise, add DISK_SNAPSHOT_PERIOD + next_snapshot_height = current_snapshot_height + DISK_SNAPSHOT_PERIOD; + } + + if (next_snapshot_height > stop_index->nHeight) { + break; + } + + const CBlockIndex* next_snapshot_index = stop_index->GetAncestor(next_snapshot_height); + if (!next_snapshot_index) { + break; + } + + snapshot_blocks.push_back(next_snapshot_index); + current_snapshot_height = next_snapshot_height; + } + + return snapshot_blocks; +} + +bool CDeterministicMNManager::VerifySnapshotPair( + const CBlockIndex* from_index, const CBlockIndex* to_index, const CDeterministicMNList& from_snapshot, + const CDeterministicMNList& to_snapshot, RecalcDiffsResult& result) +{ + // Verify this snapshot pair by applying all stored diffs sequentially + CDeterministicMNList test_list = from_snapshot; + + try { + for (int nHeight = from_index->nHeight + 1; nHeight <= to_index->nHeight; ++nHeight) { + const CBlockIndex* pIndex = to_index->GetAncestor(nHeight); + if (!pIndex) { + result.verification_errors.push_back(strprintf("Failed to get ancestor at height %d", nHeight)); + return false; + } + + CDeterministicMNListDiff diff; + if (!m_evoDb.Read(std::make_pair(DB_LIST_DIFF, pIndex->GetBlockHash()), diff)) { + result.verification_errors.push_back(strprintf("Failed to read diff at height %d", nHeight)); + return false; + } + + diff.nHeight = nHeight; + test_list.ApplyDiff(pIndex, diff); + } + } catch (const std::exception& e) { + result.verification_errors.push_back(strprintf("Exception during verification: %s", e.what())); + return false; + } + + // Verify that applying all diffs results in the target snapshot + bool is_snapshot_pair_valid = test_list.IsEqual(to_snapshot); + + if (is_snapshot_pair_valid) { + result.snapshots_verified++; + } else { + result.verification_errors.push_back( + strprintf("Verification failed between snapshots at heights %d and %d: " + "Applied diffs do not match target snapshot", + from_index->nHeight, to_index->nHeight)); + } + + return is_snapshot_pair_valid; +} + +std::vector> CDeterministicMNManager::RepairSnapshotPair( + const CBlockIndex* from_index, const CBlockIndex* to_index, const CDeterministicMNList& from_snapshot, + const CDeterministicMNList& to_snapshot, BuildListFromBlockFunc build_list_func, RecalcDiffsResult& result) +{ + CDeterministicMNList current_list = from_snapshot; + // Temporary storage for recalculated diffs (one per block in this snapshot interval) + std::vector> temp_diffs; + temp_diffs.reserve(to_index->nHeight - from_index->nHeight); + + LogPrintf("CDeterministicMNManager::%s -- Repairing: recalculating diffs between snapshots at heights %d and %d\n", + __func__, from_index->nHeight, to_index->nHeight); + + try { + for (int nHeight = from_index->nHeight + 1; nHeight <= to_index->nHeight; ++nHeight) { + const CBlockIndex* pIndex = to_index->GetAncestor(nHeight); + + // Read the actual block from disk + CBlock block; + if (!node::ReadBlockFromDisk(block, pIndex, Params().GetConsensus())) { + result.repair_errors.push_back(strprintf("CRITICAL: Failed to read block at height %d. " + "Cannot repair - full reindex required.", nHeight)); + return {}; // Critical error - cannot continue repair + } + + // Use a dummy coins view to avoid UTXO lookups. At chain tip, coins from + // historical blocks may already be spent. Since these blocks were fully + // validated when originally connected, we don't need to re-verify coin + // availability - we only need to extract special transactions. + CCoinsView view_dummy; + CCoinsViewCache view(&view_dummy); + + // Build the new list by processing this block's special transactions + // Starting from current_list (our trusted state), not from corrupted diffs + CDeterministicMNList next_list; + BlockValidationState state; + if (!build_list_func(block, pIndex->pprev, current_list, view, false, state, next_list)) { + result.repair_errors.push_back( + strprintf("CRITICAL: Failed to build list for block at height %d: %s. " + "Cannot repair - full reindex required.", nHeight, state.ToString())); + return {}; // Critical error - cannot continue repair + } + + // Set the correct block hash + next_list.SetBlockHash(pIndex->GetBlockHash()); + + // Calculate the diff between current and next + CDeterministicMNListDiff recalc_diff = current_list.BuildDiff(next_list); + recalc_diff.nHeight = nHeight; + // Store in temporary vector for this snapshot pair + temp_diffs.emplace_back(pIndex->GetBlockHash(), recalc_diff); + + // Move forward + current_list = next_list; // TODO: make CDeterministicMNList moveable + } + + // Verify that applying all diffs results in the target snapshot + if (current_list.IsEqual(to_snapshot)) { + LogPrintf("CDeterministicMNManager::%s -- Successfully recalculated %d diffs between heights %d and %d\n", + __func__, temp_diffs.size(), from_index->nHeight, to_index->nHeight); + return temp_diffs; // Success - return recalculated diffs + } else { + result.repair_errors.push_back( + strprintf("CRITICAL: Recalculation failed between snapshots at heights %d and %d: " + "Applied diffs do not match target snapshot. Cannot repair - full reindex required.", + from_index->nHeight, to_index->nHeight)); + return {}; // Failed verification - return empty vector + } + } catch (const std::exception& e) { + result.repair_errors.push_back(strprintf("CRITICAL: Exception during recalculation: %s. " + "Cannot repair - full reindex required.", e.what())); + return {}; // Exception - return empty vector + } +} + +void CDeterministicMNManager::WriteRepairedDiffs( + const std::vector>& recalculated_diffs, RecalcDiffsResult& result) +{ + AssertLockNotHeld(cs); + + if (recalculated_diffs.empty()) { + return; + } + + CDBBatch batch(m_evoDb.GetRawDB()); + const size_t BATCH_SIZE_THRESHOLD = 1 << 24; // 16MB + size_t diffs_written = 0; + + LogPrintf("CDeterministicMNManager::%s -- Writing %d repaired diffs to database...\n", + __func__, recalculated_diffs.size()); + + for (const auto& [block_hash, diff] : recalculated_diffs) { + batch.Write(std::make_pair(DB_LIST_DIFF, block_hash), diff); + diffs_written++; + + // Write batch when it gets too large + if (batch.SizeEstimate() >= BATCH_SIZE_THRESHOLD) { + LogPrintf("CDeterministicMNManager::%s -- Flushing batch (%d diffs written so far)...\n", + __func__, diffs_written); + m_evoDb.GetRawDB().WriteBatch(batch); + batch.Clear(); + } + } + + // Write any remaining diffs in the batch + if (batch.SizeEstimate() > 0) { + LogPrintf("CDeterministicMNManager::%s -- Writing final batch...\n", __func__); + m_evoDb.GetRawDB().WriteBatch(batch); + batch.Clear(); + } + + // Clear caches for repaired diffs so next read gets fresh data from disk + // Must clear both diff cache and list cache since lists were built from old diffs + LOCK(cs); + for (const auto& [block_hash, diff] : recalculated_diffs) { + mnListDiffsCache.erase(block_hash); + mnListsCache.erase(block_hash); + } + + LogPrintf("CDeterministicMNManager::%s -- Successfully repaired %d diffs (caches cleared)\n", __func__, + recalculated_diffs.size()); +} diff --git a/src/evo/deterministicmns.h b/src/evo/deterministicmns.h index 12643e5f1f1a..80aabbe113aa 100644 --- a/src/evo/deterministicmns.h +++ b/src/evo/deterministicmns.h @@ -5,9 +5,8 @@ #ifndef BITCOIN_EVO_DETERMINISTICMNS_H #define BITCOIN_EVO_DETERMINISTICMNS_H -#include - #include +#include #include #include @@ -35,7 +34,10 @@ class CEvoDB; class CSimplifiedMNList; class CSimplifiedMNListEntry; class CMasternodeMetaMan; +class ChainstateManager; +class CSpecialTxProcessor; class TxValidationState; +struct RPCResult; extern RecursiveMutex cs_main; @@ -86,6 +88,8 @@ class CDeterministicMN [[nodiscard]] CSimplifiedMNListEntry to_sml_entry() const; [[nodiscard]] std::string ToString() const; + + [[nodiscard]] static RPCResult GetJsonHelp(const std::string& key, bool optional); [[nodiscard]] UniValue ToJson() const; }; @@ -160,7 +164,7 @@ class CDeterministicMNList mutable std::shared_ptr m_cached_sml GUARDED_BY(m_cached_sml_mutex); // Private helper method to invalidate SML cache - void InvalidateSMLCache() + void InvalidateSMLCache() EXCLUSIVE_LOCKS_REQUIRED(!m_cached_sml_mutex) { LOCK(m_cached_sml_mutex); m_cached_sml = nullptr; @@ -191,6 +195,7 @@ class CDeterministicMNList // Assignment operator CDeterministicMNList& operator=(const CDeterministicMNList& other) + EXCLUSIVE_LOCKS_REQUIRED(!m_cached_sml_mutex, !other.m_cached_sml_mutex) { if (this != &other) { blockHash = other.blockHash; @@ -227,7 +232,7 @@ class CDeterministicMNList } template - void Unserialize(Stream& s) + void Unserialize(Stream& s) EXCLUSIVE_LOCKS_REQUIRED(!m_cached_sml_mutex) { Clear(); @@ -238,7 +243,7 @@ class CDeterministicMNList } } - void Clear() + void Clear() EXCLUSIVE_LOCKS_REQUIRED(!m_cached_sml_mutex) { blockHash = uint256{}; nHeight = -1; @@ -370,7 +375,7 @@ class CDeterministicMNList * Calculates CSimplifiedMNList for current list and cache it * Thread safety: Uses internal mutex for thread-safe cache access */ - gsl::not_null> to_sml() const; + gsl::not_null> to_sml() const EXCLUSIVE_LOCKS_REQUIRED(!m_cached_sml_mutex); /** * Calculates the maximum penalty which is allowed at the height of this MN list. It is dynamic and might change @@ -391,14 +396,14 @@ class CDeterministicMNList * Penalty scores are only increased when the MN is not already banned, which means that after banning the penalty * might appear lower then the current max penalty, while the MN is still banned. */ - void PoSePunish(const uint256& proTxHash, int penalty, bool debugLogs); + void PoSePunish(const uint256& proTxHash, int penalty, bool debugLogs) EXCLUSIVE_LOCKS_REQUIRED(!m_cached_sml_mutex); - void DecreaseScores(); + void DecreaseScores() EXCLUSIVE_LOCKS_REQUIRED(!m_cached_sml_mutex); /** * Decrease penalty score of MN by 1. * Only allowed on non-banned MNs. */ - void PoSeDecrease(const CDeterministicMN& dmn); + void PoSeDecrease(const CDeterministicMN& dmn) EXCLUSIVE_LOCKS_REQUIRED(!m_cached_sml_mutex); [[nodiscard]] CDeterministicMNListDiff BuildDiff(const CDeterministicMNList& to) const; /** @@ -406,13 +411,17 @@ class CDeterministicMNList * It is more efficient than creating a copy due to heavy copy constructor. * Calculating for old block may require up to {DISK_SNAPSHOT_PERIOD} object copy & destroy. */ - void ApplyDiff(gsl::not_null pindex, const CDeterministicMNListDiff& diff); - - void AddMN(const CDeterministicMNCPtr& dmn, bool fBumpTotalCount = true); - void UpdateMN(const CDeterministicMN& oldDmn, const std::shared_ptr& pdmnState); - void UpdateMN(const uint256& proTxHash, const std::shared_ptr& pdmnState); - void UpdateMN(const CDeterministicMN& oldDmn, const CDeterministicMNStateDiff& stateDiff); - void RemoveMN(const uint256& proTxHash); + void ApplyDiff(gsl::not_null pindex, const CDeterministicMNListDiff& diff) + EXCLUSIVE_LOCKS_REQUIRED(!m_cached_sml_mutex); + + void AddMN(const CDeterministicMNCPtr& dmn, bool fBumpTotalCount = true) EXCLUSIVE_LOCKS_REQUIRED(!m_cached_sml_mutex); + void UpdateMN(const CDeterministicMN& oldDmn, const std::shared_ptr& pdmnState) + EXCLUSIVE_LOCKS_REQUIRED(!m_cached_sml_mutex); + void UpdateMN(const uint256& proTxHash, const std::shared_ptr& pdmnState) + EXCLUSIVE_LOCKS_REQUIRED(!m_cached_sml_mutex); + void UpdateMN(const CDeterministicMN& oldDmn, const CDeterministicMNStateDiff& stateDiff) + EXCLUSIVE_LOCKS_REQUIRED(!m_cached_sml_mutex); + void RemoveMN(const uint256& proTxHash) EXCLUSIVE_LOCKS_REQUIRED(!m_cached_sml_mutex); template [[nodiscard]] bool HasUniqueProperty(const T& v) const @@ -429,6 +438,46 @@ class CDeterministicMNList return GetMN(p->first); } + // Compare two masternode lists for equality, ignoring non-deterministic members. + // Non-deterministic members (nTotalRegisteredCount, internalId) can differ between + // nodes due to different sync histories, but don't affect consensus validity. + bool IsEqual(const CDeterministicMNList& rhs) const + { + // Compare deterministic metadata + if (blockHash != rhs.blockHash || + nHeight != rhs.nHeight || + mnUniquePropertyMap != rhs.mnUniquePropertyMap) { + return false; + } + + // Compare map sizes (actual entries compared below) + // Note: Not comparing nTotalRegisteredCount (non-deterministic) + if (mnMap.size() != rhs.mnMap.size() || + mnInternalIdMap.size() != rhs.mnInternalIdMap.size()) { + return false; + } + + // Compare each masternode entry + for (const auto& [proTxHash, dmn] : mnMap) { + auto dmn_rhs = rhs.mnMap.find(proTxHash); + if (dmn_rhs == nullptr) { + return false; + } + + // Compare deterministic masternode fields + // Note: Not comparing internalId (non-deterministic) + if (dmn->proTxHash != dmn_rhs->get()->proTxHash || + dmn->collateralOutpoint != dmn_rhs->get()->collateralOutpoint || + dmn->nOperatorReward != dmn_rhs->get()->nOperatorReward || + dmn->nType != dmn_rhs->get()->nType || + // Use SerializeHash for pdmnState to avoid enumerating all state fields + SerializeHash(*dmn->pdmnState) != SerializeHash(*dmn_rhs->get()->pdmnState)) { + return false; + } + } + return true; + } + private: template [[nodiscard]] uint256 GetUniquePropertyHash(const T& v) const @@ -442,7 +491,17 @@ class CDeterministicMNList DMNL_NO_TEMPLATE(NetInfoInterface); DMNL_NO_TEMPLATE(std::shared_ptr); #undef DMNL_NO_TEMPLATE - return ::SerializeHash(v); + int ser_version{PROTOCOL_VERSION}; + if constexpr (std::is_same_v, CService>) { + // Special handling is required if we're using addresses that can only be (de)serialized using + // ADDRv2. Without this step, the address gets truncated, the hashmap gets contaminated with + // an invalid entry and subsequent attempts at registering ADDRv2 entries get blocked. We cannot + // apply this treatment ADDRv1 compatible addresses for backwards compatibility with the existing map. + if (!v.IsAddrV1Compatible()) { + ser_version |= ADDRV2_FORMAT; + } + } + return ::SerializeHash(v, /*nType=*/SER_GETHASH, /*nVersion=*/ser_version); } template [[nodiscard]] bool AddUniqueProperty(const CDeterministicMN& dmn, const T& v) @@ -637,12 +696,11 @@ class CDeterministicMNManager const CBlockIndex* m_initial_snapshot_index GUARDED_BY(cs) {nullptr}; public: - explicit CDeterministicMNManager(CEvoDB& evoDb, CMasternodeMetaMan& mn_metaman) : - m_evoDb(evoDb), - m_mn_metaman(mn_metaman) - { - } - ~CDeterministicMNManager() = default; + CDeterministicMNManager() = delete; + CDeterministicMNManager(const CDeterministicMNManager&) = delete; + CDeterministicMNManager& operator=(const CDeterministicMNManager&) = delete; + explicit CDeterministicMNManager(CEvoDB& evoDb, CMasternodeMetaMan& mn_metaman); + ~CDeterministicMNManager(); bool ProcessBlock(const CBlock& block, gsl::not_null pindex, BlockValidationState& state, const CDeterministicMNList& newList, std::optional& updatesRet) @@ -660,7 +718,32 @@ class CDeterministicMNManager // Test if given TX is a ProRegTx which also contains the collateral at index n static bool IsProTxWithCollateral(const CTransactionRef& tx, uint32_t n); - void DoMaintenance() EXCLUSIVE_LOCKS_REQUIRED(!cs); + void DoMaintenance() EXCLUSIVE_LOCKS_REQUIRED(!cs, !cs_cleanup); + + // Recalculate and optionally repair diffs between snapshots + struct RecalcDiffsResult { + int start_height{0}; + int stop_height{0}; + int diffs_recalculated{0}; + int snapshots_verified{0}; + std::vector verification_errors; + std::vector repair_errors; + }; + + // Callback type for building a new MN list from a block + using BuildListFromBlockFunc = std::function pindexPrev, + const CDeterministicMNList& prevList, + const CCoinsViewCache& view, + bool debugLogs, + BlockValidationState& state, + CDeterministicMNList& mnListRet)>; + + [[nodiscard]] RecalcDiffsResult RecalculateAndRepairDiffs(const CBlockIndex* start_index, + const CBlockIndex* stop_index, ChainstateManager& chainman, + BuildListFromBlockFunc build_list_func, bool repair) + EXCLUSIVE_LOCKS_REQUIRED(!cs); // Migration support for nVersion-first CDeterministicMNStateDiff format [[nodiscard]] bool IsMigrationRequired() const EXCLUSIVE_LOCKS_REQUIRED(!cs, ::cs_main); @@ -669,6 +752,18 @@ class CDeterministicMNManager private: void CleanupCache(int nHeight) EXCLUSIVE_LOCKS_REQUIRED(cs); CDeterministicMNList GetListForBlockInternal(gsl::not_null pindex) EXCLUSIVE_LOCKS_REQUIRED(cs); + + // Helper methods for RecalculateAndRepairDiffs + std::vector CollectSnapshotBlocks(const CBlockIndex* start_index, const CBlockIndex* stop_index, + const Consensus::Params& consensus_params); + bool VerifySnapshotPair(const CBlockIndex* from_index, const CBlockIndex* to_index, + const CDeterministicMNList& from_snapshot, const CDeterministicMNList& to_snapshot, + RecalcDiffsResult& result); + std::vector> RepairSnapshotPair( + const CBlockIndex* from_index, const CBlockIndex* to_index, const CDeterministicMNList& from_snapshot, + const CDeterministicMNList& to_snapshot, BuildListFromBlockFunc build_list_func, RecalcDiffsResult& result); + void WriteRepairedDiffs(const std::vector>& recalculated_diffs, + RecalcDiffsResult& result) EXCLUSIVE_LOCKS_REQUIRED(!cs); }; bool CheckProRegTx(CDeterministicMNManager& dmnman, const CTransaction& tx, gsl::not_null pindexPrev, TxValidationState& state, const CCoinsViewCache& view, bool check_sigs); diff --git a/src/evo/dmnstate.cpp b/src/evo/dmnstate.cpp index c9d9a9e71948..54d463db3d13 100644 --- a/src/evo/dmnstate.cpp +++ b/src/evo/dmnstate.cpp @@ -32,38 +32,6 @@ std::string CDeterministicMNState::ToString() const EncodeDestination(PKHash(keyIDVoting)), netInfo->ToString(), payoutAddress, operatorPayoutAddress); } -UniValue CDeterministicMNState::ToJson(MnType nType) const -{ - UniValue obj(UniValue::VOBJ); - obj.pushKV("version", nVersion); - obj.pushKV("service", netInfo->GetPrimary().ToStringAddrPort()); - obj.pushKV("addresses", GetNetInfoWithLegacyFields(*this, nType)); - obj.pushKV("registeredHeight", nRegisteredHeight); - obj.pushKV("lastPaidHeight", nLastPaidHeight); - obj.pushKV("consecutivePayments", nConsecutivePayments); - obj.pushKV("PoSePenalty", nPoSePenalty); - obj.pushKV("PoSeRevivedHeight", nPoSeRevivedHeight); - obj.pushKV("PoSeBanHeight", nPoSeBanHeight); - obj.pushKV("revocationReason", nRevocationReason); - obj.pushKV("ownerAddress", EncodeDestination(PKHash(keyIDOwner))); - obj.pushKV("votingAddress", EncodeDestination(PKHash(keyIDVoting))); - if (nType == MnType::Evo) { - obj.pushKV("platformNodeID", platformNodeID.ToString()); - obj.pushKV("platformP2PPort", GetPlatformPort(*this)); - obj.pushKV("platformHTTPPort", GetPlatformPort(*this)); - } - - CTxDestination dest; - if (ExtractDestination(scriptPayout, dest)) { - obj.pushKV("payoutAddress", EncodeDestination(dest)); - } - obj.pushKV("pubKeyOperator", pubKeyOperator.ToString()); - if (ExtractDestination(scriptOperatorPayout, dest)) { - obj.pushKV("operatorPayoutAddress", EncodeDestination(dest)); - } - return obj; -} - UniValue CDeterministicMNStateDiff::ToJson(MnType nType) const { UniValue obj(UniValue::VOBJ); diff --git a/src/evo/dmnstate.h b/src/evo/dmnstate.h index d63460b2d931..b2f93fad0ccd 100644 --- a/src/evo/dmnstate.h +++ b/src/evo/dmnstate.h @@ -19,16 +19,15 @@ #include #include -class CProRegTx; -class UniValue; - class CDeterministicMNState; - -namespace llmq -{ - class CFinalCommitment; +class CProRegTx; +struct RPCResult; +namespace llmq { +class CFinalCommitment; } // namespace llmq +class UniValue; + class CDeterministicMNState { private: @@ -150,6 +149,7 @@ class CDeterministicMNState public: std::string ToString() const; + [[nodiscard]] static RPCResult GetJsonHelp(const std::string& key, bool optional); [[nodiscard]] UniValue ToJson(MnType nType) const; }; @@ -243,6 +243,7 @@ class CDeterministicMNStateDiff template CDeterministicMNStateDiff(deserialize_type, Stream& s) { s >> *this; } + [[nodiscard]] static RPCResult GetJsonHelp(const std::string& key, bool optional); [[nodiscard]] UniValue ToJson(MnType nType) const; SERIALIZE_METHODS(CDeterministicMNStateDiff, obj) @@ -355,28 +356,54 @@ class CDeterministicMNStateDiffLegacy s >> *this; } + // Used for testing only + template + void Serialize(Stream& s) const + { + s << VARINT(fields); + + boost::hana::for_each(legacy_members, [&](auto&& member) { + using BaseType = std::decay_t; + if constexpr (BaseType::mask == LegacyField_pubKeyOperator) { + if (fields & member.mask) { + // We serialize it as is, no version wrapper is used here + s << state.pubKeyOperator; + } + } else if constexpr (BaseType::mask == LegacyField_netInfo) { + if (fields & member.mask) { + // Legacy format supports non-extended addresses only + s << NetInfoSerWrapper(const_cast&>(state.netInfo), + /*is_extended=*/false); + } + } else { + if (fields & member.mask) { + s << member.get(state); + } + } + }); + } + // Deserialize using legacy format - SERIALIZE_METHODS(CDeterministicMNStateDiffLegacy, obj) + template + void Unserialize(Stream& s) { - READWRITE(VARINT(obj.fields)); + s >> VARINT(fields); boost::hana::for_each(legacy_members, [&](auto&& member) { using BaseType = std::decay_t; if constexpr (BaseType::mask == LegacyField_pubKeyOperator) { - if (obj.fields & member.mask) { + if (fields & member.mask) { // We'll set proper scheme later in MigrateLegacyDiffs() - READWRITE(CBLSLazyPublicKeyVersionWrapper(const_cast(obj.state.pubKeyOperator), - /*legacy=*/true)); + s >> CBLSLazyPublicKeyVersionWrapper(state.pubKeyOperator, /*legacy=*/true); } } else if constexpr (BaseType::mask == LegacyField_netInfo) { - if (obj.fields & member.mask) { + if (fields & member.mask) { // Legacy format supports non-extended addresses only - READWRITE(NetInfoSerWrapper(const_cast&>(obj.state.netInfo), - /*is_extended=*/false)); + s >> NetInfoSerWrapper(state.netInfo, /*is_extended=*/false); } } else { - if (obj.fields & member.mask) { - READWRITE(member.get(obj.state)); + if (fields & member.mask) { + s >> member.get(state); } } }); diff --git a/src/evo/evodb.cpp b/src/evo/evodb.cpp index b1396e9ef423..371e07ff466e 100644 --- a/src/evo/evodb.cpp +++ b/src/evo/evodb.cpp @@ -31,14 +31,16 @@ void CEvoDBScopedCommitter::Rollback() evoDB.RollbackCurTransaction(); } -CEvoDB::CEvoDB(size_t nCacheSize, bool fMemory, bool fWipe) : - db(fMemory ? "" : (gArgs.GetDataDirNet() / "evodb"), nCacheSize, fMemory, fWipe), - rootBatch(db), - rootDBTransaction(db, rootBatch), - curDBTransaction(rootDBTransaction, rootDBTransaction) +CEvoDB::CEvoDB(const util::DbWrapperParams& db_params) : + db{util::MakeDbWrapper({db_params.path / "evodb", db_params.memory, db_params.wipe, /*cache_size=*/64 << 20})}, + rootBatch{*db}, + rootDBTransaction{*db, rootBatch}, + curDBTransaction{rootDBTransaction, rootDBTransaction} { } +CEvoDB::~CEvoDB() = default; + void CEvoDB::CommitCurTransaction() { LOCK(cs); @@ -56,7 +58,7 @@ bool CEvoDB::CommitRootTransaction() LOCK(cs); assert(curDBTransaction.IsClean()); rootDBTransaction.Commit(); - bool ret = db.WriteBatch(rootBatch); + bool ret = db->WriteBatch(rootBatch); rootBatch.Clear(); return ret; } diff --git a/src/evo/evodb.h b/src/evo/evodb.h index 594ced2cc5fb..32d5d655b1c6 100644 --- a/src/evo/evodb.h +++ b/src/evo/evodb.h @@ -9,6 +9,10 @@ #include class uint256; +namespace util { +struct DbWrapperParams; +} // namespace util + // "b_b" was used in the initial version of deterministic MN storage // "b_b2" was used after compact diffs were introduced // "b_b3" was used after masternode type introduction in evoDB @@ -36,7 +40,7 @@ class CEvoDB public: Mutex cs; private: - CDBWrapper db; + std::unique_ptr db; using RootTransaction = CDBTransaction; using CurTransaction = CDBTransaction; @@ -46,7 +50,11 @@ class CEvoDB CurTransaction curDBTransaction; public: - explicit CEvoDB(size_t nCacheSize, bool fMemory = false, bool fWipe = false); + CEvoDB() = delete; + CEvoDB(const CEvoDB&) = delete; + CEvoDB& operator=(const CEvoDB&) = delete; + explicit CEvoDB(const util::DbWrapperParams& db_params); + ~CEvoDB(); std::unique_ptr BeginTransaction() EXCLUSIVE_LOCKS_REQUIRED(!cs) { @@ -90,7 +98,7 @@ class CEvoDB CDBWrapper& GetRawDB() { - return db; + return *db; } [[nodiscard]] size_t GetMemoryUsage() const @@ -100,7 +108,7 @@ class CEvoDB bool CommitRootTransaction() EXCLUSIVE_LOCKS_REQUIRED(!cs); - bool IsEmpty() { return db.IsEmpty(); } + bool IsEmpty() { return db->IsEmpty(); } bool VerifyBestBlock(const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(!cs); void WriteBestBlock(const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(!cs); diff --git a/src/evo/mnauth.cpp b/src/evo/mnauth.cpp index 3c2b080059c1..caba4172e567 100644 --- a/src/evo/mnauth.cpp +++ b/src/evo/mnauth.cpp @@ -36,15 +36,7 @@ void CMNAuth::PushMNAUTH(CNode& peer, CConnman& connman, const CActiveMasternode if (Params().NetworkIDString() != CBaseChainParams::MAIN && gArgs.IsArgSet("-pushversion")) { nOurNodeVersion = gArgs.GetIntArg("-pushversion", PROTOCOL_VERSION); } - auto pk = mn_activeman.GetPubKey(); - const CBLSPublicKey pubKey(pk); - uint256 signHash = [&]() { - if (peer.nVersion < MNAUTH_NODE_VER_VERSION || nOurNodeVersion < MNAUTH_NODE_VER_VERSION) { - return ::SerializeHash(std::make_tuple(pubKey, receivedMNAuthChallenge, peer.IsInboundConn())); - } else { - return ::SerializeHash(std::make_tuple(pubKey, receivedMNAuthChallenge, peer.IsInboundConn(), nOurNodeVersion)); - } - }(); + const uint256 signHash{::SerializeHash(std::make_tuple(mn_activeman.GetPubKey(), receivedMNAuthChallenge, peer.IsInboundConn(), nOurNodeVersion))}; mnauth.proRegTxHash = mn_activeman.GetProTxHash(); @@ -97,18 +89,9 @@ MessageProcessingResult CMNAuth::ProcessMessage(CNode& peer, ServiceFlags node_s return MisbehavingError{10, "missing mnauth masternode"}; } - uint256 signHash; - int nOurNodeVersion{PROTOCOL_VERSION}; - if (Params().NetworkIDString() != CBaseChainParams::MAIN && gArgs.IsArgSet("-pushversion")) { - nOurNodeVersion = gArgs.GetIntArg("-pushversion", PROTOCOL_VERSION); - } const CBLSPublicKey pubKey(dmn->pdmnState->pubKeyOperator.Get()); // See comment in PushMNAUTH (fInbound is negated here as we're on the other side of the connection) - if (peer.nVersion < MNAUTH_NODE_VER_VERSION || nOurNodeVersion < MNAUTH_NODE_VER_VERSION) { - signHash = ::SerializeHash(std::make_tuple(pubKey, peer.GetSentMNAuthChallenge(), !peer.IsInboundConn())); - } else { - signHash = ::SerializeHash(std::make_tuple(pubKey, peer.GetSentMNAuthChallenge(), !peer.IsInboundConn(), peer.nVersion.load())); - } + const uint256 signHash{::SerializeHash(std::make_tuple(pubKey, peer.GetSentMNAuthChallenge(), !peer.IsInboundConn(), peer.nVersion.load()))}; LogPrint(BCLog::NET_NETCONN, "CMNAuth::%s -- constructed signHash for nVersion %d, peer=%d\n", __func__, peer.nVersion, peer.GetId()); if (!mnauth.sig.VerifyInsecure(dmn->pdmnState->pubKeyOperator.Get(), signHash, false)) { @@ -118,7 +101,7 @@ MessageProcessingResult CMNAuth::ProcessMessage(CNode& peer, ServiceFlags node_s } if (!peer.IsInboundConn()) { - mn_metaman.GetMetaInfo(mnauth.proRegTxHash)->SetLastOutboundSuccess(GetTime().count()); + mn_metaman.SetLastOutboundSuccess(mnauth.proRegTxHash, GetTime().count()); if (peer.m_masternode_probe_connection) { LogPrint(BCLog::NET_NETCONN, "CMNAuth::ProcessMessage -- Masternode probe successful for %s, disconnecting. peer=%d\n", mnauth.proRegTxHash.ToString(), peer.GetId()); diff --git a/src/evo/mnauth.h b/src/evo/mnauth.h index 9508cca595c8..0ab8acf4dc95 100644 --- a/src/evo/mnauth.h +++ b/src/evo/mnauth.h @@ -6,6 +6,8 @@ #define BITCOIN_EVO_MNAUTH_H #include +#include + #include #include #include diff --git a/src/evo/mnhftx.cpp b/src/evo/mnhftx.cpp index 7e1da6cbafdc..54e5d0c29ce0 100644 --- a/src/evo/mnhftx.cpp +++ b/src/evo/mnhftx.cpp @@ -45,7 +45,7 @@ CMutableTransaction MNHFTxPayload::PrepareTx() const } CMNHFManager::CMNHFManager(CEvoDB& evoDb) : - m_evoDb(evoDb) + m_evoDb{evoDb} { assert(globalInstance == nullptr); globalInstance = this; diff --git a/src/evo/mnhftx.h b/src/evo/mnhftx.h index 8adda3655368..2c4260956763 100644 --- a/src/evo/mnhftx.h +++ b/src/evo/mnhftx.h @@ -26,6 +26,7 @@ class CEvoDB; class CTransaction; class ChainstateManager; class TxValidationState; +struct RPCResult; namespace llmq { class CQuorumManager; } @@ -50,14 +51,8 @@ class MNHFTx std::string ToString() const; - [[nodiscard]] UniValue ToJson() const - { - UniValue obj(UniValue::VOBJ); - obj.pushKV("versionBit", versionBit); - obj.pushKV("quorumHash", quorumHash.ToString()); - obj.pushKV("sig", sig.ToString()); - return obj; - } + [[nodiscard]] static RPCResult GetJsonHelp(const std::string& key, bool optional); + [[nodiscard]] UniValue ToJson() const; }; class MNHFTxPayload @@ -87,6 +82,7 @@ class MNHFTxPayload std::string ToString() const; + [[nodiscard]] static RPCResult GetJsonHelp(const std::string& key, bool optional); [[nodiscard]] UniValue ToJson() const; }; @@ -103,9 +99,11 @@ class CMNHFManager : public AbstractEHFManager Uint256LruHashMap mnhfCache GUARDED_BY(cs_cache){MNHFCacheSize}; public: + CMNHFManager() = delete; + CMNHFManager(const CMNHFManager&) = delete; + CMNHFManager& operator=(const CMNHFManager&) = delete; explicit CMNHFManager(CEvoDB& evoDb); ~CMNHFManager(); - explicit CMNHFManager(const CMNHFManager&) = delete; /** * Every new block should be processed when Tip() is updated by calling of CMNHFManager::ProcessBlock. @@ -114,7 +112,8 @@ class CMNHFManager : public AbstractEHFManager * @pre Caller must ensure that LLMQContext has been initialized and the llmq::CQuorumManager pointer has been * set by calling ConnectManagers() for this CMNHFManager instance */ - std::optional ProcessBlock(const CBlock& block, const CBlockIndex* const pindex, bool fJustCheck, BlockValidationState& state); + std::optional ProcessBlock(const CBlock& block, const CBlockIndex* const pindex, bool fJustCheck, + BlockValidationState& state) EXCLUSIVE_LOCKS_REQUIRED(!cs_cache); /** * Every undo block should be processed when Tip() is updated by calling of CMNHFManager::UndoBlock @@ -124,10 +123,10 @@ class CMNHFManager : public AbstractEHFManager * @pre Caller must ensure that LLMQContext has been initialized and the llmq::CQuorumManager pointer has been * set by calling ConnectManagers() for this CMNHFManager instance */ - bool UndoBlock(const CBlock& block, const CBlockIndex* const pindex); + bool UndoBlock(const CBlock& block, const CBlockIndex* const pindex) EXCLUSIVE_LOCKS_REQUIRED(!cs_cache); // Implements interface - Signals GetSignalsStage(const CBlockIndex* const pindexPrev) override; + Signals GetSignalsStage(const CBlockIndex* const pindexPrev) override EXCLUSIVE_LOCKS_REQUIRED(!cs_cache); /** * Helper that used in Unit Test to forcely setup EHF signal for specific block @@ -149,10 +148,10 @@ class CMNHFManager : public AbstractEHFManager */ void DisconnectManagers(); - bool ForceSignalDBUpdate() EXCLUSIVE_LOCKS_REQUIRED(::cs_main); + bool ForceSignalDBUpdate() EXCLUSIVE_LOCKS_REQUIRED(::cs_main, !cs_cache); private: - void AddToCache(const Signals& signals, const CBlockIndex* const pindex); + void AddToCache(const Signals& signals, const CBlockIndex* const pindex) EXCLUSIVE_LOCKS_REQUIRED(!cs_cache); /** * This function returns list of signals available on previous block. @@ -160,13 +159,13 @@ class CMNHFManager : public AbstractEHFManager * until state won't be recovered. * NOTE: that some signals could expired between blocks. */ - Signals GetForBlock(const CBlockIndex* const pindex); + Signals GetForBlock(const CBlockIndex* const pindex) EXCLUSIVE_LOCKS_REQUIRED(!cs_cache); /** * This function access to in-memory cache or to evo db but does not calculate anything * NOTE: that some signals could expired between blocks. */ - std::optional GetFromCache(const CBlockIndex* const pindex); + std::optional GetFromCache(const CBlockIndex* const pindex) EXCLUSIVE_LOCKS_REQUIRED(!cs_cache); }; std::optional extractEHFSignal(const CTransaction& tx); diff --git a/src/evo/netinfo.cpp b/src/evo/netinfo.cpp index 2c4dc7ef712c..3a8a920d46eb 100644 --- a/src/evo/netinfo.cpp +++ b/src/evo/netinfo.cpp @@ -18,13 +18,54 @@ namespace { static std::unique_ptr g_main_params{nullptr}; static std::once_flag g_main_params_flag; +/** Maximum length of a label in a domain per RFC 1035 */ +static constexpr uint8_t DOMAIN_LABEL_MAX_LEN{63}; +/** Maximum possible length of a ASCII FQDN */ +static constexpr uint8_t DOMAIN_MAX_LEN{253}; +/** Minimum length of a FQDN */ +static constexpr uint8_t DOMAIN_MIN_LEN{3}; + +static constexpr std::string_view SAFE_CHARS_ALPHA{"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"}; static constexpr std::string_view SAFE_CHARS_IPV4{"1234567890."}; static constexpr std::string_view SAFE_CHARS_IPV4_6{"abcdefABCDEF1234567890.:[]"}; +static constexpr std::string_view SAFE_CHARS_RFC1035{"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-"}; +static constexpr std::array TLDS_BAD{ + // ICANN resolution 2018.02.04.12 + ".mail", + // Infrastructure TLD + ".arpa", + // RFC 6761 + ".example", ".invalid", ".localhost", ".test", + // RFC 6762 + ".local", + // RFC 6762, Appendix G + ".corp", ".home", ".internal", ".intranet", ".lan", ".private", +}; +static constexpr std::array TLDS_PRIVACY{".i2p", ".onion"}; bool MatchCharsFilter(std::string_view input, std::string_view filter) { return std::all_of(input.begin(), input.end(), [&filter](char c) { return filter.find(c) != std::string_view::npos; }); } + +bool MatchSuffix(const std::string& str, Span list) +{ + if (str.empty()) return false; + for (const auto& suffix : list) { + if (suffix.size() > str.size()) continue; + if (std::string_view{str}.ends_with(suffix)) return true; + } + return false; +} + +bool IsAllowedPlatformHTTPPort(uint16_t port) +{ + switch (port) { + case 443: + return true; + } + return false; +} } // anonymous namespace bool IsNodeOnMainnet() { return Params().NetworkIDString() == CBaseChainParams::MAIN; } @@ -42,6 +83,57 @@ UniValue ArrFromService(const CService& addr) return obj; } +DomainPort::Status DomainPort::ValidateDomain(const std::string& addr) +{ + if (addr.length() > DOMAIN_MAX_LEN || addr.length() < DOMAIN_MIN_LEN) { + return DomainPort::Status::BadLen; + } + if (!MatchCharsFilter(addr, SAFE_CHARS_RFC1035)) { + return DomainPort::Status::BadChar; + } + if (addr.front() == '.' || addr.back() == '.') { + return DomainPort::Status::BadCharPos; + } + std::vector labels{SplitString(addr, '.')}; + if (labels.size() < 2) { + return DomainPort::Status::BadDotless; + } + for (const auto& label : labels) { + if (label.empty() || label.length() > DOMAIN_LABEL_MAX_LEN) { + return DomainPort::Status::BadLabelLen; + } + if (label.front() == '-' || label.back() == '-') { + return DomainPort::Status::BadLabelCharPos; + } + } + return DomainPort::Status::Success; +} + +DomainPort::Status DomainPort::Set(const std::string& addr, const uint16_t port) +{ + if (port == 0) { + return DomainPort::Status::BadPort; + } + const auto ret{ValidateDomain(addr)}; + if (ret == DomainPort::Status::Success) { + // Convert to lowercase to avoid duplication by changing case (domains are case-insensitive) + m_addr = ToLower(addr); + m_port = port; + } + return ret; +} + +DomainPort::Status DomainPort::Validate() const +{ + if (m_addr.empty() || m_addr != ToLower(m_addr)) { + return DomainPort::Status::Malformed; + } + if (m_port == 0) { + return DomainPort::Status::BadPort; + } + return ValidateDomain(m_addr); +} + bool NetInfoEntry::operator==(const NetInfoEntry& rhs) const { if (m_type != rhs.m_type) return false; @@ -65,6 +157,10 @@ bool NetInfoEntry::operator<(const NetInfoEntry& rhs) const if constexpr (std::is_same_v) { // Both the same type, compare as usual return lhs < rhs; + } else if constexpr ((std::is_same_v || std::is_same_v) && + (std::is_same_v || std::is_same_v)) { + // Differing types but both implement ToStringAddrPort(), lexicographical compare strings + return lhs.ToStringAddrPort() < rhs.ToStringAddrPort(); } // If lhs is monostate, it less than rhs; otherwise rhs is greater return std::is_same_v; @@ -81,12 +177,21 @@ std::optional NetInfoEntry::GetAddrPort() const return std::nullopt; } +std::optional NetInfoEntry::GetDomainPort() const +{ + if (const auto* data_ptr{std::get_if(&m_data)}; m_type == NetInfoType::Domain && data_ptr) { + ASSERT_IF_DEBUG(data_ptr->IsValid()); + return *data_ptr; + } + return std::nullopt; +} + uint16_t NetInfoEntry::GetPort() const { return std::visit( [](auto&& input) -> uint16_t { using T1 = std::decay_t; - if constexpr (std::is_same_v) { + if constexpr (std::is_same_v || std::is_same_v) { return input.GetPort(); } return 0; @@ -103,7 +208,8 @@ bool NetInfoEntry::IsTriviallyValid() const return std::visit( [this](auto&& input) -> bool { using T1 = std::decay_t; - static_assert(std::is_same_v || std::is_same_v, "Unexpected type"); + static_assert(std::is_same_v || std::is_same_v || std::is_same_v, + "Unexpected type"); if constexpr (std::is_same_v) { // Empty underlying data isn't a valid entry return false; @@ -112,6 +218,11 @@ bool NetInfoEntry::IsTriviallyValid() const if (m_type != NetInfoType::Service) return false; // Underlying data must meet surface-level validity checks for its type if (!input.IsValid()) return false; + } else if constexpr (std::is_same_v) { + // Type code should be truthful as it decides what underlying type is used when (de)serializing + if (m_type != NetInfoType::Domain) return false; + // Underlying data should at least meet surface-level validity checks + if (!input.IsValid()) return false; } return true; }, @@ -125,6 +236,8 @@ std::string NetInfoEntry::ToString() const using T1 = std::decay_t; if constexpr (std::is_same_v) { return strprintf("CService(addr=%s, port=%u)", input.ToStringAddr(), input.GetPort()); + } else if constexpr (std::is_same_v) { + return strprintf("DomainPort(addr=%s, port=%u)", input.ToStringAddr(), input.GetPort()); } return "[invalid entry]"; }, @@ -136,7 +249,7 @@ std::string NetInfoEntry::ToStringAddr() const return std::visit( [](auto&& input) -> std::string { using T1 = std::decay_t; - if constexpr (std::is_same_v) { + if constexpr (std::is_same_v || std::is_same_v) { return input.ToStringAddr(); } return "[invalid entry]"; @@ -149,7 +262,7 @@ std::string NetInfoEntry::ToStringAddrPort() const return std::visit( [](auto&& input) -> std::string { using T1 = std::decay_t; - if constexpr (std::is_same_v) { + if constexpr (std::is_same_v || std::is_same_v) { return input.ToStringAddrPort(); } return "[invalid entry]"; @@ -307,6 +420,10 @@ NetInfoStatus ExtNetInfo::ProcessCandidate(const NetInfoPurpose purpose, const N if (IsAddrPortDuplicate(candidate)) { return NetInfoStatus::Duplicate; } + if (candidate.GetDomainPort().has_value() && purpose != NetInfoPurpose::PLATFORM_HTTPS) { + // Domains only allowed for Platform HTTPS API + return NetInfoStatus::BadInput; + } if (auto it{m_data.find(purpose)}; it != m_data.end()) { // Existing entries list found, check limit auto& [_, entries] = *it; @@ -333,15 +450,43 @@ NetInfoStatus ExtNetInfo::ValidateService(const CService& service) if (!service.IsValid()) { return NetInfoStatus::BadAddress; } - if (!service.IsIPv4() && !service.IsIPv6()) { + if (!service.IsCJDNS() && !service.IsI2P() && !service.IsIPv4() && !service.IsIPv6() && !service.IsTor()) { return NetInfoStatus::BadType; } if (Params().RequireRoutableExternalIP() && !service.IsRoutable()) { return NetInfoStatus::NotRoutable; } - if (IsBadPort(service.GetPort()) || service.GetPort() == 0) { + const uint16_t service_port{service.GetPort()}; + if (service.IsI2P()) { + if (service_port != I2P_SAM31_PORT) { + // I2P SAM 3.1 and earlier don't support arbitrary ports + return NetInfoStatus::BadPort; + } + } else { + if (service_port == 0 || IsBadPort(service_port)) { + return NetInfoStatus::BadPort; + } + } + + return NetInfoStatus::Success; +} + +NetInfoStatus ExtNetInfo::ValidateDomainPort(const DomainPort& domain) +{ + if (!domain.IsValid()) { + return NetInfoStatus::BadInput; + } + const uint16_t domain_port{domain.GetPort()}; + if (domain_port == 0 || (IsBadPort(domain_port) && !IsAllowedPlatformHTTPPort(domain_port))) { return NetInfoStatus::BadPort; } + const std::string& addr{domain.ToStringAddr()}; + if (MatchSuffix(addr, TLDS_BAD) || MatchSuffix(addr, TLDS_PRIVACY)) { + return NetInfoStatus::BadInput; + } + if (const auto labels{SplitString(addr, '.')}; !MatchCharsFilter(labels.at(labels.size() - 1), SAFE_CHARS_ALPHA)) { + return NetInfoStatus::BadInput; + } return NetInfoStatus::Success; } @@ -357,15 +502,42 @@ NetInfoStatus ExtNetInfo::AddEntry(const NetInfoPurpose purpose, const std::stri std::string addr; uint16_t port{0}; SplitHostPort(input, port, addr); - // Contains invalid characters, unlikely to pass Lookup(), fast-fail + if (!MatchCharsFilter(addr, SAFE_CHARS_IPV4_6)) { - return NetInfoStatus::BadInput; + if (!MatchCharsFilter(addr, SAFE_CHARS_RFC1035)) { + // Neither IP:port safe nor domain-safe, we can safely assume it's bad input + return NetInfoStatus::BadInput; + } + + // Not IP:port safe but domain safe + if (MatchSuffix(addr, TLDS_PRIVACY)) { + // Special domain, try storing it as CService + CNetAddr netaddr; + if (netaddr.SetSpecial(addr)) { + const CService service{netaddr, port}; + const auto ret{ValidateService(service)}; + if (ret == NetInfoStatus::Success) { + return ProcessCandidate(purpose, NetInfoEntry{service}); + } + return ret; /* ValidateService() failed */ + } + } else if (DomainPort domain; domain.Set(addr, port) == DomainPort::Status::Success) { + // Regular domain + const auto ret{ValidateDomainPort(domain)}; + if (ret == NetInfoStatus::Success) { + return ProcessCandidate(purpose, NetInfoEntry{domain}); + } + return ret; /* ValidateDomainPort() failed */ + } + return NetInfoStatus::BadInput; /* CNetAddr::SetSpecial() or DomainPort::Set() failed */ } + // IP:port safe, try to parse it as IP:port if (auto service_opt{Lookup(addr, /*portDefault=*/port, /*fAllowLookup=*/false)}) { - const auto ret{ValidateService(*service_opt)}; + const auto service{MaybeFlipIPv6toCJDNS(*service_opt)}; + const auto ret{ValidateService(service)}; if (ret == NetInfoStatus::Success) { - return ProcessCandidate(purpose, NetInfoEntry{*service_opt}); + return ProcessCandidate(purpose, NetInfoEntry{service}); } return ret; /* ValidateService() failed */ } @@ -436,6 +608,15 @@ NetInfoStatus ExtNetInfo::Validate() const // Stores CService underneath but doesn't pass validation rules return ret; } + } else if (const auto domain_opt{entry.GetDomainPort()}) { + if (purpose != NetInfoPurpose::PLATFORM_HTTPS) { + // Domains only allowed for Platform HTTPS API + return NetInfoStatus::BadInput; + } + if (auto ret{ValidateDomainPort(*domain_opt)}; ret != NetInfoStatus::Success) { + // Stores DomainPort underneath but doesn't pass validation rules + return ret; + } } else { // Doesn't store valid type underneath return NetInfoStatus::Malformed; diff --git a/src/evo/netinfo.h b/src/evo/netinfo.h index 4f1cdb9f1717..0f33649de0fd 100644 --- a/src/evo/netinfo.h +++ b/src/evo/netinfo.h @@ -106,28 +106,109 @@ UniValue ArrFromService(const CService& addr); /** Equivalent to Params() if node is running on mainnet */ const CChainParams& MainParams(); +class DomainPort +{ +public: + enum class Status : uint8_t { + BadChar, + BadCharPos, + BadDotless, + BadLabelCharPos, + BadLabelLen, + BadLen, + BadPort, + Malformed, + + Success + }; + + static constexpr std::string_view StatusToString(const DomainPort::Status code) + { + switch (code) { + case DomainPort::Status::BadChar: + return "invalid character"; + case DomainPort::Status::BadCharPos: + return "bad domain character position"; + case DomainPort::Status::BadDotless: + return "prohibited dotless"; + case DomainPort::Status::BadLabelCharPos: + return "bad label character position"; + case DomainPort::Status::BadLabelLen: + return "bad label length"; + case DomainPort::Status::BadLen: + return "bad domain length"; + case DomainPort::Status::BadPort: + return "bad port"; + case DomainPort::Status::Malformed: + return "malformed"; + case DomainPort::Status::Success: + return "success"; + } // no default case, so the compiler can warn about missing cases + assert(false); + } + +private: + std::string m_addr{}; + uint16_t m_port{0}; + +private: + static DomainPort::Status ValidateDomain(const std::string& input); + +public: + DomainPort() = default; + template + DomainPort(deserialize_type, Stream& s) { s >> *this; } + + ~DomainPort() = default; + + bool operator<(const DomainPort& rhs) const { return std::tie(m_addr, m_port) < std::tie(rhs.m_addr, rhs.m_port); } + bool operator==(const DomainPort& rhs) const { return std::tie(m_addr, m_port) == std::tie(rhs.m_addr, rhs.m_port); } + bool operator!=(const DomainPort& rhs) const { return !(*this == rhs); } + + SERIALIZE_METHODS(DomainPort, obj) + { + READWRITE(obj.m_addr); + READWRITE(Using>(obj.m_port)); + } + + bool IsEmpty() const { return m_addr.empty() && m_port == 0; } + bool IsValid() const { return Validate() == DomainPort::Status::Success; } + DomainPort::Status Set(const std::string& addr, const uint16_t port); + DomainPort::Status Validate() const; + uint16_t GetPort() const { return m_port; } + std::string ToStringAddr() const { return m_addr; } + std::string ToStringAddrPort() const { return strprintf("%s:%d", m_addr, m_port); } +}; + class NetInfoEntry { public: enum NetInfoType : uint8_t { Service = 0x01, + Domain = 0x02, Invalid = 0xff }; private: uint8_t m_type{NetInfoType::Invalid}; - std::variant m_data{std::monostate{}}; + std::variant m_data{std::monostate{}}; public: NetInfoEntry() = default; - NetInfoEntry(const CService& service) + explicit NetInfoEntry(const DomainPort& domain) + { + if (!domain.IsValid()) return; + m_type = NetInfoType::Domain; + m_data = domain; + } + explicit NetInfoEntry(const CService& service) { if (!service.IsValid()) return; m_type = NetInfoType::Service; m_data = service; } template - NetInfoEntry(deserialize_type, Stream& s) { s >> *this; } + explicit NetInfoEntry(deserialize_type, Stream& s) { s >> *this; } ~NetInfoEntry() = default; @@ -139,9 +220,12 @@ class NetInfoEntry void Serialize(Stream& s_) const { OverrideStream s(&s_, /*nType=*/0, s_.GetVersion() | ADDRV2_FORMAT); - if (const auto* data_ptr{std::get_if(&m_data)}; - m_type == NetInfoType::Service && data_ptr && data_ptr->IsValid()) { - s << m_type << *data_ptr; + if (const auto* data_ptr_service{std::get_if(&m_data)}; + m_type == NetInfoType::Service && data_ptr_service && data_ptr_service->IsValid()) { + s << m_type << *data_ptr_service; + } else if (const auto* data_ptr_domain{std::get_if(&m_data)}; + m_type == NetInfoType::Domain && data_ptr_domain && data_ptr_domain->IsValid()) { + s << m_type << *data_ptr_domain; } else { s << NetInfoType::Invalid; } @@ -153,12 +237,17 @@ class NetInfoEntry OverrideStream s(&s_, /*nType=*/0, s_.GetVersion() | ADDRV2_FORMAT); s >> m_type; if (m_type == NetInfoType::Service) { - m_data = CService{}; try { - CService& service{std::get(m_data)}; + auto& service{m_data.emplace()}; s >> service; if (!service.IsValid()) { Clear(); } // Invalid CService, mark as invalid } catch (const std::ios_base::failure&) { Clear(); } // Deser failed, mark as invalid + } else if (m_type == NetInfoType::Domain) { + try { + auto& domain{m_data.emplace()}; + s >> domain; + if (!domain.IsValid()) { Clear(); } // Invalid DomainPort, mark as invalid + } catch (const std::ios_base::failure&) { Clear(); } // Deser failed, mark as invalid } else { Clear(); } // Invalid type code, mark as invalid } @@ -169,6 +258,7 @@ class NetInfoEntry } std::optional GetAddrPort() const; + std::optional GetDomainPort() const; uint16_t GetPort() const; bool IsEmpty() const { return *this == NetInfoEntry{}; } bool IsTriviallyValid() const; @@ -294,6 +384,7 @@ class ExtNetInfo final : public NetInfoInterface /** Validate CService candidate address against ruleset */ static NetInfoStatus ValidateService(const CService& service); + static NetInfoStatus ValidateDomainPort(const DomainPort& domain); private: uint8_t m_version{CURRENT_VERSION}; diff --git a/src/evo/providertx.cpp b/src/evo/providertx.cpp index 6702ede99223..99e046955bf2 100644 --- a/src/evo/providertx.cpp +++ b/src/evo/providertx.cpp @@ -23,7 +23,7 @@ template : DeploymentActiveAfter(pindexPrev, Params().GetConsensus(), Consensus::DEPLOYMENT_V19), is_extaddr_eligible ? DeploymentActiveAfter(pindexPrev, Params().GetConsensus(), - Consensus::DEPLOYMENT_V23) + Consensus::DEPLOYMENT_V24) : false); } template uint16_t GetMaxFromDeployment(gsl::not_null pindexPrev, std::optional is_basic_override); diff --git a/src/evo/providertx.h b/src/evo/providertx.h index f2173b20e086..038fabe1e83a 100644 --- a/src/evo/providertx.h +++ b/src/evo/providertx.h @@ -6,22 +6,23 @@ #define BITCOIN_EVO_PROVIDERTX_H #include +#include #include #include #include #include -#include #include #include #include -#include #include +#include #include class CBlockIndex; class TxValidationState; +struct RPCResult; namespace ProTxVersion { enum : uint16_t { @@ -37,7 +38,7 @@ enum : uint16_t { if (is_extended_addr) { // Requires *both* forks to be active to use extended addresses. is_basic_scheme_active could // be set to false due to RPC specialization, so we must evaluate is_extended_addr *last* to - // avoid accidentally upgrading a legacy BLS node to basic BLS due to v23 activation. + // avoid accidentally upgrading a legacy BLS node to basic BLS due to v24 activation. return ProTxVersion::ExtAddr; } return ProTxVersion::BasicBLS; @@ -120,6 +121,7 @@ class CProRegTx std::string ToString() const; + [[nodiscard]] static RPCResult GetJsonHelp(const std::string& key, bool optional); [[nodiscard]] UniValue ToJson() const; bool IsTriviallyValid(gsl::not_null pindexPrev, TxValidationState& state) const; @@ -180,6 +182,7 @@ class CProUpServTx std::string ToString() const; + [[nodiscard]] static RPCResult GetJsonHelp(const std::string& key, bool optional); [[nodiscard]] UniValue ToJson() const; bool IsTriviallyValid(gsl::not_null pindexPrev, TxValidationState& state) const; @@ -226,6 +229,7 @@ class CProUpRegTx std::string ToString() const; + [[nodiscard]] static RPCResult GetJsonHelp(const std::string& key, bool optional); [[nodiscard]] UniValue ToJson() const; bool IsTriviallyValid(gsl::not_null pindexPrev, TxValidationState& state) const; @@ -275,6 +279,7 @@ class CProUpRevTx std::string ToString() const; + [[nodiscard]] static RPCResult GetJsonHelp(const std::string& key, bool optional); [[nodiscard]] UniValue ToJson() const; bool IsTriviallyValid(gsl::not_null pindexPrev, TxValidationState& state) const; diff --git a/src/evo/simplifiedmns.h b/src/evo/simplifiedmns.h index 9153d0b025e1..cbc1e9434fe4 100644 --- a/src/evo/simplifiedmns.h +++ b/src/evo/simplifiedmns.h @@ -9,15 +9,19 @@ #include #include #include -#include +#include + #include #include #include -#include + +#include #include #include +struct RPCResult; + class UniValue; class CSimplifiedMNListEntry @@ -95,6 +99,7 @@ class CSimplifiedMNListEntry uint256 CalcHash() const; + [[nodiscard]] static RPCResult GetJsonHelp(const std::string& key, bool optional); std::string ToString() const; [[nodiscard]] UniValue ToJson(bool extended = false) const; }; diff --git a/src/evo/smldiff.h b/src/evo/smldiff.h index 5296ddf4941d..0154403d840b 100644 --- a/src/evo/smldiff.h +++ b/src/evo/smldiff.h @@ -5,12 +5,12 @@ #ifndef BITCOIN_EVO_SMLDIFF_H #define BITCOIN_EVO_SMLDIFF_H -#include - #include #include #include #include +#include + #include #include #include @@ -21,6 +21,7 @@ class CBlockIndex; class CDeterministicMNManager; class UniValue; class ChainstateManager; +struct RPCResult; namespace llmq { class CFinalCommitment; @@ -85,6 +86,7 @@ class CSimplifiedMNListDiff const llmq::CQuorumBlockProcessor& quorum_block_processor); bool BuildQuorumChainlockInfo(const llmq::CQuorumManager& qman, const CBlockIndex* blockIndex); + [[nodiscard]] static RPCResult GetJsonHelp(const std::string& key, bool optional); [[nodiscard]] UniValue ToJson(bool extended = false) const; }; diff --git a/src/evo/specialtxman.cpp b/src/evo/specialtxman.cpp index 9fcffe753299..33e1493331fa 100644 --- a/src/evo/specialtxman.cpp +++ b/src/evo/specialtxman.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -175,20 +176,31 @@ bool CSpecialTxProcessor::BuildNewListFromBlock(const CBlock& block, gsl::not_nu BlockValidationState& state, CDeterministicMNList& mnListRet) { AssertLockHeld(cs_main); + CDeterministicMNList oldList = m_dmnman.GetListForBlock(pindexPrev); + return RebuildListFromBlock(block, pindexPrev, oldList, view, debugLogs, state, mnListRet); +} + +bool CSpecialTxProcessor::RebuildListFromBlock(const CBlock& block, gsl::not_null pindexPrev, + const CDeterministicMNList& prevList, const CCoinsViewCache& view, + bool debugLogs, BlockValidationState& state, + CDeterministicMNList& mnListRet) +{ + // Verify that prevList either represents an empty/initial state (default-constructed), + // or it matches the previous block's hash. + assert(prevList == CDeterministicMNList() || prevList.GetBlockHash() == pindexPrev->GetBlockHash()); int nHeight = pindexPrev->nHeight + 1; - CDeterministicMNList oldList = m_dmnman.GetListForBlock(pindexPrev); - CDeterministicMNList newList = oldList; + CDeterministicMNList newList = prevList; newList.SetBlockHash(uint256()); // we can't know the final block hash, so better not return a (invalid) block hash newList.SetHeight(nHeight); - auto payee = oldList.GetMNPayee(pindexPrev); + auto payee = prevList.GetMNPayee(pindexPrev); - // we iterate the oldList here and update the newList + // we iterate the prevList here and update the newList // this is only valid as long these have not diverged at this point, which is the case as long as we don't add // code above this loop that modifies newList - oldList.ForEachMN(false, [&pindexPrev, &newList, this](auto& dmn) { + prevList.ForEachMN(false, [&pindexPrev, &newList, this](auto& dmn) { if (!dmn.pdmnState->confirmedHash.IsNull()) { // already confirmed return; @@ -206,7 +218,7 @@ bool CSpecialTxProcessor::BuildNewListFromBlock(const CBlock& block, gsl::not_nu newList.DecreaseScores(); const bool isMNRewardReallocation{DeploymentActiveAfter(pindexPrev, m_consensus_params, Consensus::DEPLOYMENT_MN_RR)}; - const bool is_v23_deployed{DeploymentActiveAfter(pindexPrev, m_consensus_params, Consensus::DEPLOYMENT_V23)}; + const bool is_v24_deployed{DeploymentActiveAfter(pindexPrev, m_consensus_params, Consensus::DEPLOYMENT_V24)}; // we skip the coinbase for (int i = 1; i < (int)block.vtx.size(); i++) { @@ -234,13 +246,18 @@ bool CSpecialTxProcessor::BuildNewListFromBlock(const CBlock& block, gsl::not_nu dmn->collateralOutpoint = proTx.collateralOutpoint; } - Coin coin; - CAmount expectedCollateral = GetMnType(proTx.nType).collat_amount; - if (!proTx.collateralOutpoint.hash.IsNull() && (!view.GetCoin(dmn->collateralOutpoint, coin) || - coin.IsSpent() || coin.out.nValue != expectedCollateral)) { - // should actually never get to this point as CheckProRegTx should have handled this case. - // We do this additional check nevertheless to be 100% sure - return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-collateral"); + // Complain about spent collaterals only when we process the tip. + // This is safe because blocks below the tip were verified + // when they were connected initially. + if (!view.GetBestBlock().IsNull()) { + Coin coin; + CAmount expectedCollateral = GetMnType(proTx.nType).collat_amount; + if (!proTx.collateralOutpoint.hash.IsNull() && (!view.GetCoin(dmn->collateralOutpoint, coin) || + coin.IsSpent() || coin.out.nValue != expectedCollateral)) { + // should actually never get to this point as CheckProRegTx should have handled this case. + // We do this additional check nevertheless to be 100% sure + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-collateral"); + } } auto replacedDmn = newList.GetMNByCollateral(dmn->collateralOutpoint); @@ -262,6 +279,10 @@ bool CSpecialTxProcessor::BuildNewListFromBlock(const CBlock& block, gsl::not_nu if (newList.HasUniqueProperty(*service_opt)) { return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-dup-netinfo-entry"); } + } else if (const auto domain_opt{entry.GetDomainPort()}) { + if (newList.HasUniqueProperty(*domain_opt)) { + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-dup-netinfo-entry"); + } } else { return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-netinfo-entry"); } @@ -298,6 +319,11 @@ bool CSpecialTxProcessor::BuildNewListFromBlock(const CBlock& block, gsl::not_nu newList.GetUniquePropertyMN(*service_opt)->proTxHash != opt_proTx->proTxHash) { return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-dup-netinfo-entry"); } + } else if (const auto domain_opt{entry.GetDomainPort()}) { + if (newList.HasUniqueProperty(*domain_opt) && + newList.GetUniquePropertyMN(*domain_opt)->proTxHash != opt_proTx->proTxHash) { + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-dup-netinfo-entry"); + } } else { return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-netinfo-entry"); } @@ -315,8 +341,8 @@ bool CSpecialTxProcessor::BuildNewListFromBlock(const CBlock& block, gsl::not_nu } auto newState = std::make_shared(*dmn->pdmnState); - if (is_v23_deployed) { - // Extended addresses support in v23 means that the version can be updated + if (is_v24_deployed) { + // Extended addresses support in v24 means that the version can be updated newState->nVersion = opt_proTx->nVersion; } newState->netInfo = opt_proTx->netInfo; @@ -476,7 +502,7 @@ bool CSpecialTxProcessor::BuildNewListFromBlock(const CBlock& block, gsl::not_nu newList.UpdateMN(dmn.proTxHash, newState); }); - mnListRet = std::move(newList); + mnListRet = newList; return true; } diff --git a/src/evo/specialtxman.h b/src/evo/specialtxman.h index 84f74cd06e85..de293d0dfaba 100644 --- a/src/evo/specialtxman.h +++ b/src/evo/specialtxman.h @@ -79,6 +79,12 @@ class CSpecialTxProcessor const CCoinsViewCache& view, bool debugLogs, BlockValidationState& state, CDeterministicMNList& mnListRet) EXCLUSIVE_LOCKS_REQUIRED(cs_main); + // Variant that takes an explicit starting list instead of loading from GetListForBlock + // Used for rebuilding diffs from trusted snapshots + bool RebuildListFromBlock(const CBlock& block, gsl::not_null pindexPrev, + const CDeterministicMNList& prevList, const CCoinsViewCache& view, bool debugLogs, + BlockValidationState& state, CDeterministicMNList& mnListRet); + private: bool CheckCreditPoolDiffForBlock(const CBlock& block, const CBlockIndex* pindex, const CCbTx& cbTx, BlockValidationState& state) EXCLUSIVE_LOCKS_REQUIRED(::cs_main); diff --git a/src/external_signer.cpp b/src/external_signer.cpp new file mode 100644 index 000000000000..9659cc1a06dc --- /dev/null +++ b/src/external_signer.cpp @@ -0,0 +1,117 @@ +// Copyright (c) 2018-2021 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +ExternalSigner::ExternalSigner(const std::string& command, const std::string chain, const std::string& fingerprint, const std::string name): m_command(command), m_chain(chain), m_fingerprint(fingerprint), m_name(name) {} + +std::string ExternalSigner::NetworkArg() const +{ + return " --chain " + m_chain; +} + +bool ExternalSigner::Enumerate(const std::string& command, std::vector& signers, const std::string chain) +{ + // Call enumerate + const UniValue result = RunCommandParseJSON(command + " enumerate"); + if (!result.isArray()) { + throw std::runtime_error(strprintf("'%s' received invalid response, expected array of signers", command)); + } + for (const UniValue& signer : result.getValues()) { + // Check for error + const UniValue& error = signer.find_value("error"); + if (!error.isNull()) { + if (!error.isStr()) { + throw std::runtime_error(strprintf("'%s' error", command)); + } + throw std::runtime_error(strprintf("'%s' error: %s", command, error.getValStr())); + } + // Check if fingerprint is present + const UniValue& fingerprint = signer.find_value("fingerprint"); + if (fingerprint.isNull()) { + throw std::runtime_error(strprintf("'%s' received invalid response, missing signer fingerprint", command)); + } + const std::string& fingerprintStr = fingerprint.get_str(); + // Skip duplicate signer + bool duplicate = false; + for (const ExternalSigner& signer : signers) { + if (signer.m_fingerprint.compare(fingerprintStr) == 0) duplicate = true; + } + if (duplicate) break; + std::string name; + const UniValue& model_field = signer.find_value("model"); + if (model_field.isStr() && model_field.getValStr() != "") { + name += model_field.getValStr(); + } + signers.push_back(ExternalSigner(command, chain, fingerprintStr, name)); + } + return true; +} + +UniValue ExternalSigner::DisplayAddress(const std::string& descriptor) const +{ + return RunCommandParseJSON(m_command + " --fingerprint " + m_fingerprint + NetworkArg() + " displayaddress --desc " + descriptor); +} + +UniValue ExternalSigner::GetDescriptors(const int account) +{ + return RunCommandParseJSON(m_command + " --fingerprint " + m_fingerprint + NetworkArg() + " getdescriptors --account " + strprintf("%d", account)); +} + +bool ExternalSigner::SignTransaction(PartiallySignedTransaction& psbtx, std::string& error) +{ + // Serialize the PSBT + CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); + ssTx << psbtx; + // parse ExternalSigner master fingerprint + std::vector parsed_m_fingerprint = ParseHex(m_fingerprint); + // 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; + } + return false; + }; + + if (!std::any_of(psbtx.inputs.begin(), psbtx.inputs.end(), matches_signer_fingerprint)) { + error = "Signer fingerprint " + m_fingerprint + " does not match any of the inputs:\n" + EncodeBase64(ssTx.str()); + return false; + } + + const std::string command = m_command + " --stdin --fingerprint " + m_fingerprint + NetworkArg(); + const std::string stdinStr = "signtx " + EncodeBase64(ssTx.str()); + + const UniValue signer_result = RunCommandParseJSON(command, stdinStr); + + if (signer_result.find_value("error").isStr()) { + error = signer_result.find_value("error").get_str(); + return false; + } + + if (!signer_result.find_value("psbt").isStr()) { + error = "Unexpected result from signer"; + return false; + } + + PartiallySignedTransaction signer_psbtx; + std::string signer_psbt_error; + if (!DecodeBase64PSBT(signer_psbtx, signer_result.find_value("psbt").get_str(), signer_psbt_error)) { + error = strprintf("TX decode failed %s", signer_psbt_error); + return false; + } + + psbtx = signer_psbtx; + + return true; +} diff --git a/src/external_signer.h b/src/external_signer.h new file mode 100644 index 000000000000..cf301d2780bc --- /dev/null +++ b/src/external_signer.h @@ -0,0 +1,66 @@ +// Copyright (c) 2018-2021 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_EXTERNAL_SIGNER_H +#define BITCOIN_EXTERNAL_SIGNER_H + +#include +#include + +#include +#include + +struct PartiallySignedTransaction; + +//! Enables interaction with an external signing device or service, such as +//! a hardware wallet. See doc/external-signer.md +class ExternalSigner +{ +private: + //! The command which handles interaction with the external signer. + std::string m_command; + + //! Dash mainnet, testnet, etc + std::string m_chain; + + std::string NetworkArg() const; + +public: + //! @param[in] command the command which handles interaction with the external signer + //! @param[in] fingerprint master key fingerprint of the signer + //! @param[in] chain "main", "test", "regtest" or "signet" + //! @param[in] name device name + ExternalSigner(const std::string& command, const std::string chain, const std::string& fingerprint, const std::string name); + + //! Master key fingerprint of the signer + std::string m_fingerprint; + + //! Name of signer + std::string m_name; + + //! Obtain a list of signers. Calls ` enumerate`. + //! @param[in] command the command which handles interaction with the external signer + //! @param[in,out] signers vector to which new signers (with a unique master key fingerprint) are added + //! @param chain "main", "test", "regtest" or "signet" + //! @returns success + static bool Enumerate(const std::string& command, std::vector& signers, const std::string chain); + + //! Display address on the device. Calls ` displayaddress --desc `. + //! @param[in] descriptor Descriptor specifying which address to display. + //! Must include a public key or xpub, as well as key origin. + UniValue DisplayAddress(const std::string& descriptor) const; + + //! Get receive and change Descriptor(s) from device for a given account. + //! Calls ` getdescriptors --account ` + //! @param[in] account which BIP32 account to use (e.g. `m/44'/0'/account'`) + //! @returns see doc/external-signer.md + UniValue GetDescriptors(const int account); + + //! Sign PartiallySignedTransaction on the device. + //! Calls ` signtransaction` and passes the PSBT via stdin. + //! @param[in,out] psbt PartiallySignedTransaction to be signed + bool SignTransaction(PartiallySignedTransaction& psbt, std::string& error); +}; + +#endif // BITCOIN_EXTERNAL_SIGNER_H diff --git a/src/flat-database.h b/src/flat-database.h index 75fd91225ac9..3fd0002e4b27 100644 --- a/src/flat-database.h +++ b/src/flat-database.h @@ -49,9 +49,9 @@ class CFlatDB uint256 hash = Hash(ssObj); ssObj << hash; - // open output file, and associate with CAutoFile + // open output file, and associate with AutoFile FILE *file = fsbridge::fopen(pathDB, "wb"); - CAutoFile fileout(file, SER_DISK, CLIENT_VERSION); + AutoFile fileout{file}; if (fileout.IsNull()) { return error("%s: Failed to open file %s", __func__, fs::PathToString(pathDB)); } @@ -76,9 +76,9 @@ class CFlatDB //LOCK(objToLoad.cs); const auto start{SteadyClock::now()}; - // open input file, and associate with CAutoFile + // open input file, and associate with AutoFile FILE *file = fsbridge::fopen(pathDB, "rb"); - CAutoFile filein(file, SER_DISK, CLIENT_VERSION); + AutoFile filein{file}; if (filein.IsNull()) { // It is not actually error, maybe it's a first initialization of core. return ReadResult::FileError; diff --git a/src/governance/governance.cpp b/src/governance/governance.cpp index 1ff5ddda0e01..108f3690b163 100644 --- a/src/governance/governance.cpp +++ b/src/governance/governance.cpp @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include @@ -24,23 +23,25 @@ #include #include #include +#include #include #include -int nSubmittedFinalBudget; - const std::string GovernanceStore::SERIALIZATION_VERSION_STRING = "CGovernanceManager-Version-16"; -const int CGovernanceManager::MAX_TIME_FUTURE_DEVIATION = 60 * 60; -const int CGovernanceManager::RELIABLE_PROPAGATION_TIME = 60; namespace { +constexpr std::chrono::seconds GOVERNANCE_DELETION_DELAY{10min}; +constexpr std::chrono::seconds GOVERNANCE_ORPHAN_EXPIRATION_TIME{10min}; +constexpr std::chrono::seconds MAX_TIME_FUTURE_DEVIATION{1h}; +constexpr std::chrono::seconds RELIABLE_PROPAGATION_TIME{1min}; + class ScopedLockBool { bool& ref; bool fPrevValue; public: - ScopedLockBool(RecursiveMutex& _cs, bool& _ref, bool _value) : + ScopedLockBool(Mutex& _cs, bool& _ref, bool _value) : ref(_ref) { AssertLockHeld(_cs); @@ -53,10 +54,9 @@ class ScopedLockBool } // anonymous namespace GovernanceStore::GovernanceStore() : - cs(), + cs_store(), mapObjects(), mapErasedGovernanceObjects(), - cmapVoteToObject(MAX_CACHE_SIZE), cmapInvalidVotes(MAX_CACHE_SIZE), cmmapOrphanVotes(MAX_CACHE_SIZE), mapLastMasternodeObject(), @@ -73,10 +73,8 @@ CGovernanceManager::CGovernanceManager(CMasternodeMetaMan& mn_metaman, CNetFulfi m_chainman{chainman}, m_dmnman{dmnman}, m_mn_sync{mn_sync}, - nTimeLastDiff(0), - nCachedBlockHeight(0), - fRateChecksEnabled(true), - votedFundingYesTriggerHash(std::nullopt), + cmapVoteToObject{MAX_CACHE_SIZE}, + mapPostponedObjects{}, mapTrigger{} { } @@ -87,8 +85,41 @@ CGovernanceManager::~CGovernanceManager() m_db->Store(*this); } +void CGovernanceManager::Schedule(CScheduler& scheduler, CConnman& connman, PeerManager& peerman) +{ + AssertLockNotHeld(cs_store); + AssertLockNotHeld(cs_relay); + + assert(IsValid()); + + scheduler.scheduleEvery( + [this, &connman]() -> void { + if (!m_mn_sync.IsSynced()) return; + + // CHECK OBJECTS WE'VE ASKED FOR, REMOVE OLD ENTRIES + CleanOrphanObjects(); + RequestOrphanObjects(connman); + + // CHECK AND REMOVE - REPROCESS GOVERNANCE OBJECTS + CheckAndRemove(); + }, + std::chrono::minutes{5}); + + scheduler.scheduleEvery( + [this, &peerman]() -> void { + LOCK(cs_relay); + for (const auto& inv : m_relay_invs) { + peerman.RelayInv(inv); + } + m_relay_invs.clear(); + }, + // Tests need tighter timings to avoid timeouts, use more relaxed pacing otherwise + Params().IsMockableChain() ? std::chrono::seconds{1} : std::chrono::seconds{5}); +} + bool CGovernanceManager::LoadCache(bool load_cache) { + AssertLockNotHeld(cs_store); assert(m_db != nullptr); is_valid = load_cache ? m_db->Load(*this) : m_db->Store(*this); if (is_valid && load_cache) { @@ -98,16 +129,46 @@ bool CGovernanceManager::LoadCache(bool load_cache) return is_valid; } +void CGovernanceManager::RelayObject(const CGovernanceObject& obj) +{ + AssertLockNotHeld(cs_relay); + if (!m_mn_sync.IsSynced()) { + LogPrint(BCLog::GOBJECT, "%s -- won't relay until fully synced\n", __func__); + return; + } + + LOCK(cs_relay); + m_relay_invs.emplace_back(MSG_GOVERNANCE_OBJECT, obj.GetHash()); +} + +void CGovernanceManager::RelayVote(const CGovernanceVote& vote) +{ + AssertLockNotHeld(cs_relay); + if (!m_mn_sync.IsSynced()) { + LogPrint(BCLog::GOBJECT, "%s -- won't relay until fully synced\n", __func__); + return; + } + + const auto tip_mn_list = Assert(m_dmnman)->GetListAtChainTip(); + auto dmn = tip_mn_list.GetMNByCollateral(vote.GetMasternodeOutpoint()); + if (!dmn) { + return; + } + + LOCK(cs_relay); + m_relay_invs.emplace_back(MSG_GOVERNANCE_OBJECT_VOTE, vote.GetHash()); +} + // Accessors for thread-safe access to maps bool CGovernanceManager::HaveObjectForHash(const uint256& nHash) const { - LOCK(cs); + LOCK(cs_store); return (mapObjects.count(nHash) == 1 || mapPostponedObjects.count(nHash) == 1); } bool CGovernanceManager::SerializeObjectForHash(const uint256& nHash, CDataStream& ss) const { - LOCK(cs); + LOCK(cs_store); auto it = mapObjects.find(nHash); if (it == mapObjects.end()) { it = mapPostponedObjects.find(nHash); @@ -120,28 +181,43 @@ bool CGovernanceManager::SerializeObjectForHash(const uint256& nHash, CDataStrea bool CGovernanceManager::HaveVoteForHash(const uint256& nHash) const { - LOCK(cs); + LOCK(cs_store); - CGovernanceObject* pGovobj = nullptr; - return cmapVoteToObject.Get(nHash, pGovobj) && pGovobj->GetVoteFile().HasVote(nHash); + std::shared_ptr pGovobj{nullptr}; + return cmapVoteToObject.Get(nHash, pGovobj) && WITH_LOCK(pGovobj->cs, return pGovobj->GetVoteFile().HasVote(nHash)); } int CGovernanceManager::GetVoteCount() const { - LOCK(cs); + LOCK(cs_store); return (int)cmapVoteToObject.GetSize(); } bool CGovernanceManager::SerializeVoteForHash(const uint256& nHash, CDataStream& ss) const { - LOCK(cs); + LOCK(cs_store); + + std::shared_ptr pGovobj{nullptr}; + return cmapVoteToObject.Get(nHash, pGovobj) && WITH_LOCK(pGovobj->cs, return pGovobj->GetVoteFile().SerializeVoteToStream(nHash, ss)); +} - CGovernanceObject* pGovobj = nullptr; - return cmapVoteToObject.Get(nHash, pGovobj) && pGovobj->GetVoteFile().SerializeVoteToStream(nHash, ss); +void CGovernanceManager::AddPostponedObject(const CGovernanceObject& govobj) +{ + LOCK(cs_store); + AddPostponedObjectInternal(govobj); +} + +void CGovernanceManager::AddPostponedObjectInternal(const CGovernanceObject& govobj) +{ + AssertLockHeld(cs_store); + mapPostponedObjects.emplace(govobj.GetHash(), std::make_shared(govobj)); } -MessageProcessingResult CGovernanceManager::ProcessMessage(CNode& peer, CConnman& connman, PeerManager& peerman, std::string_view msg_type, CDataStream& vRecv) +MessageProcessingResult CGovernanceManager::ProcessMessage(CNode& peer, CConnman& connman, std::string_view msg_type, + CDataStream& vRecv) { + AssertLockNotHeld(cs_store); + AssertLockNotHeld(cs_relay); if (!IsValid()) return {}; if (!m_mn_sync.IsBlockchainSynced()) return {}; @@ -159,6 +235,7 @@ MessageProcessingResult CGovernanceManager::ProcessMessage(CNode& peer, CConnman vRecv >> filter; LogPrint(BCLog::GOBJECT, "MNGOVERNANCESYNC -- syncing governance objects to our peer %s\n", peer.GetLogString()); + LOCK(cs_store); if (nProp == uint256()) { return SyncObjects(peer, connman); } else { @@ -194,7 +271,7 @@ MessageProcessingResult CGovernanceManager::ProcessMessage(CNode& peer, CConnman return ret; } - LOCK2(::cs_main, cs); + LOCK2(::cs_main, cs_store); if (mapObjects.count(nHash) || mapPostponedObjects.count(nHash) || mapErasedGovernanceObjects.count(nHash)) { // TODO - print error code? what if it's GOVOBJ_ERROR_IMMATURE? @@ -214,14 +291,15 @@ MessageProcessingResult CGovernanceManager::ProcessMessage(CNode& peer, CConnman bool fMissingConfirmations = false; bool fIsValid = govobj.IsValidLocally(tip_mn_list, m_chainman, strError, fMissingConfirmations, true); - if (fRateCheckBypassed && fIsValid && !MasternodeRateCheck(govobj, true)) { + bool unused_rcb; + if (fRateCheckBypassed && fIsValid && !MasternodeRateCheck(govobj, true, true, unused_rcb)) { LogPrint(BCLog::GOBJECT, "MNGOVERNANCEOBJECT -- masternode rate check failed (after signature verification) - %s - (current block height %d)\n", strHash, nCachedBlockHeight); return ret; } if (!fIsValid) { if (fMissingConfirmations) { - AddPostponedObject(govobj); + AddPostponedObjectInternal(govobj); LogPrintf("MNGOVERNANCEOBJECT -- Not enough fee confirmations for: %s, strError = %s\n", strHash, strError); } else { LogPrint(BCLog::GOBJECT, "MNGOVERNANCEOBJECT -- Governance object is invalid - %s\n", strError); @@ -233,7 +311,7 @@ MessageProcessingResult CGovernanceManager::ProcessMessage(CNode& peer, CConnman return ret; } - AddGovernanceObject(govobj, peerman, &peer); + AddGovernanceObjectInternal(govobj, &peer); return ret; } @@ -267,7 +345,7 @@ MessageProcessingResult CGovernanceManager::ProcessMessage(CNode& peer, CConnman if (ProcessVote(&peer, vote, exception, connman)) { LogPrint(BCLog::GOBJECT, "MNGOVERNANCEOBJECTVOTE -- %s new\n", strHash); m_mn_sync.BumpAssetLastTime("MNGOVERNANCEOBJECTVOTE"); - vote.Relay(peerman, m_mn_sync, tip_mn_list); + RelayVote(vote); } else { LogPrint(BCLog::GOBJECT, "MNGOVERNANCEOBJECTVOTE -- Rejected vote, error = %s\n", exception.what()); if ((exception.GetNodePenalty() != 0) && m_mn_sync.IsSynced()) { @@ -282,24 +360,27 @@ MessageProcessingResult CGovernanceManager::ProcessMessage(CNode& peer, CConnman return {}; } -void CGovernanceManager::CheckOrphanVotes(CGovernanceObject& govobj, PeerManager& peerman) +void CGovernanceManager::CheckOrphanVotes(CGovernanceObject& govobj) { + AssertLockHeld(cs_store); + AssertLockNotHeld(cs_relay); + uint256 nHash = govobj.GetHash(); std::vector vecVotePairs; cmmapOrphanVotes.GetAll(nHash, vecVotePairs); - ScopedLockBool guard(cs, fRateChecksEnabled, false); + ScopedLockBool guard(cs_store, fRateChecksEnabled, false); int64_t nNow = GetAdjustedTime(); const auto tip_mn_list = Assert(m_dmnman)->GetListAtChainTip(); for (const auto& pairVote : vecVotePairs) { + const auto& [vote, time] = pairVote; bool fRemove = false; - const CGovernanceVote& vote = pairVote.first; CGovernanceException e; - if (pairVote.second < nNow) { + if (time < nNow) { fRemove = true; } else if (govobj.ProcessVote(m_mn_metaman, *this, tip_mn_list, vote, e)) { - vote.Relay(peerman, m_mn_sync, tip_mn_list); + RelayVote(vote); fRemove = true; } if (fRemove) { @@ -308,68 +389,79 @@ void CGovernanceManager::CheckOrphanVotes(CGovernanceObject& govobj, PeerManager } } -void CGovernanceManager::AddGovernanceObject(CGovernanceObject& govobj, PeerManager& peerman, const CNode* pfrom) +void CGovernanceManager::AddGovernanceObjectInternal(CGovernanceObject& insert_obj, const CNode* pfrom) { - uint256 nHash = govobj.GetHash(); + AssertLockHeld(::cs_main); + AssertLockHeld(cs_store); + AssertLockNotHeld(cs_relay); + + uint256 nHash = insert_obj.GetHash(); std::string strHash = nHash.ToString(); const auto tip_mn_list = Assert(m_dmnman)->GetListAtChainTip(); // UPDATE CACHED VARIABLES FOR THIS OBJECT AND ADD IT TO OUR MANAGED DATA - govobj.UpdateSentinelVariables(tip_mn_list); //this sets local vars in object + insert_obj.UpdateSentinelVariables(tip_mn_list); //this sets local vars in object - LOCK2(::cs_main, cs); std::string strError; // MAKE SURE THIS OBJECT IS OK - if (!govobj.IsValidLocally(tip_mn_list, m_chainman, strError, true)) { + if (!insert_obj.IsValidLocally(tip_mn_list, m_chainman, strError, true)) { LogPrint(BCLog::GOBJECT, "CGovernanceManager::AddGovernanceObject -- invalid governance object - %s - (nCachedBlockHeight %d) \n", strError, nCachedBlockHeight); return; } LogPrint(BCLog::GOBJECT, "CGovernanceManager::AddGovernanceObject -- Adding object: hash = %s, type = %d\n", nHash.ToString(), - ToUnderlying(govobj.GetObjectType())); + ToUnderlying(insert_obj.GetObjectType())); // INSERT INTO OUR GOVERNANCE OBJECT MEMORY // IF WE HAVE THIS OBJECT ALREADY, WE DON'T WANT ANOTHER COPY - auto objpair = mapObjects.emplace(nHash, govobj); + auto [emplace_ret, emplace_status] = mapObjects.emplace(nHash, std::make_shared(insert_obj)); - if (!objpair.second) { + if (!emplace_status) { LogPrint(BCLog::GOBJECT, "CGovernanceManager::AddGovernanceObject -- already have governance object %s\n", nHash.ToString()); return; } // SHOULD WE ADD THIS OBJECT TO ANY OTHER MANAGERS? + auto& [_, govobj] = *emplace_ret; LogPrint(BCLog::GOBJECT, "CGovernanceManager::AddGovernanceObject -- Before trigger block, GetDataAsPlainString = %s, nObjectType = %d\n", - govobj.GetDataAsPlainString(), ToUnderlying(govobj.GetObjectType())); + Assert(govobj)->GetDataAsPlainString(), ToUnderlying(govobj->GetObjectType())); - if (govobj.GetObjectType() == GovernanceObject::TRIGGER && !AddNewTrigger(nHash)) { + if (govobj->GetObjectType() == GovernanceObject::TRIGGER && !AddNewTrigger(nHash)) { LogPrint(BCLog::GOBJECT, "CGovernanceManager::AddGovernanceObject -- undo adding invalid trigger object: hash = %s\n", nHash.ToString()); - objpair.first->second.PrepareDeletion(GetTime().count()); + govobj->PrepareDeletion(GetTime().count()); return; } LogPrint(BCLog::GOBJECT, "CGovernanceManager::AddGovernanceObject -- %s new, received from peer %s\n", strHash, pfrom ? pfrom->GetLogString() : "nullptr"); - govobj.Relay(peerman, m_mn_sync); + RelayObject(*govobj); // Update the rate buffer - MasternodeRateUpdate(govobj); + MasternodeRateUpdate(*govobj); m_mn_sync.BumpAssetLastTime("CGovernanceManager::AddGovernanceObject"); // WE MIGHT HAVE PENDING/ORPHAN VOTES FOR THIS OBJECT - CheckOrphanVotes(govobj, peerman); + CheckOrphanVotes(*govobj); // SEND NOTIFICATION TO SCRIPT/ZMQ - GetMainSignals().NotifyGovernanceObject(std::make_shared(govobj.Object()), nHash.ToString()); + GetMainSignals().NotifyGovernanceObject(std::make_shared(govobj->Object()), nHash.ToString()); +} + +void CGovernanceManager::AddGovernanceObject(CGovernanceObject& govobj, const CNode* pfrom) +{ + LOCK2(::cs_main, cs_store); + AddGovernanceObjectInternal(govobj, pfrom); } void CGovernanceManager::CheckAndRemove() { + AssertLockNotHeld(cs_store); assert(m_mn_metaman.IsValid()); // Return on initial sync, spammed the debug.log and provided no use @@ -381,32 +473,29 @@ void CGovernanceManager::CheckAndRemove() const auto tip_mn_list = Assert(m_dmnman)->GetListAtChainTip(); - LOCK2(::cs_main, cs); + { + LOCK2(::cs_main, cs_store); for (const uint256& nHash : vecDirtyHashes) { auto it = mapObjects.find(nHash); if (it == mapObjects.end()) { continue; } - it->second.ClearMasternodeVotes(tip_mn_list); + Assert(it->second)->ClearMasternodeVotes(tip_mn_list); } - ScopedLockBool guard(cs, fRateChecksEnabled, false); + ScopedLockBool guard(cs_store, fRateChecksEnabled, false); // Clean up any expired or invalid triggers CleanAndRemoveTriggers(); - auto it = mapObjects.begin(); - int64_t nNow = GetTime().count(); - - while (it != mapObjects.end()) { - CGovernanceObject* pObj = &((*it).second); - - uint256 nHash = it->first; + const auto nNow = GetTime(); + for (auto it = mapObjects.begin(); it != mapObjects.end();) { + auto [nHash, pObj] = *it; std::string strHash = nHash.ToString(); // IF CACHE IS NOT DIRTY, WHY DO THIS? - if (pObj->IsSetDirtyCache()) { + if (Assert(pObj)->IsSetDirtyCache()) { // UPDATE LOCAL VALIDITY AGAINST CRYPTO DATA pObj->UpdateLocalValidity(tip_mn_list, m_chainman); @@ -416,20 +505,19 @@ void CGovernanceManager::CheckAndRemove() // IF DELETE=TRUE, THEN CLEAN THE MESS UP! - int64_t nTimeSinceDeletion = nNow - pObj->GetDeletionTime(); + const auto nTimeSinceDeletion = nNow - std::chrono::seconds{pObj->GetDeletionTime()}; LogPrint(BCLog::GOBJECT, "CGovernanceManager::UpdateCachesAndClean -- Checking object for deletion: %s, deletion time = %d, time since deletion = %d, delete flag = %d, expired flag = %d\n", - strHash, pObj->GetDeletionTime(), nTimeSinceDeletion, pObj->IsSetCachedDelete(), pObj->IsSetExpired()); + strHash, pObj->GetDeletionTime(), nTimeSinceDeletion.count(), pObj->IsSetCachedDelete(), pObj->IsSetExpired()); if ((pObj->IsSetCachedDelete() || pObj->IsSetExpired()) && (nTimeSinceDeletion >= GOVERNANCE_DELETION_DELAY)) { - LogPrint(BCLog::GOBJECT, "CGovernanceManager::UpdateCachesAndClean -- erase obj %s\n", (*it).first.ToString()); + LogPrint(BCLog::GOBJECT, "CGovernanceManager::UpdateCachesAndClean -- erase obj %s\n", nHash.ToString()); m_mn_metaman.RemoveGovernanceObject(pObj->GetHash()); // Remove vote references const object_ref_cm_t::list_t& listItems = cmapVoteToObject.GetItemList(); - auto lit = listItems.begin(); - while (lit != listItems.end()) { + for (auto lit = listItems.begin(); lit != listItems.end();) { if (lit->value == pObj) { uint256 nKey = lit->key; ++lit; @@ -446,7 +534,9 @@ void CGovernanceManager::CheckAndRemove() nTimeExpired = std::numeric_limits::max(); } else { int64_t nSuperblockCycleSeconds = Params().GetConsensus().nSuperblockCycle * Params().GetConsensus().nPowTargetSpacing; - nTimeExpired = pObj->GetCreationTime() + 2 * nSuperblockCycleSeconds + GOVERNANCE_DELETION_DELAY; + nTimeExpired = (std::chrono::seconds{pObj->GetCreationTime()} + + std::chrono::seconds{2 * nSuperblockCycleSeconds} + GOVERNANCE_DELETION_DELAY) + .count(); } mapErasedGovernanceObjects.insert(std::make_pair(nHash, nTimeExpired)); @@ -456,7 +546,7 @@ void CGovernanceManager::CheckAndRemove() CProposalValidator validator(pObj->GetDataAsHexString()); if (!validator.Validate()) { LogPrint(BCLog::GOBJECT, "CGovernanceManager::UpdateCachesAndClean -- set for deletion expired obj %s\n", strHash); - pObj->PrepareDeletion(nNow); + pObj->PrepareDeletion(nNow.count()); } } ++it; @@ -464,9 +554,8 @@ void CGovernanceManager::CheckAndRemove() } // forget about expired deleted objects - auto s_it = mapErasedGovernanceObjects.begin(); - while (s_it != mapErasedGovernanceObjects.end()) { - if (s_it->second < nNow) { + for (auto s_it = mapErasedGovernanceObjects.begin(); s_it != mapErasedGovernanceObjects.end();) { + if (s_it->second < nNow.count()) { mapErasedGovernanceObjects.erase(s_it++); } else { ++s_it; @@ -474,67 +563,68 @@ void CGovernanceManager::CheckAndRemove() } // forget about expired requests - auto r_it = m_requested_hash_time.begin(); - while (r_it != m_requested_hash_time.end()) { - if (r_it->second < std::chrono::seconds(nNow)) { + for (auto r_it = m_requested_hash_time.begin(); r_it != m_requested_hash_time.end();) { + if (r_it->second < nNow) { m_requested_hash_time.erase(r_it++); } else { ++r_it; } } + } LogPrint(BCLog::GOBJECT, "CGovernanceManager::UpdateCachesAndClean -- %s, m_requested_hash_time size=%d\n", ToString(), m_requested_hash_time.size()); } -const CGovernanceObject* CGovernanceManager::FindConstGovernanceObject(const uint256& nHash) const +std::shared_ptr CGovernanceManager::FindConstGovernanceObject(const uint256& nHash) const { - AssertLockHeld(cs); - - auto it = mapObjects.find(nHash); - if (it != mapObjects.end()) return &(it->second); - - return nullptr; + LOCK(cs_store); + return FindConstGovernanceObjectInternal(nHash); } -CGovernanceObject* CGovernanceManager::FindGovernanceObject(const uint256& nHash) +std::shared_ptr CGovernanceManager::FindConstGovernanceObjectInternal(const uint256& nHash) const { - AssertLockHeld(cs); + AssertLockHeld(cs_store); - if (mapObjects.count(nHash)) return &mapObjects[nHash]; + auto it = mapObjects.find(nHash); + if (it != mapObjects.end()) return (it->second); return nullptr; } -CGovernanceObject* CGovernanceManager::FindGovernanceObjectByDataHash(const uint256 &nDataHash) +std::shared_ptr CGovernanceManager::FindGovernanceObject(const uint256& nHash) { - AssertLockHeld(cs); - - for (const auto& [nHash, object] : mapObjects) { - if (object.GetDataHash() == nDataHash) return &mapObjects[nHash]; - } + AssertLockNotHeld(cs_store); + LOCK(cs_store); + return FindGovernanceObjectInternal(nHash); +} +std::shared_ptr CGovernanceManager::FindGovernanceObjectInternal(const uint256& nHash) +{ + AssertLockHeld(cs_store); + if (mapObjects.count(nHash)) return mapObjects[nHash]; return nullptr; } -void CGovernanceManager::DeleteGovernanceObject(const uint256& nHash) +std::shared_ptr CGovernanceManager::FindGovernanceObjectByDataHash(const uint256 &nDataHash) { - LOCK(cs); - - if (mapObjects.count(nHash)) { - mapObjects.erase(nHash); + AssertLockNotHeld(cs_store); + LOCK(cs_store); + for (const auto& [nHash, govobj] : mapObjects) { + if (Assert(govobj)->GetDataHash() == nDataHash) return govobj; } + return nullptr; } std::vector CGovernanceManager::GetCurrentVotes(const uint256& nParentHash, const COutPoint& mnCollateralOutpointFilter) const { - LOCK(cs); + LOCK(cs_store); std::vector vecResult; // Find the governance object or short-circuit. auto it = mapObjects.find(nParentHash); if (it == mapObjects.end()) return vecResult; - const CGovernanceObject& govobj = it->second; + const auto& govobj = *Assert(it->second); const auto tip_mn_list = Assert(m_dmnman)->GetListAtChainTip(); std::map mapMasternodes; @@ -550,13 +640,13 @@ std::vector CGovernanceManager::GetCurrentVotes(const uint256& } // Loop through each MN collateral outpoint and get the votes for the `nParentHash` governance object - for (const auto& mnpair : mapMasternodes) { + for (const auto& [outpoint, _] : mapMasternodes) { // get a vote_rec_t from the govobj vote_rec_t voteRecord; - if (!govobj.GetCurrentMNVotes(mnpair.first, voteRecord)) continue; + if (!govobj.GetCurrentMNVotes(outpoint, voteRecord)) continue; for (const auto& [signal, vote_instance] : voteRecord.mapInstances) { - CGovernanceVote vote = CGovernanceVote(mnpair.first, nParentHash, (vote_signal_enum_t)signal, + CGovernanceVote vote = CGovernanceVote(outpoint, nParentHash, (vote_signal_enum_t)signal, vote_instance.eOutcome); vote.SetTime(vote_instance.nCreationTime); vecResult.push_back(vote); @@ -568,320 +658,27 @@ std::vector CGovernanceManager::GetCurrentVotes(const uint256& void CGovernanceManager::GetAllNewerThan(std::vector& objs, int64_t nMoreThanTime) const { - LOCK(cs); + LOCK(cs_store); - for (const auto& objPair : mapObjects) { + for (const auto& [_, govobj] : mapObjects) { // IF THIS OBJECT IS OLDER THAN TIME, CONTINUE - if (objPair.second.GetCreationTime() < nMoreThanTime) { + if (Assert(govobj)->GetCreationTime() < nMoreThanTime) { continue; } // ADD GOVERNANCE OBJECT TO LIST - objs.push_back(objPair.second); - } -} - -// -// Sort by votes, if there's a tie sort by their feeHash TX -// -struct sortProposalsByVotes { - bool operator()(const std::pair& left, const std::pair& right) const - { - if (left.second != right.second) return (left.second > right.second); - return (UintToArith256(left.first->GetCollateralHash()) > UintToArith256(right.first->GetCollateralHash())); - } -}; - -std::optional CGovernanceManager::CreateSuperblockCandidate(int nHeight) const -{ - if (!IsValid()) return std::nullopt; - if (!m_mn_sync.IsSynced()) return std::nullopt; - if (nHeight % Params().GetConsensus().nSuperblockCycle < Params().GetConsensus().nSuperblockCycle - Params().GetConsensus().nSuperblockMaturityWindow) return std::nullopt; - if (HasAlreadyVotedFundingTrigger()) return std::nullopt; - - // A proposal is considered passing if (YES votes) >= (Total Weight of Masternodes / 10), - // count total valid (ENABLED) masternodes to determine passing threshold. - const auto tip_mn_list = Assert(m_dmnman)->GetListAtChainTip(); - const int nWeightedMnCount = tip_mn_list.GetValidWeightedMNsCount(); - const int nAbsVoteReq = std::max(Params().GetConsensus().nGovernanceMinQuorum, nWeightedMnCount / 10); - - // Use std::vector of std::shared_ptr because CGovernanceObject doesn't support move operations (needed for sorting the vector later) - std::vector> approvedProposals; - - { - LOCK(cs); - for (const auto& [unused, object] : mapObjects) { - // Skip all non-proposals objects - if (object.GetObjectType() != GovernanceObject::PROPOSAL) continue; - - const int absYesCount = object.GetAbsoluteYesCount(tip_mn_list, VOTE_SIGNAL_FUNDING); - // Skip non-passing proposals - if (absYesCount < nAbsVoteReq) continue; - - approvedProposals.emplace_back(std::make_shared(object)); - } - } // cs - - // Sort approved proposals by absolute Yes votes descending - std::sort(approvedProposals.begin(), approvedProposals.end(), [tip_mn_list](std::shared_ptr a, std::shared_ptr b) { - const auto a_yes = a->GetAbsoluteYesCount(tip_mn_list, VOTE_SIGNAL_FUNDING); - const auto b_yes = b->GetAbsoluteYesCount(tip_mn_list, VOTE_SIGNAL_FUNDING); - return a_yes == b_yes ? UintToArith256(a->GetHash()) > UintToArith256(b->GetHash()) : a_yes > b_yes; - }); - - if (approvedProposals.empty()) { - LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s nHeight:%d empty approvedProposals\n", __func__, nHeight); - return std::nullopt; - } - - std::vector payments; - int nLastSuperblock; - int nNextSuperblock; - - CSuperblock::GetNearestSuperblocksHeights(nHeight, nLastSuperblock, nNextSuperblock); - auto SBEpochTime = static_cast(GetTime().count() + (nNextSuperblock - nHeight) * 2.62 * 60); - auto governanceBudget = CSuperblock::GetPaymentsLimit(m_chainman.ActiveChain(), nNextSuperblock); - - CAmount budgetAllocated{}; - for (const auto& proposal : approvedProposals) { - // Extract payment address and amount from proposal - UniValue jproposal = proposal->GetJSONObject(); - - CTxDestination dest = DecodeDestination(jproposal["payment_address"].getValStr()); - if (!IsValidDestination(dest)) continue; - - CAmount nAmount{}; - try { - nAmount = ParsePaymentAmount(jproposal["payment_amount"].getValStr()); - } - catch (const std::runtime_error& e) { - LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s nHeight:%d Skipping payment exception:%s\n", __func__,nHeight, e.what()); - continue; - } - - // Construct CGovernancePayment object and make sure it is valid - CGovernancePayment payment(dest, nAmount, proposal->GetHash()); - if (!payment.IsValid()) continue; - - // Skip proposals that are too expensive - if (budgetAllocated + payment.nAmount > governanceBudget) continue; - - int64_t windowStart = jproposal["start_epoch"].getInt() - GOVERNANCE_FUDGE_WINDOW; - int64_t windowEnd = jproposal["end_epoch"].getInt() + GOVERNANCE_FUDGE_WINDOW; - - // Skip proposals if the SB isn't within the proposal time window - if (SBEpochTime < windowStart) { - LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s nHeight:%d SB:%d windowStart:%d\n", __func__,nHeight, SBEpochTime, windowStart); - continue; - } - if (SBEpochTime > windowEnd) { - LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s nHeight:%d SB:%d windowEnd:%d\n", __func__,nHeight, SBEpochTime, windowEnd); - continue; - } - - // Keep track of total budget allocation - budgetAllocated += payment.nAmount; - - // Add the payment - payments.push_back(payment); + objs.push_back(*govobj); } - - // No proposals made the cut - if (payments.empty()) { - LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s CreateSuperblockCandidate nHeight:%d empty payments\n", __func__, nHeight); - return std::nullopt; - } - - // Sort by proposal hash descending - std::sort(payments.begin(), payments.end(), [](const CGovernancePayment& a, const CGovernancePayment& b) { - return UintToArith256(a.proposalHash) > UintToArith256(b.proposalHash); - }); - - // Create Superblock - return CSuperblock(nNextSuperblock, std::move(payments)); -} - -std::optional CGovernanceManager::CreateGovernanceTrigger(const std::optional& sb_opt, PeerManager& peerman, - const CActiveMasternodeManager& mn_activeman) -{ - // no sb_opt, no trigger - if (!sb_opt.has_value()) return std::nullopt; - - //TODO: Check if nHashParentIn, nRevision and nCollateralHashIn are correct - LOCK2(::cs_main, cs); - - // Check if identical trigger (equal DataHash()) is already created (signed by other masternode) - CGovernanceObject gov_sb(uint256(), 1, GetAdjustedTime(), uint256(), sb_opt.value().GetHexStrData()); - if (auto identical_sb = FindGovernanceObjectByDataHash(gov_sb.GetDataHash())) { - // Somebody submitted a trigger with the same data, support it instead of submitting a duplicate - return std::make_optional(*identical_sb); - } - - // Nobody submitted a trigger we'd like to see, so let's do it but only if we are the payee - const CBlockIndex *tip = WITH_LOCK(::cs_main, return m_chainman.ActiveChain().Tip()); - const auto mnList = Assert(m_dmnman)->GetListForBlock(tip); - const auto mn_payees = mnList.GetProjectedMNPayees(tip); - - if (mn_payees.empty()) { - LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s payee list is empty\n", __func__); - return std::nullopt; - } - - if (mn_payees.front()->proTxHash != mn_activeman.GetProTxHash()) { - LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s we are not the payee, skipping\n", __func__); - return std::nullopt; - } - gov_sb.SetMasternodeOutpoint(mn_activeman.GetOutPoint()); - gov_sb.Sign(mn_activeman); - - if (std::string strError; !gov_sb.IsValidLocally(m_dmnman->GetListAtChainTip(), m_chainman, strError, true)) { - LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s Created trigger is invalid:%s\n", __func__, strError); - return std::nullopt; - } - - if (!MasternodeRateCheck(gov_sb)) { - LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s Trigger rejected because of rate check failure hash(%s)\n", __func__, gov_sb.GetHash().ToString()); - return std::nullopt; - } - - // The trigger we just created looks good, submit it - AddGovernanceObject(gov_sb, peerman); - return std::make_optional(gov_sb); -} - -void CGovernanceManager::VoteGovernanceTriggers(const std::optional& trigger_opt, CConnman& connman, PeerManager& peerman, - const CActiveMasternodeManager& mn_activeman) -{ - // only active masternodes can vote on triggers - if (mn_activeman.GetProTxHash().IsNull()) return; - - LOCK2(::cs_main, cs); - - if (trigger_opt.has_value()) { - // We should never vote "yes" on another trigger or the same trigger twice - assert(!votedFundingYesTriggerHash.has_value()); - // Vote YES-FUNDING for the trigger we like, unless we already did - const uint256 gov_sb_hash = trigger_opt.value().GetHash(); - bool voted_already{false}; - if (vote_rec_t voteRecord; trigger_opt.value().GetCurrentMNVotes(mn_activeman.GetOutPoint(), voteRecord)) { - const auto& strFunc = __func__; - // Let's see if there is a VOTE_SIGNAL_FUNDING vote from us already - voted_already = ranges::any_of(voteRecord.mapInstances, [&](const auto& voteInstancePair) { - if (voteInstancePair.first == VOTE_SIGNAL_FUNDING) { - if (voteInstancePair.second.eOutcome == VOTE_OUTCOME_YES) { - votedFundingYesTriggerHash = gov_sb_hash; - } - LogPrint(BCLog::GOBJECT, /* Continued */ - "CGovernanceManager::%s " - "Not voting YES-FUNDING for trigger:%s, we voted %s for it already\n", - strFunc, gov_sb_hash.ToString(), - CGovernanceVoting::ConvertOutcomeToString(voteInstancePair.second.eOutcome)); - return true; - } - return false; - }); - } - if (!voted_already) { - // No previous VOTE_SIGNAL_FUNDING was found, vote now - if (VoteFundingTrigger(gov_sb_hash, VOTE_OUTCOME_YES, connman, peerman, mn_activeman)) { - LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s Voting YES-FUNDING for new trigger:%s success\n", - __func__, gov_sb_hash.ToString()); - votedFundingYesTriggerHash = gov_sb_hash; - } else { - LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s Voting YES-FUNDING for new trigger:%s failed\n", - __func__, gov_sb_hash.ToString()); - // this should never happen, bail out - return; - } - } - } - - // Vote NO-FUNDING for the rest of the active triggers - const auto activeTriggers = GetActiveTriggers(); - for (const auto& trigger : activeTriggers) { - const auto govobj = FindGovernanceObject(trigger->GetGovernanceObjHash()); - const uint256 trigger_hash = govobj->GetHash(); - if (trigger->GetBlockHeight() <= nCachedBlockHeight) { - // ignore triggers from the past - LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s Not voting NO-FUNDING for outdated trigger:%s\n", __func__, trigger_hash.ToString()); - continue; - } - if (trigger_hash == votedFundingYesTriggerHash) { - // Skip actual trigger - LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s Not voting NO-FUNDING for trigger:%s, we voted yes for it already\n", __func__, trigger_hash.ToString()); - continue; - } - if (vote_rec_t voteRecord; govobj->GetCurrentMNVotes(mn_activeman.GetOutPoint(), voteRecord)) { - const auto& strFunc = __func__; - if (ranges::any_of(voteRecord.mapInstances, [&](const auto& voteInstancePair) { - if (voteInstancePair.first == VOTE_SIGNAL_FUNDING) { - LogPrint(BCLog::GOBJECT, /* Continued */ - "CGovernanceManager::%s " - "Not voting NO-FUNDING for trigger:%s, we voted %s for it already\n", - strFunc, trigger_hash.ToString(), - CGovernanceVoting::ConvertOutcomeToString(voteInstancePair.second.eOutcome)); - return true; - } - return false; - })) { - continue; - } - } - if (!VoteFundingTrigger(trigger_hash, VOTE_OUTCOME_NO, connman, peerman, mn_activeman)) { - LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s Voting NO-FUNDING for trigger:%s failed\n", __func__, trigger_hash.ToString()); - // failing here is ok-ish - continue; - } - LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s Voting NO-FUNDING for trigger:%s success\n", __func__, trigger_hash.ToString()); - } -} - -bool CGovernanceManager::VoteFundingTrigger(const uint256& nHash, const vote_outcome_enum_t outcome, CConnman& connman, PeerManager& peerman, - const CActiveMasternodeManager& mn_activeman) -{ - CGovernanceVote vote(mn_activeman.GetOutPoint(), nHash, VOTE_SIGNAL_FUNDING, outcome); - vote.SetTime(GetAdjustedTime()); - vote.Sign(mn_activeman); - - CGovernanceException exception; - if (!ProcessVoteAndRelay(vote, exception, connman, peerman)) { - LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s Vote FUNDING %d for trigger:%s failed:%s\n", __func__, outcome, nHash.ToString(), exception.what()); - return false; - } - - return true; -} - -bool CGovernanceManager::HasAlreadyVotedFundingTrigger() const -{ - return votedFundingYesTriggerHash.has_value(); -} - -void CGovernanceManager::ResetVotedFundingTrigger() -{ - votedFundingYesTriggerHash = std::nullopt; -} - -void CGovernanceManager::DoMaintenance(CConnman& connman) -{ - if (!IsValid()) return; - if (!m_mn_sync.IsSynced()) return; - if (ShutdownRequested()) return; - - // CHECK OBJECTS WE'VE ASKED FOR, REMOVE OLD ENTRIES - CleanOrphanObjects(); - RequestOrphanObjects(connman); - - // CHECK AND REMOVE - REPROCESS GOVERNANCE OBJECTS - CheckAndRemove(); } bool CGovernanceManager::ConfirmInventoryRequest(const CInv& inv) { + AssertLockNotHeld(cs_store); + // do not request objects until it's time to sync if (!m_mn_sync.IsBlockchainSynced()) return false; - LOCK(cs); + LOCK(cs_store); LogPrint(BCLog::GOBJECT, "CGovernanceManager::ConfirmInventoryRequest inv = %s\n", inv.ToString()); @@ -906,7 +703,7 @@ bool CGovernanceManager::ConfirmInventoryRequest(const CInv& inv) return false; } - const auto valid_until = GetTime() + std::chrono::seconds(RELIABLE_PROPAGATION_TIME); + const auto valid_until = GetTime() + RELIABLE_PROPAGATION_TIME; const auto& [_itr, inserted] = m_requested_hash_time.emplace(inv.hash, valid_until); if (inserted) { @@ -921,6 +718,7 @@ bool CGovernanceManager::ConfirmInventoryRequest(const CInv& inv) MessageProcessingResult CGovernanceManager::SyncSingleObjVotes(CNode& peer, const uint256& nProp, const CBloomFilter& filter, CConnman& connman) { + AssertLockHeld(cs_store); // do not provide any data until our node is synced if (!m_mn_sync.IsSynced()) return {}; @@ -928,15 +726,13 @@ MessageProcessingResult CGovernanceManager::SyncSingleObjVotes(CNode& peer, cons LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s -- syncing single object to peer=%d, nProp = %s\n", __func__, peer.GetId(), nProp.ToString()); - LOCK(cs); - // single valid object and its valid votes auto it = mapObjects.find(nProp); if (it == mapObjects.end()) { LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s -- no matching object for hash %s, peer=%d\n", __func__, nProp.ToString(), peer.GetId()); return {}; } - const CGovernanceObject& govobj = it->second; + const auto& govobj = *Assert(it->second); std::string strHash = it->first.ToString(); LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s -- attempting to sync govobj: %s, peer=%d\n", __func__, strHash, peer.GetId()); @@ -947,10 +743,12 @@ MessageProcessingResult CGovernanceManager::SyncSingleObjVotes(CNode& peer, cons return {}; } - const auto& fileVotes = govobj.GetVoteFile(); + MessageProcessingResult ret{}; const auto tip_mn_list = Assert(m_dmnman)->GetListAtChainTip(); - MessageProcessingResult ret{}; + { + LOCK(govobj.cs); + const auto& fileVotes = govobj.GetVoteFile(); for (const auto& vote : fileVotes.GetVotes()) { uint256 nVoteHash = vote.GetHash(); @@ -961,6 +759,7 @@ MessageProcessingResult CGovernanceManager::SyncSingleObjVotes(CNode& peer, cons } ret.m_inventory.emplace_back(MSG_GOVERNANCE_OBJECT_VOTE, nVoteHash); } + } CNetMsgMaker msgMaker(peer.GetCommonVersion()); connman.PushMessage(&peer, msgMaker.Make(NetMsgType::SYNCSTATUSCOUNT, MASTERNODE_SYNC_GOVOBJ_VOTE, @@ -972,6 +771,7 @@ MessageProcessingResult CGovernanceManager::SyncSingleObjVotes(CNode& peer, cons MessageProcessingResult CGovernanceManager::SyncObjects(CNode& peer, CConnman& connman) const { + AssertLockHeld(cs_store); assert(m_netfulfilledman.IsValid()); // do not provide any data until our node is synced @@ -988,36 +788,18 @@ MessageProcessingResult CGovernanceManager::SyncObjects(CNode& peer, CConnman& c LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s -- syncing all objects to peer=%d\n", __func__, peer.GetId()); - LOCK(cs); - // all valid objects, no votes MessageProcessingResult ret{}; - for (const auto& objPair : mapObjects) { - uint256 nHash = objPair.first; - const CGovernanceObject& govobj = objPair.second; + for (const auto& [nHash, govobj] : mapObjects) { std::string strHash = nHash.ToString(); - LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s -- attempting to sync govobj: %s, peer=%d\n", __func__, strHash, peer.GetId()); - if (govobj.IsSetCachedDelete() || govobj.IsSetExpired()) { + if (Assert(govobj)->IsSetCachedDelete() || govobj->IsSetExpired()) { LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s -- not syncing deleted/expired govobj: %s, peer=%d\n", __func__, strHash, peer.GetId()); continue; } - if (peer.nVersion < GOVSCRIPT_PROTO_VERSION && govobj.GetObjectType() == GovernanceObject::PROPOSAL) { - // We know this proposal is valid locally, otherwise we would not store it. - // But we don't want to relay it to pre-GOVSCRIPT_PROTO_VERSION peers if payment_address is p2sh - // because they won't accept it anyway and will simply ban us eventually. - CProposalValidator validator(govobj.GetDataAsHexString(), false /* no script */); - if (!validator.Validate(false /* ignore expiration */)) { - // The only way we could get here is when proposal is valid but payment_address is actually p2sh. - LogPrintf("CGovernanceManager::%s -- not syncing p2sh govobj to older node: %s, peer=%d\n", __func__, - strHash, peer.GetId()); - continue; - } - } - // Push the inventory budget proposal message over to the other client LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s -- syncing govobj: %s, peer=%d\n", __func__, strHash, peer.GetId()); ret.m_inventory.emplace_back(MSG_GOVERNANCE_OBJECT, nHash); @@ -1033,6 +815,8 @@ MessageProcessingResult CGovernanceManager::SyncObjects(CNode& peer, CConnman& c void CGovernanceManager::MasternodeRateUpdate(const CGovernanceObject& govobj) { + AssertLockHeld(cs_store); + if (govobj.GetObjectType() != GovernanceObject::TRIGGER) return; const COutPoint& masternodeOutpoint = govobj.GetMasternodeOutpoint(); @@ -1045,7 +829,7 @@ void CGovernanceManager::MasternodeRateUpdate(const CGovernanceObject& govobj) int64_t nTimestamp = govobj.GetCreationTime(); it->second.triggerBuffer.AddTimestamp(nTimestamp); - if (nTimestamp > GetTime() + MAX_TIME_FUTURE_DEVIATION - RELIABLE_PROPAGATION_TIME) { + if (nTimestamp > GetTime() + count_seconds(MAX_TIME_FUTURE_DEVIATION) - count_seconds(RELIABLE_PROPAGATION_TIME)) { // schedule additional relay for the object setAdditionalRelayObjects.insert(govobj.GetHash()); } @@ -1055,13 +839,14 @@ void CGovernanceManager::MasternodeRateUpdate(const CGovernanceObject& govobj) bool CGovernanceManager::MasternodeRateCheck(const CGovernanceObject& govobj, bool fUpdateFailStatus) { + LOCK(cs_store); bool fRateCheckBypassed; return MasternodeRateCheck(govobj, fUpdateFailStatus, true, fRateCheckBypassed); } bool CGovernanceManager::MasternodeRateCheck(const CGovernanceObject& govobj, bool fUpdateFailStatus, bool fForce, bool& fRateCheckBypassed) { - LOCK(cs); + AssertLockHeld(cs_store); fRateCheckBypassed = false; @@ -1086,7 +871,7 @@ bool CGovernanceManager::MasternodeRateCheck(const CGovernanceObject& govobj, bo return false; } - if (nTimestamp > nNow + MAX_TIME_FUTURE_DEVIATION) { + if (nTimestamp > nNow + count_seconds(MAX_TIME_FUTURE_DEVIATION)) { LogPrint(BCLog::GOBJECT, "CGovernanceManager::MasternodeRateCheck -- object %s rejected due to too new (future) timestamp, masternode = %s, timestamp = %d, current time = %d\n", strHash, masternodeOutpoint.ToStringShort(), nTimestamp, nNow); return false; @@ -1123,25 +908,28 @@ bool CGovernanceManager::MasternodeRateCheck(const CGovernanceObject& govobj, bo return false; } -bool CGovernanceManager::ProcessVoteAndRelay(const CGovernanceVote& vote, CGovernanceException& exception, CConnman& connman, PeerManager& peerman) +bool CGovernanceManager::ProcessVoteAndRelay(const CGovernanceVote& vote, CGovernanceException& exception, CConnman& connman) { - bool fOK = ProcessVote(/* pfrom = */ nullptr, vote, exception, connman); + AssertLockNotHeld(cs_store); + AssertLockNotHeld(cs_relay); + bool fOK = ProcessVote(/*pfrom=*/nullptr, vote, exception, connman); if (fOK) { - vote.Relay(peerman, m_mn_sync, Assert(m_dmnman)->GetListAtChainTip()); + RelayVote(vote); } return fOK; } bool CGovernanceManager::ProcessVote(CNode* pfrom, const CGovernanceVote& vote, CGovernanceException& exception, CConnman& connman) { - ENTER_CRITICAL_SECTION(cs); + AssertLockNotHeld(cs_store); + ENTER_CRITICAL_SECTION(cs_store); uint256 nHashVote = vote.GetHash(); uint256 nHashGovobj = vote.GetParentHash(); if (cmapVoteToObject.HasKey(nHashVote)) { LogPrint(BCLog::GOBJECT, "CGovernanceObject::%s -- skipping known valid vote %s for object %s\n", __func__, nHashVote.ToString(), nHashGovobj.ToString()); - LEAVE_CRITICAL_SECTION(cs); + LEAVE_CRITICAL_SECTION(cs_store); return false; } @@ -1150,7 +938,7 @@ bool CGovernanceManager::ProcessVote(CNode* pfrom, const CGovernanceVote& vote, __func__, vote.GetMasternodeOutpoint().ToStringShort(), nHashGovobj.ToString())}; LogPrint(BCLog::GOBJECT, "%s\n", msg); exception = CGovernanceException(msg, GOVERNANCE_EXCEPTION_PERMANENT_ERROR, 20); - LEAVE_CRITICAL_SECTION(cs); + LEAVE_CRITICAL_SECTION(cs_store); return false; } @@ -1159,42 +947,49 @@ bool CGovernanceManager::ProcessVote(CNode* pfrom, const CGovernanceVote& vote, std::string msg{strprintf("CGovernanceManager::%s -- Unknown parent object %s, MN outpoint = %s", __func__, nHashGovobj.ToString(), vote.GetMasternodeOutpoint().ToStringShort())}; exception = CGovernanceException(msg, GOVERNANCE_EXCEPTION_WARNING); - if (cmmapOrphanVotes.Insert(nHashGovobj, vote_time_pair_t(vote, GetTime().count() + GOVERNANCE_ORPHAN_EXPIRATION_TIME))) { - LEAVE_CRITICAL_SECTION(cs); + if (cmmapOrphanVotes.Insert(nHashGovobj, vote_time_pair_t(vote, count_seconds(GetTime() + + GOVERNANCE_ORPHAN_EXPIRATION_TIME)))) { + LEAVE_CRITICAL_SECTION(cs_store); RequestGovernanceObject(pfrom, nHashGovobj, connman); LogPrint(BCLog::GOBJECT, "%s\n", msg); return false; } LogPrint(BCLog::GOBJECT, "%s\n", msg); - LEAVE_CRITICAL_SECTION(cs); + LEAVE_CRITICAL_SECTION(cs_store); return false; } - CGovernanceObject& govobj = it->second; + auto& govobj = *Assert(it->second); if (govobj.IsSetCachedDelete() || govobj.IsSetExpired()) { LogPrint(BCLog::GOBJECT, "CGovernanceObject::%s -- ignoring vote for expired or deleted object, hash = %s\n", __func__, nHashGovobj.ToString()); - LEAVE_CRITICAL_SECTION(cs); + LEAVE_CRITICAL_SECTION(cs_store); return false; } - bool fOk = govobj.ProcessVote(m_mn_metaman, *this, Assert(m_dmnman)->GetListAtChainTip(), vote, exception) && cmapVoteToObject.Insert(nHashVote, &govobj); - LEAVE_CRITICAL_SECTION(cs); + bool fOk = govobj.ProcessVote(m_mn_metaman, *this, Assert(m_dmnman)->GetListAtChainTip(), vote, exception); + if (fOk) { + fOk = cmapVoteToObject.Insert(nHashVote, it->second); + } else if (exception.GetType() == GOVERNANCE_EXCEPTION_PERMANENT_ERROR && exception.GetNodePenalty() == 20) { + cmapInvalidVotes.Insert(nHashVote, vote); + } + LEAVE_CRITICAL_SECTION(cs_store); return fOk; } -void CGovernanceManager::CheckPostponedObjects(PeerManager& peerman) +void CGovernanceManager::CheckPostponedObjects() { + AssertLockHeld(::cs_main); + AssertLockHeld(cs_store); + AssertLockNotHeld(cs_relay); if (!m_mn_sync.IsSynced()) return; - LOCK2(::cs_main, cs); - // Check postponed proposals for (auto it = mapPostponedObjects.begin(); it != mapPostponedObjects.end();) { const uint256& nHash = it->first; - CGovernanceObject& govobj = it->second; + auto& govobj = *Assert(it->second); assert(govobj.GetObjectType() != GovernanceObject::TRIGGER); @@ -1202,7 +997,7 @@ void CGovernanceManager::CheckPostponedObjects(PeerManager& peerman) bool fMissingConfirmations; if (govobj.IsCollateralValid(m_chainman, strError, fMissingConfirmations)) { if (govobj.IsValidLocally(Assert(m_dmnman)->GetListAtChainTip(), m_chainman, strError, false)) { - AddGovernanceObject(govobj, peerman); + AddGovernanceObjectInternal(govobj); } else { LogPrint(BCLog::GOBJECT, "CGovernanceManager::CheckPostponedObjects -- %s invalid\n", nHash.ToString()); } @@ -1225,17 +1020,19 @@ void CGovernanceManager::CheckPostponedObjects(PeerManager& peerman) for (auto it = setAdditionalRelayObjects.begin(); it != setAdditionalRelayObjects.end();) { auto itObject = mapObjects.find(*it); if (itObject != mapObjects.end()) { - const CGovernanceObject& govobj = itObject->second; + const auto& govobj = *Assert(itObject->second); int64_t nTimestamp = govobj.GetCreationTime(); - bool fValid = (nTimestamp <= nNow + MAX_TIME_FUTURE_DEVIATION) && (nTimestamp >= nNow - 2 * nSuperblockCycleSeconds); - bool fReady = (nTimestamp <= nNow + MAX_TIME_FUTURE_DEVIATION - RELIABLE_PROPAGATION_TIME); + bool fValid = (nTimestamp <= nNow + count_seconds(MAX_TIME_FUTURE_DEVIATION)) && + (nTimestamp >= nNow - 2 * nSuperblockCycleSeconds); + bool fReady = (nTimestamp <= + nNow + count_seconds(MAX_TIME_FUTURE_DEVIATION) - count_seconds(RELIABLE_PROPAGATION_TIME)); if (fValid) { if (fReady) { LogPrint(BCLog::GOBJECT, "CGovernanceManager::CheckPostponedObjects -- additional relay: hash = %s\n", govobj.GetHash().ToString()); - govobj.Relay(peerman, m_mn_sync); + RelayObject(govobj); } else { it++; continue; @@ -1252,6 +1049,7 @@ void CGovernanceManager::CheckPostponedObjects(PeerManager& peerman) void CGovernanceManager::RequestGovernanceObject(CNode* pfrom, const uint256& nHash, CConnman& connman, bool fUseFilter) const { + AssertLockNotHeld(cs_store); if (!pfrom) { return; } @@ -1264,12 +1062,12 @@ void CGovernanceManager::RequestGovernanceObject(CNode* pfrom, const uint256& nH size_t nVoteCount = 0; if (fUseFilter) { - LOCK(cs); - const CGovernanceObject* pObj = FindConstGovernanceObject(nHash); + LOCK(cs_store); + auto pObj = FindConstGovernanceObjectInternal(nHash); if (pObj) { filter = CBloomFilter(Params().GetConsensus().nGovernanceFilterElements, GOVERNANCE_FILTER_FP_RATE, GetRand(/*nMax=*/999999), BLOOM_UPDATE_ALL); - std::vector vecVotes = pObj->GetVoteFile().GetVotes(); + std::vector vecVotes = WITH_LOCK(pObj->cs, return pObj->GetVoteFile().GetVotes()); nVoteCount = vecVotes.size(); for (const auto& vote : vecVotes) { filter.insert(vote.GetHash()); @@ -1290,6 +1088,8 @@ int CGovernanceManager::RequestGovernanceObjectVotes(CNode& peer, CConnman& conn int CGovernanceManager::RequestGovernanceObjectVotes(const std::vector& vNodesCopy, CConnman& connman, const PeerManager& peerman) const { + AssertLockNotHeld(cs_store); + static std::map > mapAskedRecently; // Maximum number of nodes to request votes from for the same object hash on real networks // (mainnet, testnet, devnets). Keep this low to avoid unnecessary bandwidth usage. @@ -1321,15 +1121,14 @@ int CGovernanceManager::RequestGovernanceObjectVotes(const std::vector& } { - LOCK(cs); + LOCK(cs_store); if (mapObjects.empty()) return -2; for (const auto& [nHash, govobj] : mapObjects) { - if (govobj.IsSetCachedDelete()) continue; + if (Assert(govobj)->IsSetCachedDelete()) continue; if (mapAskedRecently.count(nHash)) { - auto it = mapAskedRecently[nHash].begin(); - while (it != mapAskedRecently[nHash].end()) { + for (auto it = mapAskedRecently[nHash].begin(); it != mapAskedRecently[nHash].end();) { if (it->second < nNow) { mapAskedRecently[nHash].erase(it++); } else { @@ -1339,7 +1138,7 @@ int CGovernanceManager::RequestGovernanceObjectVotes(const std::vector& if (mapAskedRecently[nHash].size() >= nPeersPerHashMax) continue; } - if (govobj.GetObjectType() == GovernanceObject::TRIGGER) { + if (govobj->GetObjectType() == GovernanceObject::TRIGGER) { vTriggerObjHashes.push_back(nHash); } else { vOtherObjHashes.push_back(nHash); @@ -1400,7 +1199,8 @@ int CGovernanceManager::RequestGovernanceObjectVotes(const std::vector& bool CGovernanceManager::AcceptMessage(const uint256& nHash) { - LOCK(cs); + AssertLockNotHeld(cs_store); + LOCK(cs_store); auto it = m_requested_hash_time.find(nHash); if (it == m_requested_hash_time.end()) { // We never requested this @@ -1413,72 +1213,85 @@ bool CGovernanceManager::AcceptMessage(const uint256& nHash) void CGovernanceManager::RebuildIndexes() { - LOCK(cs); + AssertLockHeld(cs_store); cmapVoteToObject.Clear(); - for (auto& objPair : mapObjects) { - CGovernanceObject& govobj = objPair.second; - std::vector vecVotes = govobj.GetVoteFile().GetVotes(); + for (auto& [_, govobj] : mapObjects) { + assert(govobj); + std::vector vecVotes = WITH_LOCK(govobj->cs, return govobj->GetVoteFile().GetVotes()); for (const auto& vecVote : vecVotes) { - cmapVoteToObject.Insert(vecVote.GetHash(), &govobj); + cmapVoteToObject.Insert(vecVote.GetHash(), govobj); } } } void CGovernanceManager::AddCachedTriggers() { - LOCK(cs); + AssertLockHeld(cs_store); int64_t nNow = GetTime().count(); - for (auto& objpair : mapObjects) { - CGovernanceObject& govobj = objpair.second; - - if (govobj.GetObjectType() != GovernanceObject::TRIGGER) { + for (auto& [_, govobj] : mapObjects) { + if (Assert(govobj)->GetObjectType() != GovernanceObject::TRIGGER) { continue; } - if (!AddNewTrigger(govobj.GetHash())) { - govobj.PrepareDeletion(nNow); + if (!AddNewTrigger(govobj->GetHash())) { + govobj->PrepareDeletion(nNow); } } } void CGovernanceManager::InitOnLoad() { - LOCK(cs); + { + LOCK(cs_store); const auto start{SteadyClock::now()}; LogPrintf("Preparing masternode indexes and governance triggers...\n"); RebuildIndexes(); AddCachedTriggers(); LogPrintf("Masternode indexes and governance triggers prepared %dms\n", Ticks(SteadyClock::now() - start)); + } LogPrintf(" %s\n", ToString()); } void GovernanceStore::Clear() { - LOCK(cs); - - LogPrint(BCLog::GOBJECT, "Governance object manager was cleared\n"); + LOCK(cs_store); mapObjects.clear(); mapErasedGovernanceObjects.clear(); - cmapVoteToObject.Clear(); cmapInvalidVotes.Clear(); cmmapOrphanVotes.Clear(); mapLastMasternodeObject.clear(); + lastMNListForVotingKeys = std::make_shared(); +} + +void CGovernanceManager::Clear() +{ + AssertLockNotHeld(cs_store); + LogPrint(BCLog::GOBJECT, "Governance object manager was cleared\n"); + GovernanceStore::Clear(); + nTimeLastDiff = 0; + nCachedBlockHeight = 0; + cmapVoteToObject.Clear(); + mapPostponedObjects.clear(); + setAdditionalRelayObjects.clear(); + m_requested_hash_time.clear(); + fRateChecksEnabled = true; + mapTrigger.clear(); } std::string GovernanceStore::ToString() const { - LOCK(cs); + LOCK(cs_store); int nProposalCount = 0; int nTriggerCount = 0; int nOtherCount = 0; - for (const auto& objPair : mapObjects) { - switch (objPair.second.GetObjectType()) { + for (const auto& [_, govobj] : mapObjects) { + switch (Assert(govobj)->GetObjectType()) { case GovernanceObject::PROPOSAL: nProposalCount++; break; @@ -1491,22 +1304,27 @@ std::string GovernanceStore::ToString() const } } - return strprintf("Governance Objects: %d (Proposals: %d, Triggers: %d, Other: %d; Erased: %d), Votes: %d", + return strprintf("Governance Objects: %d (Proposals: %d, Triggers: %d, Other: %d; Erased: %d)", (int)mapObjects.size(), - nProposalCount, nTriggerCount, nOtherCount, (int)mapErasedGovernanceObjects.size(), - (int)cmapVoteToObject.GetSize()); + nProposalCount, nTriggerCount, nOtherCount, (int)mapErasedGovernanceObjects.size()); +} + +std::string CGovernanceManager::ToString() const +{ + AssertLockNotHeld(cs_store); + return strprintf("%s, Votes: %d", GovernanceStore::ToString(), (int)cmapVoteToObject.GetSize()); } UniValue CGovernanceManager::ToJson() const { - LOCK(cs); + LOCK(cs_store); int nProposalCount = 0; int nTriggerCount = 0; int nOtherCount = 0; - for (const auto& objpair : mapObjects) { - switch (objpair.second.GetObjectType()) { + for (const auto& [_, govobj] : mapObjects) { + switch (Assert(govobj)->GetObjectType()) { case GovernanceObject::PROPOSAL: nProposalCount++; break; @@ -1529,8 +1347,10 @@ UniValue CGovernanceManager::ToJson() const return jsonObj; } -void CGovernanceManager::UpdatedBlockTip(const CBlockIndex* pindex, CConnman& connman, PeerManager& peerman, const CActiveMasternodeManager* const mn_activeman) +void CGovernanceManager::UpdatedBlockTip(const CBlockIndex* pindex) { + AssertLockNotHeld(cs_store); + AssertLockNotHeld(cs_relay); // Note this gets called from ActivateBestChain without cs_main being held // so it should be safe to lock our mutex here without risking a deadlock // On the other hand it should be safe for us to access pindex without holding a lock @@ -1540,32 +1360,28 @@ void CGovernanceManager::UpdatedBlockTip(const CBlockIndex* pindex, CConnman& co return; } - if (mn_activeman) { - const auto sb_opt = CreateSuperblockCandidate(pindex->nHeight); - const auto trigger_opt = CreateGovernanceTrigger(sb_opt, peerman, *mn_activeman); - VoteGovernanceTriggers(trigger_opt, connman, peerman, *mn_activeman); - } - nCachedBlockHeight = pindex->nHeight; LogPrint(BCLog::GOBJECT, "CGovernanceManager::UpdatedBlockTip -- nCachedBlockHeight: %d\n", nCachedBlockHeight); + LOCK2(::cs_main, cs_store); if (DeploymentDIP0003Enforced(pindex->nHeight, Params().GetConsensus())) { RemoveInvalidVotes(); } - CheckPostponedObjects(peerman); + CheckPostponedObjects(); ExecuteBestSuperblock(Assert(m_dmnman)->GetListAtChainTip(), pindex->nHeight); } void CGovernanceManager::RequestOrphanObjects(CConnman& connman) { + AssertLockNotHeld(cs_store); const CConnman::NodesSnapshot snap{connman, /* cond = */ CConnman::FullyConnectedOnly}; std::vector vecHashesFiltered; { + LOCK(cs_store); std::vector vecHashes; - LOCK(cs); cmmapOrphanVotes.GetKeys(vecHashes); for (const uint256& nHash : vecHashes) { if (mapObjects.find(nHash) == mapObjects.end()) { @@ -1587,17 +1403,16 @@ void CGovernanceManager::RequestOrphanObjects(CConnman& connman) void CGovernanceManager::CleanOrphanObjects() { - LOCK(cs); + LOCK(cs_store); const vote_cmm_t::list_t& items = cmmapOrphanVotes.GetItemList(); int64_t nNow = GetTime().count(); - auto it = items.begin(); - while (it != items.end()) { + for (auto it = items.begin(); it != items.end();) { auto prevIt = it; ++it; - const vote_time_pair_t& pairVote = prevIt->value; - if (pairVote.second < nNow) { + const auto& [vote, time] = prevIt->value; + if (time < nNow) { cmmapOrphanVotes.Erase(prevIt->key, prevIt->value); } } @@ -1605,24 +1420,24 @@ void CGovernanceManager::CleanOrphanObjects() void CGovernanceManager::RemoveInvalidVotes() { + AssertLockHeld(cs_store); + if (!m_mn_sync.IsSynced()) { return; } - LOCK(cs); - const auto tip_mn_list = Assert(m_dmnman)->GetListAtChainTip(); auto diff = lastMNListForVotingKeys->BuildDiff(tip_mn_list); std::vector changedKeyMNs; - for (const auto& p : diff.updatedMNs) { - auto oldDmn = lastMNListForVotingKeys->GetMNByInternalId(p.first); + for (const auto& [internalId, pdmnState] : diff.updatedMNs) { + auto oldDmn = lastMNListForVotingKeys->GetMNByInternalId(internalId); // BuildDiff will construct itself with MNs that we already have knowledge // of, meaning that fetch operations should never fail. assert(oldDmn); - if ((p.second.fields & CDeterministicMNStateDiff::Field_keyIDVoting) && p.second.state.keyIDVoting != oldDmn->pdmnState->keyIDVoting) { + if ((pdmnState.fields & CDeterministicMNStateDiff::Field_keyIDVoting) && pdmnState.state.keyIDVoting != oldDmn->pdmnState->keyIDVoting) { changedKeyMNs.emplace_back(oldDmn->collateralOutpoint); - } else if ((p.second.fields & CDeterministicMNStateDiff::Field_pubKeyOperator) && p.second.state.pubKeyOperator != oldDmn->pdmnState->pubKeyOperator) { + } else if ((pdmnState.fields & CDeterministicMNStateDiff::Field_pubKeyOperator) && pdmnState.state.pubKeyOperator != oldDmn->pdmnState->pubKeyOperator) { changedKeyMNs.emplace_back(oldDmn->collateralOutpoint); } } @@ -1635,8 +1450,8 @@ void CGovernanceManager::RemoveInvalidVotes() } for (const auto& outpoint : changedKeyMNs) { - for (auto& p : mapObjects) { - auto removed = p.second.RemoveInvalidVotes(tip_mn_list, outpoint); + for (auto& [_, govobj] : mapObjects) { + auto removed = Assert(govobj)->RemoveInvalidVotes(tip_mn_list, outpoint); if (removed.empty()) { continue; } @@ -1659,7 +1474,7 @@ void CGovernanceManager::RemoveInvalidVotes() bool CGovernanceManager::AddNewTrigger(uint256 nHash) { - AssertLockHeld(cs); + AssertLockHeld(cs_store); // IF WE ALREADY HAVE THIS HASH, RETURN if (mapTrigger.count(nHash)) { @@ -1670,7 +1485,7 @@ bool CGovernanceManager::AddNewTrigger(uint256 nHash) CSuperblock_sptr pSuperblock; try { - const CGovernanceObject* pGovObj = FindGovernanceObject(nHash); + auto pGovObj = FindGovernanceObjectInternal(nHash); if (!pGovObj) { throw std::runtime_error("CSuperblock: Failed to find Governance Object"); } @@ -1698,21 +1513,20 @@ bool CGovernanceManager::AddNewTrigger(uint256 nHash) void CGovernanceManager::CleanAndRemoveTriggers() { - AssertLockHeld(cs); + AssertLockHeld(cs_store); // Remove triggers that are invalid or expired LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s -- mapTrigger.size() = %d\n", __func__, mapTrigger.size()); - auto it = mapTrigger.begin(); - while (it != mapTrigger.end()) { + for (auto it = mapTrigger.begin(); it != mapTrigger.end();) { bool remove = false; - CGovernanceObject* pObj = nullptr; + std::shared_ptr pObj = nullptr; const CSuperblock_sptr& pSuperblock = it->second; if (!pSuperblock) { LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s -- nullptr superblock\n", __func__); remove = true; } else { - pObj = FindGovernanceObject(it->first); + pObj = FindGovernanceObjectInternal(it->first); if (!pObj || pObj->GetObjectType() != GovernanceObject::TRIGGER) { LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s -- Unknown or non-trigger superblock\n", __func__); pSuperblock->SetStatus(SeenObjectStatus::ErrorInvalid); @@ -1765,17 +1579,23 @@ void CGovernanceManager::CleanAndRemoveTriggers() * - Look through triggers and scan for active ones * - Return the triggers in a list */ - std::vector CGovernanceManager::GetActiveTriggers() const { - AssertLockHeld(cs); + AssertLockNotHeld(cs_store); + LOCK(cs_store); + return GetActiveTriggersInternal(); +} + +std::vector CGovernanceManager::GetActiveTriggersInternal() const +{ + AssertLockHeld(cs_store); std::vector vecResults; // LOOK AT THESE OBJECTS AND COMPILE A VALID LIST OF TRIGGERS - for (const auto& pair : mapTrigger) { - const CGovernanceObject* pObj = FindConstGovernanceObject(pair.first); + for (const auto& [nHash, pSuperblock] : mapTrigger) { + auto pObj = FindConstGovernanceObjectInternal(nHash); if (pObj) { - vecResults.push_back(pair.second); + vecResults.push_back(pSuperblock); } } @@ -1784,14 +1604,15 @@ std::vector CGovernanceManager::GetActiveTriggers() const bool CGovernanceManager::IsSuperblockTriggered(const CDeterministicMNList& tip_mn_list, int nBlockHeight) { + AssertLockNotHeld(cs_store); LogPrint(BCLog::GOBJECT, "IsSuperblockTriggered -- Start nBlockHeight = %d\n", nBlockHeight); if (!CSuperblock::IsValidBlockHeight(nBlockHeight)) { return false; } - LOCK(cs); + LOCK(cs_store); // GET ALL ACTIVE TRIGGERS - std::vector vecTriggers = GetActiveTriggers(); + std::vector vecTriggers = GetActiveTriggersInternal(); LogPrint(BCLog::GOBJECT, "IsSuperblockTriggered -- vecTriggers.size() = %d\n", vecTriggers.size()); @@ -1801,7 +1622,7 @@ bool CGovernanceManager::IsSuperblockTriggered(const CDeterministicMNList& tip_m continue; } - CGovernanceObject* pObj = FindGovernanceObject(pSuperblock->GetGovernanceObjHash()); + auto pObj = FindGovernanceObjectInternal(pSuperblock->GetGovernanceObjHash()); if (!pObj) { LogPrintf("IsSuperblockTriggered -- pObj == nullptr, continuing\n"); continue; @@ -1834,16 +1655,23 @@ bool CGovernanceManager::IsSuperblockTriggered(const CDeterministicMNList& tip_m return false; } - bool CGovernanceManager::GetBestSuperblock(const CDeterministicMNList& tip_mn_list, CSuperblock_sptr& pSuperblockRet, int nBlockHeight) +{ + AssertLockNotHeld(cs_store); + LOCK(cs_store); + return GetBestSuperblockInternal(tip_mn_list, pSuperblockRet, nBlockHeight); +} + +bool CGovernanceManager::GetBestSuperblockInternal(const CDeterministicMNList& tip_mn_list, + CSuperblock_sptr& pSuperblockRet, int nBlockHeight) { if (!CSuperblock::IsValidBlockHeight(nBlockHeight)) { return false; } - AssertLockHeld(cs); - std::vector vecTriggers = GetActiveTriggers(); + AssertLockHeld(cs_store); + std::vector vecTriggers = GetActiveTriggersInternal(); int nYesCount = 0; for (const auto& pSuperblock : vecTriggers) { @@ -1851,7 +1679,7 @@ bool CGovernanceManager::GetBestSuperblock(const CDeterministicMNList& tip_mn_li continue; } - const CGovernanceObject* pObj = FindGovernanceObject(pSuperblock->GetGovernanceObjHash()); + auto pObj = FindGovernanceObjectInternal(pSuperblock->GetGovernanceObjHash()); if (!pObj) { continue; } @@ -1871,12 +1699,12 @@ bool CGovernanceManager::GetBestSuperblock(const CDeterministicMNList& tip_mn_li bool CGovernanceManager::GetSuperblockPayments(const CDeterministicMNList& tip_mn_list, int nBlockHeight, std::vector& voutSuperblockRet) { - LOCK(cs); + LOCK(cs_store); // GET THE BEST SUPERBLOCK FOR THIS BLOCK HEIGHT CSuperblock_sptr pSuperblock; - if (!GetBestSuperblock(tip_mn_list, pSuperblock, nBlockHeight)) { + if (!GetBestSuperblockInternal(tip_mn_list, pSuperblock, nBlockHeight)) { LogPrint(BCLog::GOBJECT, "GetSuperblockPayments -- Can't find superblock for height %d\n", nBlockHeight); return false; } @@ -1919,10 +1747,10 @@ bool CGovernanceManager::IsValidSuperblock(const CChain& active_chain, const CDe const CTransaction& txNew, int nBlockHeight, CAmount blockReward) { // GET BEST SUPERBLOCK, SHOULD MATCH - LOCK(cs); + LOCK(cs_store); CSuperblock_sptr pSuperblock; - if (GetBestSuperblock(tip_mn_list, pSuperblock, nBlockHeight)) { + if (GetBestSuperblockInternal(tip_mn_list, pSuperblock, nBlockHeight)) { return pSuperblock->IsValid(active_chain, txNew, nBlockHeight, blockReward); } @@ -1931,17 +1759,48 @@ bool CGovernanceManager::IsValidSuperblock(const CChain& active_chain, const CDe void CGovernanceManager::ExecuteBestSuperblock(const CDeterministicMNList& tip_mn_list, int nBlockHeight) { - LOCK(cs); + AssertLockHeld(cs_store); CSuperblock_sptr pSuperblock; - if (GetBestSuperblock(tip_mn_list, pSuperblock, nBlockHeight)) { + if (GetBestSuperblockInternal(tip_mn_list, pSuperblock, nBlockHeight)) { // All checks are done in CSuperblock::IsValid via IsBlockValueValid and IsBlockPayeeValid, // tip wouldn't be updated if anything was wrong. Mark this trigger as executed. pSuperblock->SetExecuted(); - ResetVotedFundingTrigger(); } } +std::vector> CGovernanceManager::GetApprovedProposals( + const CDeterministicMNList& tip_mn_list) +{ + AssertLockNotHeld(cs_store); + + // Use std::vector of std::shared_ptr because CGovernanceObject doesn't support move operations (needed for sorting the vector later) + std::vector> ret{}; + + // A proposal is considered passing if (YES votes) >= (Total Weight of Masternodes / 10), + // count total valid (ENABLED) masternodes to determine passing threshold. + const int nWeightedMnCount = tip_mn_list.GetValidWeightedMNsCount(); + const int nAbsVoteReq = std::max(Params().GetConsensus().nGovernanceMinQuorum, nWeightedMnCount / 10); + + LOCK(cs_store); + for (const auto& [_, govobj] : mapObjects) { + // Skip all non-proposals objects + if (Assert(govobj)->GetObjectType() != GovernanceObject::PROPOSAL) continue; + // Skip non-passing proposals + const int absYesCount = govobj->GetAbsoluteYesCount(tip_mn_list, VOTE_SIGNAL_FUNDING); + if (absYesCount < nAbsVoteReq) continue; + ret.emplace_back(govobj); + } + + // Sort approved proposals by absolute Yes votes descending + std::sort(ret.begin(), ret.end(), [&tip_mn_list](auto& lhs, auto& rhs) { + const auto lhs_yes = lhs->GetAbsoluteYesCount(tip_mn_list, VOTE_SIGNAL_FUNDING); + const auto rhs_yes = rhs->GetAbsoluteYesCount(tip_mn_list, VOTE_SIGNAL_FUNDING); + return lhs_yes == rhs_yes ? UintToArith256(lhs->GetHash()) > UintToArith256(rhs->GetHash()) : lhs_yes > rhs_yes; + }); + + return ret; +} bool AreSuperblocksEnabled(const CSporkManager& sporkman) { diff --git a/src/governance/governance.h b/src/governance/governance.h index 2657c94602c0..6d4a9bbf9b02 100644 --- a/src/governance/governance.h +++ b/src/governance/governance.h @@ -5,27 +5,39 @@ #ifndef BITCOIN_GOVERNANCE_GOVERNANCE_H #define BITCOIN_GOVERNANCE_GOVERNANCE_H -#include -#include - #include #include +#include +#include + #include -#include +#include +#include +#include +#include +#include #include +#include +#include #include +#include class CBloomFilter; class CBlockIndex; +class CChain; class CConnman; +class ChainstateManager; template class CFlatDB; class CInv; +class CNode; +class CScheduler; class PeerManager; class CDeterministicMNList; class CDeterministicMNManager; +class CGovernanceException; class CGovernanceManager; class CGovernanceObject; class CGovernanceVote; @@ -33,10 +45,20 @@ class CMasternodeMetaMan; class CMasternodeSync; class CNetFulfilledRequestManager; class CSporkManager; +class CSuperblock; +class GovernanceSigner; + +class UniValue; + +using CDeterministicMNListPtr = std::shared_ptr; +using CSuperblock_sptr = std::shared_ptr; +using vote_time_pair_t = std::pair; static constexpr int RATE_BUFFER_SIZE = 5; static constexpr bool DEFAULT_GOVERNANCE_ENABLE{true}; +extern RecursiveMutex cs_main; + class CRateCheckBuffer { private: @@ -151,7 +173,6 @@ class GovernanceStore bool fStatusOK; }; - using object_ref_cm_t = CacheMap; using txout_m_t = std::map; using vote_cmm_t = CacheMultiMap; @@ -159,32 +180,30 @@ class GovernanceStore static constexpr int MAX_CACHE_SIZE = 1000000; static const std::string SERIALIZATION_VERSION_STRING; -public: +protected: // critical section to protect the inner data structures - mutable RecursiveMutex cs; + mutable Mutex cs_store; -protected: // keep track of the scanning errors - std::map mapObjects GUARDED_BY(cs); + std::map> mapObjects GUARDED_BY(cs_store); // mapErasedGovernanceObjects contains key-value pairs, where // key - governance object's hash // value - expiration time for deleted objects - std::map mapErasedGovernanceObjects; - object_ref_cm_t cmapVoteToObject; - CacheMap cmapInvalidVotes; - vote_cmm_t cmmapOrphanVotes; - txout_m_t mapLastMasternodeObject; + std::map mapErasedGovernanceObjects GUARDED_BY(cs_store); + CacheMap cmapInvalidVotes GUARDED_BY(cs_store); + vote_cmm_t cmmapOrphanVotes GUARDED_BY(cs_store); + txout_m_t mapLastMasternodeObject GUARDED_BY(cs_store); // used to check for changed voting keys - std::shared_ptr lastMNListForVotingKeys; + std::shared_ptr lastMNListForVotingKeys GUARDED_BY(cs_store); public: GovernanceStore(); ~GovernanceStore() = default; template - void Serialize(Stream &s) const + void Serialize(Stream &s) const EXCLUSIVE_LOCKS_REQUIRED(!cs_store) { - LOCK(cs); + LOCK(cs_store); s << SERIALIZATION_VERSION_STRING << mapErasedGovernanceObjects << cmapInvalidVotes @@ -195,11 +214,11 @@ class GovernanceStore } template - void Unserialize(Stream &s) + void Unserialize(Stream &s) EXCLUSIVE_LOCKS_REQUIRED(!cs_store) { Clear(); - LOCK(cs); + LOCK(cs_store); std::string strVersion; s >> strVersion; if (strVersion != SERIALIZATION_VERSION_STRING) { @@ -214,24 +233,23 @@ class GovernanceStore >> *lastMNListForVotingKeys; } - void Clear(); + void Clear() + EXCLUSIVE_LOCKS_REQUIRED(!cs_store); - std::string ToString() const; + std::string ToString() const + EXCLUSIVE_LOCKS_REQUIRED(!cs_store); }; // // Governance Manager : Contains all proposals for the budget // -class CGovernanceManager : public GovernanceStore +class CGovernanceManager : public GovernanceStore, public GovernanceSignerParent { friend class CGovernanceObject; private: using db_type = CFlatDB; - -private: - static const int MAX_TIME_FUTURE_DEVIATION; - static const int RELIABLE_PROPAGATION_TIME; + using object_ref_cm_t = CacheMap>; private: const std::unique_ptr m_db; @@ -243,171 +261,205 @@ class CGovernanceManager : public GovernanceStore const std::unique_ptr& m_dmnman; CMasternodeSync& m_mn_sync; - int64_t nTimeLastDiff; + int64_t nTimeLastDiff{0}; // keep track of current block height - int nCachedBlockHeight; - std::map mapPostponedObjects; + int nCachedBlockHeight{0}; + object_ref_cm_t cmapVoteToObject; + std::map> mapPostponedObjects; std::set setAdditionalRelayObjects; std::map m_requested_hash_time; - bool fRateChecksEnabled; - std::optional votedFundingYesTriggerHash; + bool fRateChecksEnabled{true}; std::map> mapTrigger; + mutable Mutex cs_relay; + std::vector m_relay_invs GUARDED_BY(cs_relay); + public: + CGovernanceManager() = delete; + CGovernanceManager(const CGovernanceManager&) = delete; + CGovernanceManager& operator=(const CGovernanceManager&) = delete; explicit CGovernanceManager(CMasternodeMetaMan& mn_metaman, CNetFulfilledRequestManager& netfulfilledman, const ChainstateManager& chainman, const std::unique_ptr& dmnman, CMasternodeSync& mn_sync); ~CGovernanceManager(); - bool LoadCache(bool load_cache); - - bool IsValid() const { return is_valid; } + // Basic initialization and querying + bool IsValid() const override { return is_valid; } + bool LoadCache(bool load_cache) + EXCLUSIVE_LOCKS_REQUIRED(!cs_store); + std::string ToString() const + EXCLUSIVE_LOCKS_REQUIRED(!cs_store); + UniValue ToJson() const + EXCLUSIVE_LOCKS_REQUIRED(!cs_store); + void Clear() + EXCLUSIVE_LOCKS_REQUIRED(!cs_store); + void CheckAndRemove() + EXCLUSIVE_LOCKS_REQUIRED(!cs_store); + void Schedule(CScheduler& scheduler, CConnman& connman, PeerManager& peerman) + EXCLUSIVE_LOCKS_REQUIRED(!cs_store, !cs_relay); + + // CGovernanceObject + bool AreRateChecksEnabled() const { return fRateChecksEnabled; } + + // Getters/Setters + int GetCachedBlockHeight() const override { return nCachedBlockHeight; } + int64_t GetLastDiffTime() const { return nTimeLastDiff; } + std::vector GetCurrentVotes(const uint256& nParentHash, const COutPoint& mnCollateralOutpointFilter) const + EXCLUSIVE_LOCKS_REQUIRED(!cs_store); + void GetAllNewerThan(std::vector& objs, int64_t nMoreThanTime) const + EXCLUSIVE_LOCKS_REQUIRED(!cs_store); + void UpdateLastDiffTime(int64_t nTimeIn) { nTimeLastDiff = nTimeIn; } + // Networking /** * This is called by AlreadyHave in net_processing.cpp as part of the inventory * retrieval process. Returns true if we want to retrieve the object, otherwise * false. (Note logic is inverted in AlreadyHave). */ - bool ConfirmInventoryRequest(const CInv& inv); - - [[nodiscard]] MessageProcessingResult SyncSingleObjVotes(CNode& peer, const uint256& nProp, const CBloomFilter& filter, CConnman& connman); - [[nodiscard]] MessageProcessingResult SyncObjects(CNode& peer, CConnman& connman) const; - - [[nodiscard]] MessageProcessingResult ProcessMessage(CNode& peer, CConnman& connman, PeerManager& peerman, std::string_view msg_type, CDataStream& vRecv); - -private: - void ResetVotedFundingTrigger(); - -public: - void DoMaintenance(CConnman& connman); - - const CGovernanceObject* FindConstGovernanceObject(const uint256& nHash) const EXCLUSIVE_LOCKS_REQUIRED(cs); - CGovernanceObject* FindGovernanceObject(const uint256& nHash) EXCLUSIVE_LOCKS_REQUIRED(cs); - CGovernanceObject* FindGovernanceObjectByDataHash(const uint256& nDataHash) EXCLUSIVE_LOCKS_REQUIRED(cs); - void DeleteGovernanceObject(const uint256& nHash); - - // These commands are only used in RPC - std::vector GetCurrentVotes(const uint256& nParentHash, const COutPoint& mnCollateralOutpointFilter) const; - void GetAllNewerThan(std::vector& objs, int64_t nMoreThanTime) const; - - void AddGovernanceObject(CGovernanceObject& govobj, PeerManager& peerman, const CNode* pfrom = nullptr); - - void CheckAndRemove(); - - UniValue ToJson() const; - - void UpdatedBlockTip(const CBlockIndex* pindex, CConnman& connman, PeerManager& peerman, const CActiveMasternodeManager* const mn_activeman); - int64_t GetLastDiffTime() const { return nTimeLastDiff; } - void UpdateLastDiffTime(int64_t nTimeIn) { nTimeLastDiff = nTimeIn; } - - int GetCachedBlockHeight() const { return nCachedBlockHeight; } - - // Accessors for thread-safe access to maps - bool HaveObjectForHash(const uint256& nHash) const; - - bool HaveVoteForHash(const uint256& nHash) const; - - int GetVoteCount() const; - - bool SerializeObjectForHash(const uint256& nHash, CDataStream& ss) const; - - bool SerializeVoteForHash(const uint256& nHash, CDataStream& ss) const; - + bool ConfirmInventoryRequest(const CInv& inv) + EXCLUSIVE_LOCKS_REQUIRED(!cs_store); + bool ProcessVoteAndRelay(const CGovernanceVote& vote, CGovernanceException& exception, CConnman& connman) override + EXCLUSIVE_LOCKS_REQUIRED(!cs_store, !cs_relay); + int RequestGovernanceObjectVotes(CNode& peer, CConnman& connman, const PeerManager& peerman) const + EXCLUSIVE_LOCKS_REQUIRED(!cs_store); + int RequestGovernanceObjectVotes(const std::vector& vNodesCopy, CConnman& connman, + const PeerManager& peerman) const + EXCLUSIVE_LOCKS_REQUIRED(!cs_store); + [[nodiscard]] MessageProcessingResult ProcessMessage(CNode& peer, CConnman& connman, std::string_view msg_type, + CDataStream& vRecv) + EXCLUSIVE_LOCKS_REQUIRED(!cs_store, !cs_relay); + void RelayObject(const CGovernanceObject& obj) + EXCLUSIVE_LOCKS_REQUIRED(!cs_relay); + void RelayVote(const CGovernanceVote& vote) + EXCLUSIVE_LOCKS_REQUIRED(!cs_relay); + + // Notification interface trigger + void UpdatedBlockTip(const CBlockIndex* pindex) + EXCLUSIVE_LOCKS_REQUIRED(!cs_store, !cs_relay); + + // Signer interface + bool MasternodeRateCheck(const CGovernanceObject& govobj, bool fUpdateFailStatus = false) override + EXCLUSIVE_LOCKS_REQUIRED(!cs_store); + std::shared_ptr FindGovernanceObjectByDataHash(const uint256& nDataHash) override + EXCLUSIVE_LOCKS_REQUIRED(!cs_store); + std::vector> GetApprovedProposals(const CDeterministicMNList& tip_mn_list) override + EXCLUSIVE_LOCKS_REQUIRED(!cs_store); + void AddGovernanceObject(CGovernanceObject& govobj, const CNode* pfrom = nullptr) override + EXCLUSIVE_LOCKS_REQUIRED(!cs_store, !cs_relay); + + // Superblocks + bool GetSuperblockPayments(const CDeterministicMNList& tip_mn_list, int nBlockHeight, + std::vector& voutSuperblockRet) + EXCLUSIVE_LOCKS_REQUIRED(!cs_store); + bool IsSuperblockTriggered(const CDeterministicMNList& tip_mn_list, int nBlockHeight) + EXCLUSIVE_LOCKS_REQUIRED(!cs_store); + bool IsValidSuperblock(const CChain& active_chain, const CDeterministicMNList& tip_mn_list, + const CTransaction& txNew, int nBlockHeight, CAmount blockReward) + EXCLUSIVE_LOCKS_REQUIRED(!cs_store); + + // Thread-safe accessors + bool GetBestSuperblock(const CDeterministicMNList& tip_mn_list, CSuperblock_sptr& pSuperblockRet, + int nBlockHeight) override + EXCLUSIVE_LOCKS_REQUIRED(!cs_store); + bool HaveObjectForHash(const uint256& nHash) const + EXCLUSIVE_LOCKS_REQUIRED(!cs_store); + bool HaveVoteForHash(const uint256& nHash) const + EXCLUSIVE_LOCKS_REQUIRED(!cs_store); + bool SerializeObjectForHash(const uint256& nHash, CDataStream& ss) const + EXCLUSIVE_LOCKS_REQUIRED(!cs_store); + bool SerializeVoteForHash(const uint256& nHash, CDataStream& ss) const + EXCLUSIVE_LOCKS_REQUIRED(!cs_store); + std::shared_ptr FindGovernanceObject(const uint256& nHash) override + EXCLUSIVE_LOCKS_REQUIRED(!cs_store); + int GetVoteCount() const + EXCLUSIVE_LOCKS_REQUIRED(!cs_store); + std::vector> GetActiveTriggers() const override + EXCLUSIVE_LOCKS_REQUIRED(!cs_store); void AddPostponedObject(const CGovernanceObject& govobj) - { - LOCK(cs); - mapPostponedObjects.insert(std::make_pair(govobj.GetHash(), govobj)); - } - - void MasternodeRateUpdate(const CGovernanceObject& govobj); - - bool MasternodeRateCheck(const CGovernanceObject& govobj, bool fUpdateFailStatus = false); - - bool MasternodeRateCheck(const CGovernanceObject& govobj, bool fUpdateFailStatus, bool fForce, bool& fRateCheckBypassed); - - bool ProcessVoteAndRelay(const CGovernanceVote& vote, CGovernanceException& exception, CConnman& connman, PeerManager& peerman); - - void CheckPostponedObjects(PeerManager& peerman); - - bool AreRateChecksEnabled() const - { - LOCK(cs); - return fRateChecksEnabled; - } + EXCLUSIVE_LOCKS_REQUIRED(!cs_store); - void InitOnLoad(); + std::shared_ptr FindConstGovernanceObject(const uint256& nHash) const + EXCLUSIVE_LOCKS_REQUIRED(!cs_store); - int RequestGovernanceObjectVotes(CNode& peer, CConnman& connman, const PeerManager& peerman) const; - int RequestGovernanceObjectVotes(const std::vector& vNodesCopy, CConnman& connman, - const PeerManager& peerman) const; +private: + // Branches of ProcessMessage + [[nodiscard]] MessageProcessingResult SyncObjects(CNode& peer, CConnman& connman) const + EXCLUSIVE_LOCKS_REQUIRED(cs_store); + [[nodiscard]] MessageProcessingResult SyncSingleObjVotes(CNode& peer, const uint256& nProp, const CBloomFilter& filter, + CConnman& connman) + EXCLUSIVE_LOCKS_REQUIRED(cs_store); + + // Internal counterparts to "Thread-safe accessors" + void AddPostponedObjectInternal(const CGovernanceObject& govobj) + EXCLUSIVE_LOCKS_REQUIRED(cs_store); + bool GetBestSuperblockInternal(const CDeterministicMNList& tip_mn_list, CSuperblock_sptr& pSuperblockRet, + int nBlockHeight) + EXCLUSIVE_LOCKS_REQUIRED(cs_store); + std::shared_ptr FindGovernanceObjectInternal(const uint256& nHash) + EXCLUSIVE_LOCKS_REQUIRED(cs_store); + std::vector> GetActiveTriggersInternal() const + EXCLUSIVE_LOCKS_REQUIRED(cs_store); + + std::shared_ptr FindConstGovernanceObjectInternal(const uint256& nHash) const + EXCLUSIVE_LOCKS_REQUIRED(cs_store); + + // Internal counterpart to "Signer interface" + void AddGovernanceObjectInternal(CGovernanceObject& govobj, const CNode* pfrom = nullptr) + EXCLUSIVE_LOCKS_REQUIRED(::cs_main, cs_store, !cs_relay); + + // ... + void MasternodeRateUpdate(const CGovernanceObject& govobj) + EXCLUSIVE_LOCKS_REQUIRED(cs_store); + + bool MasternodeRateCheck(const CGovernanceObject& govobj, bool fUpdateFailStatus, bool fForce, bool& fRateCheckBypassed) + EXCLUSIVE_LOCKS_REQUIRED(cs_store); + + void CheckPostponedObjects() + EXCLUSIVE_LOCKS_REQUIRED(::cs_main, cs_store, !cs_relay); + + void InitOnLoad() + EXCLUSIVE_LOCKS_REQUIRED(!cs_store); /* * Trigger Management (formerly CGovernanceTriggerManager) * - Track governance objects which are triggers * - After triggers are activated and executed, they can be removed */ - std::vector> GetActiveTriggers() const EXCLUSIVE_LOCKS_REQUIRED(cs); - bool AddNewTrigger(uint256 nHash) EXCLUSIVE_LOCKS_REQUIRED(cs); - void CleanAndRemoveTriggers() EXCLUSIVE_LOCKS_REQUIRED(cs); - - // Superblocks related: - - /** - * Is Superblock Triggered - * - * - Does this block have a non-executed and activated trigger? - */ - bool IsSuperblockTriggered(const CDeterministicMNList& tip_mn_list, int nBlockHeight); - - /** - * Get Superblock Payments - * - * - Returns payments for superblock - */ - bool GetSuperblockPayments(const CDeterministicMNList& tip_mn_list, int nBlockHeight, - std::vector& voutSuperblockRet); + bool AddNewTrigger(uint256 nHash) + EXCLUSIVE_LOCKS_REQUIRED(cs_store); + void CleanAndRemoveTriggers() + EXCLUSIVE_LOCKS_REQUIRED(cs_store); - bool IsValidSuperblock(const CChain& active_chain, const CDeterministicMNList& tip_mn_list, - const CTransaction& txNew, int nBlockHeight, CAmount blockReward); + void ExecuteBestSuperblock(const CDeterministicMNList& tip_mn_list, int nBlockHeight) + EXCLUSIVE_LOCKS_REQUIRED(cs_store); -private: - void ExecuteBestSuperblock(const CDeterministicMNList& tip_mn_list, int nBlockHeight); - bool GetBestSuperblock(const CDeterministicMNList& tip_mn_list, CSuperblock_sptr& pSuperblockRet, int nBlockHeight) - EXCLUSIVE_LOCKS_REQUIRED(cs); - - std::optional CreateSuperblockCandidate(int nHeight) const; - std::optional CreateGovernanceTrigger(const std::optional& sb_opt, PeerManager& peerman, - const CActiveMasternodeManager& mn_activeman); - void VoteGovernanceTriggers(const std::optional& trigger_opt, CConnman& connman, PeerManager& peerman, - const CActiveMasternodeManager& mn_activeman); - bool VoteFundingTrigger(const uint256& nHash, const vote_outcome_enum_t outcome, CConnman& connman, PeerManager& peerman, - const CActiveMasternodeManager& mn_activeman); - bool HasAlreadyVotedFundingTrigger() const; - - void RequestGovernanceObject(CNode* pfrom, const uint256& nHash, CConnman& connman, bool fUseFilter = false) const; - - void AddInvalidVote(const CGovernanceVote& vote) - { - cmapInvalidVotes.Insert(vote.GetHash(), vote); - } + void RequestGovernanceObject(CNode* pfrom, const uint256& nHash, CConnman& connman, bool fUseFilter = false) const + EXCLUSIVE_LOCKS_REQUIRED(!cs_store); - bool ProcessVote(CNode* pfrom, const CGovernanceVote& vote, CGovernanceException& exception, CConnman& connman); + bool ProcessVote(CNode* pfrom, const CGovernanceVote& vote, CGovernanceException& exception, CConnman& connman) + EXCLUSIVE_LOCKS_REQUIRED(!cs_store); /// Called to indicate a requested object or vote has been received - bool AcceptMessage(const uint256& nHash); - - void CheckOrphanVotes(CGovernanceObject& govobj, PeerManager& peerman); + bool AcceptMessage(const uint256& nHash) + EXCLUSIVE_LOCKS_REQUIRED(!cs_store); - void RebuildIndexes(); + void CheckOrphanVotes(CGovernanceObject& govobj) + EXCLUSIVE_LOCKS_REQUIRED(cs_store, !cs_relay); - void AddCachedTriggers(); + void RebuildIndexes() + EXCLUSIVE_LOCKS_REQUIRED(cs_store); - void RequestOrphanObjects(CConnman& connman); + void AddCachedTriggers() + EXCLUSIVE_LOCKS_REQUIRED(cs_store); - void CleanOrphanObjects(); + void RequestOrphanObjects(CConnman& connman) + EXCLUSIVE_LOCKS_REQUIRED(!cs_store); - void RemoveInvalidVotes(); + void CleanOrphanObjects() + EXCLUSIVE_LOCKS_REQUIRED(!cs_store); + void RemoveInvalidVotes() + EXCLUSIVE_LOCKS_REQUIRED(cs_store); }; bool AreSuperblocksEnabled(const CSporkManager& sporkman); diff --git a/src/governance/object.cpp b/src/governance/object.cpp index ddf3231537aa..173d2ab8db88 100644 --- a/src/governance/object.cpp +++ b/src/governance/object.cpp @@ -5,16 +5,16 @@ #include #include -#include -#include #include #include #include -#include #include -#include #include -#include + +#include +#include +#include +#include #include #include #include @@ -144,18 +144,10 @@ bool CGovernanceObject::ProcessVote(CMasternodeMetaMan& mn_metaman, CGovernanceM __func__, vote.GetMasternodeOutpoint().ToStringShort(), GetHash().ToString(), vote.GetHash().ToString())}; LogPrintf("%s\n", msg); exception = CGovernanceException(msg, GOVERNANCE_EXCEPTION_PERMANENT_ERROR, 20); - govman.AddInvalidVote(vote); return false; } - if (!mn_metaman.AddGovernanceVote(dmn->proTxHash, vote.GetParentHash())) { - std::string msg{strprintf("CGovernanceObject::%s -- Unable to add governance vote, MN outpoint = %s, " - "governance object hash = %s", - __func__, vote.GetMasternodeOutpoint().ToStringShort(), GetHash().ToString())}; - LogPrint(BCLog::GOBJECT, "%s\n", msg); - exception = CGovernanceException(msg, GOVERNANCE_EXCEPTION_PERMANENT_ERROR); - return false; - } + mn_metaman.AddGovernanceVote(dmn->proTxHash, vote.GetParentHash()); voteInstanceRef = vote_instance_t(vote.GetOutcome(), nVoteTimeUpdate, vote.GetTimestamp()); fileVotes.AddVote(vote); @@ -244,14 +236,9 @@ void CGovernanceObject::SetMasternodeOutpoint(const COutPoint& outpoint) m_obj.masternodeOutpoint = outpoint; } -bool CGovernanceObject::Sign(const CActiveMasternodeManager& mn_activeman) +void CGovernanceObject::SetSignature(Span sig) { - CBLSSignature sig = mn_activeman.Sign(GetSignatureHash(), false); - if (!sig.IsValid()) { - return false; - } - m_obj.vchSig = sig.ToByteVector(false); - return true; + m_obj.vchSig.assign(sig.begin(), sig.end()); } bool CGovernanceObject::CheckSignature(const CBLSPublicKey& pubKey) const @@ -283,8 +270,8 @@ UniValue CGovernanceObject::GetJSONObject() const if (objResult.isObject()) { obj = objResult; } else { - std::vector arr1 = objResult.getValues(); - std::vector arr2 = arr1.at(0).getValues(); + const std::vector& arr1 = objResult.getValues(); + const std::vector& arr2 = arr1.at(0).getValues(); obj = arr2.at(1); } @@ -540,13 +527,12 @@ int CGovernanceObject::CountMatchingVotes(const CDeterministicMNList& tip_mn_lis LOCK(cs); int nCount = 0; - for (const auto& votepair : mapCurrentMNVotes) { - const vote_rec_t& recVote = votepair.second; + for (const auto& [outpoint, recVote] : mapCurrentMNVotes) { auto it2 = recVote.mapInstances.find(eVoteSignalIn); if (it2 != recVote.mapInstances.end() && it2->second.eOutcome == eVoteOutcomeIn) { // 4x times weight vote for EvoNode owners. // No need to check if v19 is active since no EvoNode are allowed to register before v19s - auto dmn = tip_mn_list.GetMNByCollateral(votepair.first); + auto dmn = tip_mn_list.GetMNByCollateral(outpoint); if (dmn != nullptr) nCount += GetMnType(dmn->nType).voting_weight; } } @@ -559,26 +545,31 @@ int CGovernanceObject::CountMatchingVotes(const CDeterministicMNList& tip_mn_lis int CGovernanceObject::GetAbsoluteYesCount(const CDeterministicMNList& tip_mn_list, vote_signal_enum_t eVoteSignalIn) const { + AssertLockNotHeld(cs); return GetYesCount(tip_mn_list, eVoteSignalIn) - GetNoCount(tip_mn_list, eVoteSignalIn); } int CGovernanceObject::GetAbsoluteNoCount(const CDeterministicMNList& tip_mn_list, vote_signal_enum_t eVoteSignalIn) const { + AssertLockNotHeld(cs); return GetNoCount(tip_mn_list, eVoteSignalIn) - GetYesCount(tip_mn_list, eVoteSignalIn); } int CGovernanceObject::GetYesCount(const CDeterministicMNList& tip_mn_list, vote_signal_enum_t eVoteSignalIn) const { + AssertLockNotHeld(cs); return CountMatchingVotes(tip_mn_list, eVoteSignalIn, VOTE_OUTCOME_YES); } int CGovernanceObject::GetNoCount(const CDeterministicMNList& tip_mn_list, vote_signal_enum_t eVoteSignalIn) const { + AssertLockNotHeld(cs); return CountMatchingVotes(tip_mn_list, eVoteSignalIn, VOTE_OUTCOME_NO); } int CGovernanceObject::GetAbstainCount(const CDeterministicMNList& tip_mn_list, vote_signal_enum_t eVoteSignalIn) const { + AssertLockNotHeld(cs); return CountMatchingVotes(tip_mn_list, eVoteSignalIn, VOTE_OUTCOME_ABSTAIN); } @@ -594,33 +585,10 @@ bool CGovernanceObject::GetCurrentMNVotes(const COutPoint& mnCollateralOutpoint, return true; } -void CGovernanceObject::Relay(PeerManager& peerman, const CMasternodeSync& mn_sync) const -{ - // Do not relay until fully synced - if (!mn_sync.IsSynced()) { - LogPrint(BCLog::GOBJECT, "CGovernanceObject::Relay -- won't relay until fully synced\n"); - return; - } - - int minProtoVersion = MIN_PEER_PROTO_VERSION; - if (m_obj.type == GovernanceObject::PROPOSAL) { - // We know this proposal is valid locally, otherwise we would not get to the point we should relay it. - // But we don't want to relay it to pre-GOVSCRIPT_PROTO_VERSION peers if payment_address is p2sh - // because they won't accept it anyway and will simply ban us eventually. - CProposalValidator validator(GetDataAsHexString(), false /* no script */); - if (!validator.Validate(false /* ignore expiration */)) { - // The only way we could get here is when proposal is valid but payment_address is actually p2sh. - LogPrint(BCLog::GOBJECT, "CGovernanceObject::Relay -- won't relay %s to older peers\n", GetHash().ToString()); - minProtoVersion = GOVSCRIPT_PROTO_VERSION; - } - } - - CInv inv(MSG_GOVERNANCE_OBJECT, GetHash()); - peerman.RelayInv(inv, minProtoVersion); -} - void CGovernanceObject::UpdateSentinelVariables(const CDeterministicMNList& tip_mn_list) { + AssertLockNotHeld(cs); + // CALCULATE MINIMUM SUPPORT LEVELS REQUIRED int nWeightedMnCount = (int)tip_mn_list.GetValidWeightedMNsCount(); @@ -644,6 +612,7 @@ void CGovernanceObject::UpdateSentinelVariables(const CDeterministicMNList& tip_ if (GetAbsoluteYesCount(tip_mn_list, VOTE_SIGNAL_FUNDING) >= nAbsVoteReq) fCachedFunding = true; if ((GetAbsoluteYesCount(tip_mn_list, VOTE_SIGNAL_DELETE) >= nAbsDeleteReq) && !fCachedDelete) { fCachedDelete = true; + LOCK(cs); if (nDeletionTime == 0) { nDeletionTime = GetTime().count(); } diff --git a/src/governance/object.h b/src/governance/object.h index 66324a75d62b..01bd7b65b35d 100644 --- a/src/governance/object.h +++ b/src/governance/object.h @@ -11,9 +11,10 @@ #include #include +#include + #include -class CActiveMasternodeManager; class CBLSPublicKey; class CDeterministicMNList; class CGovernanceManager; @@ -21,23 +22,14 @@ class CGovernanceObject; class CGovernanceVote; class ChainstateManager; class CMasternodeMetaMan; -class CMasternodeSync; -class CNode; -class PeerManager; extern RecursiveMutex cs_main; static constexpr double GOVERNANCE_FILTER_FP_RATE = 0.001; - - static constexpr CAmount GOVERNANCE_PROPOSAL_FEE_TX = (1 * COIN); - static constexpr int64_t GOVERNANCE_FEE_CONFIRMATIONS = 6; static constexpr int64_t GOVERNANCE_MIN_RELAY_FEE_CONFIRMATIONS = 1; static constexpr int64_t GOVERNANCE_UPDATE_MIN = 60 * 60; -static constexpr int64_t GOVERNANCE_DELETION_DELAY = 10 * 60; -static constexpr int64_t GOVERNANCE_ORPHAN_EXPIRATION_TIME = 10 * 60; -static constexpr int64_t GOVERNANCE_FUDGE_WINDOW = 60 * 60 * 2; // FOR SEEN MAP ARRAYS - GOVERNANCE OBJECTS AND VOTES enum class SeenObjectStatus { @@ -96,15 +88,15 @@ class CGovernanceObject public: // Types using vote_m_t = std::map; -private: +public: /// critical section to protect the inner data structures - mutable RecursiveMutex cs; + mutable Mutex cs; +private: Governance::Object m_obj; /// time this object was marked for deletion - int64_t nDeletionTime{0}; - + int64_t nDeletionTime GUARDED_BY(cs){0}; /// is valid by blockchain bool fCachedLocalValidity{false}; @@ -130,119 +122,82 @@ class CGovernanceObject bool fDirtyCache{true}; /// Object is no longer of interest - bool fExpired{false}; + bool fExpired GUARDED_BY(cs){false}; /// Failed to parse object data bool fUnparsable{false}; - vote_m_t mapCurrentMNVotes; + vote_m_t mapCurrentMNVotes GUARDED_BY(cs); - CGovernanceObjectVoteFile fileVotes; + CGovernanceObjectVoteFile fileVotes GUARDED_BY(cs); public: CGovernanceObject(); - CGovernanceObject(const uint256& nHashParentIn, int nRevisionIn, int64_t nTime, const uint256& nCollateralHashIn, const std::string& strDataHexIn); - CGovernanceObject(const CGovernanceObject& other); - - // Public Getter methods - - const Governance::Object& Object() const - { - return m_obj; - } - - int64_t GetCreationTime() const + template + CGovernanceObject(deserialize_type, Stream& s) { s >> *this; } + + // Getters + bool IsSetCachedFunding() const { return fCachedFunding; } + bool IsSetCachedValid() const { return fCachedValid; } + bool IsSetCachedDelete() const { return fCachedDelete; } + bool IsSetCachedEndorsed() const { return fCachedEndorsed; } + bool IsSetDirtyCache() const { return fDirtyCache; } + bool IsSetExpired() const EXCLUSIVE_LOCKS_REQUIRED(!cs) { - return m_obj.time; + return WITH_LOCK(cs, return fExpired); } - - int64_t GetDeletionTime() const - { - return nDeletionTime; - } - - GovernanceObject GetObjectType() const + GovernanceObject GetObjectType() const { return m_obj.type; } + int64_t GetCreationTime() const { return m_obj.time; } + int64_t GetDeletionTime() const EXCLUSIVE_LOCKS_REQUIRED(!cs) { - return m_obj.type; + return WITH_LOCK(cs, return nDeletionTime); } - const uint256& GetCollateralHash() const + const CGovernanceObjectVoteFile& GetVoteFile() const EXCLUSIVE_LOCKS_REQUIRED(cs) { - return m_obj.collateralHash; - } - - const COutPoint& GetMasternodeOutpoint() const - { - return m_obj.masternodeOutpoint; - } - - bool IsSetCachedFunding() const - { - return fCachedFunding; - } - - bool IsSetCachedValid() const - { - return fCachedValid; - } - - bool IsSetCachedDelete() const - { - return fCachedDelete; - } - - bool IsSetCachedEndorsed() const - { - return fCachedEndorsed; - } - - bool IsSetDirtyCache() const - { - return fDirtyCache; - } - - bool IsSetExpired() const - { - return fExpired; - } - - void SetExpired() - { - fExpired = true; + AssertLockHeld(cs); + return fileVotes; } + const COutPoint& GetMasternodeOutpoint() const { return m_obj.masternodeOutpoint; } + const Governance::Object& Object() const { return m_obj; } + const uint256& GetCollateralHash() const { return m_obj.collateralHash; } - const CGovernanceObjectVoteFile& GetVoteFile() const + // Setters + void SetExpired() EXCLUSIVE_LOCKS_REQUIRED(!cs) { - return fileVotes; + WITH_LOCK(cs, fExpired = true); } + void SetMasternodeOutpoint(const COutPoint& outpoint); + void SetSignature(Span sig); // Signature related functions - - void SetMasternodeOutpoint(const COutPoint& outpoint); - bool Sign(const CActiveMasternodeManager& mn_activeman); bool CheckSignature(const CBLSPublicKey& pubKey) const; - uint256 GetSignatureHash() const; // CORE OBJECT FUNCTIONS - bool IsValidLocally(const CDeterministicMNList& tip_mn_list, const ChainstateManager& chainman, std::string& strError, bool fCheckCollateral) const EXCLUSIVE_LOCKS_REQUIRED(::cs_main); + bool IsValidLocally(const CDeterministicMNList& tip_mn_list, const ChainstateManager& chainman, std::string& strError, bool fCheckCollateral) const + EXCLUSIVE_LOCKS_REQUIRED(::cs_main); - bool IsValidLocally(const CDeterministicMNList& tip_mn_list, const ChainstateManager& chainman, std::string& strError, bool& fMissingConfirmations, bool fCheckCollateral) const EXCLUSIVE_LOCKS_REQUIRED(::cs_main); + bool IsValidLocally(const CDeterministicMNList& tip_mn_list, const ChainstateManager& chainman, std::string& strError, bool& fMissingConfirmations, bool fCheckCollateral) const + EXCLUSIVE_LOCKS_REQUIRED(::cs_main); /// Check the collateral transaction for the budget proposal/finalized budget - bool IsCollateralValid(const ChainstateManager& chainman, std::string& strError, bool& fMissingConfirmations) const EXCLUSIVE_LOCKS_REQUIRED(::cs_main); + bool IsCollateralValid(const ChainstateManager& chainman, std::string& strError, bool& fMissingConfirmations) const + EXCLUSIVE_LOCKS_REQUIRED(::cs_main); void UpdateLocalValidity(const CDeterministicMNList& tip_mn_list, const ChainstateManager& chainman) EXCLUSIVE_LOCKS_REQUIRED(::cs_main); - void UpdateSentinelVariables(const CDeterministicMNList& tip_mn_list); + void UpdateSentinelVariables(const CDeterministicMNList& tip_mn_list) + EXCLUSIVE_LOCKS_REQUIRED(!cs); - void PrepareDeletion(int64_t nDeletionTime_) + void PrepareDeletion(int64_t nDeletionTime_) EXCLUSIVE_LOCKS_REQUIRED(!cs) { fCachedDelete = true; + LOCK(cs); if (nDeletionTime == 0) { nDeletionTime = nDeletionTime_; } @@ -252,22 +207,27 @@ class CGovernanceObject UniValue GetJSONObject() const; - void Relay(PeerManager& peerman, const CMasternodeSync& mn_sync) const; - uint256 GetHash() const; uint256 GetDataHash() const; // GET VOTE COUNT FOR SIGNAL - int CountMatchingVotes(const CDeterministicMNList& tip_mn_list, vote_signal_enum_t eVoteSignalIn, vote_outcome_enum_t eVoteOutcomeIn) const; + int CountMatchingVotes(const CDeterministicMNList& tip_mn_list, vote_signal_enum_t eVoteSignalIn, vote_outcome_enum_t eVoteOutcomeIn) const + EXCLUSIVE_LOCKS_REQUIRED(!cs); - int GetAbsoluteYesCount(const CDeterministicMNList& tip_mn_list, vote_signal_enum_t eVoteSignalIn) const; - int GetAbsoluteNoCount(const CDeterministicMNList& tip_mn_list, vote_signal_enum_t eVoteSignalIn) const; - int GetYesCount(const CDeterministicMNList& tip_mn_list, vote_signal_enum_t eVoteSignalIn) const; - int GetNoCount(const CDeterministicMNList& tip_mn_list, vote_signal_enum_t eVoteSignalIn) const; - int GetAbstainCount(const CDeterministicMNList& tip_mn_list, vote_signal_enum_t eVoteSignalIn) const; + int GetAbsoluteYesCount(const CDeterministicMNList& tip_mn_list, vote_signal_enum_t eVoteSignalIn) const + EXCLUSIVE_LOCKS_REQUIRED(!cs); + int GetAbsoluteNoCount(const CDeterministicMNList& tip_mn_list, vote_signal_enum_t eVoteSignalIn) const + EXCLUSIVE_LOCKS_REQUIRED(!cs); + int GetYesCount(const CDeterministicMNList& tip_mn_list, vote_signal_enum_t eVoteSignalIn) const + EXCLUSIVE_LOCKS_REQUIRED(!cs); + int GetNoCount(const CDeterministicMNList& tip_mn_list, vote_signal_enum_t eVoteSignalIn) const + EXCLUSIVE_LOCKS_REQUIRED(!cs); + int GetAbstainCount(const CDeterministicMNList& tip_mn_list, vote_signal_enum_t eVoteSignalIn) const + EXCLUSIVE_LOCKS_REQUIRED(!cs); - bool GetCurrentMNVotes(const COutPoint& mnCollateralOutpoint, vote_rec_t& voteRecord) const; + bool GetCurrentMNVotes(const COutPoint& mnCollateralOutpoint, vote_rec_t& voteRecord) const + EXCLUSIVE_LOCKS_REQUIRED(!cs); // FUNCTIONS FOR DEALING WITH DATA STRING @@ -276,15 +236,27 @@ class CGovernanceObject // SERIALIZER - SERIALIZE_METHODS(CGovernanceObject, obj) + template + void Serialize(Stream& s) const EXCLUSIVE_LOCKS_REQUIRED(!cs) { // SERIALIZE DATA FOR SAVING/LOADING OR NETWORK FUNCTIONS - READWRITE(obj.m_obj); + s << m_obj; if (s.GetType() & SER_DISK) { // Only include these for the disk file format - READWRITE(obj.nDeletionTime, obj.fExpired, obj.mapCurrentMNVotes, obj.fileVotes); + LOCK(cs); + s << nDeletionTime << fExpired << mapCurrentMNVotes << fileVotes; } + } + template + void Unserialize(Stream& s) EXCLUSIVE_LOCKS_REQUIRED(!cs) + { + s >> m_obj; + if (s.GetType() & SER_DISK) { + // Only include these for the disk file format + LOCK(cs); + s >> nDeletionTime >> fExpired >> mapCurrentMNVotes >> fileVotes; + } // AFTER DESERIALIZATION OCCURS, CACHED VARIABLES MUST BE CALCULATED MANUALLY } @@ -295,17 +267,19 @@ class CGovernanceObject void GetData(UniValue& objResult) const; bool ProcessVote(CMasternodeMetaMan& mn_metaman, CGovernanceManager& govman, const CDeterministicMNList& tip_mn_list, - const CGovernanceVote& vote, CGovernanceException& exception); + const CGovernanceVote& vote, CGovernanceException& exception) + EXCLUSIVE_LOCKS_REQUIRED(!cs); /// Called when MN's which have voted on this object have been removed - void ClearMasternodeVotes(const CDeterministicMNList& tip_mn_list); + void ClearMasternodeVotes(const CDeterministicMNList& tip_mn_list) + EXCLUSIVE_LOCKS_REQUIRED(!cs); // Revalidate all votes from this MN and delete them if validation fails. // This is the case for DIP3 MNs that changed voting or operator keys and // also for MNs that were removed from the list completely. // Returns deleted vote hashes. - std::set RemoveInvalidVotes(const CDeterministicMNList& tip_mn_list, const COutPoint& mnOutpoint); + std::set RemoveInvalidVotes(const CDeterministicMNList& tip_mn_list, const COutPoint& mnOutpoint) + EXCLUSIVE_LOCKS_REQUIRED(!cs); }; - #endif // BITCOIN_GOVERNANCE_OBJECT_H diff --git a/src/governance/signing.cpp b/src/governance/signing.cpp new file mode 100644 index 000000000000..ea06dee33051 --- /dev/null +++ b/src/governance/signing.cpp @@ -0,0 +1,296 @@ +// Copyright (c) 2014-2025 The Dash Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +namespace { +constexpr std::chrono::seconds GOVERNANCE_FUDGE_WINDOW{2h}; +} // anonymous namespace + +GovernanceSigner::GovernanceSigner(CConnman& connman, CDeterministicMNManager& dmnman, GovernanceSignerParent& govman, + const CActiveMasternodeManager& mn_activeman, const ChainstateManager& chainman, + const CMasternodeSync& mn_sync) : + m_connman{connman}, + m_dmnman{dmnman}, + m_govman{govman}, + m_mn_activeman{mn_activeman}, + m_chainman{chainman}, + m_mn_sync{mn_sync} +{ +} + +GovernanceSigner::~GovernanceSigner() = default; + +std::optional GovernanceSigner::CreateSuperblockCandidate(int nHeight) const +{ + if (!m_govman.IsValid()) return std::nullopt; + if (!m_mn_sync.IsSynced()) return std::nullopt; + if (nHeight % Params().GetConsensus().nSuperblockCycle < + Params().GetConsensus().nSuperblockCycle - Params().GetConsensus().nSuperblockMaturityWindow) + return std::nullopt; + if (HasAlreadyVotedFundingTrigger()) return std::nullopt; + + const auto approvedProposals = m_govman.GetApprovedProposals(m_dmnman.GetListAtChainTip()); + if (approvedProposals.empty()) { + LogPrint(BCLog::GOBJECT, "%s -- nHeight:%d empty approvedProposals\n", __func__, nHeight); + return std::nullopt; + } + + std::vector payments; + int nLastSuperblock; + int nNextSuperblock; + + CSuperblock::GetNearestSuperblocksHeights(nHeight, nLastSuperblock, nNextSuperblock); + auto SBEpochTime = static_cast(GetTime().count() + + (nNextSuperblock - nHeight) * 2.62 * 60); + auto governanceBudget = CSuperblock::GetPaymentsLimit(m_chainman.ActiveChain(), nNextSuperblock); + + CAmount budgetAllocated{}; + for (const auto& proposal : approvedProposals) { + // Extract payment address and amount from proposal + UniValue jproposal = proposal->GetJSONObject(); + + CTxDestination dest = DecodeDestination(jproposal["payment_address"].getValStr()); + if (!IsValidDestination(dest)) continue; + + CAmount nAmount{}; + try { + nAmount = ParsePaymentAmount(jproposal["payment_amount"].getValStr()); + } catch (const std::runtime_error& e) { + LogPrint(BCLog::GOBJECT, "%s -- nHeight:%d Skipping payment exception:%s\n", __func__, nHeight, e.what()); + continue; + } + + // Construct CGovernancePayment object and make sure it is valid + CGovernancePayment payment(dest, nAmount, proposal->GetHash()); + if (!payment.IsValid()) continue; + + // Skip proposals that are too expensive + if (budgetAllocated + payment.nAmount > governanceBudget) continue; + + int64_t windowStart = jproposal["start_epoch"].getInt() - count_seconds(GOVERNANCE_FUDGE_WINDOW); + int64_t windowEnd = jproposal["end_epoch"].getInt() + count_seconds(GOVERNANCE_FUDGE_WINDOW); + + // Skip proposals if the SB isn't within the proposal time window + if (SBEpochTime < windowStart) { + LogPrint(BCLog::GOBJECT, "%s -- nHeight:%d SB:%d windowStart:%d\n", __func__, nHeight, SBEpochTime, + windowStart); + continue; + } + if (SBEpochTime > windowEnd) { + LogPrint(BCLog::GOBJECT, "%s -- nHeight:%d SB:%d windowEnd:%d\n", __func__, nHeight, SBEpochTime, windowEnd); + continue; + } + + // Keep track of total budget allocation + budgetAllocated += payment.nAmount; + + // Add the payment + payments.push_back(payment); + } + + // No proposals made the cut + if (payments.empty()) { + LogPrint(BCLog::GOBJECT, "%s -- CreateSuperblockCandidate nHeight:%d empty payments\n", __func__, nHeight); + return std::nullopt; + } + + // Sort by proposal hash descending + std::sort(payments.begin(), payments.end(), [](const CGovernancePayment& a, const CGovernancePayment& b) { + return UintToArith256(a.proposalHash) > UintToArith256(b.proposalHash); + }); + + // Create Superblock + return CSuperblock(nNextSuperblock, std::move(payments)); +} + +std::optional GovernanceSigner::CreateGovernanceTrigger(const std::optional& sb_opt) +{ + // no sb_opt, no trigger + if (!sb_opt.has_value()) return std::nullopt; + + // TODO: Check if nHashParentIn, nRevision and nCollateralHashIn are correct + LOCK(::cs_main); + + // Check if identical trigger (equal DataHash()) is already created (signed by other masternode) + CGovernanceObject gov_sb(uint256(), 1, GetAdjustedTime(), uint256(), sb_opt.value().GetHexStrData()); + if (auto identical_sb = m_govman.FindGovernanceObjectByDataHash(gov_sb.GetDataHash())) { + // Somebody submitted a trigger with the same data, support it instead of submitting a duplicate + return std::make_optional(*identical_sb); + } + + // Nobody submitted a trigger we'd like to see, so let's do it but only if we are the payee + const CBlockIndex* tip = m_chainman.ActiveChain().Tip(); + const auto mnList = m_dmnman.GetListForBlock(tip); + const auto mn_payees = mnList.GetProjectedMNPayees(tip); + + if (mn_payees.empty()) { + LogPrint(BCLog::GOBJECT, "%s -- payee list is empty\n", __func__); + return std::nullopt; + } + + if (mn_payees.front()->proTxHash != m_mn_activeman.GetProTxHash()) { + LogPrint(BCLog::GOBJECT, "%s -- we are not the payee, skipping\n", __func__); + return std::nullopt; + } + gov_sb.SetMasternodeOutpoint(m_mn_activeman.GetOutPoint()); + gov_sb.SetSignature(m_mn_activeman.SignBasic(gov_sb.GetSignatureHash())); + + if (std::string strError; !gov_sb.IsValidLocally(m_dmnman.GetListAtChainTip(), m_chainman, strError, true)) { + LogPrint(BCLog::GOBJECT, "%s -- Created trigger is invalid:%s\n", __func__, strError); + return std::nullopt; + } + + if (!m_govman.MasternodeRateCheck(gov_sb)) { + LogPrint(BCLog::GOBJECT, "%s -- Trigger rejected because of rate check failure hash(%s)\n", __func__, + gov_sb.GetHash().ToString()); + return std::nullopt; + } + + // The trigger we just created looks good, submit it + m_govman.AddGovernanceObject(gov_sb); + return std::make_optional(gov_sb); +} + +void GovernanceSigner::VoteGovernanceTriggers(const std::optional& trigger_opt) +{ + // only active masternodes can vote on triggers + if (m_mn_activeman.GetProTxHash().IsNull()) return; + + LOCK(::cs_main); + + if (trigger_opt.has_value()) { + // We should never vote "yes" on another trigger or the same trigger twice + assert(!votedFundingYesTriggerHash.has_value()); + // Vote YES-FUNDING for the trigger we like, unless we already did + const uint256 gov_sb_hash = trigger_opt.value().GetHash(); + bool voted_already{false}; + if (vote_rec_t voteRecord; trigger_opt.value().GetCurrentMNVotes(m_mn_activeman.GetOutPoint(), voteRecord)) { + const auto& strFunc = __func__; + // Let's see if there is a VOTE_SIGNAL_FUNDING vote from us already + voted_already = ranges::any_of(voteRecord.mapInstances, [&](const auto& voteInstancePair) { + if (voteInstancePair.first == VOTE_SIGNAL_FUNDING) { + if (voteInstancePair.second.eOutcome == VOTE_OUTCOME_YES) { + votedFundingYesTriggerHash = gov_sb_hash; + } + LogPrint(BCLog::GOBJECT, /* Continued */ + "%s -- Not voting YES-FUNDING for trigger:%s, we voted %s for it already\n", strFunc, + gov_sb_hash.ToString(), + CGovernanceVoting::ConvertOutcomeToString(voteInstancePair.second.eOutcome)); + return true; + } + return false; + }); + } + if (!voted_already) { + // No previous VOTE_SIGNAL_FUNDING was found, vote now + if (VoteFundingTrigger(gov_sb_hash, VOTE_OUTCOME_YES)) { + LogPrint(BCLog::GOBJECT, "%s -- Voting YES-FUNDING for new trigger:%s success\n", __func__, + gov_sb_hash.ToString()); + votedFundingYesTriggerHash = gov_sb_hash; + } else { + LogPrint(BCLog::GOBJECT, "%s -- Voting YES-FUNDING for new trigger:%s failed\n", __func__, + gov_sb_hash.ToString()); + // this should never happen, bail out + return; + } + } + } + + // Vote NO-FUNDING for the rest of the active triggers + const auto activeTriggers = m_govman.GetActiveTriggers(); + for (const auto& trigger : activeTriggers) { + auto govobj = m_govman.FindGovernanceObject(trigger->GetGovernanceObjHash()); + if (!govobj) { + LogPrint(BCLog::GOBJECT, "%s -- Not voting NO-FUNDING for unknown trigger %s\n", __func__, + trigger->GetGovernanceObjHash().ToString()); + continue; + } + + const uint256 trigger_hash = govobj->GetHash(); + if (trigger->GetBlockHeight() <= m_govman.GetCachedBlockHeight()) { + // ignore triggers from the past + LogPrint(BCLog::GOBJECT, "%s -- Not voting NO-FUNDING for outdated trigger:%s\n", __func__, + trigger_hash.ToString()); + continue; + } + if (trigger_hash == votedFundingYesTriggerHash) { + // Skip actual trigger + LogPrint(BCLog::GOBJECT, "%s -- Not voting NO-FUNDING for trigger:%s, we voted yes for it already\n", + __func__, trigger_hash.ToString()); + continue; + } + if (vote_rec_t voteRecord; govobj->GetCurrentMNVotes(m_mn_activeman.GetOutPoint(), voteRecord)) { + const auto& strFunc = __func__; + if (ranges::any_of(voteRecord.mapInstances, [&](const auto& voteInstancePair) { + if (voteInstancePair.first == VOTE_SIGNAL_FUNDING) { + LogPrint(BCLog::GOBJECT, /* Continued */ + "%s -- Not voting NO-FUNDING for trigger:%s, we voted %s for it already\n", strFunc, + trigger_hash.ToString(), + CGovernanceVoting::ConvertOutcomeToString(voteInstancePair.second.eOutcome)); + return true; + } + return false; + })) { + continue; + } + } + if (!VoteFundingTrigger(trigger_hash, VOTE_OUTCOME_NO)) { + LogPrint(BCLog::GOBJECT, "%s -- Voting NO-FUNDING for trigger:%s failed\n", __func__, trigger_hash.ToString()); + // failing here is ok-ish + continue; + } + LogPrint(BCLog::GOBJECT, "%s -- Voting NO-FUNDING for trigger:%s success\n", __func__, trigger_hash.ToString()); + } +} + +bool GovernanceSigner::VoteFundingTrigger(const uint256& nHash, const vote_outcome_enum_t outcome) +{ + CGovernanceVote vote(m_mn_activeman.GetOutPoint(), nHash, VOTE_SIGNAL_FUNDING, outcome); + vote.SetTime(GetAdjustedTime()); + vote.SetSignature(m_mn_activeman.SignBasic(vote.GetSignatureHash())); + + CGovernanceException exception; + if (!m_govman.ProcessVoteAndRelay(vote, exception, m_connman)) { + LogPrint(BCLog::GOBJECT, "%s -- Vote FUNDING %d for trigger:%s failed:%s\n", __func__, outcome, + nHash.ToString(), exception.what()); + return false; + } + + return true; +} + +bool GovernanceSigner::HasAlreadyVotedFundingTrigger() const +{ + return votedFundingYesTriggerHash.has_value(); +} + +void GovernanceSigner::ResetVotedFundingTrigger() +{ + votedFundingYesTriggerHash = std::nullopt; +} + +void GovernanceSigner::UpdatedBlockTip(const CBlockIndex* pindex) +{ + const auto sb_opt = CreateSuperblockCandidate(pindex->nHeight); + const auto trigger_opt = CreateGovernanceTrigger(sb_opt); + VoteGovernanceTriggers(trigger_opt); + CSuperblock_sptr pSuperblock; + if (m_govman.GetBestSuperblock(m_dmnman.GetListAtChainTip(), pSuperblock, pindex->nHeight)) { + ResetVotedFundingTrigger(); + } +} diff --git a/src/governance/signing.h b/src/governance/signing.h new file mode 100644 index 000000000000..f03aec29096d --- /dev/null +++ b/src/governance/signing.h @@ -0,0 +1,81 @@ +// Copyright (c) 2014-2025 The Dash Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_GOVERNANCE_SIGNING_H +#define BITCOIN_GOVERNANCE_SIGNING_H + +#include +#include + +#include + +#include +#include +#include + +class CActiveMasternodeManager; +class CBlockIndex; +class CConnman; +class CDeterministicMNList; +class CDeterministicMNManager; +class CGovernanceException; +class CGovernanceVote; +class ChainstateManager; +class CMasternodeSync; +class CNode; +enum vote_outcome_enum_t : int; + +class GovernanceSignerParent +{ +public: + virtual ~GovernanceSignerParent() = default; + + virtual bool IsValid() const = 0; + virtual bool GetBestSuperblock(const CDeterministicMNList& tip_mn_list, + std::shared_ptr& pSuperblockRet, int nBlockHeight) = 0; + virtual bool MasternodeRateCheck(const CGovernanceObject& govobj, bool fUpdateFailStatus = false) = 0; + virtual bool ProcessVoteAndRelay(const CGovernanceVote& vote, CGovernanceException& exception, CConnman& connman) = 0; + virtual int GetCachedBlockHeight() const = 0; + virtual std::shared_ptr FindGovernanceObject(const uint256& nHash) = 0; + virtual std::shared_ptr FindGovernanceObjectByDataHash(const uint256& nDataHash) = 0; + virtual std::vector> GetActiveTriggers() const = 0; + virtual std::vector> GetApprovedProposals( + const CDeterministicMNList& tip_mn_list) = 0; + virtual void AddGovernanceObject(CGovernanceObject& govobj, const CNode* pfrom = nullptr) = 0; +}; + +class GovernanceSigner +{ +private: + CConnman& m_connman; + CDeterministicMNManager& m_dmnman; + GovernanceSignerParent& m_govman; + const CActiveMasternodeManager& m_mn_activeman; + const ChainstateManager& m_chainman; + const CMasternodeSync& m_mn_sync; + +private: + std::optional votedFundingYesTriggerHash{std::nullopt}; + +public: + GovernanceSigner() = delete; + GovernanceSigner(const GovernanceSigner&) = delete; + GovernanceSigner& operator=(const GovernanceSigner&) = delete; + explicit GovernanceSigner(CConnman& connman, CDeterministicMNManager& dmnman, GovernanceSignerParent& govman, + const CActiveMasternodeManager& mn_activeman, const ChainstateManager& chainman, + const CMasternodeSync& mn_sync); + ~GovernanceSigner(); + + void UpdatedBlockTip(const CBlockIndex* pindex); + +private: + bool HasAlreadyVotedFundingTrigger() const; + bool VoteFundingTrigger(const uint256& nHash, const vote_outcome_enum_t outcome); + std::optional CreateGovernanceTrigger(const std::optional& sb_opt); + std::optional CreateSuperblockCandidate(int nHeight) const; + void ResetVotedFundingTrigger(); + void VoteGovernanceTriggers(const std::optional& trigger_opt); +}; + +#endif // BITCOIN_GOVERNANCE_SIGNING_H diff --git a/src/governance/vote.cpp b/src/governance/vote.cpp index 57c6e5d69ffd..2a013465e38c 100644 --- a/src/governance/vote.cpp +++ b/src/governance/vote.cpp @@ -5,13 +5,13 @@ #include #include -#include #include #include -#include #include #include -#include + +#include +#include #include #include @@ -102,23 +102,6 @@ std::string CGovernanceVote::ToString(const CDeterministicMNList& tip_mn_list) c voteWeight); } -void CGovernanceVote::Relay(PeerManager& peerman, const CMasternodeSync& mn_sync, const CDeterministicMNList& tip_mn_list) const -{ - // Do not relay until fully synced - if (!mn_sync.IsSynced()) { - LogPrint(BCLog::GOBJECT, "CGovernanceVote::Relay -- won't relay until fully synced\n"); - return; - } - - auto dmn = tip_mn_list.GetMNByCollateral(masternodeOutpoint); - if (!dmn) { - return; - } - - CInv inv(MSG_GOVERNANCE_OBJECT_VOTE, GetHash()); - peerman.RelayInv(inv); -} - void CGovernanceVote::UpdateHash() const { // Note: doesn't match serialization @@ -158,16 +141,6 @@ bool CGovernanceVote::CheckSignature(const CKeyID& keyID) const return true; } -bool CGovernanceVote::Sign(const CActiveMasternodeManager& mn_activeman) -{ - CBLSSignature sig = mn_activeman.Sign(GetSignatureHash(), false); - if (!sig.IsValid()) { - return false; - } - vchSig = sig.ToByteVector(false); - return true; -} - bool CGovernanceVote::CheckSignature(const CBLSPublicKey& pubKey) const { CBLSSignature sig; diff --git a/src/governance/vote.h b/src/governance/vote.h index 6d2388a132af..18664f8b97ec 100644 --- a/src/governance/vote.h +++ b/src/governance/vote.h @@ -10,14 +10,10 @@ #include #include -class CActiveMasternodeManager; class CBLSPublicKey; class CDeterministicMNList; class CGovernanceVote; -class CMasternodeSync; -class CKey; class CKeyID; -class PeerManager; // INTENTION OF MASTERNODES REGARDING ITEM enum vote_outcome_enum_t : int { @@ -97,9 +93,7 @@ class CGovernanceVote void SetSignature(const std::vector& vchSigIn) { vchSig = vchSigIn; } - bool Sign(const CKey& key, const CKeyID& keyID); bool CheckSignature(const CKeyID& keyID) const; - bool Sign(const CActiveMasternodeManager& mn_activeman); bool CheckSignature(const CBLSPublicKey& pubKey) const; bool IsValid(const CDeterministicMNList& tip_mn_list, bool useVotingKey) const; std::string GetSignatureString() const @@ -109,7 +103,6 @@ class CGovernanceVote ::ToString(nVoteOutcome) + "|" + ::ToString(nTime); } - void Relay(PeerManager& peerman, const CMasternodeSync& mn_sync, const CDeterministicMNList& tip_mn_list) const; const COutPoint& GetMasternodeOutpoint() const { return masternodeOutpoint; } diff --git a/src/hash.cpp b/src/hash.cpp index 87ffc3982a39..0544468bfd94 100644 --- a/src/hash.cpp +++ b/src/hash.cpp @@ -82,9 +82,9 @@ uint256 SHA256Uint256(const uint256& input) return result; } -CHashWriter TaggedHash(const std::string& tag) +HashWriter TaggedHash(const std::string& tag) { - CHashWriter writer(SER_GETHASH, 0); + HashWriter writer{}; uint256 taghash; CSHA256().Write((const unsigned char*)tag.data(), tag.size()).Finalize(taghash.begin()); writer << taghash << taghash; diff --git a/src/hash.h b/src/hash.h index 5dad7c72bcf7..8db12e811cd4 100644 --- a/src/hash.h +++ b/src/hash.h @@ -242,12 +242,12 @@ unsigned int MurmurHash3(unsigned int nHashSeed, Span vData void BIP32Hash(const ChainCode &chainCode, unsigned int nChild, unsigned char header, const unsigned char data[32], unsigned char output[64]); -/** Return a CHashWriter primed for tagged hashes (as specified in BIP 340). +/** Return a HashWriter primed for tagged hashes (as specified in BIP 340). * * The returned object will have SHA256(tag) written to it twice (= 64 bytes). * A tagged hash can be computed by feeding the message into this object, and - * then calling CHashWriter::GetSHA256(). + * then calling HashWriter::GetSHA256(). */ -CHashWriter TaggedHash(const std::string& tag); +HashWriter TaggedHash(const std::string& tag); #endif // BITCOIN_HASH_H diff --git a/src/httprpc.cpp b/src/httprpc.cpp index 22c1be063a8b..46cb1041c23e 100644 --- a/src/httprpc.cpp +++ b/src/httprpc.cpp @@ -4,7 +4,6 @@ #include -#include #include #include #include @@ -12,7 +11,6 @@ #include #include #include -#include #include #include @@ -21,6 +19,7 @@ #include #include #include +#include /** WWW-Authenticate to present with 401 Unauthorized response */ static const char* WWW_AUTH_HEADER_DATA = "Basic realm=\"jsonrpc\""; @@ -288,12 +287,14 @@ static bool InitRPCAuthentication() 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","") != "") - { + if (gArgs.GetArg("-rpcauth", "") != "") { LogPrintf("Using rpcauth authentication.\n"); for (const std::string& rpcauth : gArgs.GetArgs("-rpcauth")) { - std::vector fields = SplitString(rpcauth, ":$"); - if (fields.size() == 3) { + std::vector fields{SplitString(rpcauth, ':')}; + const std::vector salt_hmac{SplitString(fields.back(), '$')}; + if (fields.size() == 2 && salt_hmac.size() == 2) { + fields.pop_back(); + fields.insert(fields.end(), salt_hmac.begin(), salt_hmac.end()); g_rpcauth.push_back(fields); } else { LogPrintf("Invalid -rpcauth argument.\n"); diff --git a/src/httpserver.cpp b/src/httpserver.cpp index fe8c8879ea43..6155b28e230e 100644 --- a/src/httpserver.cpp +++ b/src/httpserver.cpp @@ -72,20 +72,18 @@ class WorkQueue std::condition_variable cond GUARDED_BY(cs); std::deque> queue GUARDED_BY(cs); std::deque> external_queue GUARDED_BY(cs); - bool running GUARDED_BY(cs); + bool running GUARDED_BY(cs){true}; const size_t maxDepth; const size_t m_external_depth; public: - explicit WorkQueue(size_t _maxDepth, size_t external_depth) : running(true), + explicit WorkQueue(size_t _maxDepth, size_t external_depth) : maxDepth(_maxDepth), m_external_depth(external_depth) { } /** Precondition: worker threads have all stopped (they have been joined). */ - ~WorkQueue() - { - } + ~WorkQueue() = default; /** Enqueue a work item */ bool Enqueue(WorkItem* item, bool is_external) EXCLUSIVE_LOCKS_REQUIRED(!cs) { @@ -159,7 +157,7 @@ static std::unique_ptr> g_work_queue{nullptr}; //! List of 'external' RPC users (global variable, used by httprpc) std::vector g_external_usernames; //! Handlers for (sub)paths -static Mutex g_httppathhandlers_mutex; +static GlobalMutex g_httppathhandlers_mutex; static std::vector pathHandlers GUARDED_BY(g_httppathhandlers_mutex); //! Bound listening sockets static std::vector boundSockets; @@ -684,6 +682,9 @@ std::optional HTTPRequest::GetQueryParameter(const std::string& key std::optional GetQueryParameterFromUri(const char* uri, const std::string& key) { evhttp_uri* uri_parsed{evhttp_uri_parse(uri)}; + if (!uri_parsed) { + throw std::runtime_error("URI parsing failed, it likely contained RFC 3986 invalid characters"); + } const char* query{evhttp_uri_get_query(uri_parsed)}; std::optional result; diff --git a/src/index/base.cpp b/src/index/base.cpp index c3368088c44c..d585cac6dd53 100644 --- a/src/index/base.cpp +++ b/src/index/base.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include diff --git a/src/index/blockfilterindex.cpp b/src/index/blockfilterindex.cpp index c0cf84e51285..5449a93b0954 100644 --- a/src/index/blockfilterindex.cpp +++ b/src/index/blockfilterindex.cpp @@ -9,6 +9,7 @@ #include #include #include +#include using node::UndoReadFromDisk; @@ -166,7 +167,7 @@ bool BlockFilterIndex::CommitInternal(CDBBatch& batch) } // Flush current filter file to disk. - CAutoFile file(m_filter_fileseq->Open(pos), SER_DISK, CLIENT_VERSION); + AutoFile file{m_filter_fileseq->Open(pos)}; if (file.IsNull()) { return error("%s: Failed to open filter file %d", __func__, pos.nFile); } @@ -180,7 +181,7 @@ bool BlockFilterIndex::CommitInternal(CDBBatch& batch) bool BlockFilterIndex::ReadFilterFromDisk(const FlatFilePos& pos, const uint256& hash, BlockFilter& filter) const { - CAutoFile filein(m_filter_fileseq->Open(pos, true), SER_DISK, CLIENT_VERSION); + AutoFile filein{m_filter_fileseq->Open(pos, true)}; if (filein.IsNull()) { return false; } @@ -210,7 +211,7 @@ size_t BlockFilterIndex::WriteFilterToDisk(FlatFilePos& pos, const BlockFilter& // If writing the filter would overflow the file, flush and move to the next one. if (pos.nPos + data_size > MAX_FLTR_FILE_SIZE) { - CAutoFile last_file(m_filter_fileseq->Open(pos), SER_DISK, CLIENT_VERSION); + AutoFile last_file{m_filter_fileseq->Open(pos)}; if (last_file.IsNull()) { LogPrintf("%s: Failed to open filter file %d\n", __func__, pos.nFile); return 0; @@ -236,7 +237,7 @@ size_t BlockFilterIndex::WriteFilterToDisk(FlatFilePos& pos, const BlockFilter& return 0; } - CAutoFile fileout(m_filter_fileseq->Open(pos), SER_DISK, CLIENT_VERSION); + AutoFile fileout{m_filter_fileseq->Open(pos)}; if (fileout.IsNull()) { LogPrintf("%s: Failed to open filter file %d\n", __func__, pos.nFile); return 0; diff --git a/src/index/coinstatsindex.cpp b/src/index/coinstatsindex.cpp index 457590ec9c3f..49c81ba1efbc 100644 --- a/src/index/coinstatsindex.cpp +++ b/src/index/coinstatsindex.cpp @@ -10,13 +10,15 @@ #include #include #include +#include #include #include -using node::CCoinsStats; -using node::GetBogoSize; +using kernel::CCoinsStats; +using kernel::GetBogoSize; +using kernel::TxOutSer; + using node::ReadBlockFromDisk; -using node::TxOutSer; using node::UndoReadFromDisk; static constexpr uint8_t DB_BLOCK_HASH{'s'}; @@ -315,28 +317,31 @@ static bool LookUpOne(const CDBWrapper& db, const CBlockIndex* block_index, DBVa return db.Read(DBHashKey(block_index->GetBlockHash()), result); } -bool CoinStatsIndex::LookUpStats(const CBlockIndex* block_index, CCoinsStats& coins_stats) const +std::optional CoinStatsIndex::LookUpStats(const CBlockIndex* block_index) const { + CCoinsStats stats{Assert(block_index)->nHeight, block_index->GetBlockHash()}; + stats.index_used = true; + DBVal entry; if (!LookUpOne(*m_db, block_index, entry)) { - return false; + return std::nullopt; } - coins_stats.hashSerialized = entry.muhash; - coins_stats.nTransactionOutputs = entry.transaction_output_count; - coins_stats.nBogoSize = entry.bogo_size; - coins_stats.total_amount = entry.total_amount; - coins_stats.total_subsidy = entry.total_subsidy; - coins_stats.total_unspendable_amount = entry.total_unspendable_amount; - coins_stats.total_prevout_spent_amount = entry.total_prevout_spent_amount; - coins_stats.total_new_outputs_ex_coinbase_amount = entry.total_new_outputs_ex_coinbase_amount; - coins_stats.total_coinbase_amount = entry.total_coinbase_amount; - coins_stats.total_unspendables_genesis_block = entry.total_unspendables_genesis_block; - coins_stats.total_unspendables_bip30 = entry.total_unspendables_bip30; - coins_stats.total_unspendables_scripts = entry.total_unspendables_scripts; - coins_stats.total_unspendables_unclaimed_rewards = entry.total_unspendables_unclaimed_rewards; - - return true; + stats.hashSerialized = entry.muhash; + stats.nTransactionOutputs = entry.transaction_output_count; + stats.nBogoSize = entry.bogo_size; + stats.total_amount = entry.total_amount; + stats.total_subsidy = entry.total_subsidy; + stats.total_unspendable_amount = entry.total_unspendable_amount; + stats.total_prevout_spent_amount = entry.total_prevout_spent_amount; + stats.total_new_outputs_ex_coinbase_amount = entry.total_new_outputs_ex_coinbase_amount; + stats.total_coinbase_amount = entry.total_coinbase_amount; + stats.total_unspendables_genesis_block = entry.total_unspendables_genesis_block; + stats.total_unspendables_bip30 = entry.total_unspendables_bip30; + stats.total_unspendables_scripts = entry.total_unspendables_scripts; + stats.total_unspendables_unclaimed_rewards = entry.total_unspendables_unclaimed_rewards; + + return stats; } bool CoinStatsIndex::Init() diff --git a/src/index/coinstatsindex.h b/src/index/coinstatsindex.h index 0eb42b1ca35d..40b19ca9315c 100644 --- a/src/index/coinstatsindex.h +++ b/src/index/coinstatsindex.h @@ -9,7 +9,7 @@ #include #include #include -#include +#include /** * CoinStatsIndex maintains statistics on the UTXO set. @@ -56,7 +56,7 @@ class CoinStatsIndex final : public BaseIndex explicit CoinStatsIndex(size_t n_cache_size, bool f_memory = false, bool f_wipe = false); // Look up stats for a specific block using CBlockIndex - bool LookUpStats(const CBlockIndex* block_index, node::CCoinsStats& coins_stats) const; + std::optional LookUpStats(const CBlockIndex* block_index) const; }; /// The global UTXO set hash object. diff --git a/src/index/txindex.cpp b/src/index/txindex.cpp index 75e8bea7033f..1a6a0cf7fe01 100644 --- a/src/index/txindex.cpp +++ b/src/index/txindex.cpp @@ -52,7 +52,7 @@ TxIndex::TxIndex(size_t n_cache_size, bool f_memory, bool f_wipe) : m_db(std::make_unique(n_cache_size, f_memory, f_wipe)) {} -TxIndex::~TxIndex() {} +TxIndex::~TxIndex() = default; bool TxIndex::WriteBlock(const CBlock& block, const CBlockIndex* pindex) { @@ -80,7 +80,7 @@ bool TxIndex::FindTx(const uint256& tx_hash, uint256& block_hash, CTransactionRe return false; } - CAutoFile file(OpenBlockFile(postx, true), SER_DISK, CLIENT_VERSION); + AutoFile file{OpenBlockFile(postx, true)}; if (file.IsNull()) { return error("%s: OpenBlockFile failed", __func__); } diff --git a/src/init.cpp b/src/init.cpp index d9d2cbde48ec..c831ed4986a8 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include @@ -32,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -78,8 +78,8 @@ #include #include -#include #include +#include #include #include #include @@ -87,6 +87,7 @@ #include #include #include +#include #include #include #include @@ -121,7 +122,6 @@ #include #ifndef WIN32 -#include #include #include #include @@ -135,10 +135,10 @@ #include #endif +using kernel::CoinStatsHashType; + using node::CacheSizes; using node::CalculateCacheSizes; -using node::CCoinsStats; -using node::CoinStatsHashType; using node::ChainstateLoadingError; using node::ChainstateLoadVerifyError; using node::DashChainstateSetupClose; @@ -225,13 +225,35 @@ static fs::path GetPidFile(const ArgsManager& args) // shutdown thing. // +#if HAVE_SYSTEM +static void ShutdownNotify(const ArgsManager& args) +{ + std::vector threads; + for (const auto& cmd : args.GetArgs("-shutdownnotify")) { + threads.emplace_back(runCommand, cmd); + } + for (auto& t : threads) { + t.join(); + } +} +#endif + void Interrupt(NodeContext& node) { +#if HAVE_SYSTEM + ShutdownNotify(*node.args); +#endif InterruptHTTPServer(); InterruptHTTPRPC(); InterruptRPC(); InterruptREST(); InterruptTorControl(); + if (node.active_ctx) { + node.active_ctx->Interrupt(); + } + if (node.peerman) { + node.peerman->InterruptHandlers(); + } if (node.llmq_ctx) { node.llmq_ctx->Interrupt(); } @@ -267,6 +289,9 @@ void PrepareShutdown(NodeContext& node) StopREST(); StopRPC(); StopHTTPServer(); + + if (node.active_ctx) node.active_ctx->Stop(); + if (node.peerman) node.peerman->StopHandlers(); if (node.llmq_ctx) node.llmq_ctx->Stop(); for (const auto& client : node.chain_clients) { @@ -326,6 +351,15 @@ void PrepareShutdown(NodeContext& node) g_active_notification_interface.reset(); } + if (node.cj_walletman) { + UnregisterValidationInterface(node.cj_walletman.get()); + } + + if (g_ds_notification_interface) { + UnregisterValidationInterface(g_ds_notification_interface.get()); + g_ds_notification_interface.reset(); + } + // After all scheduled tasks have been flushed, destroy pointers // and reset all to nullptr. node.active_ctx.reset(); @@ -377,18 +411,14 @@ void PrepareShutdown(NodeContext& node) } #endif - if (g_ds_notification_interface) { - UnregisterValidationInterface(g_ds_notification_interface.get()); - g_ds_notification_interface.reset(); - } - node.mn_activeman.reset(); node.chain_clients.clear(); // After all wallets are removed, destroy all CoinJoin objects // and reset them to nullptr - node.cj_ctx.reset(); + node.cj_walletman.reset(); + node.dstxman.reset(); UnregisterAllValidationInterfaces(); GetMainSignals().UnregisterBackgroundSignalScheduler(); @@ -431,7 +461,6 @@ void Shutdown(NodeContext& node) LogPrintf("%s: Unable to remove PID file: %s\n", __func__, fsbridge::get_filesystem_error_message(e)); } - node.args = nullptr; LogPrintf("%s: done\n", __func__); } @@ -512,6 +541,7 @@ void SetupServerArgs(ArgsManager& argsman) argsman.AddArg("-assumevalid=", strprintf("If this block is in the chain assume that it and its ancestors are valid and potentially skip their script verification (0 to verify all, default: %s, testnet: %s)", defaultChainParams->GetConsensus().defaultAssumeValid.GetHex(), testnetChainParams->GetConsensus().defaultAssumeValid.GetHex()), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsman.AddArg("-blocksdir=", "Specify directory to hold blocks subdirectory for *.dat files (default: )", 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); + argsman.AddArg("-tinyblk", "Use smaller block files for testing purposes", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); #if HAVE_SYSTEM argsman.AddArg("-blocknotify=", "Execute command when the best block changes (%s in cmd is replaced by block hash)", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); #endif @@ -521,7 +551,7 @@ void SetupServerArgs(ArgsManager& argsman) argsman.AddArg("-chainlocknotify=", "Execute command when the best chainlock changes (%s in cmd is replaced by chainlocked block hash)", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); #endif argsman.AddArg("-coinstatsindex", strprintf("Maintain coinstats index used by the gettxoutsetinfo RPC (default: %u)", DEFAULT_COINSTATSINDEX), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - argsman.AddArg("-conf=", strprintf("Specify path to read-only configuration file. Relative paths will be prefixed by datadir location. (default: %s)", BITCOIN_CONF_FILENAME), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); + argsman.AddArg("-conf=", 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=", "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=", strprintf("Maximum database cache size 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); @@ -545,6 +575,7 @@ void SetupServerArgs(ArgsManager& argsman) argsman.AddArg("-syncmempool", strprintf("Sync mempool from other nodes on start (default: %u)", DEFAULT_SYNC_MEMPOOL), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); #if HAVE_SYSTEM argsman.AddArg("-startupnotify=", "Execute command on startup.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); + argsman.AddArg("-shutdownnotify=", "Execute command immediately before beginning shutdown. The need for shutdown may be urgent, so be careful not to delay it long (if the command doesn't require interaction with the server, consider having it fork into the background).", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); #endif #ifndef WIN32 argsman.AddArg("-sysperms", "Create new files with system default permissions, instead of umask 077 (only effective with disabled wallet functionality)", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); @@ -748,7 +779,7 @@ void SetupServerArgs(ArgsManager& argsman) argsman.AddArg("-acceptnonstdtxn", strprintf("Relay and mine \"non-standard\" transactions (%sdefault: %u)", "testnet/regtest only; ", !testnetChainParams->RequireStandard()), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::NODE_RELAY); argsman.AddArg("-dustrelayfee=", strprintf("Fee rate (in %s/kB) used to define dust, the value of an output such that it will cost more than its value in fees at this fee rate to spend it. (default: %s)", CURRENCY_UNIT, FormatMoney(DUST_RELAY_TX_FEE)), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::NODE_RELAY); - argsman.AddArg("-incrementalrelayfee=", strprintf("Fee rate (in %s/kB) used to define cost of relay, used for mempool limiting and BIP 125 replacement. (default: %s)", CURRENCY_UNIT, FormatMoney(DEFAULT_INCREMENTAL_RELAY_FEE)), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::NODE_RELAY); + argsman.AddArg("-incrementalrelayfee=", strprintf("Fee rate (in %s/kB) used to define cost of relay, used for mempool limiting. (default: %s)", CURRENCY_UNIT, FormatMoney(DEFAULT_INCREMENTAL_RELAY_FEE)), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::NODE_RELAY); argsman.AddArg("-bytespersigop", strprintf("Equivalent bytes per sigop in transactions for relay and mining (default: %u)", DEFAULT_BYTES_PER_SIGOP), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY); argsman.AddArg("-datacarrier", strprintf("Relay and mine data carrier transactions (default: %u)", DEFAULT_ACCEPT_DATACARRIER), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY); argsman.AddArg("-datacarriersize", strprintf("Maximum size of data in data carrier transactions we relay and mine (default: %u)", MAX_OP_RETURN_RELAY), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY); @@ -767,6 +798,7 @@ void SetupServerArgs(ArgsManager& argsman) argsman.AddArg("-rpcallowip=", "Allow JSON-RPC connections from specified source. Valid values for are a single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0), a network/CIDR (e.g. 1.2.3.4/24), all ipv4 (0.0.0.0/0), or all ipv6 (::/0). This option can be specified multiple times", ArgsManager::ALLOW_ANY, OptionsCategory::RPC); argsman.AddArg("-rpcauth=", "Username and HMAC-SHA-256 hashed password for JSON-RPC connections. The field comes in the format: :$. A canonical python script is included in share/rpcuser. The client then connects normally using the rpcuser=/rpcpassword= pair of arguments. This option can be specified multiple times", ArgsManager::ALLOW_ANY | ArgsManager::SENSITIVE, OptionsCategory::RPC); argsman.AddArg("-rpcbind=[: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, or if -rpcallowip has been specified, 0.0.0.0 and :: i.e., all addresses)", 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=", "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("-rpcexternaluser=", "List of comma-separated usernames for JSON-RPC external connections", ArgsManager::ALLOW_ANY | ArgsManager::SENSITIVE, OptionsCategory::RPC); argsman.AddArg("-rpcexternalworkqueue=", strprintf("Set the depth of the work queue to service external RPC calls (default: %d)", DEFAULT_HTTP_WORKQUEUE), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::RPC); @@ -783,7 +815,7 @@ void SetupServerArgs(ArgsManager& argsman) argsman.AddArg("-statsbatchsize=", strprintf("Specify the size of each batch of stats messages (default: %d)", DEFAULT_STATSD_BATCH_SIZE), ArgsManager::ALLOW_ANY, OptionsCategory::STATSD); argsman.AddArg("-statsduration=", strprintf("Specify the number of milliseconds between stats messages (default: %d)", DEFAULT_STATSD_DURATION), ArgsManager::ALLOW_ANY, OptionsCategory::STATSD); argsman.AddArg("-statshost=", strprintf("Specify statsd host (default: %s)", DEFAULT_STATSD_HOST), ArgsManager::ALLOW_ANY, OptionsCategory::STATSD); - argsman.AddArg("-statsport=", strprintf("Specify statsd port (default: %u)", DEFAULT_STATSD_PORT), ArgsManager::ALLOW_ANY, OptionsCategory::STATSD); + hidden_args.emplace_back("-statsport"); argsman.AddArg("-statsperiod=", strprintf("Specify the number of seconds between periodic measurements (default: %d)", DEFAULT_STATSD_PERIOD), ArgsManager::ALLOW_ANY, OptionsCategory::STATSD); argsman.AddArg("-statsprefix=", strprintf("Specify an optional string prepended to every stats key (default: %s)", DEFAULT_STATSD_PREFIX), ArgsManager::ALLOW_ANY, OptionsCategory::STATSD); argsman.AddArg("-statssuffix=", strprintf("Specify an optional string appended to every stats key (default: %s)", DEFAULT_STATSD_SUFFIX), ArgsManager::ALLOW_ANY, OptionsCategory::STATSD); @@ -800,7 +832,7 @@ void SetupServerArgs(ArgsManager& argsman) } static bool fHaveGenesis = false; -static Mutex g_genesis_wait_mutex; +static GlobalMutex g_genesis_wait_mutex; static std::condition_variable g_genesis_wait_cv; static void BlockNotifyGenesisWait(const CBlockIndex* pBlockIndex) @@ -832,15 +864,15 @@ static void PeriodicStats(NodeContext& node) ChainstateManager& chainman = *Assert(node.chainman); const CTxMemPool& mempool = *Assert(node.mempool); const llmq::CInstantSendManager& isman = *Assert(node.llmq_ctx->isman); - CCoinsStats stats{CoinStatsHashType::NONE}; chainman.ActiveChainstate().ForceFlushStateToDisk(); - if (WITH_LOCK(cs_main, return GetUTXOStats(&chainman.ActiveChainstate().CoinsDB(), chainman.m_blockman, stats, node.rpc_interruption_point, chainman.ActiveChain().Tip()))) { - ::g_stats_client->gauge("utxoset.tx", stats.nTransactions, 1.0f); - ::g_stats_client->gauge("utxoset.txOutputs", stats.nTransactionOutputs, 1.0f); - ::g_stats_client->gauge("utxoset.dbSizeBytes", stats.nDiskSize, 1.0f); - ::g_stats_client->gauge("utxoset.blockHeight", stats.nHeight, 1.0f); - if (stats.total_amount.has_value()) { - ::g_stats_client->gauge("utxoset.totalAmount", (double)stats.total_amount.value() / (double)COIN, 1.0f); + const auto maybe_stats = WITH_LOCK(::cs_main, return GetUTXOStats(&chainman.ActiveChainstate().CoinsDB(), chainman.m_blockman, /*hash_type=*/CoinStatsHashType::NONE, node.rpc_interruption_point, chainman.ActiveChain().Tip(), /*index_requested=*/true)); + if (maybe_stats.has_value()) { + ::g_stats_client->gauge("utxoset.tx", maybe_stats->nTransactions, 1.0f); + ::g_stats_client->gauge("utxoset.txOutputs", maybe_stats->nTransactionOutputs, 1.0f); + ::g_stats_client->gauge("utxoset.dbSizeBytes", maybe_stats->nDiskSize, 1.0f); + ::g_stats_client->gauge("utxoset.blockHeight", maybe_stats->nHeight, 1.0f); + if (maybe_stats->total_amount.has_value()) { + ::g_stats_client->gauge("utxoset.totalAmount", (double)maybe_stats->total_amount.value() / (double)COIN, 1.0f); } } else { // something went wrong @@ -1256,8 +1288,7 @@ bool AppInitParameterInteraction(const ArgsManager& args) int64_t nMempoolSizeMin = args.GetIntArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT) * 1000 * 40; if (nMempoolSizeMax < 0 || nMempoolSizeMax < nMempoolSizeMin) return InitError(strprintf(_("-maxmempool must be at least %d MB"), std::ceil(nMempoolSizeMin / 1000000.0))); - // incremental relay fee sets the minimum feerate increase necessary for BIP 125 replacement in the mempool - // and the amount the mempool min fee increases above the feerate of txs evicted due to mempool limiting. + // incremental relay fee sets the amount the mempool min fee increases above the feerate of txs evicted due to mempool limiting. if (args.IsArgSet("-incrementalrelayfee")) { if (std::optional inc_relay_fee = ParseMoney(args.GetArg("-incrementalrelayfee", ""))) { ::incrementalRelayFee = CFeeRate{inc_relay_fee.value()}; @@ -1409,7 +1440,7 @@ bool AppInitParameterInteraction(const ArgsManager& args) static bool LockDataDirectory(bool probeOnly) { // Make sure only a single Dash Core process is using the data directory. - fs::path datadir = gArgs.GetDataDirNet(); + const fs::path& datadir = gArgs.GetDataDirNet(); if (!DirIsWritable(datadir)) { return InitError(strprintf(_("Cannot write to data directory '%s'; check permissions."), fs::PathToString(datadir))); } @@ -1584,11 +1615,6 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) fDiscover = args.GetBoolArg("-discover", true); const bool ignores_incoming_txs{args.GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY)}; - // We need to initialize g_stats_client early as currently, g_stats_client is called - // regardless of whether transmitting stats are desirable or not and if - // g_stats_client isn't present when that attempt is made, the client will crash. - ::g_stats_client = InitStatsClient(args); - { // Read asmap file if configured @@ -1631,6 +1657,17 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) return InitError(strprintf(_("Invalid -socketevents ('%s') specified. Only these modes are supported: %s"), sem_str, GetSupportedSocketEventsStr())); } + // We need to initialize g_stats_client early as currently, g_stats_client is called + // regardless of whether transmitting stats are desirable or not and if + // g_stats_client isn't present when that attempt is made, the client will crash. + { + auto stats_client = StatsdClient::make(args); + if (!stats_client) { + return InitError(_("Cannot init Statsd client") + Untranslated(" (") + util::ErrorString(stats_client) + Untranslated(")")); + } + ::g_stats_client = std::move(*stats_client); + } + assert(!node.banman); node.banman = std::make_unique(gArgs.GetDataDirNet() / "banlist", &uiInterface, args.GetIntArg("-bantime", DEFAULT_MISBEHAVING_BANTIME)); assert(!node.connman); @@ -1968,6 +2005,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) node.mnhf_manager, node.llmq_ctx, Assert(node.mempool.get()), + args.GetDataDirNet(), fPruneMode, args.GetBoolArg("-addressindex", DEFAULT_ADDRESSINDEX), is_governance_enabled, @@ -1982,6 +2020,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) cache_sizes.coins, /*block_tree_db_in_memory=*/false, /*coins_db_in_memory=*/false, + /*dash_dbs_in_memory=*/false, /*shutdown_requested=*/ShutdownRequested, /*coins_error_cb=*/[]() { uiInterface.ThreadSafeMessageBox( @@ -2126,36 +2165,43 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) ChainstateManager& chainman = *Assert(node.chainman); + assert(!node.dstxman); + node.dstxman = std::make_unique(); + + assert(!node.cj_walletman); + if (!node.mn_activeman) { + node.cj_walletman = CJWalletManager::make(chainman, *node.dmnman, *node.mn_metaman, *node.mempool, *node.mn_sync, + *node.llmq_ctx->isman, !ignores_incoming_txs); + } + if (node.cj_walletman) { + RegisterValidationInterface(node.cj_walletman.get()); + } + assert(!node.peerman); - node.peerman = PeerManager::make(chainparams, *node.connman, *node.addrman, node.banman.get(), + node.peerman = PeerManager::make(chainparams, *node.connman, *node.addrman, node.banman.get(), *node.dstxman, chainman, *node.mempool, *node.mn_metaman, *node.mn_sync, *node.govman, *node.sporkman, node.mn_activeman.get(), node.dmnman, - node.active_ctx, node.cj_ctx, node.llmq_ctx, ignores_incoming_txs); + node.active_ctx, node.cj_walletman.get(), node.llmq_ctx, ignores_incoming_txs); RegisterValidationInterface(node.peerman.get()); g_ds_notification_interface = std::make_unique( - *node.connman, *node.mn_sync, *node.govman, *node.peerman, chainman, node.mn_activeman.get(), node.dmnman, node.llmq_ctx, node.cj_ctx + *node.connman, *node.dstxman, *node.mn_sync, *node.govman, chainman, node.dmnman, node.llmq_ctx ); RegisterValidationInterface(g_ds_notification_interface.get()); - // ********************************************************* Step 7c: Setup CoinJoin - - node.cj_ctx = std::make_unique(chainman, *node.dmnman, *node.mn_metaman, *node.mempool, - node.mn_activeman.get(), *node.mn_sync, *node.llmq_ctx->isman, - !ignores_incoming_txs); - - // ********************************************************* Step 7d: Setup masternode mode + // ********************************************************* Step 7c: Setup masternode mode assert(!node.active_ctx); assert(!g_active_notification_interface); if (node.mn_activeman) { - node.active_ctx = std::make_unique(chainman, *node.connman, *node.dmnman, *node.cj_ctx->dstxman, *node.mn_metaman, *node.mnhf_manager, - *node.llmq_ctx, *node.sporkman, *node.mempool, *node.peerman, *node.mn_activeman, - *node.mn_sync); + node.active_ctx = std::make_unique(chainman, *node.connman, *node.dmnman, *node.dstxman, *node.govman, *node.mn_metaman, + *node.mnhf_manager, *node.sporkman, *node.mempool, *node.llmq_ctx, *node.peerman, + *node.mn_activeman, *node.mn_sync); g_active_notification_interface = std::make_unique(*node.active_ctx, *node.mn_activeman); RegisterValidationInterface(g_active_notification_interface.get()); } + node.peerman->AddExtraHandler(std::make_unique(node.peerman.get(), *node.llmq_ctx->isman, *node.llmq_ctx->qman, chainman.ActiveChainstate())); - // ********************************************************* Step 7e: Setup other Dash services + // ********************************************************* Step 7d: Setup other Dash services bool fLoadCacheFiles = !(fReindex || fReindexChainState) && (chainman.ActiveChain().Tip() != nullptr); @@ -2187,10 +2233,6 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) // ********************************************************* Step 8: start indexers if (args.GetBoolArg("-txindex", DEFAULT_TXINDEX)) { - if (const auto error{WITH_LOCK(cs_main, return CheckLegacyTxindex(*Assert(chainman.m_blockman.m_block_tree_db)))}) { - return InitError(*error); - } - g_txindex = std::make_unique(cache_sizes.tx_index, false, fReindex); if (!g_txindex->Start(chainman.ActiveChainstate())) { return false; @@ -2252,25 +2294,26 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) // ********************************************************* Step 10a: schedule Dash-specific tasks - node.llmq_ctx->Start(*node.connman, *node.peerman); + node.llmq_ctx->Start(*node.peerman); + node.peerman->StartHandlers(); + if (node.active_ctx) node.active_ctx->Start(*node.connman, *node.peerman); node.scheduler->scheduleEvery(std::bind(&CNetFulfilledRequestManager::DoMaintenance, std::ref(*node.netfulfilledman)), std::chrono::minutes{1}); node.scheduler->scheduleEvery(std::bind(&CMasternodeSync::DoMaintenance, std::ref(*node.mn_sync), std::cref(*node.peerman), std::cref(*node.govman)), std::chrono::seconds{1}); - node.scheduler->scheduleEvery(std::bind(&CMasternodeUtils::DoMaintenance, std::ref(*node.connman), std::ref(*node.dmnman), std::ref(*node.mn_sync), std::ref(*node.cj_ctx)), std::chrono::minutes{1}); + node.scheduler->scheduleEvery(std::bind(&CMasternodeUtils::DoMaintenance, std::ref(*node.connman), std::ref(*node.dmnman), std::ref(*node.mn_sync), node.cj_walletman.get()), std::chrono::minutes{1}); node.scheduler->scheduleEvery(std::bind(&CDeterministicMNManager::DoMaintenance, std::ref(*node.dmnman)), std::chrono::seconds{10}); if (node.govman->IsValid()) { - node.scheduler->scheduleEvery(std::bind(&CGovernanceManager::DoMaintenance, std::ref(*node.govman), std::ref(*node.connman)), std::chrono::minutes{5}); + node.govman->Schedule(*node.scheduler, *node.connman, *node.peerman); } if (node.mn_activeman) { node.scheduler->scheduleEvery(std::bind(&CCoinJoinServer::DoMaintenance, std::ref(*node.active_ctx->cj_server)), std::chrono::seconds{1}); node.scheduler->scheduleEvery(std::bind(&llmq::CDKGSessionManager::CleanupOldContributions, std::ref(*node.llmq_ctx->qdkgsman)), std::chrono::hours{1}); -#ifdef ENABLE_WALLET - } else if (!ignores_incoming_txs) { - node.scheduler->scheduleEvery(std::bind(&CCoinJoinClientQueueManager::DoMaintenance, std::ref(*node.cj_ctx->queueman)), std::chrono::seconds{1}); - node.scheduler->scheduleEvery(std::bind(&CoinJoinWalletManager::DoMaintenance, std::ref(*node.cj_ctx->walletman), std::ref(*node.connman)), std::chrono::seconds{1}); -#endif // ENABLE_WALLET + } + + if (node.cj_walletman) { + node.cj_walletman->Schedule(*node.connman, *node.scheduler); } if (::g_stats_client->active()) { @@ -2289,6 +2332,24 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) return false; } + int chain_active_height = WITH_LOCK(cs_main, return chainman.ActiveChain().Height()); + + // On first startup, warn on low block storage space + if (!fReindex && !fReindexChainState && chain_active_height <= 1) { + uint64_t additional_bytes_needed = fPruneMode ? nPruneTarget + : chainparams.AssumedBlockchainSize() * 1024 * 1024 * 1024; + + if (!CheckDiskSpace(args.GetBlocksDirPath(), additional_bytes_needed)) { + InitWarning(strprintf(_( + "Disk space for %s may not accommodate the block files. " \ + "Approximately %u GB of data will be stored in this directory." + ), + fs::quoted(fs::PathToString(args.GetBlocksDirPath())), + chainparams.AssumedBlockchainSize() + )); + } + } + // Either install a handler to notify us when genesis activates, or set fHaveGenesis directly. // No locking, as this happens before any background thread is started. boost::signals2::connection block_notify_genesis_wait_connection; @@ -2379,8 +2440,6 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) // ********************************************************* Step 12: start node - int chain_active_height; - //// debug print { LOCK(cs_main); diff --git a/src/init/common.cpp b/src/init/common.cpp index 8ca786eaa045..d04764d0c73e 100644 --- a/src/init/common.cpp +++ b/src/init/common.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -64,13 +65,9 @@ void AddLoggingArgs(ArgsManager& argsman) ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); argsman.AddArg("-debugexclude=", "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("-logips", strprintf("Include IP addresses in debug output (default: %u)", DEFAULT_LOGIPS), ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); - argsman.AddArg("-loglevel=|:", strprintf("Set the global or per-category severity level for logging categories enabled with the -debug configuration option or the logging RPC: %s (default=%s); warning and error levels are always logged. If : is supplied, the setting will override the global one and may be specified multiple times to set multiple category-specific levels. 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("-loglevel=|:", 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 : is supplied, the setting will override the global one and may be specified multiple times to set multiple category-specific levels. 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); -#ifdef HAVE_THREAD_LOCAL argsman.AddArg("-logthreadnames", strprintf("Prepend debug output with name of the originating thread (only available on platforms supporting thread_local) (default: %u)", DEFAULT_LOGTHREADNAMES), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); -#else - argsman.AddHiddenArgs({"-logthreadnames"}); -#endif argsman.AddArg("-logsourcelocations", strprintf("Prepend debug output with name of the originating source location (source file, line number and function name) (default: %u)", DEFAULT_LOGSOURCELOCATIONS), ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); argsman.AddArg("-logtimemicros", strprintf("Add microsecond precision to debug timestamps (default: %u)", DEFAULT_LOGTIMEMICROS), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); argsman.AddArg("-printtoconsole", "Send trace/debug info to console (default: 1 when no -daemon. To disable logging to file, set -nodebuglogfile)", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); @@ -84,9 +81,7 @@ void SetLoggingOptions(const ArgsManager& args) LogInstance().m_print_to_console = args.GetBoolArg("-printtoconsole", !args.GetBoolArg("-daemon", false)); LogInstance().m_log_timestamps = args.GetBoolArg("-logtimestamps", DEFAULT_LOGTIMESTAMPS); LogInstance().m_log_time_micros = args.GetBoolArg("-logtimemicros", DEFAULT_LOGTIMEMICROS); -#ifdef HAVE_THREAD_LOCAL LogInstance().m_log_threadnames = args.GetBoolArg("-logthreadnames", DEFAULT_LOGTHREADNAMES); -#endif LogInstance().m_log_sourcelocations = args.GetBoolArg("-logsourcelocations", DEFAULT_LOGSOURCELOCATIONS); fLogIPs = args.GetBoolArg("-logips", DEFAULT_LOGIPS); diff --git a/src/instantsend/db.cpp b/src/instantsend/db.cpp index 695e297403bf..49af9762c010 100644 --- a/src/instantsend/db.cpp +++ b/src/instantsend/db.cpp @@ -26,23 +26,22 @@ static std::tuple BuildInversedISLockKey(std::st } } // anonymous namespace -CInstantSendDb::CInstantSendDb(bool unitTests, bool fWipe) : - db(std::make_unique(unitTests ? "" : (gArgs.GetDataDirNet() / "llmq/isdb"), 32 << 20, unitTests, fWipe)) +CInstantSendDb::CInstantSendDb(const util::DbWrapperParams& db_params) : + db{util::MakeDbWrapper({db_params.path / "llmq" / "isdb", db_params.memory, db_params.wipe, /*cache_size=*/32 << 20})} { - Upgrade(unitTests); + Upgrade({db_params.path / "llmq" / "isdb", db_params.memory, /*wipe=*/true, /*cache_size=*/32 << 20}); } CInstantSendDb::~CInstantSendDb() = default; -void CInstantSendDb::Upgrade(bool unitTests) +void CInstantSendDb::Upgrade(const util::DbWrapperParams& db_params) { LOCK(cs_db); int v{0}; if (!db->Read(DB_VERSION, v) || v < CInstantSendDb::CURRENT_VERSION) { // Wipe db db.reset(); - db = std::make_unique(unitTests ? "" : (gArgs.GetDataDirNet() / "llmq/isdb"), 32 << 20, unitTests, - /*fWipe=*/true); + db = util::MakeDbWrapper(db_params); CDBBatch batch(*db); batch.Write(DB_VERSION, CInstantSendDb::CURRENT_VERSION); // Sync DB changes to disk @@ -280,11 +279,7 @@ InstantSendLockPtr CInstantSendDb::GetInstantSendLockByHashInternal(const uint25 ret = std::make_shared(); bool exists = db->Read(std::make_tuple(DB_ISLOCK_BY_HASH, hash), *ret); if (!exists || (::SerializeHash(*ret) != hash)) { - ret = std::make_shared(); - exists = db->Read(std::make_tuple(DB_ISLOCK_BY_HASH, hash), *ret); - if (!exists || (::SerializeHash(*ret) != hash)) { - ret = nullptr; - } + ret = nullptr; } islockCache.insert(hash, ret); return ret; diff --git a/src/instantsend/db.h b/src/instantsend/db.h index 6ab07f4be8a5..e8b5deb405c6 100644 --- a/src/instantsend/db.h +++ b/src/instantsend/db.h @@ -24,6 +24,9 @@ class CBlockIndex; class CDBBatch; class CDBWrapper; class COutPoint; +namespace util { +struct DbWrapperParams; +} // namespace util namespace instantsend { class CInstantSendDb @@ -78,10 +81,10 @@ class CInstantSendDb uint256 GetInstantSendLockHashByTxidInternal(const uint256& txid) const EXCLUSIVE_LOCKS_REQUIRED(cs_db); - void Upgrade(bool unitTests) EXCLUSIVE_LOCKS_REQUIRED(!cs_db); + void Upgrade(const util::DbWrapperParams& db_params) EXCLUSIVE_LOCKS_REQUIRED(!cs_db); public: - explicit CInstantSendDb(bool unitTests, bool fWipe); + explicit CInstantSendDb(const util::DbWrapperParams& db_params); ~CInstantSendDb(); /** diff --git a/src/instantsend/instantsend.cpp b/src/instantsend/instantsend.cpp index b3cb1d4b677b..495eefd68119 100644 --- a/src/instantsend/instantsend.cpp +++ b/src/instantsend/instantsend.cpp @@ -4,25 +4,17 @@ #include +#include #include #include -#include -#include -#include -#include -#include - -#include -#include #include -#include -#include -#include #include +#include #include #include - -#include +#include +#include +#include // Forward declaration to break dependency over node/transaction.h namespace node { @@ -44,106 +36,38 @@ Uint256HashSet GetIdsFromLockable(const std::vector& vec) if (vec.empty()) return ret; ret.reserve(vec.size()); for (const auto& in : vec) { - ret.emplace(instantsend::GenInputLockRequestId(in)); + if constexpr (std::is_same_v) { + ret.emplace(instantsend::GenInputLockRequestId(in)); + } else if constexpr (std::is_same_v) { + ret.emplace(instantsend::GenInputLockRequestId(in.prevout)); + } else { + assert(false); + } } return ret; } } // anonymous namespace -CInstantSendManager::CInstantSendManager(CChainLocksHandler& _clhandler, CChainState& chainstate, CQuorumManager& _qman, +CInstantSendManager::CInstantSendManager(CChainLocksHandler& _clhandler, CChainState& chainstate, CSigningManager& _sigman, CSporkManager& sporkman, CTxMemPool& _mempool, - const CMasternodeSync& mn_sync, bool unitTests, bool fWipe) : - db{unitTests, fWipe}, + const CMasternodeSync& mn_sync, const util::DbWrapperParams& db_params) : + db{db_params}, clhandler{_clhandler}, m_chainstate{chainstate}, - qman{_qman}, sigman{_sigman}, spork_manager{sporkman}, mempool{_mempool}, m_mn_sync{mn_sync} { - workInterrupt.reset(); } CInstantSendManager::~CInstantSendManager() = default; -void CInstantSendManager::Start(PeerManager& peerman) -{ - // can't start new thread if we have one running already - if (workThread.joinable()) { - assert(false); - } +bool ShouldReportISLockTiming() { return g_stats_client->active() || LogAcceptDebug(BCLog::INSTANTSEND); } - workThread = std::thread(&util::TraceThread, "isman", [this, &peerman] { WorkThreadMain(peerman); }); - - if (auto signer = m_signer.load(std::memory_order_acquire); signer) { - signer->Start(); - } -} - -void CInstantSendManager::Stop() -{ - if (auto signer = m_signer.load(std::memory_order_acquire); signer) { - signer->Stop(); - } - - // make sure to call InterruptWorkerThread() first - if (!workInterrupt) { - assert(false); - } - - if (workThread.joinable()) { - workThread.join(); - } -} - -bool ShouldReportISLockTiming() { - return g_stats_client->active() || LogAcceptDebug(BCLog::INSTANTSEND); -} - -MessageProcessingResult CInstantSendManager::ProcessMessage(NodeId from, std::string_view msg_type, CDataStream& vRecv) +void CInstantSendManager::EnqueueInstantSendLock(NodeId from, const uint256& hash, + std::shared_ptr islock) { - if (!IsInstantSendEnabled() || msg_type != NetMsgType::ISDLOCK) { - return {}; - } - - const auto islock = std::make_shared(); - vRecv >> *islock; - - auto hash = ::SerializeHash(*islock); - - MessageProcessingResult ret{}; - ret.m_to_erase = CInv{MSG_ISDLOCK, hash}; - - if (!islock->TriviallyValid()) { - ret.m_error = MisbehavingError{100}; - return ret; - } - - const auto blockIndex = WITH_LOCK(::cs_main, return m_chainstate.m_blockman.LookupBlockIndex(islock->cycleHash)); - if (blockIndex == nullptr) { - // Maybe we don't have the block yet or maybe some peer spams invalid values for cycleHash - ret.m_error = MisbehavingError{1}; - return ret; - } - - // Deterministic islocks MUST use rotation based llmq - auto llmqType = Params().GetConsensus().llmqTypeDIP0024InstantSend; - const auto& llmq_params_opt = Params().GetLLMQ(llmqType); - assert(llmq_params_opt); - if (blockIndex->nHeight % llmq_params_opt->dkgInterval != 0) { - ret.m_error = MisbehavingError{100}; - return ret; - } - - if (WITH_LOCK(cs_pendingLocks, return pendingInstantSendLocks.count(hash) || pendingNoTxInstantSendLocks.count(hash)) || - db.KnownInstantSendLock(hash)) { - return ret; - } - - LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- txid=%s, islock=%s: received islock, peer=%d\n", __func__, - islock->txid.ToString(), hash.ToString(), from); - if (ShouldReportISLockTiming()) { auto time_diff = [&]() -> int64_t { LOCK(cs_timingsTxSeen); @@ -162,189 +86,40 @@ MessageProcessingResult CInstantSendManager::ProcessMessage(NodeId from, std::st } LOCK(cs_pendingLocks); - pendingInstantSendLocks.emplace(hash, std::make_pair(from, islock)); - return ret; + pendingInstantSendLocks.emplace(hash, instantsend::PendingISLockFromPeer{from, std::move(islock)}); } -instantsend::PendingState CInstantSendManager::ProcessPendingInstantSendLocks() +instantsend::PendingState CInstantSendManager::FetchPendingLocks() { - decltype(pendingInstantSendLocks) pend; instantsend::PendingState ret; - if (!IsInstantSendEnabled()) { - return ret; - } - - { - LOCK(cs_pendingLocks); - // only process a max 32 locks at a time to avoid duplicate verification of recovered signatures which have been - // verified by CSigningManager in parallel - const size_t maxCount = 32; - // The keys of the removed values are temporaily stored here to avoid invalidating an iterator - std::vector removed; - removed.reserve(maxCount); - - for (const auto& [islockHash, nodeid_islptr_pair] : pendingInstantSendLocks) { - // Check if we've reached max count - if (pend.size() >= maxCount) { - ret.m_pending_work = true; - break; - } - pend.emplace(islockHash, std::move(nodeid_islptr_pair)); - removed.emplace_back(islockHash); - } - - for (const auto& islockHash : removed) { - pendingInstantSendLocks.erase(islockHash); + LOCK(cs_pendingLocks); + // only process a max 32 locks at a time to avoid duplicate verification of recovered signatures which have been + // verified by CSigningManager in parallel + const size_t maxCount = 32; + // The keys of the removed values are temporaily stored here to avoid invalidating an iterator + std::vector removed; + removed.reserve(std::min(maxCount, pendingInstantSendLocks.size())); + + for (auto& [islockHash, nodeid_islptr_pair] : pendingInstantSendLocks) { + // Check if we've reached max count + if (ret.m_pending_is.size() >= maxCount) { + ret.m_pending_work = true; + break; } + ret.m_pending_is.emplace_back(islockHash, std::move(nodeid_islptr_pair)); + removed.emplace_back(islockHash); } - if (pend.empty()) { - ret.m_pending_work = false; - return ret; - } - - // TODO Investigate if leaving this is ok - auto llmqType = Params().GetConsensus().llmqTypeDIP0024InstantSend; - const auto& llmq_params_opt = Params().GetLLMQ(llmqType); - assert(llmq_params_opt); - const auto& llmq_params = llmq_params_opt.value(); - auto dkgInterval = llmq_params.dkgInterval; - - // First check against the current active set and don't ban - auto badISLocks = ProcessPendingInstantSendLocks(llmq_params, /*signOffset=*/0, /*ban=*/false, pend, ret.m_peer_activity); - if (!badISLocks.empty()) { - LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- doing verification on old active set\n", __func__); - - // filter out valid IS locks from "pend" - for (auto it = pend.begin(); it != pend.end();) { - if (!badISLocks.count(it->first)) { - it = pend.erase(it); - } else { - ++it; - } - } - // Now check against the previous active set and perform banning if this fails - ProcessPendingInstantSendLocks(llmq_params, dkgInterval, /*ban=*/true, pend, ret.m_peer_activity); + for (const auto& islockHash : removed) { + pendingInstantSendLocks.erase(islockHash); } return ret; } -Uint256HashSet CInstantSendManager::ProcessPendingInstantSendLocks( - const Consensus::LLMQParams& llmq_params, int signOffset, bool ban, - const Uint256HashMap>& pend, - std::vector>& peer_activity) -{ - CBLSBatchVerifier batchVerifier(false, true, 8); - Uint256HashMap recSigs; - - size_t verifyCount = 0; - size_t alreadyVerified = 0; - for (const auto& p : pend) { - const auto& hash = p.first; - auto nodeId = p.second.first; - const auto& islock = p.second.second; - - if (batchVerifier.badSources.count(nodeId)) { - continue; - } - - if (!islock->sig.Get().IsValid()) { - batchVerifier.badSources.emplace(nodeId); - continue; - } - - auto id = islock->GetRequestId(); - - // no need to verify an ISLOCK if we already have verified the recovered sig that belongs to it - if (sigman.HasRecoveredSig(llmq_params.type, id, islock->txid)) { - alreadyVerified++; - continue; - } - - const auto blockIndex = WITH_LOCK(::cs_main, return m_chainstate.m_blockman.LookupBlockIndex(islock->cycleHash)); - if (blockIndex == nullptr) { - batchVerifier.badSources.emplace(nodeId); - continue; - } - - int nSignHeight{-1}; - const auto dkgInterval = llmq_params.dkgInterval; - if (blockIndex->nHeight + dkgInterval < m_chainstate.m_chain.Height()) { - nSignHeight = blockIndex->nHeight + dkgInterval - 1; - } - // For RegTest non-rotating quorum cycleHash has directly quorum hash - auto quorum = llmq_params.useRotation ? llmq::SelectQuorumForSigning(llmq_params, m_chainstate.m_chain, qman, - id, nSignHeight, signOffset) - : qman.GetQuorum(llmq_params.type, islock->cycleHash); - - if (!quorum) { - // should not happen, but if one fails to select, all others will also fail to select - return {}; - } - uint256 signHash = llmq::SignHash{llmq_params.type, quorum->qc->quorumHash, id, islock->txid}.Get(); - batchVerifier.PushMessage(nodeId, hash, signHash, islock->sig.Get(), quorum->qc->quorumPublicKey); - verifyCount++; - - // We can reconstruct the CRecoveredSig objects from the islock and pass it to the signing manager, which - // avoids unnecessary double-verification of the signature. We however only do this when verification here - // turns out to be good (which is checked further down) - if (!sigman.HasRecoveredSigForId(llmq_params.type, id)) { - recSigs.try_emplace(hash, - CRecoveredSig(llmq_params.type, quorum->qc->quorumHash, id, islock->txid, islock->sig)); - } - } - - cxxtimer::Timer verifyTimer(true); - batchVerifier.Verify(); - verifyTimer.stop(); - - LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- verified locks. count=%d, alreadyVerified=%d, vt=%d, nodes=%d\n", __func__, - verifyCount, alreadyVerified, verifyTimer.count(), batchVerifier.GetUniqueSourceCount()); - - Uint256HashSet badISLocks; - - if (ban && !batchVerifier.badSources.empty()) { - LOCK(::cs_main); - for (const auto& nodeId : batchVerifier.badSources) { - // Let's not be too harsh, as the peer might simply be unlucky and might have sent us an old lock which - // does not validate anymore due to changed quorums - peer_activity.emplace_back(nodeId, MisbehavingError{20}); - } - } - for (const auto& p : pend) { - const auto& hash = p.first; - auto nodeId = p.second.first; - const auto& islock = p.second.second; - - if (batchVerifier.badMessages.count(hash)) { - LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- txid=%s, islock=%s: invalid sig in islock, peer=%d\n", - __func__, islock->txid.ToString(), hash.ToString(), nodeId); - badISLocks.emplace(hash); - continue; - } - - peer_activity.emplace_back(nodeId, ProcessInstantSendLock(nodeId, hash, islock)); - - // See comment further on top. We pass a reconstructed recovered sig to the signing manager to avoid - // double-verification of the sig. - auto it = recSigs.find(hash); - if (it != recSigs.end()) { - auto recSig = std::make_shared(std::move(it->second)); - if (!sigman.HasRecoveredSigForId(llmq_params.type, recSig->getId())) { - LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- txid=%s, islock=%s: passing reconstructed recSig to signing mgr, peer=%d\n", __func__, - islock->txid.ToString(), hash.ToString(), nodeId); - sigman.PushReconstructedRecoveredSig(recSig); - } - } - } - - return badISLocks; -} - -MessageProcessingResult CInstantSendManager::ProcessInstantSendLock(NodeId from, const uint256& hash, - const instantsend::InstantSendLockPtr& islock) +std::variant CInstantSendManager::ProcessInstantSendLock( + NodeId from, const uint256& hash, const instantsend::InstantSendLockPtr& islock) { LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- txid=%s, islock=%s: processing islock, peer=%d\n", __func__, islock->txid.ToString(), hash.ToString(), from); @@ -353,12 +128,12 @@ MessageProcessingResult CInstantSendManager::ProcessInstantSendLock(NodeId from, signer->ClearLockFromQueue(islock); } if (db.KnownInstantSendLock(hash)) { - return {}; + return std::monostate{}; } if (const auto sameTxIsLock = db.GetInstantSendLockByTxid(islock->txid)) { // can happen, nothing to do - return {}; + return std::monostate{}; } for (const auto& in : islock->inputs) { const auto sameOutpointIsLock = db.GetInstantSendLockByInput(in); @@ -370,30 +145,37 @@ MessageProcessingResult CInstantSendManager::ProcessInstantSendLock(NodeId from, uint256 hashBlock{}; const auto tx = GetTransaction(nullptr, &mempool, islock->txid, Params().GetConsensus(), hashBlock); - const CBlockIndex* pindexMined{nullptr}; const bool found_transaction{tx != nullptr}; // we ignore failure here as we must be able to propagate the lock even if we don't have the TX locally - if (found_transaction && !hashBlock.IsNull()) { - pindexMined = WITH_LOCK(::cs_main, return m_chainstate.m_blockman.LookupBlockIndex(hashBlock)); - + std::optional minedHeight = GetBlockHeight(hashBlock); + if (found_transaction) { + if (!minedHeight.has_value()) { + const CBlockIndex* pindexMined = WITH_LOCK(::cs_main, return m_chainstate.m_blockman.LookupBlockIndex(hashBlock)); + if (pindexMined != nullptr) { + CacheBlockHeight(pindexMined); + minedHeight = pindexMined->nHeight; + } + } // Let's see if the TX that was locked by this islock is already mined in a ChainLocked block. If yes, // we can simply ignore the islock, as the ChainLock implies locking of all TXs in that chain - if (pindexMined != nullptr && clhandler.HasChainLock(pindexMined->nHeight, pindexMined->GetBlockHash())) { - LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- txlock=%s, islock=%s: dropping islock as it already got a ChainLock in block %s, peer=%d\n", __func__, - islock->txid.ToString(), hash.ToString(), hashBlock.ToString(), from); - return {}; + if (minedHeight.has_value() && clhandler.HasChainLock(*minedHeight, hashBlock)) { + LogPrint(BCLog::INSTANTSEND, /* Continued */ + "CInstantSendManager::%s -- txlock=%s, islock=%s: dropping islock as it already got a " + "ChainLock in block %s, peer=%d\n", + __func__, islock->txid.ToString(), hash.ToString(), hashBlock.ToString(), from); + return std::monostate{}; } } if (found_transaction) { db.WriteNewInstantSendLock(hash, islock); - if (pindexMined) { - db.WriteInstantSendLockMined(hash, pindexMined->nHeight); + if (minedHeight.has_value()) { + db.WriteInstantSendLockMined(hash, *minedHeight); } } else { // put it in a separate pending map and try again later LOCK(cs_pendingLocks); - pendingNoTxInstantSendLocks.try_emplace(hash, std::make_pair(from, islock)); + pendingNoTxInstantSendLocks.try_emplace(hash, instantsend::PendingISLockFromPeer{from, islock}); } // This will also add children TXs to pendingRetryTxs @@ -412,17 +194,10 @@ MessageProcessingResult CInstantSendManager::ProcessInstantSendLock(NodeId from, mempool.AddTransactionsUpdated(1); } - MessageProcessingResult ret{}; - CInv inv(MSG_ISDLOCK, hash); if (found_transaction) { - ret.m_inv_filter = std::make_pair(inv, tx); - } else { - // we don't have the TX yet, so we only filter based on txid. Later when that TX arrives, we will re-announce - // with the TX taken into account. - ret.m_inv_filter = std::make_pair(inv, islock->txid); - ret.m_request_tx = islock->txid; + return tx; } - return ret; + return islock->txid; } void CInstantSendManager::TransactionAddedToMempool(const CTransactionRef& tx) @@ -436,11 +211,11 @@ void CInstantSendManager::TransactionAddedToMempool(const CTransactionRef& tx) LOCK(cs_pendingLocks); auto it = pendingNoTxInstantSendLocks.begin(); while (it != pendingNoTxInstantSendLocks.end()) { - if (it->second.second->txid == tx->GetHash()) { + if (it->second.islock->txid == tx->GetHash()) { // we received an islock earlier LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- txid=%s, islock=%s\n", __func__, tx->GetHash().ToString(), it->first.ToString()); - islock = it->second.second; + islock = it->second.islock; pendingInstantSendLocks.try_emplace(it->first, it->second); pendingNoTxInstantSendLocks.erase(it); break; @@ -483,6 +258,8 @@ void CInstantSendManager::BlockConnected(const std::shared_ptr& pb return; } + CacheTipHeight(pindex); + if (m_mn_sync.IsBlockchainSynced()) { const bool has_chainlock = clhandler.HasChainLock(pindex->nHeight, pindex->GetBlockHash()); for (const auto& tx : pblock->vtx) { @@ -510,6 +287,13 @@ void CInstantSendManager::BlockConnected(const std::shared_ptr& pb void CInstantSendManager::BlockDisconnected(const std::shared_ptr& pblock, const CBlockIndex* pindexDisconnected) { + { + LOCK(cs_height_cache); + m_cached_block_heights.erase(pindexDisconnected->GetBlockHash()); + } + + CacheTipHeight(pindexDisconnected->pprev); + db.RemoveBlockInstantSendLocks(pblock, pindexDisconnected); } @@ -533,7 +317,7 @@ void CInstantSendManager::AddNonLockedTx(const CTransactionRef& tx, const CBlock LOCK(cs_pendingLocks); auto it = pendingNoTxInstantSendLocks.begin(); while (it != pendingNoTxInstantSendLocks.end()) { - if (it->second.second->txid == tx->GetHash()) { + if (it->second.islock->txid == tx->GetHash()) { // we received an islock earlier, let's put it back into pending and verify/lock LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- txid=%s, islock=%s\n", __func__, tx->GetHash().ToString(), it->first.ToString()); @@ -595,6 +379,24 @@ void CInstantSendManager::RemoveNonLockedTx(const uint256& txid, bool retryChild __func__, txid.ToString(), retryChildren, retryChildrenCount); } +std::vector CInstantSendManager::PrepareTxToRetry() +{ + std::vector txns{}; + + LOCK2(cs_nonLocked, cs_pendingRetry); + if (pendingRetryTxs.empty()) return txns; + txns.reserve(pendingRetryTxs.size()); + for (const auto& txid : pendingRetryTxs) { + if (auto it = nonLockedTxs.find(txid); it != nonLockedTxs.end()) { + const auto& [_, tx_info] = *it; + if (tx_info.tx) { + txns.push_back(tx_info.tx); + } + } + } + return txns; +} + void CInstantSendManager::RemoveConflictedTx(const CTransaction& tx) { RemoveNonLockedTx(tx.GetHash(), false); @@ -620,7 +422,7 @@ void CInstantSendManager::TryEmplacePendingLock(const uint256& hash, const NodeI if (db.KnownInstantSendLock(hash)) return; LOCK(cs_pendingLocks); if (!pendingInstantSendLocks.count(hash)) { - pendingInstantSendLocks.emplace(hash, std::make_pair(id, islock)); + pendingInstantSendLocks.emplace(hash, instantsend::PendingISLockFromPeer{id, islock}); } } @@ -631,6 +433,8 @@ void CInstantSendManager::NotifyChainLock(const CBlockIndex* pindexChainLock) void CInstantSendManager::UpdatedBlockTip(const CBlockIndex* pindexNew) { + CacheTipHeight(pindexNew); + bool fDIP0008Active = pindexNew->pprev && pindexNew->pprev->nHeight >= Params().GetConsensus().DIP0008Height; if (AreChainLocksEnabled(spork_manager) && fDIP0008Active) { @@ -811,7 +615,7 @@ void CInstantSendManager::RemoveConflictingLock(const uint256& islockHash, const { LogPrintf("CInstantSendManager::%s -- txid=%s, islock=%s: Removing ISLOCK and its chained children\n", __func__, islock.txid.ToString(), islockHash.ToString()); - int tipHeight = WITH_LOCK(::cs_main, return m_chainstate.m_chain.Height()); + const int tipHeight = GetTipHeight(); auto removedIslocks = db.RemoveChainedInstantSendLocks(islockHash, islock.txid, tipHeight); for (const auto& h : removedIslocks) { @@ -842,11 +646,11 @@ bool CInstantSendManager::GetInstantSendLockByHash(const uint256& hash, instants LOCK(cs_pendingLocks); auto it = pendingInstantSendLocks.find(hash); if (it != pendingInstantSendLocks.end()) { - islock = it->second.second; + islock = it->second.islock; } else { auto itNoTx = pendingNoTxInstantSendLocks.find(hash); if (itNoTx != pendingNoTxInstantSendLocks.end()) { - islock = itNoTx->second.second; + islock = itNoTx->second.islock; } else { return false; } @@ -883,7 +687,7 @@ bool CInstantSendManager::IsWaitingForTx(const uint256& txHash) const LOCK(cs_pendingLocks); auto it = pendingNoTxInstantSendLocks.begin(); while (it != pendingNoTxInstantSendLocks.end()) { - if (it->second.second->txid == txHash) { + if (it->second.islock->txid == txHash) { LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- txid=%s, islock=%s\n", __func__, txHash.ToString(), it->first.ToString()); return true; @@ -917,41 +721,62 @@ size_t CInstantSendManager::GetInstantSendLockCount() const return db.GetInstantSendLockCount(); } -void CInstantSendManager::WorkThreadMain(PeerManager& peerman) +void CInstantSendManager::CacheBlockHeightInternal(const CBlockIndex* const block_index) const { - while (!workInterrupt) { - bool fMoreWork = [&]() -> bool { - if (!IsInstantSendEnabled()) return false; - auto [more_work, peer_activity] = ProcessPendingInstantSendLocks(); - for (auto& [node_id, mpr] : peer_activity) { - peerman.PostProcessMessage(std::move(mpr), node_id); - } - auto signer = m_signer.load(std::memory_order_acquire); - if (!signer) return more_work; - // Construct set of non-locked transactions that are pending to retry - std::vector txns{}; - { - LOCK2(cs_nonLocked, cs_pendingRetry); - if (pendingRetryTxs.empty()) return more_work; - txns.reserve(pendingRetryTxs.size()); - for (const auto& txid : pendingRetryTxs) { - if (auto it = nonLockedTxs.find(txid); it != nonLockedTxs.end()) { - const auto& [_, tx_info] = *it; - if (tx_info.tx) { - txns.push_back(tx_info.tx); - } - } - } - } - // Retry processing them - signer->ProcessPendingRetryLockTxs(txns); - return more_work; - }(); + AssertLockHeld(cs_height_cache); + m_cached_block_heights.insert(block_index->GetBlockHash(), block_index->nHeight); +} + +void CInstantSendManager::CacheBlockHeight(const CBlockIndex* const block_index) const +{ + LOCK(cs_height_cache); + CacheBlockHeightInternal(block_index); +} - if (!fMoreWork && !workInterrupt.sleep_for(std::chrono::milliseconds(100))) { - return; +std::optional CInstantSendManager::GetBlockHeight(const uint256& hash) const +{ + if (hash.IsNull()) { + return std::nullopt; + } + { + LOCK(cs_height_cache); + int cached_height{0}; + if (m_cached_block_heights.get(hash, cached_height)) return cached_height; + } + + const CBlockIndex* pindex = WITH_LOCK(::cs_main, return m_chainstate.m_blockman.LookupBlockIndex(hash)); + if (pindex == nullptr) { + return std::nullopt; + } + + CacheBlockHeight(pindex); + return pindex->nHeight; +} + +void CInstantSendManager::CacheTipHeight(const CBlockIndex* const tip) const +{ + LOCK(cs_height_cache); + if (tip) { + CacheBlockHeightInternal(tip); + m_cached_tip_height = tip->nHeight; + } else { + m_cached_tip_height = -1; + } +} + +int CInstantSendManager::GetTipHeight() const +{ + { + LOCK(cs_height_cache); + if (m_cached_tip_height >= 0) { + return m_cached_tip_height; } } + + const CBlockIndex* tip = WITH_LOCK(::cs_main, return m_chainstate.m_chain.Tip()); + + CacheTipHeight(tip); + return tip ? tip->nHeight : -1; } bool CInstantSendManager::IsInstantSendEnabled() const diff --git a/src/instantsend/instantsend.h b/src/instantsend/instantsend.h index ddeb91c9d144..9b93198e85f4 100644 --- a/src/instantsend/instantsend.h +++ b/src/instantsend/instantsend.h @@ -5,21 +5,24 @@ #ifndef BITCOIN_INSTANTSEND_INSTANTSEND_H #define BITCOIN_INSTANTSEND_INSTANTSEND_H +#include +#include +#include + #include #include #include #include #include -#include - -#include -#include -#include #include #include -#include +#include #include +#include +#include + +#include class CBlockIndex; class CChainState; @@ -27,23 +30,29 @@ class CDataStream; class CMasternodeSync; class CSporkManager; class CTxMemPool; -class PeerManager; namespace Consensus { struct LLMQParams; } // namespace Consensus +namespace util { +struct DbWrapperParams; +} // namespace util namespace instantsend { class InstantSendSigner; +struct PendingISLockFromPeer { + NodeId node_id; + InstantSendLockPtr islock; +}; + struct PendingState { bool m_pending_work{false}; - std::vector> m_peer_activity{}; + std::vector> m_pending_is; }; } // namespace instantsend namespace llmq { class CChainLocksHandler; -class CQuorumManager; class CSigningManager; class CInstantSendManager final : public instantsend::InstantSendSignerParent @@ -53,7 +62,6 @@ class CInstantSendManager final : public instantsend::InstantSendSignerParent CChainLocksHandler& clhandler; CChainState& m_chainstate; - CQuorumManager& qman; CSigningManager& sigman; CSporkManager& spork_manager; CTxMemPool& mempool; @@ -61,14 +69,11 @@ class CInstantSendManager final : public instantsend::InstantSendSignerParent std::atomic m_signer{nullptr}; - std::thread workThread; - CThreadInterrupt workInterrupt; - mutable Mutex cs_pendingLocks; // Incoming and not verified yet - Uint256HashMap> pendingInstantSendLocks GUARDED_BY(cs_pendingLocks); + Uint256HashMap pendingInstantSendLocks GUARDED_BY(cs_pendingLocks); // Tried to verify but there is no tx yet - Uint256HashMap> pendingNoTxInstantSendLocks GUARDED_BY(cs_pendingLocks); + Uint256HashMap pendingNoTxInstantSendLocks GUARDED_BY(cs_pendingLocks); // TXs which are neither IS locked nor ChainLocked. We use this to determine for which TXs we need to retry IS // locking of child TXs @@ -88,10 +93,21 @@ class CInstantSendManager final : public instantsend::InstantSendSignerParent mutable Mutex cs_timingsTxSeen; Uint256HashMap timingsTxSeen GUARDED_BY(cs_timingsTxSeen); + mutable Mutex cs_height_cache; + static constexpr size_t MAX_BLOCK_HEIGHT_CACHE{16384}; + mutable unordered_lru_cache m_cached_block_heights + GUARDED_BY(cs_height_cache); + mutable int m_cached_tip_height GUARDED_BY(cs_height_cache){-1}; + + void CacheBlockHeightInternal(const CBlockIndex* const block_index) const EXCLUSIVE_LOCKS_REQUIRED(cs_height_cache); + public: - explicit CInstantSendManager(CChainLocksHandler& _clhandler, CChainState& chainstate, CQuorumManager& _qman, - CSigningManager& _sigman, CSporkManager& sporkman, CTxMemPool& _mempool, - const CMasternodeSync& mn_sync, bool unitTests, bool fWipe); + CInstantSendManager() = delete; + CInstantSendManager(const CInstantSendManager&) = delete; + CInstantSendManager& operator=(const CInstantSendManager&) = delete; + explicit CInstantSendManager(CChainLocksHandler& _clhandler, CChainState& chainstate, CSigningManager& _sigman, + CSporkManager& sporkman, CTxMemPool& _mempool, const CMasternodeSync& mn_sync, + const util::DbWrapperParams& db_params); ~CInstantSendManager(); void ConnectSigner(gsl::not_null signer) @@ -102,24 +118,11 @@ class CInstantSendManager final : public instantsend::InstantSendSignerParent } void DisconnectSigner() { m_signer.store(nullptr, std::memory_order_release); } - void Start(PeerManager& peerman); - void Stop(); - void InterruptWorkerThread() { workInterrupt(); }; + instantsend::InstantSendSigner* Signer() const { return m_signer.load(); } private: - instantsend::PendingState ProcessPendingInstantSendLocks() - EXCLUSIVE_LOCKS_REQUIRED(!cs_nonLocked, !cs_pendingLocks, !cs_pendingRetry); - - Uint256HashSet ProcessPendingInstantSendLocks(const Consensus::LLMQParams& llmq_params, int signOffset, bool ban, - const Uint256HashMap>& pend, - std::vector>& peer_activity) - EXCLUSIVE_LOCKS_REQUIRED(!cs_nonLocked, !cs_pendingLocks, !cs_pendingRetry); - MessageProcessingResult ProcessInstantSendLock(NodeId from, const uint256& hash, - const instantsend::InstantSendLockPtr& islock) - EXCLUSIVE_LOCKS_REQUIRED(!cs_nonLocked, !cs_pendingLocks, !cs_pendingRetry); - void AddNonLockedTx(const CTransactionRef& tx, const CBlockIndex* pindexMined) - EXCLUSIVE_LOCKS_REQUIRED(!cs_nonLocked, !cs_pendingLocks); + EXCLUSIVE_LOCKS_REQUIRED(!cs_nonLocked, !cs_pendingLocks, !cs_timingsTxSeen); void RemoveNonLockedTx(const uint256& txid, bool retryChildren) EXCLUSIVE_LOCKS_REQUIRED(!cs_nonLocked, !cs_pendingRetry); void RemoveConflictedTx(const CTransaction& tx) @@ -129,10 +132,7 @@ class CInstantSendManager final : public instantsend::InstantSendSignerParent void RemoveMempoolConflictsForLock(const uint256& hash, const instantsend::InstantSendLock& islock) EXCLUSIVE_LOCKS_REQUIRED(!cs_nonLocked, !cs_pendingRetry); void ResolveBlockConflicts(const uint256& islockHash, const instantsend::InstantSendLock& islock) - EXCLUSIVE_LOCKS_REQUIRED(!cs_nonLocked, !cs_pendingLocks, !cs_pendingRetry); - - void WorkThreadMain(PeerManager& peerman) - EXCLUSIVE_LOCKS_REQUIRED(!cs_nonLocked, !cs_pendingLocks, !cs_pendingRetry); + EXCLUSIVE_LOCKS_REQUIRED(!cs_nonLocked, !cs_pendingLocks, !cs_pendingRetry, !cs_height_cache); void HandleFullyConfirmedBlock(const CBlockIndex* pindex) EXCLUSIVE_LOCKS_REQUIRED(!cs_nonLocked, !cs_pendingRetry); @@ -142,14 +142,25 @@ class CInstantSendManager final : public instantsend::InstantSendSignerParent bool IsWaitingForTx(const uint256& txHash) const EXCLUSIVE_LOCKS_REQUIRED(!cs_pendingLocks); instantsend::InstantSendLockPtr GetConflictingLock(const CTransaction& tx) const override; - [[nodiscard]] MessageProcessingResult ProcessMessage(NodeId from, std::string_view msg_type, CDataStream& vRecv); + /* Helpers for communications between CInstantSendManager & NetInstantSend */ + // This helper returns up to 32 pending locks and remove them from queue of pending + [[nodiscard]] instantsend::PendingState FetchPendingLocks() EXCLUSIVE_LOCKS_REQUIRED(!cs_pendingLocks); + void EnqueueInstantSendLock(NodeId from, const uint256& hash, std::shared_ptr islock) + EXCLUSIVE_LOCKS_REQUIRED(!cs_pendingLocks); + [[nodiscard]] std::vector PrepareTxToRetry() + EXCLUSIVE_LOCKS_REQUIRED(!cs_nonLocked, !cs_pendingRetry); + CSigningManager& Sigman() { return sigman; } + [[nodiscard]] std::variant ProcessInstantSendLock( + NodeId from, const uint256& hash, const instantsend::InstantSendLockPtr& islock) + EXCLUSIVE_LOCKS_REQUIRED(!cs_nonLocked, !cs_pendingLocks, !cs_pendingRetry, !cs_height_cache); void TransactionAddedToMempool(const CTransactionRef& tx) - EXCLUSIVE_LOCKS_REQUIRED(!cs_nonLocked, !cs_pendingLocks, !cs_pendingRetry); - void TransactionRemovedFromMempool(const CTransactionRef& tx); + EXCLUSIVE_LOCKS_REQUIRED(!cs_nonLocked, !cs_pendingLocks, !cs_pendingRetry, !cs_timingsTxSeen); + void TransactionRemovedFromMempool(const CTransactionRef& tx) EXCLUSIVE_LOCKS_REQUIRED(!cs_height_cache); void BlockConnected(const std::shared_ptr& pblock, const CBlockIndex* pindex) - EXCLUSIVE_LOCKS_REQUIRED(!cs_nonLocked, !cs_pendingLocks, !cs_pendingRetry); - void BlockDisconnected(const std::shared_ptr& pblock, const CBlockIndex* pindexDisconnected); + EXCLUSIVE_LOCKS_REQUIRED(!cs_nonLocked, !cs_pendingLocks, !cs_pendingRetry, !cs_timingsTxSeen, !cs_height_cache); + void BlockDisconnected(const std::shared_ptr& pblock, const CBlockIndex* pindexDisconnected) + EXCLUSIVE_LOCKS_REQUIRED(!cs_height_cache); bool AlreadyHave(const CInv& inv) const EXCLUSIVE_LOCKS_REQUIRED(!cs_pendingLocks); bool GetInstantSendLockByHash(const uint256& hash, instantsend::InstantSendLock& ret) const @@ -159,14 +170,20 @@ class CInstantSendManager final : public instantsend::InstantSendSignerParent void NotifyChainLock(const CBlockIndex* pindexChainLock) EXCLUSIVE_LOCKS_REQUIRED(!cs_nonLocked, !cs_pendingRetry); void UpdatedBlockTip(const CBlockIndex* pindexNew) - EXCLUSIVE_LOCKS_REQUIRED(!cs_nonLocked, !cs_pendingRetry); + EXCLUSIVE_LOCKS_REQUIRED(!cs_nonLocked, !cs_pendingRetry, !cs_height_cache); - void RemoveConflictingLock(const uint256& islockHash, const instantsend::InstantSendLock& islock); + void RemoveConflictingLock(const uint256& islockHash, const instantsend::InstantSendLock& islock) + EXCLUSIVE_LOCKS_REQUIRED(!cs_height_cache); void TryEmplacePendingLock(const uint256& hash, const NodeId id, const instantsend::InstantSendLockPtr& islock) override EXCLUSIVE_LOCKS_REQUIRED(!cs_pendingLocks); size_t GetInstantSendLockCount() const; + void CacheBlockHeight(const CBlockIndex* const block_index) const EXCLUSIVE_LOCKS_REQUIRED(!cs_height_cache); + std::optional GetBlockHeight(const uint256& hash) const override EXCLUSIVE_LOCKS_REQUIRED(!cs_height_cache); + void CacheTipHeight(const CBlockIndex* const tip) const EXCLUSIVE_LOCKS_REQUIRED(!cs_height_cache); + int GetTipHeight() const override EXCLUSIVE_LOCKS_REQUIRED(!cs_height_cache); + bool IsInstantSendEnabled() const override; /** * If true, MN should sign all transactions, if false, MN should not sign diff --git a/src/instantsend/lock.cpp b/src/instantsend/lock.cpp index 10ef0afc3c2d..f0f2c1d1508d 100644 --- a/src/instantsend/lock.cpp +++ b/src/instantsend/lock.cpp @@ -38,11 +38,8 @@ bool InstantSendLock::TriviallyValid() const return inputs_set.size() == inputs.size(); } -template -uint256 GenInputLockRequestId(const T& val) +uint256 GenInputLockRequestId(const COutPoint& outpoint) { - return ::SerializeHash(std::make_pair(INPUTLOCK_REQUESTID_PREFIX, val)); + return ::SerializeHash(std::make_pair(INPUTLOCK_REQUESTID_PREFIX, outpoint)); } -template uint256 GenInputLockRequestId(const COutPoint& val); -template uint256 GenInputLockRequestId(const CTxIn& val); } // namespace instantsend diff --git a/src/instantsend/lock.h b/src/instantsend/lock.h index 2786ba1ff7cf..b0536e8421bc 100644 --- a/src/instantsend/lock.h +++ b/src/instantsend/lock.h @@ -40,8 +40,7 @@ struct InstantSendLock { bool TriviallyValid() const; }; -template -uint256 GenInputLockRequestId(const T& val); +uint256 GenInputLockRequestId(const COutPoint& outpoint); using InstantSendLockPtr = std::shared_ptr; } // namespace instantsend diff --git a/src/instantsend/net_instantsend.cpp b/src/instantsend/net_instantsend.cpp new file mode 100644 index 000000000000..efd217c10d51 --- /dev/null +++ b/src/instantsend/net_instantsend.cpp @@ -0,0 +1,268 @@ +// Copyright (c) 2025 The Dash Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void NetInstantSend::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRecv) +{ + if (msg_type != NetMsgType::ISDLOCK) { + return; + } + + if (!m_is_manager.IsInstantSendEnabled()) return; + + auto islock = std::make_shared(); + vRecv >> *islock; + + uint256 hash = ::SerializeHash(*islock); + + WITH_LOCK(::cs_main, m_peer_manager->PeerEraseObjectRequest(pfrom.GetId(), CInv{MSG_ISDLOCK, hash})); + + if (!islock->TriviallyValid()) { + m_peer_manager->PeerMisbehaving(pfrom.GetId(), 100); + return; + } + + auto cycleHeightOpt = m_is_manager.GetBlockHeight(islock->cycleHash); + if (!cycleHeightOpt) { + const auto blockIndex = WITH_LOCK(::cs_main, return m_chainstate.m_blockman.LookupBlockIndex(islock->cycleHash)); + if (blockIndex == nullptr) { + // Maybe we don't have the block yet or maybe some peer spams invalid values for cycleHash + m_peer_manager->PeerMisbehaving(pfrom.GetId(), 1); + return; + } + m_is_manager.CacheBlockHeight(blockIndex); + cycleHeightOpt = blockIndex->nHeight; + } + const int block_height = *cycleHeightOpt; + + // Deterministic islocks MUST use rotation based llmq + auto llmqType = Params().GetConsensus().llmqTypeDIP0024InstantSend; + const auto& llmq_params_opt = Params().GetLLMQ(llmqType); + assert(llmq_params_opt); + if (block_height % llmq_params_opt->dkgInterval != 0) { + m_peer_manager->PeerMisbehaving(pfrom.GetId(), 100); + return; + } + + if (!m_is_manager.AlreadyHave(CInv{MSG_ISDLOCK, hash})) { + LogPrint(BCLog::INSTANTSEND, "NetInstantSend -- ISDLOCK txid=%s, islock=%s: received islock, peer=%d\n", + islock->txid.ToString(), hash.ToString(), pfrom.GetId()); + + m_is_manager.EnqueueInstantSendLock(pfrom.GetId(), hash, std::move(islock)); + } +} + +void NetInstantSend::Start() +{ + // can't start new thread if we have one running already + if (workThread.joinable()) { + assert(false); + } + + workThread = std::thread(&util::TraceThread, "isman", [this] { WorkThreadMain(); }); + + if (auto signer = m_is_manager.Signer(); signer) { + signer->Start(); + } +} + +void NetInstantSend::Stop() +{ + if (auto signer = m_is_manager.Signer(); signer) { + signer->Stop(); + } + + // make sure to call Interrupt() first + if (!workInterrupt) { + assert(false); + } + + if (workThread.joinable()) { + workThread.join(); + } +} + +Uint256HashSet NetInstantSend::ProcessPendingInstantSendLocks( + const Consensus::LLMQParams& llmq_params, int signOffset, bool ban, + const std::vector>& pend) +{ + CBLSBatchVerifier batchVerifier(false, true, 8); + Uint256HashMap recSigs; + + size_t verifyCount = 0; + size_t alreadyVerified = 0; + for (const auto& p : pend) { + const auto& hash = p.first; + auto nodeId = p.second.node_id; + const auto& islock = p.second.islock; + + if (batchVerifier.badSources.count(nodeId)) { + continue; + } + + if (!islock->sig.Get().IsValid()) { + batchVerifier.badSources.emplace(nodeId); + continue; + } + + auto id = islock->GetRequestId(); + + // no need to verify an ISLOCK if we already have verified the recovered sig that belongs to it + if (m_is_manager.Sigman().HasRecoveredSig(llmq_params.type, id, islock->txid)) { + alreadyVerified++; + continue; + } + + auto cycleHeightOpt = m_is_manager.GetBlockHeight(islock->cycleHash); + if (!cycleHeightOpt) { + batchVerifier.badSources.emplace(nodeId); + continue; + } + + int nSignHeight{-1}; + const auto dkgInterval = llmq_params.dkgInterval; + const int tipHeight = m_is_manager.GetTipHeight(); + const int cycleHeight = *cycleHeightOpt; + if (cycleHeight + dkgInterval < tipHeight) { + nSignHeight = cycleHeight + dkgInterval - 1; + } + // For RegTest non-rotating quorum cycleHash has directly quorum hash + auto quorum = llmq_params.useRotation ? llmq::SelectQuorumForSigning(llmq_params, m_chainstate.m_chain, m_qman, + id, nSignHeight, signOffset) + : m_qman.GetQuorum(llmq_params.type, islock->cycleHash); + + if (!quorum) { + // should not happen, but if one fails to select, all others will also fail to select + return {}; + } + uint256 signHash = llmq::SignHash{llmq_params.type, quorum->qc->quorumHash, id, islock->txid}.Get(); + batchVerifier.PushMessage(nodeId, hash, signHash, islock->sig.Get(), quorum->qc->quorumPublicKey); + verifyCount++; + + // We can reconstruct the CRecoveredSig objects from the islock and pass it to the signing manager, which + // avoids unnecessary double-verification of the signature. We however only do this when verification here + // turns out to be good (which is checked further down) + if (!m_is_manager.Sigman().HasRecoveredSigForId(llmq_params.type, id)) { + recSigs.try_emplace(hash, llmq::CRecoveredSig(llmq_params.type, quorum->qc->quorumHash, id, islock->txid, + islock->sig)); + } + } + + cxxtimer::Timer verifyTimer(true); + batchVerifier.Verify(); + verifyTimer.stop(); + + LogPrint(BCLog::INSTANTSEND, "NetInstantSend::%s -- verified locks. count=%d, alreadyVerified=%d, vt=%d, nodes=%d\n", + __func__, verifyCount, alreadyVerified, verifyTimer.count(), batchVerifier.GetUniqueSourceCount()); + + Uint256HashSet badISLocks; + + if (ban && !batchVerifier.badSources.empty()) { + for (const auto& nodeId : batchVerifier.badSources) { + // Let's not be too harsh, as the peer might simply be unlucky and might have sent us an old lock which + // does not validate anymore due to changed quorums + m_peer_manager->PeerMisbehaving(nodeId, 20); + } + } + for (const auto& p : pend) { + const auto& hash = p.first; + auto nodeId = p.second.node_id; + const auto& islock = p.second.islock; + + if (batchVerifier.badMessages.count(hash)) { + LogPrint(BCLog::INSTANTSEND, "NetInstantSend::%s -- txid=%s, islock=%s: invalid sig in islock, peer=%d\n", + __func__, islock->txid.ToString(), hash.ToString(), nodeId); + badISLocks.emplace(hash); + continue; + } + + CInv inv(MSG_ISDLOCK, hash); + auto ret = m_is_manager.ProcessInstantSendLock(nodeId, hash, islock); + if (std::holds_alternative(ret)) { + m_peer_manager->PeerRelayInvFiltered(inv, std::get(ret)); + m_peer_manager->PeerAskPeersForTransaction(islock->txid); + } else if (std::holds_alternative(ret)) { + m_peer_manager->PeerRelayInvFiltered(inv, *std::get(ret)); + } else { + assert(std::holds_alternative(ret)); + } + + // See comment further on top. We pass a reconstructed recovered sig to the signing manager to avoid + // double-verification of the sig. + auto it = recSigs.find(hash); + if (it != recSigs.end()) { + auto recSig = std::make_shared(std::move(it->second)); + if (!m_is_manager.Sigman().HasRecoveredSigForId(llmq_params.type, recSig->getId())) { + LogPrint(BCLog::INSTANTSEND, /* Continued */ + "NetInstantSend::%s -- txid=%s, islock=%s: " + "passing reconstructed recSig to signing mgr, peer=%d\n", + __func__, islock->txid.ToString(), hash.ToString(), nodeId); + m_is_manager.Sigman().PushReconstructedRecoveredSig(recSig); + } + } + } + + return badISLocks; +} + + +void NetInstantSend::ProcessPendingISLocks(std::vector>&& locks_to_process) +{ + // TODO Investigate if leaving this is ok + auto llmqType = Params().GetConsensus().llmqTypeDIP0024InstantSend; + const auto& llmq_params_opt = Params().GetLLMQ(llmqType); + assert(llmq_params_opt); + const auto& llmq_params = llmq_params_opt.value(); + auto dkgInterval = llmq_params.dkgInterval; + + // First check against the current active set and don't ban + auto bad_is_locks = ProcessPendingInstantSendLocks(llmq_params, /*signOffset=*/0, /*ban=*/false, locks_to_process); + if (!bad_is_locks.empty()) { + LogPrint(BCLog::INSTANTSEND, "NetInstantSend::%s -- doing verification on old active set\n", __func__); + + // filter out valid IS locks from "pend" - keep only bad ones + std::vector> still_pending; + still_pending.reserve(bad_is_locks.size()); + for (auto& p : locks_to_process) { + if (bad_is_locks.contains(p.first)) { + still_pending.emplace_back(std::move(p)); + } + } + // Now check against the previous active set and perform banning if this fails + ProcessPendingInstantSendLocks(llmq_params, dkgInterval, /*ban=*/true, still_pending); + } +} + +void NetInstantSend::WorkThreadMain() +{ + while (!workInterrupt) { + bool fMoreWork = [&]() -> bool { + if (!m_is_manager.IsInstantSendEnabled()) return false; + + auto [more_work, locks] = m_is_manager.FetchPendingLocks(); + if (!locks.empty()) { + ProcessPendingISLocks(std::move(locks)); + } + if (auto signer = m_is_manager.Signer(); signer) { + signer->ProcessPendingRetryLockTxs(m_is_manager.PrepareTxToRetry()); + } + return more_work; + }(); + + if (!fMoreWork && !workInterrupt.sleep_for(std::chrono::milliseconds(100))) { + return; + } + } +} diff --git a/src/instantsend/net_instantsend.h b/src/instantsend/net_instantsend.h new file mode 100644 index 000000000000..d21ffb734ef1 --- /dev/null +++ b/src/instantsend/net_instantsend.h @@ -0,0 +1,56 @@ +// Copyright (c) 2025 The Dash Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_INSTANTSEND_NET_INSTANTSEND_H +#define BITCOIN_INSTANTSEND_NET_INSTANTSEND_H + +#include + +#include + +namespace instantsend { +struct InstantSendLock; +struct PendingISLockFromPeer; +using InstantSendLockPtr = std::shared_ptr; +} // namespace instantsend +namespace llmq { +class CInstantSendManager; +class CQuorumManager; +} // namespace llmq + +class NetInstantSend final : public NetHandler +{ +public: + NetInstantSend(PeerManagerInternal* peer_manager, llmq::CInstantSendManager& is_manager, llmq::CQuorumManager& qman, + CChainState& chainstate) : + NetHandler(peer_manager), + m_is_manager{is_manager}, + m_qman(qman), + m_chainstate{chainstate} + { + workInterrupt.reset(); + } + void ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRecv) override; + + void Start() override; + void Stop() override; + void Interrupt() override { workInterrupt(); }; + + void WorkThreadMain(); + +private: + void ProcessPendingISLocks(std::vector>&& locks_to_process); + + Uint256HashSet ProcessPendingInstantSendLocks( + const Consensus::LLMQParams& llmq_params, int signOffset, bool ban, + const std::vector>& pend); + llmq::CInstantSendManager& m_is_manager; + llmq::CQuorumManager& m_qman; + const CChainState& m_chainstate; + + std::thread workThread; + CThreadInterrupt workInterrupt; +}; + +#endif // BITCOIN_INSTANTSEND_NET_INSTANTSEND_H diff --git a/src/instantsend/signing.cpp b/src/instantsend/signing.cpp index 93d2320f7fa3..984968d9c53d 100644 --- a/src/instantsend/signing.cpp +++ b/src/instantsend/signing.cpp @@ -13,6 +13,7 @@ #include #include +#include #include #include @@ -203,16 +204,28 @@ bool InstantSendSigner::CheckCanLock(const COutPoint& outpoint, bool printDebug, return false; } - const CBlockIndex* pindexMined; - int nTxAge; - { - LOCK(::cs_main); - pindexMined = m_chainstate.m_blockman.LookupBlockIndex(hashBlock); - nTxAge = m_chainstate.m_chain.Height() - pindexMined->nHeight + 1; + const auto blockHeight = m_isman.GetBlockHeight(hashBlock); + if (!blockHeight) { + if (printDebug) { + LogPrint(BCLog::INSTANTSEND, "%s -- txid=%s: failed to determine mined height for parent TX %s\n", __func__, + txHash.ToString(), outpoint.hash.ToString()); + } + return false; + } + + const int tipHeight = m_isman.GetTipHeight(); + + if (tipHeight < *blockHeight) { + if (printDebug) { + LogPrint(BCLog::INSTANTSEND, "%s -- txid=%s: cached tip height %d is below block height %d for parent TX %s\n", + __func__, txHash.ToString(), tipHeight, *blockHeight, outpoint.hash.ToString()); + } + return false; } - if (nTxAge < nInstantSendConfirmationsRequired && - !m_clhandler.HasChainLock(pindexMined->nHeight, pindexMined->GetBlockHash())) { + const int nTxAge = tipHeight - *blockHeight + 1; + + if (nTxAge < nInstantSendConfirmationsRequired && !m_clhandler.HasChainLock(*blockHeight, hashBlock)) { if (printDebug) { LogPrint(BCLog::INSTANTSEND, "%s -- txid=%s: outpoint %s too new and not ChainLocked. nTxAge=%d, nInstantSendConfirmationsRequired=%d\n", __func__, txHash.ToString(), outpoint.ToStringShort(), nTxAge, nInstantSendConfirmationsRequired); @@ -295,7 +308,7 @@ bool InstantSendSigner::TrySignInputLocks(const CTransaction& tx, bool fRetroact size_t alreadyVotedCount = 0; for (const auto& in : tx.vin) { - auto id = GenInputLockRequestId(in); + auto id = GenInputLockRequestId(in.prevout); ids.emplace_back(id); uint256 otherTxHash; @@ -330,7 +343,7 @@ bool InstantSendSigner::TrySignInputLocks(const CTransaction& tx, bool fRetroact WITH_LOCK(cs_input_requests, inputRequestIds.emplace(id)); LogPrint(BCLog::INSTANTSEND, "%s -- txid=%s: trying to vote on input %s with id %s. fRetroactive=%d\n", __func__, tx.GetHash().ToString(), in.prevout.ToStringShort(), id.ToString(), fRetroactive); - if (m_sigman.AsyncSignIfMember(llmqType, m_shareman, id, tx.GetHash(), {}, fRetroactive)) { + if (m_shareman.AsyncSignIfMember(llmqType, m_sigman, id, tx.GetHash(), {}, fRetroactive)) { LogPrint(BCLog::INSTANTSEND, "%s -- txid=%s: voted on input %s with id %s\n", __func__, tx.GetHash().ToString(), in.prevout.ToStringShort(), id.ToString()); } @@ -344,7 +357,7 @@ void InstantSendSigner::TrySignInstantSendLock(const CTransaction& tx) const auto llmqType = Params().GetConsensus().llmqTypeDIP0024InstantSend; for (const auto& in : tx.vin) { - auto id = GenInputLockRequestId(in); + auto id = GenInputLockRequestId(in.prevout); if (!m_sigman.HasRecoveredSig(llmqType, id, tx.GetHash())) { return; } @@ -388,6 +401,6 @@ void InstantSendSigner::TrySignInstantSendLock(const CTransaction& tx) txToCreatingInstantSendLocks.emplace(tx.GetHash(), &e.first->second); } - m_sigman.AsyncSignIfMember(llmqType, m_shareman, id, tx.GetHash(), quorum->m_quorum_base_block_index->GetBlockHash()); + m_shareman.AsyncSignIfMember(llmqType, m_sigman, id, tx.GetHash(), quorum->m_quorum_base_block_index->GetBlockHash()); } } // namespace instantsend diff --git a/src/instantsend/signing.h b/src/instantsend/signing.h index 3cf41a843142..cf878e8c21e9 100644 --- a/src/instantsend/signing.h +++ b/src/instantsend/signing.h @@ -8,6 +8,8 @@ #include #include +#include + class CMasternodeSync; class CSporkManager; class CTxMemPool; @@ -34,6 +36,8 @@ class InstantSendSignerParent virtual bool IsLocked(const uint256& txHash) const = 0; virtual InstantSendLockPtr GetConflictingLock(const CTransaction& tx) const = 0; virtual void TryEmplacePendingLock(const uint256& hash, const NodeId id, const InstantSendLockPtr& islock) = 0; + virtual std::optional GetBlockHeight(const uint256& hash) const = 0; + virtual int GetTipHeight() const = 0; }; class InstantSendSigner final : public llmq::CRecoveredSigsListener @@ -69,6 +73,9 @@ class InstantSendSigner final : public llmq::CRecoveredSigsListener Uint256HashMap txToCreatingInstantSendLocks GUARDED_BY(cs_creating); public: + InstantSendSigner() = delete; + InstantSendSigner(const InstantSendSigner&) = delete; + InstantSendSigner& operator=(const InstantSendSigner&) = delete; explicit InstantSendSigner(CChainState& chainstate, llmq::CChainLocksHandler& clhandler, InstantSendSignerParent& isman, llmq::CSigningManager& sigman, llmq::CSigSharesManager& shareman, llmq::CQuorumManager& qman, CSporkManager& sporkman, diff --git a/src/interfaces/node.h b/src/interfaces/node.h index 5a7414b84fa0..e3429afcd888 100644 --- a/src/interfaces/node.h +++ b/src/interfaces/node.h @@ -5,13 +5,14 @@ #ifndef BITCOIN_INTERFACES_NODE_H #define BITCOIN_INTERFACES_NODE_H -#include // For CAmount -#include // For NodeId -#include // For banmap_t -#include // For Network -#include // For ConnectionDirection +#include // For CAmount +#include // For NodeId +#include // For banmap_t +#include // For Network +#include // For ConnectionDirection #include // For SecureString #include +#include // For util::SettingsValue #include #include @@ -157,6 +158,16 @@ struct BlockAndHeaderTipInfo double verification_progress; }; +//! External signer interface used by the GUI. +class ExternalSigner +{ +public: + virtual ~ExternalSigner() {}; + + //! Get signer display name + virtual std::string getName() = 0; +}; + //! Top-level interface for a dash node (dashd process). class Node { @@ -193,6 +204,24 @@ class Node //! Return whether shutdown was requested. virtual bool shutdownRequested() = 0; + //! Return whether a particular setting in /settings.json is or + //! would be ignored because it is also specified in the command line. + virtual bool isSettingIgnored(const std::string& name) = 0; + + //! Return setting value from /settings.json or dash.conf. + virtual util::SettingsValue getPersistentSetting(const std::string& name) = 0; + + //! Update a setting in /settings.json. + virtual void updateRwSetting(const std::string& name, const util::SettingsValue& value) = 0; + + //! Force a setting value to be applied, overriding any other configuration + //! source, but not being persisted. + virtual void forceSetting(const std::string& name, const util::SettingsValue& value) = 0; + + //! Clear all settings in /settings.json and store a backup of + //! previous settings in /settings.json.bak. + virtual void resetSettings() = 0; + //! Map port. virtual void mapPort(bool use_upnp, bool use_natpmp) = 0; @@ -221,6 +250,9 @@ class Node //! Disconnect node by id. virtual bool disconnectById(NodeId id) = 0; + //! Return list of external signers (attached devices which can sign transactions). + virtual std::vector> listExternalSigners() = 0; + //! Get total bytes recv. virtual int64_t getTotalBytesRecv() = 0; diff --git a/src/interfaces/wallet.h b/src/interfaces/wallet.h index f704bd197ef7..e9f209df28f4 100644 --- a/src/interfaces/wallet.h +++ b/src/interfaces/wallet.h @@ -151,6 +151,9 @@ class Wallet //! Save or remove receive request. virtual bool setAddressReceiveRequest(const CTxDestination& dest, const std::string& id, const std::string& value) = 0; + //! Display address on external signer + virtual bool displayAddress(const CTxDestination& dest) = 0; + //! Lock coin. virtual bool lockCoin(const COutPoint& output, const bool write_to_db) = 0; @@ -288,6 +291,9 @@ class Wallet // Return whether private keys enabled. virtual bool privateKeysDisabled() = 0; + // Return whether wallet uses an external signer. + virtual bool hasExternalSigner() = 0; + //! Get max tx fee. virtual CAmount getDefaultMaxTxFee() = 0; @@ -297,6 +303,9 @@ class Wallet //! Return whether is a legacy wallet virtual bool isLegacy() = 0; + //! Get mnemonic phrase from wallet. + virtual bool getMnemonic(SecureString& mnemonic_out, SecureString& mnemonic_passphrase_out) = 0; + //! Register handler for unload message. using UnloadFn = std::function; virtual std::unique_ptr handleUnload(UnloadFn fn) = 0; diff --git a/src/node/coinstats.cpp b/src/kernel/coinstats.cpp similarity index 70% rename from src/node/coinstats.cpp rename to src/kernel/coinstats.cpp index c31509e15304..217ac9e810ec 100644 --- a/src/node/coinstats.cpp +++ b/src/kernel/coinstats.cpp @@ -1,14 +1,12 @@ -// Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// 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 +#include #include #include #include -#include #include #include #include @@ -18,7 +16,12 @@ #include -namespace node { +namespace kernel { + +CCoinsStats::CCoinsStats(int block_height, const uint256& block_hash) + : nHeight(block_height), + hashBlock(block_hash) {} + // Database-independent metric indicating the UTXO set size uint64_t GetBogoSize(const CScript& script_pub_key) { @@ -50,7 +53,7 @@ CDataStream TxOutSer(const COutPoint& outpoint, const Coin& coin) { //! It is also possible, though very unlikely, that a change in this //! construction could cause a previously invalid (and potentially malicious) //! UTXO snapshot to be considered valid. -static void ApplyHash(CHashWriter& ss, const uint256& hash, const std::map& outputs) +static void ApplyHash(HashWriter& ss, const uint256& hash, const std::map& outputs) { for (auto it = outputs.begin(); it != outputs.end(); ++it) { if (it == outputs.begin()) { @@ -94,24 +97,11 @@ static void ApplyStats(CCoinsStats& stats, const uint256& hash, const std::map -static bool GetUTXOStats(CCoinsView* view, BlockManager& blockman, CCoinsStats& stats, T hash_obj, const std::function& interruption_point, const CBlockIndex* pindex) +static bool ComputeUTXOStats(CCoinsView* view, CCoinsStats& stats, T hash_obj, const std::function& interruption_point) { std::unique_ptr pcursor(view->Cursor()); assert(pcursor); - if (!pindex) { - LOCK(cs_main); - pindex = blockman.LookupBlockIndex(view->GetBestBlock()); - } - stats.nHeight = Assert(pindex)->nHeight; - stats.hashBlock = pindex->GetBlockHash(); - - // Use CoinStatsIndex if it is requested and available and a hash_type of Muhash or None was requested - if ((stats.m_hash_type == CoinStatsHashType::MUHASH || stats.m_hash_type == CoinStatsHashType::NONE) && g_coin_stats_index && stats.index_requested) { - stats.index_used = true; - return g_coin_stats_index->LookUpStats(pindex, stats); - } - PrepareHash(hash_obj, stats); uint256 prevkey; @@ -142,29 +132,40 @@ static bool GetUTXOStats(CCoinsView* view, BlockManager& blockman, CCoinsStats& FinalizeHash(hash_obj, stats); stats.nDiskSize = view->EstimateSize(); + return true; } -bool GetUTXOStats(CCoinsView* view, BlockManager& blockman, CCoinsStats& stats, const std::function& interruption_point, const CBlockIndex* pindex) +std::optional ComputeUTXOStats(CoinStatsHashType hash_type, CCoinsView* view, node::BlockManager& blockman, const std::function& interruption_point) { - switch (stats.m_hash_type) { - case(CoinStatsHashType::HASH_SERIALIZED): { - CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION); - return GetUTXOStats(view, blockman, stats, ss, interruption_point, pindex); - } - case(CoinStatsHashType::MUHASH): { - MuHash3072 muhash; - return GetUTXOStats(view, blockman, stats, muhash, interruption_point, pindex); - } - case(CoinStatsHashType::NONE): { - return GetUTXOStats(view, blockman, stats, nullptr, interruption_point, pindex); + CBlockIndex* pindex = WITH_LOCK(::cs_main, return blockman.LookupBlockIndex(view->GetBestBlock())); + CCoinsStats stats{Assert(pindex)->nHeight, pindex->GetBlockHash()}; + + bool success = [&]() -> bool { + switch (hash_type) { + case(CoinStatsHashType::HASH_SERIALIZED): { + HashWriter ss{}; + return ComputeUTXOStats(view, stats, ss, interruption_point); + } + case(CoinStatsHashType::MUHASH): { + MuHash3072 muhash; + return ComputeUTXOStats(view, stats, muhash, interruption_point); + } + case(CoinStatsHashType::NONE): { + return ComputeUTXOStats(view, stats, nullptr, interruption_point); + } + } // no default case, so the compiler can warn about missing cases + assert(false); + }(); + + if (!success) { + return std::nullopt; } - } // no default case, so the compiler can warn about missing cases - assert(false); + return stats; } // The legacy hash serializes the hashBlock -static void PrepareHash(CHashWriter& ss, const CCoinsStats& stats) +static void PrepareHash(HashWriter& ss, const CCoinsStats& stats) { ss << stats.hashBlock; } @@ -172,7 +173,7 @@ static void PrepareHash(CHashWriter& ss, const CCoinsStats& stats) static void PrepareHash(MuHash3072& muhash, CCoinsStats& stats) {} static void PrepareHash(std::nullptr_t, CCoinsStats& stats) {} -static void FinalizeHash(CHashWriter& ss, CCoinsStats& stats) +static void FinalizeHash(HashWriter& ss, CCoinsStats& stats) { stats.hashSerialized = ss.GetHash(); } @@ -183,4 +184,5 @@ static void FinalizeHash(MuHash3072& muhash, CCoinsStats& stats) stats.hashSerialized = out; } static void FinalizeHash(std::nullptr_t, CCoinsStats& stats) {} -} // namespace node + +} // namespace kernel diff --git a/src/node/coinstats.h b/src/kernel/coinstats.h similarity index 75% rename from src/node/coinstats.h rename to src/kernel/coinstats.h index 4ca9274db35f..c103966568f2 100644 --- a/src/node/coinstats.h +++ b/src/kernel/coinstats.h @@ -1,10 +1,9 @@ -// Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// 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_COINSTATS_H -#define BITCOIN_NODE_COINSTATS_H +#ifndef BITCOIN_KERNEL_COINSTATS_H +#define BITCOIN_KERNEL_COINSTATS_H #include #include @@ -21,17 +20,14 @@ namespace node { class BlockManager; } // namespace node -namespace node { -enum class CoinStatsHashType { +namespace kernel { +enum class CoinStatsHashType : uint8_t { HASH_SERIALIZED, MUHASH, NONE, }; struct CCoinsStats { - //! Which hash type to use - const CoinStatsHashType m_hash_type; - int nHeight{0}; uint256 hashBlock{}; uint64_t nTransactions{0}; @@ -45,8 +41,6 @@ struct CCoinsStats { //! The number of coins contained. uint64_t coins_count{0}; - //! Signals if the coinstatsindex should be used (when available). - bool index_requested{true}; //! Signals if the coinstatsindex was used to retrieve the statistics. bool index_used{false}; @@ -71,15 +65,15 @@ struct CCoinsStats { //! Total cumulative amount of coins lost due to unclaimed miner rewards up to and including this block CAmount total_unspendables_unclaimed_rewards{0}; - CCoinsStats(CoinStatsHashType hash_type) : m_hash_type(hash_type) {} + CCoinsStats() = default; + CCoinsStats(int block_height, const uint256& block_hash); }; -//! Calculate statistics about the unspent transaction output set -bool GetUTXOStats(CCoinsView* view, node::BlockManager& blockman, CCoinsStats& stats, const std::function& interruption_point = {}, const CBlockIndex* pindex = nullptr); - uint64_t GetBogoSize(const CScript& script_pub_key); CDataStream TxOutSer(const COutPoint& outpoint, const Coin& coin); -} // namespace node -#endif // BITCOIN_NODE_COINSTATS_H +std::optional ComputeUTXOStats(CoinStatsHashType hash_type, CCoinsView* view, node::BlockManager& blockman, const std::function& interruption_point = {}); +} // namespace kernel + +#endif // BITCOIN_KERNEL_COINSTATS_H diff --git a/src/key.cpp b/src/key.cpp index 947a799412eb..9f4b597d155d 100644 --- a/src/key.cpp +++ b/src/key.cpp @@ -341,6 +341,7 @@ ECDHSecret CKey::ComputeBIP324ECDHSecret(const EllSwiftPubKey& their_ellswift, c } bool CExtKey::Derive(CExtKey &out, unsigned int _nChild) const { + if (nDepth == std::numeric_limits::max()) return false; out.nDepth = nDepth + 1; CKeyID id = key.GetPubKey().GetID(); memcpy(out.vchFingerprint, &id, 4); diff --git a/src/key.h b/src/key.h index 00d3e1206dd9..babffd406b0a 100644 --- a/src/key.h +++ b/src/key.h @@ -135,7 +135,7 @@ class CKey bool SignCompact(const uint256& hash, std::vector& vchSig) const; //! Derive BIP32 child key. - bool Derive(CKey& keyChild, ChainCode &ccChild, unsigned int nChild, const ChainCode& cc) const; + [[nodiscard]] bool Derive(CKey& keyChild, ChainCode &ccChild, unsigned int nChild, const ChainCode& cc) const; /** * Verify thoroughly whether a private key and a public key match. @@ -186,7 +186,7 @@ struct CExtKey { void Encode(unsigned char code[BIP32_EXTKEY_SIZE]) const; void Decode(const unsigned char code[BIP32_EXTKEY_SIZE]); - bool Derive(CExtKey& out, unsigned int nChild) const; + [[nodiscard]] bool Derive(CExtKey& out, unsigned int nChild) const; CExtPubKey Neuter() const; void SetSeed(Span seed); }; diff --git a/src/llmq/blockprocessor.cpp b/src/llmq/blockprocessor.cpp index d8a8d74c1184..4fc57aba77de 100644 --- a/src/llmq/blockprocessor.cpp +++ b/src/llmq/blockprocessor.cpp @@ -47,10 +47,10 @@ static const std::string DB_BEST_BLOCK_UPGRADE = "q_bbu2"; CQuorumBlockProcessor::CQuorumBlockProcessor(CChainState& chainstate, CDeterministicMNManager& dmnman, CEvoDB& evoDb, CQuorumSnapshotManager& qsnapman) : - m_chainstate(chainstate), - m_dmnman(dmnman), - m_evoDb(evoDb), - m_qsnapman(qsnapman) + m_chainstate{chainstate}, + m_dmnman{dmnman}, + m_evoDb{evoDb}, + m_qsnapman{qsnapman} { utils::InitQuorumsCache(mapHasMinedCommitmentCache); @@ -70,7 +70,10 @@ CQuorumBlockProcessor::CQuorumBlockProcessor(CChainState& chainstate, CDetermini m_bls_queue.StartWorkerThreads(bls_threads); } -CQuorumBlockProcessor::~CQuorumBlockProcessor() { m_bls_queue.StopWorkerThreads(); } +CQuorumBlockProcessor::~CQuorumBlockProcessor() +{ + m_bls_queue.StopWorkerThreads(); +} MessageProcessingResult CQuorumBlockProcessor::ProcessMessage(const CNode& peer, std::string_view msg_type, CDataStream& vRecv) @@ -438,7 +441,7 @@ bool CQuorumBlockProcessor::GetCommitmentsFromBlock(const CBlock& block, gsl::no for (const auto& tx : block.vtx) { if (tx->nType == TRANSACTION_QUORUM_COMMITMENT) { - const auto opt_qc = GetTxPayload(*tx); + auto opt_qc = GetTxPayload(*tx); if (!opt_qc) { // should not happen as it was verified before processing the block LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s height=%d GetTxPayload fails\n", __func__, pindex->nHeight); diff --git a/src/llmq/blockprocessor.h b/src/llmq/blockprocessor.h index f4f19ae067fe..97e4edf3f30e 100644 --- a/src/llmq/blockprocessor.h +++ b/src/llmq/blockprocessor.h @@ -5,12 +5,13 @@ #ifndef BITCOIN_LLMQ_BLOCKPROCESSOR_H #define BITCOIN_LLMQ_BLOCKPROCESSOR_H -#include - #include -#include #include #include +#include +#include + +#include #include #include #include @@ -54,22 +55,33 @@ class CQuorumBlockProcessor mutable std::map> mapHasMinedCommitmentCache GUARDED_BY(minableCommitmentsCs); public: + CQuorumBlockProcessor() = delete; + CQuorumBlockProcessor(const CQuorumBlockProcessor&) = delete; + CQuorumBlockProcessor& operator=(const CQuorumBlockProcessor&) = delete; explicit CQuorumBlockProcessor(CChainState& chainstate, CDeterministicMNManager& dmnman, CEvoDB& evoDb, CQuorumSnapshotManager& qsnapman); ~CQuorumBlockProcessor(); - [[nodiscard]] MessageProcessingResult ProcessMessage(const CNode& peer, std::string_view msg_type, CDataStream& vRecv); + [[nodiscard]] MessageProcessingResult ProcessMessage(const CNode& peer, std::string_view msg_type, CDataStream& vRecv) + EXCLUSIVE_LOCKS_REQUIRED(!minableCommitmentsCs); - bool ProcessBlock(const CBlock& block, gsl::not_null pindex, BlockValidationState& state, bool fJustCheck, bool fBLSChecks) EXCLUSIVE_LOCKS_REQUIRED(::cs_main); - bool UndoBlock(const CBlock& block, gsl::not_null pindex) EXCLUSIVE_LOCKS_REQUIRED(::cs_main); + bool ProcessBlock(const CBlock& block, gsl::not_null pindex, BlockValidationState& state, + bool fJustCheck, bool fBLSChecks) EXCLUSIVE_LOCKS_REQUIRED(::cs_main, !minableCommitmentsCs); + bool UndoBlock(const CBlock& block, gsl::not_null pindex) + EXCLUSIVE_LOCKS_REQUIRED(::cs_main, !minableCommitmentsCs); //! it returns hash of commitment if it should be relay, otherwise nullopt - std::optional AddMineableCommitment(const CFinalCommitment& fqc); - bool HasMineableCommitment(const uint256& hash) const; - bool GetMineableCommitmentByHash(const uint256& commitmentHash, CFinalCommitment& ret) const; - std::optional> GetMineableCommitments(const Consensus::LLMQParams& llmqParams, int nHeight) const EXCLUSIVE_LOCKS_REQUIRED(::cs_main); - bool GetMineableCommitmentsTx(const Consensus::LLMQParams& llmqParams, int nHeight, std::vector& ret) const EXCLUSIVE_LOCKS_REQUIRED(::cs_main); - bool HasMinedCommitment(Consensus::LLMQType llmqType, const uint256& quorumHash) const; + std::optional AddMineableCommitment(const CFinalCommitment& fqc) EXCLUSIVE_LOCKS_REQUIRED(!minableCommitmentsCs); + bool HasMineableCommitment(const uint256& hash) const EXCLUSIVE_LOCKS_REQUIRED(!minableCommitmentsCs); + bool GetMineableCommitmentByHash(const uint256& commitmentHash, CFinalCommitment& ret) const + EXCLUSIVE_LOCKS_REQUIRED(!minableCommitmentsCs); + std::optional> GetMineableCommitments(const Consensus::LLMQParams& llmqParams, + int nHeight) const + EXCLUSIVE_LOCKS_REQUIRED(::cs_main, !minableCommitmentsCs); + bool GetMineableCommitmentsTx(const Consensus::LLMQParams& llmqParams, int nHeight, std::vector& ret) const + EXCLUSIVE_LOCKS_REQUIRED(::cs_main, !minableCommitmentsCs); + bool HasMinedCommitment(Consensus::LLMQType llmqType, const uint256& quorumHash) const + EXCLUSIVE_LOCKS_REQUIRED(!minableCommitmentsCs); std::pair GetMinedCommitment(Consensus::LLMQType llmqType, const uint256& quorumHash) const; std::vector GetMinedCommitmentsUntilBlock(Consensus::LLMQType llmqType, gsl::not_null pindex, size_t maxCount) const; @@ -82,9 +94,10 @@ class CQuorumBlockProcessor std::optional GetLastMinedCommitmentsByQuorumIndexUntilBlock(Consensus::LLMQType llmqType, const CBlockIndex* pindex, int quorumIndex, size_t cycle) const; private: static bool GetCommitmentsFromBlock(const CBlock& block, gsl::not_null pindex, std::multimap& ret, BlockValidationState& state) EXCLUSIVE_LOCKS_REQUIRED(::cs_main); - bool ProcessCommitment(int nHeight, const uint256& blockHash, const CFinalCommitment& qc, - BlockValidationState& state, bool fJustCheck) EXCLUSIVE_LOCKS_REQUIRED(::cs_main); - size_t GetNumCommitmentsRequired(const Consensus::LLMQParams& llmqParams, int nHeight) const EXCLUSIVE_LOCKS_REQUIRED(::cs_main); + bool ProcessCommitment(int nHeight, const uint256& blockHash, const CFinalCommitment& qc, BlockValidationState& state, + bool fJustCheck) EXCLUSIVE_LOCKS_REQUIRED(::cs_main, !minableCommitmentsCs); + size_t GetNumCommitmentsRequired(const Consensus::LLMQParams& llmqParams, int nHeight) const + EXCLUSIVE_LOCKS_REQUIRED(::cs_main, !minableCommitmentsCs); static uint256 GetQuorumBlockHash(const Consensus::LLMQParams& llmqParams, const CChain& active_chain, int nHeight, int quorumIndex) EXCLUSIVE_LOCKS_REQUIRED(::cs_main); }; } // namespace llmq diff --git a/src/llmq/commitment.cpp b/src/llmq/commitment.cpp index 9d3d1f62153d..ee0c09a0f13a 100644 --- a/src/llmq/commitment.cpp +++ b/src/llmq/commitment.cpp @@ -51,7 +51,7 @@ bool CFinalCommitment::VerifySignatureAsync(CDeterministicMNManager& dmnman, CQu LogPrint(BCLog::LLMQ, "CFinalCommitment::%s members[%s] quorumPublicKey[%s] commitmentHash[%s]\n", __func__, ss3.str(), quorumPublicKey.ToString(), commitmentHash.ToString()); } - if (llmq_params.size == 1) { + if (llmq_params.is_single_member()) { LogPrintf("pubkey operator: %s\n", members[0]->pdmnState->pubKeyOperator.Get().ToString()); if (!membersSig.VerifyInsecure(members[0]->pdmnState->pubKeyOperator.Get(), commitmentHash)) { LogPrint(BCLog::LLMQ, "CFinalCommitment -- q[%s] invalid member signature\n", quorumHash.ToString()); @@ -138,7 +138,7 @@ bool CFinalCommitment::Verify(CDeterministicMNManager& dmnman, CQuorumSnapshotMa LogPrint(BCLog::LLMQ, "CFinalCommitment -- q[%s] invalid quorumPublicKey\n", quorumHash.ToString()); return false; } - if (llmq_params.size != 1 && quorumVvecHash.IsNull()) { + if (!llmq_params.is_single_member() && quorumVvecHash.IsNull()) { LogPrint(BCLog::LLMQ, "CFinalCommitment -- q[%s] invalid quorumVvecHash\n", quorumHash.ToString()); return false; } diff --git a/src/llmq/commitment.h b/src/llmq/commitment.h index 46d663d55105..60cf499d5a2a 100644 --- a/src/llmq/commitment.h +++ b/src/llmq/commitment.h @@ -5,15 +5,15 @@ #ifndef BITCOIN_LLMQ_COMMITMENT_H #define BITCOIN_LLMQ_COMMITMENT_H -#include -#include -#include - #include #include #include #include +#include +#include +#include + #include #include @@ -29,14 +29,14 @@ class ChainstateManager; class TxValidationState; template class CCheckQueueControl; +struct RPCResult; -namespace llmq -{ +namespace llmq { class CQuorumSnapshotManager; - namespace utils { struct BlsCheck; } // namespace utils + // This message is an aggregation of all received premature commitments and only valid if // enough (>=threshold) premature commitments were aggregated // This is mined on-chain as part of TRANSACTION_QUORUM_COMMITMENT @@ -130,23 +130,8 @@ class CFinalCommitment return true; } - [[nodiscard]] UniValue ToJson() const - { - UniValue obj(UniValue::VOBJ); - obj.pushKV("version", nVersion); - obj.pushKV("llmqType", ToUnderlying(llmqType)); - obj.pushKV("quorumHash", quorumHash.ToString()); - obj.pushKV("quorumIndex", quorumIndex); - obj.pushKV("signersCount", CountSigners()); - obj.pushKV("signers", BitsVectorToHexStr(signers)); - obj.pushKV("validMembersCount", CountValidMembers()); - obj.pushKV("validMembers", BitsVectorToHexStr(validMembers)); - obj.pushKV("quorumPublicKey", quorumPublicKey.ToString(nVersion == LEGACY_BLS_NON_INDEXED_QUORUM_VERSION || nVersion == LEGACY_BLS_INDEXED_QUORUM_VERSION)); - obj.pushKV("quorumVvecHash", quorumVvecHash.ToString()); - obj.pushKV("quorumSig", quorumSig.ToString(nVersion == LEGACY_BLS_NON_INDEXED_QUORUM_VERSION || nVersion == LEGACY_BLS_INDEXED_QUORUM_VERSION)); - obj.pushKV("membersSig", membersSig.ToString(nVersion == LEGACY_BLS_NON_INDEXED_QUORUM_VERSION || nVersion == LEGACY_BLS_INDEXED_QUORUM_VERSION)); - return obj; - } + [[nodiscard]] static RPCResult GetJsonHelp(const std::string& key, bool optional); + [[nodiscard]] UniValue ToJson() const; private: static std::string BitsVectorToHexStr(const std::vector& vBits) @@ -175,6 +160,7 @@ class CFinalCommitmentTxPayload READWRITE(obj.nVersion, obj.nHeight, obj.commitment); } + [[nodiscard]] static RPCResult GetJsonHelp(const std::string& key, bool optional); [[nodiscard]] UniValue ToJson() const; }; diff --git a/src/llmq/context.cpp b/src/llmq/context.cpp index 75e98f40bbfb..e3c7b4911f1b 100644 --- a/src/llmq/context.cpp +++ b/src/llmq/context.cpp @@ -12,15 +12,13 @@ #include #include #include -#include #include #include LLMQContext::LLMQContext(ChainstateManager& chainman, CDeterministicMNManager& dmnman, CEvoDB& evo_db, CMasternodeMetaMan& mn_metaman, CMNHFManager& mnhfman, CSporkManager& sporkman, CTxMemPool& mempool, const CActiveMasternodeManager* const mn_activeman, - const CMasternodeSync& mn_sync, bool unit_tests, bool wipe) : - is_masternode{mn_activeman != nullptr}, + const CMasternodeSync& mn_sync, const util::DbWrapperParams& db_params) : bls_worker{std::make_shared()}, dkg_debugman{std::make_unique()}, qsnapman{std::make_unique(evo_db)}, @@ -28,16 +26,14 @@ LLMQContext::LLMQContext(ChainstateManager& chainman, CDeterministicMNManager& d std::make_unique(chainman.ActiveChainstate(), dmnman, evo_db, *qsnapman)}, qdkgsman{std::make_unique(*bls_worker, chainman.ActiveChainstate(), dmnman, *dkg_debugman, mn_metaman, *quorum_block_processor, *qsnapman, mn_activeman, - sporkman, unit_tests, wipe)}, + sporkman, db_params)}, qman{std::make_unique(*bls_worker, chainman.ActiveChainstate(), dmnman, *qdkgsman, evo_db, *quorum_block_processor, *qsnapman, mn_activeman, mn_sync, sporkman, - unit_tests, wipe)}, - sigman{std::make_unique(mn_activeman, chainman.ActiveChainstate(), *qman, unit_tests, wipe)}, - shareman{std::make_unique(*sigman, mn_activeman, *qman, sporkman)}, - clhandler{std::make_unique(chainman.ActiveChainstate(), *qman, *sigman, sporkman, mempool, - mn_sync)}, - isman{std::make_unique(*clhandler, chainman.ActiveChainstate(), *qman, *sigman, sporkman, - mempool, mn_sync, unit_tests, wipe)} + db_params)}, + sigman{std::make_unique(chainman.ActiveChainstate(), *qman, db_params)}, + clhandler{std::make_unique(chainman.ActiveChainstate(), *qman, sporkman, mempool, mn_sync)}, + isman{std::make_unique(*clhandler, chainman.ActiveChainstate(), *sigman, sporkman, + mempool, mn_sync, db_params)} { // Have to start it early to let VerifyDB check ChainLock signatures in coinbase bls_worker->Start(); @@ -48,32 +44,19 @@ LLMQContext::~LLMQContext() { } void LLMQContext::Interrupt() { - isman->InterruptWorkerThread(); - shareman->InterruptWorkerThread(); sigman->InterruptWorkerThread(); } -void LLMQContext::Start(CConnman& connman, PeerManager& peerman) +void LLMQContext::Start(PeerManager& peerman) { - if (is_masternode) { - qdkgsman->StartThreads(connman, peerman); - } qman->Start(); sigman->StartWorkerThread(peerman); - shareman->RegisterAsRecoveredSigsListener(); - shareman->StartWorkerThread(connman, peerman); clhandler->Start(*isman); - isman->Start(peerman); } -void LLMQContext::Stop() { - isman->Stop(); +void LLMQContext::Stop() +{ clhandler->Stop(); - shareman->StopWorkerThread(); - shareman->UnregisterAsRecoveredSigsListener(); sigman->StopWorkerThread(); qman->Stop(); - if (is_masternode) { - qdkgsman->StopThreads(); - } } diff --git a/src/llmq/context.h b/src/llmq/context.h index d27b2a7a8137..42441e899e70 100644 --- a/src/llmq/context.h +++ b/src/llmq/context.h @@ -9,7 +9,6 @@ class CActiveMasternodeManager; class CBLSWorker; -class CConnman; class ChainstateManager; class CDeterministicMNManager; class CEvoDB; @@ -28,25 +27,25 @@ class CInstantSendManager; class CQuorumBlockProcessor; class CQuorumManager; class CQuorumSnapshotManager; -class CSigSharesManager; class CSigningManager; -} +} // namespace llmq +namespace util { +struct DbWrapperParams; +} // namespace util struct LLMQContext { -private: - const bool is_masternode; - public: LLMQContext() = delete; LLMQContext(const LLMQContext&) = delete; - LLMQContext(ChainstateManager& chainman, CDeterministicMNManager& dmnman, CEvoDB& evo_db, - CMasternodeMetaMan& mn_metaman, CMNHFManager& mnhfman, CSporkManager& sporkman, CTxMemPool& mempool, - const CActiveMasternodeManager* const mn_activeman, const CMasternodeSync& mn_sync, bool unit_tests, - bool wipe); + LLMQContext& operator=(const LLMQContext&) = delete; + explicit LLMQContext(ChainstateManager& chainman, CDeterministicMNManager& dmnman, CEvoDB& evo_db, + CMasternodeMetaMan& mn_metaman, CMNHFManager& mnhfman, CSporkManager& sporkman, + CTxMemPool& mempool, const CActiveMasternodeManager* const mn_activeman, + const CMasternodeSync& mn_sync, const util::DbWrapperParams& db_params); ~LLMQContext(); void Interrupt(); - void Start(CConnman& connman, PeerManager& peerman); + void Start(PeerManager& peerman); void Stop(); /** Guaranteed if LLMQContext is initialized then all members are valid too @@ -66,7 +65,6 @@ struct LLMQContext { const std::unique_ptr qdkgsman; const std::unique_ptr qman; const std::unique_ptr sigman; - const std::unique_ptr shareman; const std::unique_ptr clhandler; const std::unique_ptr isman; }; diff --git a/src/llmq/core_write.cpp b/src/llmq/core_write.cpp new file mode 100644 index 000000000000..5ffe3c46f956 --- /dev/null +++ b/src/llmq/core_write.cpp @@ -0,0 +1,200 @@ +// Copyright (c) 2018-2025 The Dash Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include +#include +#include + +#include +#include + +#include + +#include +#include + +namespace llmq { +RPCResult CFinalCommitment::GetJsonHelp(const std::string& key, bool optional) +{ + return {RPCResult::Type::OBJ, key, optional, key.empty() ? "" : "The quorum commitment payload", + { + {RPCResult::Type::NUM, "version", "Quorum commitment payload version"}, + GetRpcResult("llmqType"), + GetRpcResult("quorumHash"), + {RPCResult::Type::NUM, "quorumIndex", "Index of the quorum"}, + {RPCResult::Type::NUM, "signersCount", "Number of signers for the quorum"}, + {RPCResult::Type::STR_HEX, "signers", "Bitset representing the aggregated signers"}, + {RPCResult::Type::NUM, "validMembersCount", "Number of valid members in the quorum"}, + {RPCResult::Type::STR_HEX, "validMembers", "Bitset of valid members"}, + {RPCResult::Type::STR_HEX, "quorumPublicKey", "BLS public key of the quorum"}, + {RPCResult::Type::STR_HEX, "quorumVvecHash", "Hash of the quorum verification vector"}, + GetRpcResult("quorumSig"), + {RPCResult::Type::STR_HEX, "membersSig", "BLS signature from all included commitments"}, + }}; +} + +UniValue CFinalCommitment::ToJson() const +{ + UniValue obj(UniValue::VOBJ); + obj.pushKV("version", nVersion); + obj.pushKV("llmqType", ToUnderlying(llmqType)); + obj.pushKV("quorumHash", quorumHash.ToString()); + obj.pushKV("quorumIndex", quorumIndex); + obj.pushKV("signersCount", CountSigners()); + obj.pushKV("signers", BitsVectorToHexStr(signers)); + obj.pushKV("validMembersCount", CountValidMembers()); + obj.pushKV("validMembers", BitsVectorToHexStr(validMembers)); + obj.pushKV("quorumPublicKey", quorumPublicKey.ToString(nVersion == LEGACY_BLS_NON_INDEXED_QUORUM_VERSION || nVersion == LEGACY_BLS_INDEXED_QUORUM_VERSION)); + obj.pushKV("quorumVvecHash", quorumVvecHash.ToString()); + obj.pushKV("quorumSig", quorumSig.ToString(nVersion == LEGACY_BLS_NON_INDEXED_QUORUM_VERSION || nVersion == LEGACY_BLS_INDEXED_QUORUM_VERSION)); + obj.pushKV("membersSig", membersSig.ToString(nVersion == LEGACY_BLS_NON_INDEXED_QUORUM_VERSION || nVersion == LEGACY_BLS_INDEXED_QUORUM_VERSION)); + return obj; +} + +RPCResult CFinalCommitmentTxPayload::GetJsonHelp(const std::string& key, bool optional) +{ + return {RPCResult::Type::OBJ, key, optional, key.empty() ? "" : "The quorum commitment special transaction", + { + GetRpcResult("version"), + GetRpcResult("height"), + CFinalCommitment::GetJsonHelp(/*key=*/"commitment", /*optional=*/false), + }}; +} + +UniValue CFinalCommitmentTxPayload::ToJson() const +{ + UniValue ret(UniValue::VOBJ); + ret.pushKV("version", nVersion); + ret.pushKV("height", nHeight); + ret.pushKV("commitment", commitment.ToJson()); + return ret; +} + +RPCResult CQuorumRotationInfo::GetJsonHelp(const std::string& key, bool optional) +{ + return {RPCResult::Type::OBJ, key, optional, key.empty() ? "" : "The quorum rotation", + { + {RPCResult::Type::BOOL, "extraShare", "Returns true if an extra share is returned"}, + CQuorumSnapshot::GetJsonHelp(/*key=*/"quorumSnapshotAtHMinusC", /*optional=*/false), + CQuorumSnapshot::GetJsonHelp(/*key=*/"quorumSnapshotAtHMinus2C", /*optional=*/false), + CQuorumSnapshot::GetJsonHelp(/*key=*/"quorumSnapshotAtHMinus3C", /*optional=*/false), + CQuorumSnapshot::GetJsonHelp(/*key=*/"quorumSnapshotAtHMinus4C", /*optional=*/true), + CSimplifiedMNListDiff::GetJsonHelp(/*key=*/"mnListDiffTip", /*optional=*/false), + CSimplifiedMNListDiff::GetJsonHelp(/*key=*/"mnListDiffH", /*optional=*/false), + CSimplifiedMNListDiff::GetJsonHelp(/*key=*/"mnListDiffAtHMinusC", /*optional=*/false), + CSimplifiedMNListDiff::GetJsonHelp(/*key=*/"mnListDiffAtHMinus2C", /*optional=*/false), + CSimplifiedMNListDiff::GetJsonHelp(/*key=*/"mnListDiffAtHMinus3C", /*optional=*/false), + CSimplifiedMNListDiff::GetJsonHelp(/*key=*/"mnListDiffAtHMinus4C", /*optional=*/true), + {RPCResult::Type::ARR, "lastCommitmentPerIndex", "Most recent commitment for each quorumIndex", { + CFinalCommitment::GetJsonHelp(/*key=*/"", /*optional=*/false), + }}, + {RPCResult::Type::ARR, "quorumSnapshotList", "Snapshots required to reconstruct the quorums built at h' in lastCommitmentPerIndex", { + CQuorumSnapshot::GetJsonHelp(/*key=*/"", /*optional=*/false), + }}, + {RPCResult::Type::ARR, "mnListDiffList", "MnListDiffs required to calculate older quorums", { + CSimplifiedMNListDiff::GetJsonHelp(/*key=*/"", /*optional=*/false), + }}, + }}; +} + +UniValue CQuorumRotationInfo::ToJson() const +{ + UniValue obj(UniValue::VOBJ); + obj.pushKV("extraShare", extraShare); + + obj.pushKV("quorumSnapshotAtHMinusC", quorumSnapshotAtHMinusC.ToJson()); + obj.pushKV("quorumSnapshotAtHMinus2C", quorumSnapshotAtHMinus2C.ToJson()); + obj.pushKV("quorumSnapshotAtHMinus3C", quorumSnapshotAtHMinus3C.ToJson()); + + if (extraShare) { + obj.pushKV("quorumSnapshotAtHMinus4C", quorumSnapshotAtHMinus4C.ToJson()); + } + + obj.pushKV("mnListDiffTip", mnListDiffTip.ToJson()); + obj.pushKV("mnListDiffH", mnListDiffH.ToJson()); + obj.pushKV("mnListDiffAtHMinusC", mnListDiffAtHMinusC.ToJson()); + obj.pushKV("mnListDiffAtHMinus2C", mnListDiffAtHMinus2C.ToJson()); + obj.pushKV("mnListDiffAtHMinus3C", mnListDiffAtHMinus3C.ToJson()); + + if (extraShare) { + obj.pushKV("mnListDiffAtHMinus4C", mnListDiffAtHMinus4C.ToJson()); + } + UniValue hqclists(UniValue::VARR); + for (const auto& qc : lastCommitmentPerIndex) { + hqclists.push_back(qc.ToJson()); + } + obj.pushKV("lastCommitmentPerIndex", hqclists); + + UniValue snapshotlist(UniValue::VARR); + for (const auto& snap : quorumSnapshotList) { + snapshotlist.push_back(snap.ToJson()); + } + obj.pushKV("quorumSnapshotList", snapshotlist); + + UniValue mnlistdifflist(UniValue::VARR); + for (const auto& mnlist : mnListDiffList) { + mnlistdifflist.push_back(mnlist.ToJson()); + } + obj.pushKV("mnListDiffList", mnlistdifflist); + return obj; +} + +RPCResult CQuorumSnapshot::GetJsonHelp(const std::string& key, bool optional) +{ + return {RPCResult::Type::OBJ, key, optional, key.empty() ? "" : "The quorum snapshot", + { + {RPCResult::Type::ARR, "activeQuorumMembers", "Bitset of nodes already in quarters at the start of cycle", { + {RPCResult::Type::BOOL, "bit", ""} + }}, + {RPCResult::Type::NUM, "mnSkipListMode", "Mode of the skip list"}, + {RPCResult::Type::ARR, "mnSkipList", "Skiplist at height", { + {RPCResult::Type::NUM, "height", ""} + }}, + }}; +} + +UniValue CQuorumSnapshot::ToJson() const +{ + UniValue obj(UniValue::VOBJ); + UniValue activeQ(UniValue::VARR); + for (const bool h : activeQuorumMembers) { + // cppcheck-suppress useStlAlgorithm + activeQ.push_back(h); + } + obj.pushKV("activeQuorumMembers", activeQ); + obj.pushKV("mnSkipListMode", mnSkipListMode); + UniValue skipList(UniValue::VARR); + for (const auto& h : mnSkipList) { + // cppcheck-suppress useStlAlgorithm + skipList.push_back(h); + } + obj.pushKV("mnSkipList", skipList); + return obj; +} + +RPCResult CRecoveredSig::GetJsonHelp(const std::string& key, bool optional) +{ + return {RPCResult::Type::OBJ, key, optional, key.empty() ? "" : "The recovered signature", + { + GetRpcResult("llmqType"), + GetRpcResult("quorumHash"), + {RPCResult::Type::NUM, "id", "Signing session ID"}, + {RPCResult::Type::STR_HEX, "msgHash", "Hash of message"}, + {RPCResult::Type::STR_HEX, "sig", "BLS signature recovered"}, + {RPCResult::Type::STR_HEX, "hash", "Hash of the BLS signature recovered"}, + }}; +} + +UniValue CRecoveredSig::ToJson() const +{ + UniValue ret(UniValue::VOBJ); + ret.pushKV("llmqType", ToUnderlying(llmqType)); + ret.pushKV("quorumHash", quorumHash.ToString()); + ret.pushKV("id", id.ToString()); + ret.pushKV("msgHash", msgHash.ToString()); + ret.pushKV("sig", sig.Get().ToString()); + ret.pushKV("hash", sig.Get().GetHash().ToString()); + return ret; +} +} // namespace llmq diff --git a/src/llmq/debug.cpp b/src/llmq/debug.cpp index 953ece2b3d08..3445924990dc 100644 --- a/src/llmq/debug.cpp +++ b/src/llmq/debug.cpp @@ -109,6 +109,8 @@ UniValue CDKGDebugSessionStatus::ToJson(CDeterministicMNManager& dmnman, CQuorum CDKGDebugManager::CDKGDebugManager() = default; +CDKGDebugManager::~CDKGDebugManager() = default; + UniValue CDKGDebugStatus::ToJson(CDeterministicMNManager& dmnman, CQuorumSnapshotManager& qsnapman, const ChainstateManager& chainman, int detailLevel) const { diff --git a/src/llmq/debug.h b/src/llmq/debug.h index b97d6bc25cec..4ea8e597b022 100644 --- a/src/llmq/debug.h +++ b/src/llmq/debug.h @@ -101,15 +101,23 @@ class CDKGDebugManager CDKGDebugStatus localStatus GUARDED_BY(cs_lockStatus); public: + CDKGDebugManager(const CDKGDebugManager&) = delete; + CDKGDebugManager& operator=(const CDKGDebugManager&) = delete; CDKGDebugManager(); + ~CDKGDebugManager(); - void GetLocalDebugStatus(CDKGDebugStatus& ret) const; + void GetLocalDebugStatus(CDKGDebugStatus& ret) const EXCLUSIVE_LOCKS_REQUIRED(!cs_lockStatus); - void ResetLocalSessionStatus(Consensus::LLMQType llmqType, int quorumIndex); - void InitLocalSessionStatus(const Consensus::LLMQParams& llmqParams, int quorumIndex, const uint256& quorumHash, int quorumHeight); + void ResetLocalSessionStatus(Consensus::LLMQType llmqType, int quorumIndex) EXCLUSIVE_LOCKS_REQUIRED(!cs_lockStatus); + void InitLocalSessionStatus(const Consensus::LLMQParams& llmqParams, int quorumIndex, const uint256& quorumHash, + int quorumHeight) EXCLUSIVE_LOCKS_REQUIRED(!cs_lockStatus); - void UpdateLocalSessionStatus(Consensus::LLMQType llmqType, int quorumIndex, std::function&& func); - void UpdateLocalMemberStatus(Consensus::LLMQType llmqType, int quorumIndex, size_t memberIdx, std::function&& func); + void UpdateLocalSessionStatus(Consensus::LLMQType llmqType, int quorumIndex, + std::function&& func) + EXCLUSIVE_LOCKS_REQUIRED(!cs_lockStatus); + void UpdateLocalMemberStatus(Consensus::LLMQType llmqType, int quorumIndex, size_t memberIdx, + std::function&& func) + EXCLUSIVE_LOCKS_REQUIRED(!cs_lockStatus); }; } // namespace llmq diff --git a/src/llmq/dkgsession.cpp b/src/llmq/dkgsession.cpp index 062040a819a5..f7c6c4491771 100644 --- a/src/llmq/dkgsession.cpp +++ b/src/llmq/dkgsession.cpp @@ -492,12 +492,11 @@ void CDKGSession::VerifyConnectionAndMinProtoVersions(CConnman& connman) const m->badConnection = true; logger.Batch("%s does not have min proto version %d (has %d)", m->dmn->proTxHash.ToString(), MIN_MASTERNODE_PROTO_VERSION, it->second); } - const auto meta_info = m_mn_metaman.GetMetaInfo(m->dmn->proTxHash); - if (meta_info->OutboundFailedTooManyTimes()) { + if (m_mn_metaman.OutboundFailedTooManyTimes(m->dmn->proTxHash)) { m->badConnection = true; logger.Batch("%s failed to connect to it too many times", m->dmn->proTxHash.ToString()); } - if (meta_info->IsPlatformBanned()) { + if (m_mn_metaman.IsPlatformBanned(m->dmn->proTxHash)) { m->badConnection = true; logger.Batch("%s is Platform PoSe banned", m->dmn->proTxHash.ToString()); } diff --git a/src/llmq/dkgsession.h b/src/llmq/dkgsession.h index 33b11d811a14..2b1b095b93fe 100644 --- a/src/llmq/dkgsession.h +++ b/src/llmq/dkgsession.h @@ -357,30 +357,31 @@ class CDKGSession void Contribute(CDKGPendingMessages& pendingMessages, PeerManager& peerman); void SendContributions(CDKGPendingMessages& pendingMessages, PeerManager& peerman); bool PreVerifyMessage(const CDKGContribution& qc, bool& retBan) const; - std::optional ReceiveMessage(const CDKGContribution& qc); + std::optional ReceiveMessage(const CDKGContribution& qc) EXCLUSIVE_LOCKS_REQUIRED(!invCs, !cs_pending); void VerifyPendingContributions() EXCLUSIVE_LOCKS_REQUIRED(cs_pending); // Phase 2: complaint - void VerifyAndComplain(CConnman& connman, CDKGPendingMessages& pendingMessages, PeerManager& peerman); + void VerifyAndComplain(CConnman& connman, CDKGPendingMessages& pendingMessages, PeerManager& peerman) + EXCLUSIVE_LOCKS_REQUIRED(!cs_pending); void VerifyConnectionAndMinProtoVersions(CConnman& connman) const; void SendComplaint(CDKGPendingMessages& pendingMessages, PeerManager& peerman); bool PreVerifyMessage(const CDKGComplaint& qc, bool& retBan) const; - std::optional ReceiveMessage(const CDKGComplaint& qc); + std::optional ReceiveMessage(const CDKGComplaint& qc) EXCLUSIVE_LOCKS_REQUIRED(!invCs); // Phase 3: justification - void VerifyAndJustify(CDKGPendingMessages& pendingMessages, PeerManager& peerman); + void VerifyAndJustify(CDKGPendingMessages& pendingMessages, PeerManager& peerman) EXCLUSIVE_LOCKS_REQUIRED(!invCs); void SendJustification(CDKGPendingMessages& pendingMessages, PeerManager& peerman, const std::set& forMembers); bool PreVerifyMessage(const CDKGJustification& qj, bool& retBan) const; - std::optional ReceiveMessage(const CDKGJustification& qj); + std::optional ReceiveMessage(const CDKGJustification& qj) EXCLUSIVE_LOCKS_REQUIRED(!invCs); // Phase 4: commit void VerifyAndCommit(CDKGPendingMessages& pendingMessages, PeerManager& peerman); void SendCommitment(CDKGPendingMessages& pendingMessages, PeerManager& peerman); bool PreVerifyMessage(const CDKGPrematureCommitment& qc, bool& retBan) const; - std::optional ReceiveMessage(const CDKGPrematureCommitment& qc); + std::optional ReceiveMessage(const CDKGPrematureCommitment& qc) EXCLUSIVE_LOCKS_REQUIRED(!invCs); // Phase 5: aggregate/finalize - std::vector FinalizeCommitments(); + std::vector FinalizeCommitments() EXCLUSIVE_LOCKS_REQUIRED(!invCs); // All Phases 5-in-1 for single-node-quorum CFinalCommitment FinalizeSingleCommitment(); diff --git a/src/llmq/dkgsessionhandler.cpp b/src/llmq/dkgsessionhandler.cpp index c5dfcce1acfd..1a200be7cf34 100644 --- a/src/llmq/dkgsessionhandler.cpp +++ b/src/llmq/dkgsessionhandler.cpp @@ -551,7 +551,7 @@ void CDKGSessionHandler::HandleDKGRound(CConnman& connman, PeerManager& peerman) return changed; }); - if (params.size == 1) { + if (params.is_single_member()) { auto finalCommitment = curSession->FinalizeSingleCommitment(); if (!finalCommitment.IsNull()) { // it can be null only if we are not member if (auto inv_opt = quorumBlockProcessor.AddMineableCommitment(finalCommitment); inv_opt.has_value()) { diff --git a/src/llmq/dkgsessionhandler.h b/src/llmq/dkgsessionhandler.h index faab21a69b17..e40611a0238a 100644 --- a/src/llmq/dkgsessionhandler.h +++ b/src/llmq/dkgsessionhandler.h @@ -5,6 +5,8 @@ #ifndef BITCOIN_LLMQ_DKGSESSIONHANDLER_H #define BITCOIN_LLMQ_DKGSESSIONHANDLER_H +#include + #include // for NodeId #include @@ -76,14 +78,15 @@ class CDKGPendingMessages explicit CDKGPendingMessages(size_t _maxMessagesPerNode, uint32_t _invType) : invType(_invType), maxMessagesPerNode(_maxMessagesPerNode) {}; - [[nodiscard]] MessageProcessingResult PushPendingMessage(NodeId from, CDataStream& vRecv); - std::list PopPendingMessages(size_t maxCount); - bool HasSeen(const uint256& hash) const; + [[nodiscard]] MessageProcessingResult PushPendingMessage(NodeId from, CDataStream& vRecv) + EXCLUSIVE_LOCKS_REQUIRED(!cs_messages); + std::list PopPendingMessages(size_t maxCount) EXCLUSIVE_LOCKS_REQUIRED(!cs_messages); + bool HasSeen(const uint256& hash) const EXCLUSIVE_LOCKS_REQUIRED(!cs_messages); void Misbehaving(NodeId from, int score, PeerManager& peerman); - void Clear(); + void Clear() EXCLUSIVE_LOCKS_REQUIRED(!cs_messages); template - void PushPendingMessage(NodeId from, Message& msg, PeerManager& peerman) + void PushPendingMessage(NodeId from, Message& msg, PeerManager& peerman) EXCLUSIVE_LOCKS_REQUIRED(!cs_messages) { CDataStream ds(SER_NETWORK, PROTOCOL_VERSION); ds << msg; @@ -91,8 +94,9 @@ class CDKGPendingMessages } // Might return nullptr messages, which indicates that deserialization failed for some reason - template + template std::vector>> PopAndDeserializeMessages(size_t maxCount) + EXCLUSIVE_LOCKS_REQUIRED(!cs_messages) { auto binaryMessages = PopPendingMessages(maxCount); if (binaryMessages.empty()) { @@ -165,7 +169,7 @@ class CDKGSessionHandler const CSporkManager& sporkman, const Consensus::LLMQParams& _params, int _quorumIndex); ~CDKGSessionHandler(); - void UpdatedBlockTip(const CBlockIndex *pindexNew); + void UpdatedBlockTip(const CBlockIndex* pindexNew) EXCLUSIVE_LOCKS_REQUIRED(!cs_phase_qhash); [[nodiscard]] MessageProcessingResult ProcessMessage(NodeId from, std::string_view msg_type, CDataStream& vRecv); void StartThread(CConnman& connman, PeerManager& peerman); @@ -179,7 +183,7 @@ class CDKGSessionHandler private: bool InitNewQuorum(const CBlockIndex* pQuorumBaseBlockIndex); - std::pair GetPhaseAndQuorumHash() const; + std::pair GetPhaseAndQuorumHash() const EXCLUSIVE_LOCKS_REQUIRED(!cs_phase_qhash); using StartPhaseFunc = std::function; using WhileWaitFunc = std::function; @@ -189,12 +193,17 @@ class CDKGSessionHandler * @param expectedQuorumHash expected QuorumHash, defaults to null * @param shouldNotWait function that returns bool, defaults to function that returns false. If the function returns false, we will wait in the loop, if true, we don't wait */ - void WaitForNextPhase(std::optional curPhase, QuorumPhase nextPhase, const uint256& expectedQuorumHash=uint256(), const WhileWaitFunc& shouldNotWait=[]{return false;}) const; - void WaitForNewQuorum(const uint256& oldQuorumHash) const; - void SleepBeforePhase(QuorumPhase curPhase, const uint256& expectedQuorumHash, double randomSleepFactor, const WhileWaitFunc& runWhileWaiting) const; - void HandlePhase(QuorumPhase curPhase, QuorumPhase nextPhase, const uint256& expectedQuorumHash, double randomSleepFactor, const StartPhaseFunc& startPhaseFunc, const WhileWaitFunc& runWhileWaiting); - void HandleDKGRound(CConnman& connman, PeerManager& peerman); - void PhaseHandlerThread(CConnman& connman, PeerManager& peerman); + void WaitForNextPhase( + std::optional curPhase, QuorumPhase nextPhase, const uint256& expectedQuorumHash = uint256(), + const WhileWaitFunc& shouldNotWait = [] { return false; }) const EXCLUSIVE_LOCKS_REQUIRED(!cs_phase_qhash); + void WaitForNewQuorum(const uint256& oldQuorumHash) const EXCLUSIVE_LOCKS_REQUIRED(!cs_phase_qhash); + void SleepBeforePhase(QuorumPhase curPhase, const uint256& expectedQuorumHash, double randomSleepFactor, + const WhileWaitFunc& runWhileWaiting) const EXCLUSIVE_LOCKS_REQUIRED(!cs_phase_qhash); + void HandlePhase(QuorumPhase curPhase, QuorumPhase nextPhase, const uint256& expectedQuorumHash, + double randomSleepFactor, const StartPhaseFunc& startPhaseFunc, + const WhileWaitFunc& runWhileWaiting) EXCLUSIVE_LOCKS_REQUIRED(!cs_phase_qhash); + void HandleDKGRound(CConnman& connman, PeerManager& peerman) EXCLUSIVE_LOCKS_REQUIRED(!cs_phase_qhash); + void PhaseHandlerThread(CConnman& connman, PeerManager& peerman) EXCLUSIVE_LOCKS_REQUIRED(!cs_phase_qhash); }; } // namespace llmq diff --git a/src/llmq/dkgsessionmgr.cpp b/src/llmq/dkgsessionmgr.cpp index 2595967755bd..3c2fdc135fbc 100644 --- a/src/llmq/dkgsessionmgr.cpp +++ b/src/llmq/dkgsessionmgr.cpp @@ -33,15 +33,15 @@ CDKGSessionManager::CDKGSessionManager(CBLSWorker& _blsWorker, CChainState& chai CDKGDebugManager& _dkgDebugManager, CMasternodeMetaMan& mn_metaman, CQuorumBlockProcessor& _quorumBlockProcessor, CQuorumSnapshotManager& qsnapman, const CActiveMasternodeManager* const mn_activeman, - const CSporkManager& sporkman, bool unitTests, bool fWipe) : - db(std::make_unique(unitTests ? "" : (gArgs.GetDataDirNet() / "llmq/dkgdb"), 1 << 20, unitTests, fWipe)), - blsWorker(_blsWorker), - m_chainstate(chainstate), - m_dmnman(dmnman), - dkgDebugManager(_dkgDebugManager), - quorumBlockProcessor(_quorumBlockProcessor), - m_qsnapman(qsnapman), - spork_manager(sporkman) + const CSporkManager& sporkman, const util::DbWrapperParams& db_params) : + db{util::MakeDbWrapper({db_params.path / "llmq" / "dkgdb", db_params.memory, db_params.wipe, /*cache_size=*/1 << 20})}, + blsWorker{_blsWorker}, + m_chainstate{chainstate}, + m_dmnman{dmnman}, + dkgDebugManager{_dkgDebugManager}, + quorumBlockProcessor{_quorumBlockProcessor}, + m_qsnapman{qsnapman}, + spork_manager{sporkman} { if (mn_activeman == nullptr && !IsWatchQuorumsEnabled()) { // Regular nodes do not care about any DKG internals, bail out diff --git a/src/llmq/dkgsessionmgr.h b/src/llmq/dkgsessionmgr.h index 51fb2fdbe8e9..806d82eabaae 100644 --- a/src/llmq/dkgsessionmgr.h +++ b/src/llmq/dkgsessionmgr.h @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -32,6 +33,9 @@ class CDKGContribution; class CDKGComplaint; class CDKGJustification; class CDKGPrematureCommitment; +namespace util { +struct DbWrapperParams; +} // namespace util class UniValue; @@ -77,17 +81,21 @@ class CDKGSessionManager mutable std::map contributionsCache GUARDED_BY(contributionsCacheCs); public: - CDKGSessionManager(CBLSWorker& _blsWorker, CChainState& chainstate, CDeterministicMNManager& dmnman, - CDKGDebugManager& _dkgDebugManager, CMasternodeMetaMan& mn_metaman, - CQuorumBlockProcessor& _quorumBlockProcessor, CQuorumSnapshotManager& qsnapman, - const CActiveMasternodeManager* const mn_activeman, const CSporkManager& sporkman, - bool unitTests, bool fWipe); + CDKGSessionManager() = delete; + CDKGSessionManager(const CDKGSessionManager&) = delete; + CDKGSessionManager& operator=(const CDKGSessionManager&) = delete; + explicit CDKGSessionManager(CBLSWorker& _blsWorker, CChainState& chainstate, CDeterministicMNManager& dmnman, + CDKGDebugManager& _dkgDebugManager, CMasternodeMetaMan& mn_metaman, + CQuorumBlockProcessor& _quorumBlockProcessor, CQuorumSnapshotManager& qsnapman, + const CActiveMasternodeManager* const mn_activeman, const CSporkManager& sporkman, + const util::DbWrapperParams& db_params); ~CDKGSessionManager(); void StartThreads(CConnman& connman, PeerManager& peerman); void StopThreads(); - void UpdatedBlockTip(const CBlockIndex *pindexNew, bool fInitialDownload); + void UpdatedBlockTip(const CBlockIndex* pindexNew, bool fInitialDownload) + EXCLUSIVE_LOCKS_REQUIRED(!contributionsCacheCs); [[nodiscard]] MessageProcessingResult ProcessMessage(CNode& pfrom, bool is_masternode, std::string_view msg_type, CDataStream& vRecv); @@ -100,7 +108,11 @@ class CDKGSessionManager // Contributions are written while in the DKG void WriteVerifiedVvecContribution(Consensus::LLMQType llmqType, const CBlockIndex* pQuorumBaseBlockIndex, const uint256& proTxHash, const BLSVerificationVectorPtr& vvec); void WriteVerifiedSkContribution(Consensus::LLMQType llmqType, const CBlockIndex* pQuorumBaseBlockIndex, const uint256& proTxHash, const CBLSSecretKey& skContribution); - bool GetVerifiedContributions(Consensus::LLMQType llmqType, const CBlockIndex* pQuorumBaseBlockIndex, const std::vector& validMembers, std::vector& memberIndexesRet, std::vector& vvecsRet, std::vector& skContributionsRet) const; + bool GetVerifiedContributions(Consensus::LLMQType llmqType, const CBlockIndex* pQuorumBaseBlockIndex, + const std::vector& validMembers, std::vector& memberIndexesRet, + std::vector& vvecsRet, + std::vector& skContributionsRet) const + EXCLUSIVE_LOCKS_REQUIRED(!contributionsCacheCs); /// Write encrypted (unverified) DKG contributions for the member with the given proTxHash to the llmqDb void WriteEncryptedContributions(Consensus::LLMQType llmqType, const CBlockIndex* pQuorumBaseBlockIndex, const uint256& proTxHash, const CBLSIESMultiRecipientObjects& contributions); /// Read encrypted (unverified) DKG contributions for the member with the given proTxHash from the llmqDb @@ -109,7 +121,7 @@ class CDKGSessionManager void CleanupOldContributions() const; private: - void CleanupCache() const; + void CleanupCache() const EXCLUSIVE_LOCKS_REQUIRED(!contributionsCacheCs); }; } // namespace llmq diff --git a/src/llmq/ehf_signals.cpp b/src/llmq/ehf_signals.cpp index b4689e2d4a3e..afec0ae3ee94 100644 --- a/src/llmq/ehf_signals.cpp +++ b/src/llmq/ehf_signals.cpp @@ -3,17 +3,19 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include -#include -#include #include #include #include -#include #include // g_txindex #include #include +#include +#include +#include +#include + namespace llmq { CEHFSignalsHandler::CEHFSignalsHandler(ChainstateManager& chainman, CMNHFManager& mnhfman, CSigningManager& sigman, CSigSharesManager& shareman, const CQuorumManager& qman) : @@ -76,7 +78,7 @@ void CEHFSignalsHandler::trySignEHFSignal(int bit, const CBlockIndex* const pind const uint256 msgHash = mnhfPayload.PrepareTx().GetHash(); WITH_LOCK(cs, ids.insert(requestId)); - sigman.AsyncSignIfMember(llmqType, shareman, requestId, msgHash, quorum->qc->quorumHash, false, true); + shareman.AsyncSignIfMember(llmqType, sigman, requestId, msgHash, quorum->qc->quorumHash, false, true); } MessageProcessingResult CEHFSignalsHandler::HandleNewRecoveredSig(const CRecoveredSig& recoveredSig) diff --git a/src/llmq/ehf_signals.h b/src/llmq/ehf_signals.h index 33283f6dbca8..cc9893061dca 100644 --- a/src/llmq/ehf_signals.h +++ b/src/llmq/ehf_signals.h @@ -6,6 +6,7 @@ #define BITCOIN_LLMQ_EHF_SIGNALS_H #include +#include #include diff --git a/src/llmq/params.h b/src/llmq/params.h index 961f6e9a0b67..99574930075d 100644 --- a/src/llmq/params.h +++ b/src/llmq/params.h @@ -121,6 +121,7 @@ struct LLMQParams { // For how many blocks recent DKG info should be kept [[nodiscard]] constexpr int max_store_depth() const { return max_cycles(keepOldKeys) * dkgInterval; } + [[nodiscard]] constexpr bool is_single_member() const { return size == 1; } }; //static_assert(std::is_trivial_v, "LLMQParams is not a trivial type"); diff --git a/src/llmq/quorums.cpp b/src/llmq/quorums.cpp index 7368914b287b..3c467aca2530 100644 --- a/src/llmq/quorums.cpp +++ b/src/llmq/quorums.cpp @@ -211,30 +211,33 @@ CQuorumManager::CQuorumManager(CBLSWorker& _blsWorker, CChainState& chainstate, CDKGSessionManager& _dkgManager, CEvoDB& _evoDb, CQuorumBlockProcessor& _quorumBlockProcessor, CQuorumSnapshotManager& qsnapman, const CActiveMasternodeManager* const mn_activeman, const CMasternodeSync& mn_sync, - const CSporkManager& sporkman, bool unit_tests, bool wipe) : - db(std::make_unique(unit_tests ? "" : (gArgs.GetDataDirNet() / "llmq" / "quorumdb"), 1 << 20, - unit_tests, wipe)), - blsWorker(_blsWorker), - m_chainstate(chainstate), - m_dmnman(dmnman), - dkgManager(_dkgManager), - quorumBlockProcessor(_quorumBlockProcessor), - m_qsnapman(qsnapman), - m_mn_activeman(mn_activeman), - m_mn_sync(mn_sync), - m_sporkman(sporkman) + const CSporkManager& sporkman, const util::DbWrapperParams& db_params) : + db{util::MakeDbWrapper( + {db_params.path / "llmq" / "quorumdb", db_params.memory, db_params.wipe, /*cache_size=*/1 << 20})}, + blsWorker{_blsWorker}, + m_chainstate{chainstate}, + m_dmnman{dmnman}, + dkgManager{_dkgManager}, + quorumBlockProcessor{_quorumBlockProcessor}, + m_qsnapman{qsnapman}, + m_mn_activeman{mn_activeman}, + m_mn_sync{mn_sync}, + m_sporkman{sporkman} { utils::InitQuorumsCache(mapQuorumsCache, false); quorumThreadInterrupt.reset(); MigrateOldQuorumDB(_evoDb); } -CQuorumManager::~CQuorumManager() { Stop(); } +CQuorumManager::~CQuorumManager() +{ + Stop(); +} void CQuorumManager::Start() { int workerCount = std::thread::hardware_concurrency() / 2; - workerCount = std::max(std::min(1, workerCount), 4); + workerCount = std::clamp(workerCount, 1, 4); workerPool.resize(workerCount); RenameThreadPool(workerPool, "q-mngr"); } @@ -257,7 +260,7 @@ void CQuorumManager::TriggerQuorumDataRecoveryThreads(CConnman& connman, const C LogPrint(BCLog::LLMQ, "CQuorumManager::%s -- Process block %s\n", __func__, pIndex->GetBlockHash().ToString()); for (const auto& params : Params().GetConsensus().llmqs) { - const auto vecQuorums = ScanQuorums(params.type, pIndex, params.keepOldConnections); + auto vecQuorums = ScanQuorums(params.type, pIndex, params.keepOldConnections); // First check if we are member of any quorum of this type const uint256 proTxHash = m_mn_activeman != nullptr ? m_mn_activeman->GetProTxHash() : uint256(); @@ -266,7 +269,7 @@ void CQuorumManager::TriggerQuorumDataRecoveryThreads(CConnman& connman, const C return pQuorum->IsValidMember(proTxHash); }); - for (const auto& pQuorum : vecQuorums) { + for (auto& pQuorum : vecQuorums) { // If there is already a thread running for this specific quorum skip it if (pQuorum->fQuorumDataRecoveryThreadRunning) { continue; @@ -293,7 +296,7 @@ void CQuorumManager::TriggerQuorumDataRecoveryThreads(CConnman& connman, const C } // Finally start the thread which triggers the requests for this quorum - StartQuorumDataRecoveryThread(connman, pQuorum, pIndex, nDataMask); + StartQuorumDataRecoveryThread(connman, std::move(pQuorum), pIndex, nDataMask); } } } @@ -475,27 +478,23 @@ bool CQuorumManager::HasQuorum(Consensus::LLMQType llmqType, const CQuorumBlockP return quorum_block_processor.HasMinedCommitment(llmqType, quorumHash); } -bool CQuorumManager::RequestQuorumData(CNode* pfrom, CConnman& connman, CQuorumCPtr pQuorum, uint16_t nDataMask, +bool CQuorumManager::RequestQuorumData(CNode* pfrom, CConnman& connman, const CQuorum& quorum, uint16_t nDataMask, const uint256& proTxHash) const { if (pfrom == nullptr) { LogPrint(BCLog::LLMQ, "CQuorumManager::%s -- Invalid pfrom: nullptr\n", __func__); return false; } - if (pfrom->nVersion < LLMQ_DATA_MESSAGES_VERSION) { - LogPrint(BCLog::LLMQ, "CQuorumManager::%s -- Version must be %d or greater.\n", __func__, LLMQ_DATA_MESSAGES_VERSION); - return false; - } if (pfrom->GetVerifiedProRegTxHash().IsNull()) { LogPrint(BCLog::LLMQ, "CQuorumManager::%s -- pfrom is not a verified masternode\n", __func__); return false; } - const Consensus::LLMQType llmqType = pQuorum->qc->llmqType; + const Consensus::LLMQType llmqType = quorum.qc->llmqType; if (!Params().GetLLMQ(llmqType).has_value()) { LogPrint(BCLog::LLMQ, "CQuorumManager::%s -- Invalid llmqType: %d\n", __func__, ToUnderlying(llmqType)); return false; } - const CBlockIndex* pindex{pQuorum->m_quorum_base_block_index}; + const CBlockIndex* pindex{quorum.m_quorum_base_block_index}; if (pindex == nullptr) { LogPrint(BCLog::LLMQ, "CQuorumManager::%s -- Invalid m_quorum_base_block_index : nullptr\n", __func__); return false; @@ -677,7 +676,7 @@ CQuorumCPtr CQuorumManager::GetQuorum(Consensus::LLMQType llmqType, gsl::not_nul return BuildQuorumFromCommitment(llmqType, pQuorumBaseBlockIndex, populate_cache); } -size_t CQuorumManager::GetQuorumRecoveryStartOffset(const CQuorumCPtr pQuorum, const CBlockIndex* pIndex) const +size_t CQuorumManager::GetQuorumRecoveryStartOffset(const CQuorum& quorum, const CBlockIndex* pIndex) const { assert(m_mn_activeman); @@ -699,7 +698,7 @@ size_t CQuorumManager::GetQuorumRecoveryStartOffset(const CQuorumCPtr pQuorum, c } } } - return nIndex % pQuorum->qc->validMembers.size(); + return nIndex % quorum.qc->validMembers.size(); } MessageProcessingResult CQuorumManager::ProcessMessage(CNode& pfrom, CConnman& connman, std::string_view msg_type, CDataStream& vRecv) @@ -887,7 +886,7 @@ MessageProcessingResult CQuorumManager::ProcessMessage(CNode& pfrom, CConnman& c return {}; } -void CQuorumManager::StartCachePopulatorThread(const CQuorumCPtr pQuorum) const +void CQuorumManager::StartCachePopulatorThread(CQuorumCPtr pQuorum) const { if (!pQuorum->HasVerificationVector()) { return; @@ -900,7 +899,7 @@ void CQuorumManager::StartCachePopulatorThread(const CQuorumCPtr pQuorum) const pQuorum->m_quorum_base_block_index->GetBlockHash().ToString()); // when then later some other thread tries to get keys, it will be much faster - workerPool.push([pQuorum, t, this](int threadId) { + workerPool.push([pQuorum = std::move(pQuorum), t, this](int threadId) { for (const auto i : irange::range(pQuorum->members.size())) { if (quorumThreadInterrupt) { break; @@ -917,7 +916,7 @@ void CQuorumManager::StartCachePopulatorThread(const CQuorumCPtr pQuorum) const }); } -void CQuorumManager::StartQuorumDataRecoveryThread(CConnman& connman, const CQuorumCPtr pQuorum, +void CQuorumManager::StartQuorumDataRecoveryThread(CConnman& connman, CQuorumCPtr pQuorum, const CBlockIndex* pIndex, uint16_t nDataMaskIn) const { assert(m_mn_activeman); @@ -928,13 +927,13 @@ void CQuorumManager::StartQuorumDataRecoveryThread(CConnman& connman, const CQuo return; } - workerPool.push([&connman, pQuorum, pIndex, nDataMaskIn, this](int threadId) { + workerPool.push([&connman, pQuorum = std::move(pQuorum), pIndex, nDataMaskIn, this](int threadId) { size_t nTries{0}; uint16_t nDataMask{nDataMaskIn}; int64_t nTimeLastSuccess{0}; uint256* pCurrentMemberHash{nullptr}; std::vector vecMemberHashes; - const size_t nMyStartOffset{GetQuorumRecoveryStartOffset(pQuorum, pIndex)}; + const size_t nMyStartOffset{GetQuorumRecoveryStartOffset(*pQuorum, pIndex)}; const int64_t nRequestTimeout{10}; auto printLog = [&](const std::string& strMessage) { @@ -1010,7 +1009,7 @@ void CQuorumManager::StartQuorumDataRecoveryThread(CConnman& connman, const CQuo return; } - if (RequestQuorumData(pNode, connman, pQuorum, nDataMask, proTxHash)) { + if (RequestQuorumData(pNode, connman, *pQuorum, nDataMask, proTxHash)) { nTimeLastSuccess = GetTime().count(); printLog("Requested"); } else { diff --git a/src/llmq/quorums.h b/src/llmq/quorums.h index 33acc6f3bbeb..f1dc5df1849f 100644 --- a/src/llmq/quorums.h +++ b/src/llmq/quorums.h @@ -11,9 +11,9 @@ #include #include #include +#include #include -#include #include #include #include @@ -37,6 +37,9 @@ class CEvoDB; class CMasternodeSync; class CNode; class CSporkManager; +namespace util { +struct DbWrapperParams; +} // namespace util namespace llmq { @@ -197,25 +200,27 @@ class CQuorum ~CQuorum() = default; void Init(CFinalCommitmentPtr _qc, const CBlockIndex* _pQuorumBaseBlockIndex, const uint256& _minedBlockHash, Span _members); - bool SetVerificationVector(const std::vector& quorumVecIn); - void SetVerificationVector(BLSVerificationVectorPtr vvec_in) { + bool SetVerificationVector(const std::vector& quorumVecIn) EXCLUSIVE_LOCKS_REQUIRED(!cs_vvec_shShare); + void SetVerificationVector(BLSVerificationVectorPtr vvec_in) EXCLUSIVE_LOCKS_REQUIRED(!cs_vvec_shShare) + { LOCK(cs_vvec_shShare); quorumVvec = std::move(vvec_in); } - bool SetSecretKeyShare(const CBLSSecretKey& secretKeyShare, const CActiveMasternodeManager& mn_activeman); + bool SetSecretKeyShare(const CBLSSecretKey& secretKeyShare, const CActiveMasternodeManager& mn_activeman) + EXCLUSIVE_LOCKS_REQUIRED(!cs_vvec_shShare); - bool HasVerificationVector() const LOCKS_EXCLUDED(cs_vvec_shShare); + bool HasVerificationVector() const EXCLUSIVE_LOCKS_REQUIRED(!cs_vvec_shShare); bool IsMember(const uint256& proTxHash) const; bool IsValidMember(const uint256& proTxHash) const; int GetMemberIndex(const uint256& proTxHash) const; - CBLSPublicKey GetPubKeyShare(size_t memberIdx) const; - CBLSSecretKey GetSkShare() const; + CBLSPublicKey GetPubKeyShare(size_t memberIdx) const EXCLUSIVE_LOCKS_REQUIRED(!cs_vvec_shShare); + CBLSSecretKey GetSkShare() const EXCLUSIVE_LOCKS_REQUIRED(!cs_vvec_shShare); private: bool HasVerificationVectorInternal() const EXCLUSIVE_LOCKS_REQUIRED(cs_vvec_shShare); - void WriteContributions(CDBWrapper& db) const; - bool ReadContributions(const CDBWrapper& db); + void WriteContributions(CDBWrapper& db) const EXCLUSIVE_LOCKS_REQUIRED(!cs_vvec_shShare); + bool ReadContributions(const CDBWrapper& db) EXCLUSIVE_LOCKS_REQUIRED(!cs_vvec_shShare); }; /** @@ -242,7 +247,7 @@ class CQuorumManager mutable Mutex cs_map_quorums; mutable std::map> mapQuorumsCache GUARDED_BY(cs_map_quorums); - mutable Mutex cs_scan_quorums; + mutable Mutex cs_scan_quorums; // TODO: merge cs_map_quorums, cs_scan_quorums mutexes mutable std::map>> scanQuorumsCache GUARDED_BY(cs_scan_quorums); mutable Mutex cs_cleanup; @@ -257,53 +262,68 @@ class CQuorumManager mutable CThreadInterrupt quorumThreadInterrupt; public: - CQuorumManager(CBLSWorker& _blsWorker, CChainState& chainstate, CDeterministicMNManager& dmnman, - CDKGSessionManager& _dkgManager, CEvoDB& _evoDb, CQuorumBlockProcessor& _quorumBlockProcessor, - CQuorumSnapshotManager& qsnapman, const CActiveMasternodeManager* const mn_activeman, - const CMasternodeSync& mn_sync, const CSporkManager& sporkman, bool unit_tests, bool wipe); + CQuorumManager() = delete; + CQuorumManager(const CQuorumManager&) = delete; + CQuorumManager& operator=(const CQuorumManager&) = delete; + explicit CQuorumManager(CBLSWorker& _blsWorker, CChainState& chainstate, CDeterministicMNManager& dmnman, + CDKGSessionManager& _dkgManager, CEvoDB& _evoDb, + CQuorumBlockProcessor& _quorumBlockProcessor, CQuorumSnapshotManager& qsnapman, + const CActiveMasternodeManager* const mn_activeman, const CMasternodeSync& mn_sync, + const CSporkManager& sporkman, const util::DbWrapperParams& db_params); ~CQuorumManager(); void Start(); void Stop(); - void TriggerQuorumDataRecoveryThreads(CConnman& connman, const CBlockIndex* pIndex) const; + void TriggerQuorumDataRecoveryThreads(CConnman& connman, const CBlockIndex* pIndex) const + EXCLUSIVE_LOCKS_REQUIRED(!cs_db, !cs_scan_quorums, !cs_map_quorums); - void UpdatedBlockTip(const CBlockIndex* pindexNew, CConnman& connman, bool fInitialDownload) const; + void UpdatedBlockTip(const CBlockIndex* pindexNew, CConnman& connman, bool fInitialDownload) const + EXCLUSIVE_LOCKS_REQUIRED(!cs_db, !cs_scan_quorums, !cs_map_quorums); - [[nodiscard]] MessageProcessingResult ProcessMessage(CNode& pfrom, CConnman& connman, std::string_view msg_type, CDataStream& vRecv); + [[nodiscard]] MessageProcessingResult ProcessMessage(CNode& pfrom, CConnman& connman, std::string_view msg_type, + CDataStream& vRecv) + EXCLUSIVE_LOCKS_REQUIRED(!cs_map_quorums, !cs_db); static bool HasQuorum(Consensus::LLMQType llmqType, const CQuorumBlockProcessor& quorum_block_processor, const uint256& quorumHash); - bool RequestQuorumData(CNode* pfrom, CConnman& connman, const CQuorumCPtr pQuorum, uint16_t nDataMask, + bool RequestQuorumData(CNode* pfrom, CConnman& connman, const CQuorum& quorum, uint16_t nDataMask, const uint256& proTxHash = uint256()) const; // all these methods will lock cs_main for a short period of time - CQuorumCPtr GetQuorum(Consensus::LLMQType llmqType, const uint256& quorumHash) const; - std::vector ScanQuorums(Consensus::LLMQType llmqType, size_t nCountRequested) const; + CQuorumCPtr GetQuorum(Consensus::LLMQType llmqType, const uint256& quorumHash) const + EXCLUSIVE_LOCKS_REQUIRED(!cs_db, !cs_map_quorums); + std::vector ScanQuorums(Consensus::LLMQType llmqType, size_t nCountRequested) const + EXCLUSIVE_LOCKS_REQUIRED(!cs_db, !cs_map_quorums, !cs_scan_quorums); // this one is cs_main-free - std::vector ScanQuorums(Consensus::LLMQType llmqType, const CBlockIndex* pindexStart, size_t nCountRequested) const; + std::vector ScanQuorums(Consensus::LLMQType llmqType, const CBlockIndex* pindexStart, + size_t nCountRequested) const + EXCLUSIVE_LOCKS_REQUIRED(!cs_db, !cs_map_quorums, !cs_scan_quorums); private: // all private methods here are cs_main-free - void CheckQuorumConnections(CConnman& connman, const Consensus::LLMQParams& llmqParams, - const CBlockIndex* pindexNew) const; + void CheckQuorumConnections(CConnman& connman, const Consensus::LLMQParams& llmqParams, const CBlockIndex* pindexNew) const + EXCLUSIVE_LOCKS_REQUIRED(!cs_db, !cs_scan_quorums, !cs_map_quorums); - CQuorumPtr BuildQuorumFromCommitment(Consensus::LLMQType llmqType, gsl::not_null pQuorumBaseBlockIndex, bool populate_cache) const; + CQuorumPtr BuildQuorumFromCommitment(Consensus::LLMQType llmqType, + gsl::not_null pQuorumBaseBlockIndex, + bool populate_cache) const EXCLUSIVE_LOCKS_REQUIRED(!cs_db, !cs_map_quorums); bool BuildQuorumContributions(const CFinalCommitmentPtr& fqc, const std::shared_ptr& quorum) const; - CQuorumCPtr GetQuorum(Consensus::LLMQType llmqType, gsl::not_null pindex, bool populate_cache = true) const; + CQuorumCPtr GetQuorum(Consensus::LLMQType llmqType, gsl::not_null pindex, + bool populate_cache = true) const EXCLUSIVE_LOCKS_REQUIRED(!cs_db, !cs_map_quorums); /// Returns the start offset for the masternode with the given proTxHash. This offset is applied when picking data recovery members of a quorum's /// memberlist and is calculated based on a list of all member of all active quorums for the given llmqType in a way that each member /// should receive the same number of request if all active llmqType members requests data from one llmqType quorum. - size_t GetQuorumRecoveryStartOffset(const CQuorumCPtr pQuorum, const CBlockIndex* pIndex) const; + size_t GetQuorumRecoveryStartOffset(const CQuorum& quorum, const CBlockIndex* pIndex) const; - void StartCachePopulatorThread(const CQuorumCPtr pQuorum) const; - void StartQuorumDataRecoveryThread(CConnman& connman, const CQuorumCPtr pQuorum, const CBlockIndex* pIndex, + void StartCachePopulatorThread(CQuorumCPtr pQuorum) const; + void StartQuorumDataRecoveryThread(CConnman& connman, CQuorumCPtr pQuorum, const CBlockIndex* pIndex, uint16_t nDataMask) const; void StartCleanupOldQuorumDataThread(const CBlockIndex* pIndex) const; - void MigrateOldQuorumDB(CEvoDB& evoDb) const; + void MigrateOldQuorumDB(CEvoDB& evoDb) const EXCLUSIVE_LOCKS_REQUIRED(!cs_db); }; // when selecting a quorum for signing and verification, we use CQuorumManager::SelectQuorum with this offset as diff --git a/src/llmq/signing.cpp b/src/llmq/signing.cpp index f66effa2d02d..4a1ac7a6b528 100644 --- a/src/llmq/signing.cpp +++ b/src/llmq/signing.cpp @@ -27,21 +27,8 @@ namespace llmq { -UniValue CRecoveredSig::ToJson() const -{ - UniValue ret(UniValue::VOBJ); - ret.pushKV("llmqType", ToUnderlying(llmqType)); - ret.pushKV("quorumHash", quorumHash.ToString()); - ret.pushKV("id", id.ToString()); - ret.pushKV("msgHash", msgHash.ToString()); - ret.pushKV("sig", sig.Get().ToString()); - ret.pushKV("hash", sig.Get().GetHash().ToString()); - return ret; -} - - -CRecoveredSigsDb::CRecoveredSigsDb(bool fMemory, bool fWipe) : - db(std::make_unique(fMemory ? "" : (gArgs.GetDataDirNet() / "llmq/recsigdb"), 8 << 20, fMemory, fWipe)) +CRecoveredSigsDb::CRecoveredSigsDb(const util::DbWrapperParams& db_params) : + db{util::MakeDbWrapper({db_params.path / "llmq" / "recsigdb", db_params.memory, db_params.wipe, /*cache_size=*/8 << 20})} { } @@ -196,8 +183,8 @@ void CRecoveredSigsDb::RemoveRecoveredSig(CDBBatch& batch, Consensus::LLMQType l batch.Erase(k2); if (deleteHashKey) { batch.Erase(k3); + batch.Erase(k4); } - batch.Erase(k4); if (deleteTimeKey) { CDataStream writeTimeDs(SER_DISK, CLIENT_VERSION); @@ -212,14 +199,15 @@ void CRecoveredSigsDb::RemoveRecoveredSig(CDBBatch& batch, Consensus::LLMQType l LOCK(cs_cache); hasSigForIdCache.erase(std::make_pair(recSig.getLlmqType(), recSig.getId())); - hasSigForSessionCache.erase(signHash.Get()); if (deleteHashKey) { + hasSigForSessionCache.erase(signHash.Get()); hasSigForHashCache.erase(recSig.GetHash()); } } // Remove the recovered sig itself and all keys required to get from id -> recSig -// This will leave the byHash key in-place so that HasRecoveredSigForHash still returns true +// This will leave the byHash and signHash key in-place so that HasRecoveredSigForHash / +// late-share filtering still returns true void CRecoveredSigsDb::TruncateRecoveredSig(Consensus::LLMQType llmqType, const uint256& id) { CDBBatch batch(*db); @@ -345,15 +333,16 @@ void CRecoveredSigsDb::CleanupOldVotes(int64_t maxAge) ////////////////// -CSigningManager::CSigningManager(const CActiveMasternodeManager* const mn_activeman, const CChainState& chainstate, - const CQuorumManager& _qman, bool fMemory, bool fWipe) : - db(fMemory, fWipe), - m_mn_activeman(mn_activeman), - m_chainstate(chainstate), - qman(_qman) +CSigningManager::CSigningManager(const CChainState& chainstate, const CQuorumManager& _qman, + const util::DbWrapperParams& db_params) : + db{db_params}, + m_chainstate{chainstate}, + qman{_qman} { } +CSigningManager::~CSigningManager() = default; + bool CSigningManager::AlreadyHave(const CInv& inv) const { if (inv.type != MSG_QUORUM_RECOVERED_SIG) { @@ -447,15 +436,17 @@ MessageProcessingResult CSigningManager::ProcessMessage(NodeId from, std::string return ret; } -void CSigningManager::CollectPendingRecoveredSigsToVerify( +bool CSigningManager::CollectPendingRecoveredSigsToVerify( size_t maxUniqueSessions, std::unordered_map>>& retSigShares, std::unordered_map, CQuorumCPtr, StaticSaltedHasher>& retQuorums) { + bool more_work{false}; + { LOCK(cs_pending); if (pendingRecoveredSigs.empty()) { - return; + return false; } // TODO: refactor it to remove duplicated code with `CSigSharesManager::CollectPendingSigSharesToVerify` @@ -478,8 +469,12 @@ void CSigningManager::CollectPendingRecoveredSigsToVerify( }, rnd); if (retSigShares.empty()) { - return; + return false; } + + more_work = std::any_of(pendingRecoveredSigs.begin(), pendingRecoveredSigs.end(), + [](const auto& p) { return !p.second.empty(); }) || + !pendingReconstructedRecoveredSigs.empty(); } for (auto& p : retSigShares) { @@ -512,6 +507,8 @@ void CSigningManager::CollectPendingRecoveredSigsToVerify( ++it; } } + + return more_work; } void CSigningManager::ProcessPendingReconstructedRecoveredSigs(PeerManager& peerman) @@ -532,7 +529,7 @@ bool CSigningManager::ProcessPendingRecoveredSigs(PeerManager& peerman) ProcessPendingReconstructedRecoveredSigs(peerman); const size_t nMaxBatchSize{32}; - CollectPendingRecoveredSigsToVerify(nMaxBatchSize, recSigsByNode, quorums); + bool more_work = CollectPendingRecoveredSigsToVerify(nMaxBatchSize, recSigsByNode, quorums); if (recSigsByNode.empty()) { return false; } @@ -586,7 +583,7 @@ bool CSigningManager::ProcessPendingRecoveredSigs(PeerManager& peerman) } } - return recSigsByNode.size() >= nMaxBatchSize; + return more_work; } // signature must be verified already @@ -628,10 +625,6 @@ void CSigningManager::ProcessRecoveredSig(const std::shared_ptrGetHash())); - if (m_mn_activeman != nullptr) { - peerman.RelayRecoveredSig(recoveredSig->GetHash()); - } - auto listeners = WITH_LOCK(cs_listeners, return recoveredSigsListeners); for (auto& l : listeners) { peerman.PostProcessMessage(l->HandleNewRecoveredSig(*recoveredSig)); @@ -653,8 +646,8 @@ void CSigningManager::TruncateRecoveredSig(Consensus::LLMQType llmqType, const u void CSigningManager::Cleanup() { - int64_t now = TicksSinceEpoch(SystemClock::now()); - if (now - lastCleanupTime < 5000) { + constexpr auto CLEANUP_INTERVAL{5000ms}; + if (!cleanupThrottler.TryCleanup(CLEANUP_INTERVAL)) { return; } @@ -662,8 +655,6 @@ void CSigningManager::Cleanup() db.CleanupOldRecoveredSigs(maxAge); db.CleanupOldVotes(maxAge); - - lastCleanupTime = TicksSinceEpoch(SystemClock::now()); } void CSigningManager::RegisterRecoveredSigsListener(CRecoveredSigsListener* l) @@ -679,80 +670,6 @@ void CSigningManager::UnregisterRecoveredSigsListener(CRecoveredSigsListener* l) recoveredSigsListeners.erase(itRem, recoveredSigsListeners.end()); } -bool CSigningManager::AsyncSignIfMember(Consensus::LLMQType llmqType, CSigSharesManager& shareman, const uint256& id, - const uint256& msgHash, const uint256& quorumHash, bool allowReSign, - bool allowDiffMsgHashSigning) -{ - if (m_mn_activeman == nullptr) return false; - if (m_mn_activeman->GetProTxHash().IsNull()) return false; - - const auto quorum = [&]() { - if (quorumHash.IsNull()) { - // This might end up giving different results on different members - // This might happen when we are on the brink of confirming a new quorum - // This gives a slight risk of not getting enough shares to recover a signature - // But at least it shouldn't be possible to get conflicting recovered signatures - // TODO fix this by re-signing when the next block arrives, but only when that block results in a change of the quorum list and no recovered signature has been created in the mean time - const auto &llmq_params_opt = Params().GetLLMQ(llmqType); - assert(llmq_params_opt.has_value()); - return SelectQuorumForSigning(llmq_params_opt.value(), m_chainstate.m_chain, qman, id); - } else { - return qman.GetQuorum(llmqType, quorumHash); - } - }(); - - if (!quorum) { - LogPrint(BCLog::LLMQ, "CSigningManager::%s -- failed to select quorum. id=%s, msgHash=%s\n", __func__, id.ToString(), msgHash.ToString()); - return false; - } - - if (!quorum->IsValidMember(m_mn_activeman->GetProTxHash())) { - return false; - } - - { - bool hasVoted = db.HasVotedOnId(llmqType, id); - if (hasVoted) { - uint256 prevMsgHash; - db.GetVoteForId(llmqType, id, prevMsgHash); - if (msgHash != prevMsgHash) { - if (allowDiffMsgHashSigning) { - LogPrintf("CSigningManager::%s -- already voted for id=%s and msgHash=%s. Signing for different msgHash=%s\n", - __func__, id.ToString(), prevMsgHash.ToString(), msgHash.ToString()); - hasVoted = false; - } else { - LogPrintf("CSigningManager::%s -- already voted for id=%s and msgHash=%s. Not voting on conflicting msgHash=%s\n", - __func__, id.ToString(), prevMsgHash.ToString(), msgHash.ToString()); - return false; - } - } else if (allowReSign) { - LogPrint(BCLog::LLMQ, "CSigningManager::%s -- already voted for id=%s and msgHash=%s. Resigning!\n", __func__, - id.ToString(), prevMsgHash.ToString()); - } else { - LogPrint(BCLog::LLMQ, "CSigningManager::%s -- already voted for id=%s and msgHash=%s. Not voting again.\n", __func__, - id.ToString(), prevMsgHash.ToString()); - return false; - } - } - - if (db.HasRecoveredSigForId(llmqType, id)) { - // no need to sign it if we already have a recovered sig - return true; - } - if (!hasVoted) { - db.WriteVoteForId(llmqType, id, msgHash); - } - } - - if (allowReSign) { - // make us re-announce all known shares (other nodes might have run into a timeout) - shareman.ForceReAnnouncement(quorum, llmqType, id, msgHash); - } - shareman.AsyncSign(quorum, id, msgHash); - - return true; -} - bool CSigningManager::HasRecoveredSig(Consensus::LLMQType llmqType, const uint256& id, const uint256& msgHash) const { return db.HasRecoveredSig(llmqType, id, msgHash); @@ -804,7 +721,7 @@ void CSigningManager::StartWorkerThread(PeerManager& peerman) assert(false); } - workThread = std::thread(&util::TraceThread, "sigshares", [this, &peerman] { WorkThreadMain(peerman); }); + workThread = std::thread(&util::TraceThread, "recsigs", [this, &peerman] { WorkThreadMain(peerman); }); } void CSigningManager::StopWorkerThread() diff --git a/src/llmq/signing.h b/src/llmq/signing.h index b835079d5b19..d4149314c011 100644 --- a/src/llmq/signing.h +++ b/src/llmq/signing.h @@ -9,27 +9,34 @@ #include #include #include +#include #include #include -#include #include #include #include #include +#include #include +#include #include +#include #include -class CActiveMasternodeManager; class CChainState; class CDataStream; class CDBBatch; class CDBWrapper; class CInv; class PeerManager; +struct RPCResult; +namespace util { +struct DbWrapperParams; +} // namespace util + class UniValue; namespace llmq { @@ -106,7 +113,8 @@ class CRecoveredSig : virtual public CSigBase return hash; } - UniValue ToJson() const; + [[nodiscard]] static RPCResult GetJsonHelp(const std::string& key, bool optional); + [[nodiscard]] UniValue ToJson() const; }; class CRecoveredSigsDb @@ -120,19 +128,19 @@ class CRecoveredSigsDb mutable Uint256LruHashMap hasSigForHashCache GUARDED_BY(cs_cache); public: - explicit CRecoveredSigsDb(bool fMemory, bool fWipe); + explicit CRecoveredSigsDb(const util::DbWrapperParams& db_params); ~CRecoveredSigsDb(); bool HasRecoveredSig(Consensus::LLMQType llmqType, const uint256& id, const uint256& msgHash) const; - bool HasRecoveredSigForId(Consensus::LLMQType llmqType, const uint256& id) const; - bool HasRecoveredSigForSession(const uint256& signHash) const; - bool HasRecoveredSigForHash(const uint256& hash) const; + bool HasRecoveredSigForId(Consensus::LLMQType llmqType, const uint256& id) const EXCLUSIVE_LOCKS_REQUIRED(!cs_cache); + bool HasRecoveredSigForSession(const uint256& signHash) const EXCLUSIVE_LOCKS_REQUIRED(!cs_cache); + bool HasRecoveredSigForHash(const uint256& hash) const EXCLUSIVE_LOCKS_REQUIRED(!cs_cache); bool GetRecoveredSigByHash(const uint256& hash, CRecoveredSig& ret) const; bool GetRecoveredSigById(Consensus::LLMQType llmqType, const uint256& id, CRecoveredSig& ret) const; - void WriteRecoveredSig(const CRecoveredSig& recSig); - void TruncateRecoveredSig(Consensus::LLMQType llmqType, const uint256& id); + void WriteRecoveredSig(const CRecoveredSig& recSig) EXCLUSIVE_LOCKS_REQUIRED(!cs_cache); + void TruncateRecoveredSig(Consensus::LLMQType llmqType, const uint256& id) EXCLUSIVE_LOCKS_REQUIRED(!cs_cache); - void CleanupOldRecoveredSigs(int64_t maxAge); + void CleanupOldRecoveredSigs(int64_t maxAge) EXCLUSIVE_LOCKS_REQUIRED(!cs_cache); // votes are removed when the recovered sig is written to the db bool HasVotedOnId(Consensus::LLMQType llmqType, const uint256& id) const; @@ -143,7 +151,8 @@ class CRecoveredSigsDb private: bool ReadRecoveredSig(Consensus::LLMQType llmqType, const uint256& id, CRecoveredSig& ret) const; - void RemoveRecoveredSig(CDBBatch& batch, Consensus::LLMQType llmqType, const uint256& id, bool deleteHashKey, bool deleteTimeKey); + void RemoveRecoveredSig(CDBBatch& batch, Consensus::LLMQType llmqType, const uint256& id, bool deleteHashKey, + bool deleteTimeKey) EXCLUSIVE_LOCKS_REQUIRED(!cs_cache); }; class CRecoveredSigsListener @@ -159,7 +168,6 @@ class CSigningManager private: CRecoveredSigsDb db; - const CActiveMasternodeManager* const m_mn_activeman; const CChainState& m_chainstate; const CQuorumManager& qman; @@ -170,51 +178,59 @@ class CSigningManager FastRandomContext rnd GUARDED_BY(cs_pending); - int64_t lastCleanupTime{0}; + CleanupThrottler cleanupThrottler; mutable Mutex cs_listeners; std::vector recoveredSigsListeners GUARDED_BY(cs_listeners); public: - CSigningManager(const CActiveMasternodeManager* const mn_activeman, const CChainState& chainstate, - const CQuorumManager& _qman, bool fMemory, bool fWipe); - - bool AlreadyHave(const CInv& inv) const; + CSigningManager() = delete; + CSigningManager(const CSigningManager&) = delete; + CSigningManager& operator=(const CSigningManager&) = delete; + explicit CSigningManager(const CChainState& chainstate, const CQuorumManager& _qman, + const util::DbWrapperParams& db_params); + ~CSigningManager(); + + bool AlreadyHave(const CInv& inv) const EXCLUSIVE_LOCKS_REQUIRED(!cs_pending); bool GetRecoveredSigForGetData(const uint256& hash, CRecoveredSig& ret) const; - [[nodiscard]] MessageProcessingResult ProcessMessage(NodeId from, std::string_view msg_type, CDataStream& vRecv); + [[nodiscard]] MessageProcessingResult ProcessMessage(NodeId from, std::string_view msg_type, CDataStream& vRecv) + EXCLUSIVE_LOCKS_REQUIRED(!cs_pending); // This is called when a recovered signature was was reconstructed from another P2P message and is known to be valid // This is the case for example when a signature appears as part of InstantSend or ChainLocks - void PushReconstructedRecoveredSig(const std::shared_ptr& recoveredSig); + void PushReconstructedRecoveredSig(const std::shared_ptr& recoveredSig) + EXCLUSIVE_LOCKS_REQUIRED(!cs_pending); // This is called when a recovered signature can be safely removed from the DB. This is only safe when some other // mechanism prevents possible conflicts. As an example, ChainLocks prevent conflicts in confirmed TXs InstantSend votes - // This won't completely remove all traces of the recovered sig but instead leave the hash entry in the DB. This - // allows AlreadyHave to keep returning true. Cleanup will later remove the remains + // This won't completely remove all traces of the recovered sig but instead leave the hash and signHash entries in the + // DB. This allows AlreadyHave/late-share filtering to keep returning true. Cleanup will later remove the remains void TruncateRecoveredSig(Consensus::LLMQType llmqType, const uint256& id); private: - void CollectPendingRecoveredSigsToVerify(size_t maxUniqueSessions, - std::unordered_map>>& retSigShares, - std::unordered_map, CQuorumCPtr, StaticSaltedHasher>& retQuorums); - void ProcessPendingReconstructedRecoveredSigs(PeerManager& peerman); - bool ProcessPendingRecoveredSigs(PeerManager& peerman); // called from the worker thread of CSigSharesManager -public: - // TODO - should not be public! - void ProcessRecoveredSig(const std::shared_ptr& recoveredSig, PeerManager& peerman); - -private: - void Cleanup(); // called from the worker thread of CSigSharesManager + bool CollectPendingRecoveredSigsToVerify( + size_t maxUniqueSessions, std::unordered_map>>& retSigShares, + std::unordered_map, CQuorumCPtr, StaticSaltedHasher>& retQuorums) + EXCLUSIVE_LOCKS_REQUIRED(!cs_pending); + void ProcessPendingReconstructedRecoveredSigs(PeerManager& peerman) + EXCLUSIVE_LOCKS_REQUIRED(!cs_pending, !cs_listeners); + bool ProcessPendingRecoveredSigs(PeerManager& peerman) + EXCLUSIVE_LOCKS_REQUIRED(!cs_pending, !cs_listeners); // called from the worker thread of CSigSharesManager + + // Used by CSigSharesManager + CRecoveredSigsDb& GetDb() { return db; } + void ProcessRecoveredSig(const std::shared_ptr& recoveredSig, PeerManager& peerman) + EXCLUSIVE_LOCKS_REQUIRED(!cs_pending, !cs_listeners); + + // Needed for access to GetDb() and ProcessRecoveredSig() + friend class CSigSharesManager; public: // public interface - void RegisterRecoveredSigsListener(CRecoveredSigsListener* l); - void UnregisterRecoveredSigsListener(CRecoveredSigsListener* l); + void RegisterRecoveredSigsListener(CRecoveredSigsListener* l) EXCLUSIVE_LOCKS_REQUIRED(!cs_listeners); + void UnregisterRecoveredSigsListener(CRecoveredSigsListener* l) EXCLUSIVE_LOCKS_REQUIRED(!cs_listeners); - bool AsyncSignIfMember(Consensus::LLMQType llmqType, CSigSharesManager& shareman, const uint256& id, - const uint256& msgHash, const uint256& quorumHash = uint256(), bool allowReSign = false, - bool allowDiffMsgHashSigning = false); bool HasRecoveredSig(Consensus::LLMQType llmqType, const uint256& id, const uint256& msgHash) const; bool HasRecoveredSigForId(Consensus::LLMQType llmqType, const uint256& id) const; bool HasRecoveredSigForSession(const uint256& signHash) const; @@ -226,7 +242,8 @@ class CSigningManager private: std::thread workThread; CThreadInterrupt workInterrupt; - void WorkThreadMain(PeerManager& peerman); + void Cleanup(); // called from the worker thread of CSigSharesManager + void WorkThreadMain(PeerManager& peerman) EXCLUSIVE_LOCKS_REQUIRED(!cs_pending, !cs_listeners); public: void StartWorkerThread(PeerManager& peerman); diff --git a/src/llmq/signing_shares.cpp b/src/llmq/signing_shares.cpp index 1c9a911989b5..01bbd5112495 100644 --- a/src/llmq/signing_shares.cpp +++ b/src/llmq/signing_shares.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include @@ -179,15 +180,30 @@ void CSigSharesNodeState::RemoveSession(const uint256& signHash) ////////////////////// -void CSigSharesManager::StartWorkerThread(CConnman& connman, PeerManager& peerman) +CSigSharesManager::CSigSharesManager(CConnman& connman, CChainState& chainstate, CSigningManager& _sigman, + PeerManager& peerman, const CActiveMasternodeManager& mn_activeman, + const CQuorumManager& _qman, const CSporkManager& sporkman) : + m_connman{connman}, + m_chainstate{chainstate}, + sigman{_sigman}, + m_peerman{peerman}, + m_mn_activeman{mn_activeman}, + qman{_qman}, + m_sporkman{sporkman} +{ + workInterrupt.reset(); +} + +CSigSharesManager::~CSigSharesManager() = default; + +void CSigSharesManager::StartWorkerThread() { // can't start new thread if we have one running already if (workThread.joinable()) { assert(false); } - workThread = std::thread(&util::TraceThread, "sigshares", - [this, &connman, &peerman] { WorkThreadMain(connman, peerman); }); + workThread = std::thread(&util::TraceThread, "sigshares", [this] { WorkThreadMain(); }); } void CSigSharesManager::StopWorkerThread() @@ -217,25 +233,23 @@ void CSigSharesManager::InterruptWorkerThread() workInterrupt(); } -void CSigSharesManager::ProcessMessage(const CNode& pfrom, PeerManager& peerman, const CSporkManager& sporkman, - const std::string& msg_type, CDataStream& vRecv) +void CSigSharesManager::ProcessMessage(const CNode& pfrom, const std::string& msg_type, CDataStream& vRecv) { // non-masternodes are not interested in sigshares - if (m_mn_activeman == nullptr) return; - if (m_mn_activeman->GetProTxHash().IsNull()) return; + if (m_mn_activeman.GetProTxHash().IsNull()) return; - if (sporkman.IsSporkActive(SPORK_21_QUORUM_ALL_CONNECTED) && msg_type == NetMsgType::QSIGSHARE) { + if (m_sporkman.IsSporkActive(SPORK_21_QUORUM_ALL_CONNECTED) && msg_type == NetMsgType::QSIGSHARE) { std::vector receivedSigShares; vRecv >> receivedSigShares; if (receivedSigShares.size() > MAX_MSGS_SIG_SHARES) { LogPrint(BCLog::LLMQ_SIGS, "CSigSharesManager::%s -- too many sigs in QSIGSHARE message. cnt=%d, max=%d, node=%d\n", __func__, receivedSigShares.size(), MAX_MSGS_SIG_SHARES, pfrom.GetId()); - BanNode(pfrom.GetId(), peerman); + BanNode(pfrom.GetId()); return; } for (const auto& sigShare : receivedSigShares) { - ProcessMessageSigShare(pfrom.GetId(), peerman, sigShare); + ProcessMessageSigShare(pfrom.GetId(), sigShare); } } @@ -244,12 +258,12 @@ void CSigSharesManager::ProcessMessage(const CNode& pfrom, PeerManager& peerman, vRecv >> msgs; if (msgs.size() > MAX_MSGS_CNT_QSIGSESANN) { LogPrint(BCLog::LLMQ_SIGS, "CSigSharesManager::%s -- too many announcements in QSIGSESANN message. cnt=%d, max=%d, node=%d\n", __func__, msgs.size(), MAX_MSGS_CNT_QSIGSESANN, pfrom.GetId()); - BanNode(pfrom.GetId(), peerman); + BanNode(pfrom.GetId()); return; } if (!ranges::all_of(msgs, [this, &pfrom](const auto& ann){ return ProcessMessageSigSesAnn(pfrom, ann); })) { - BanNode(pfrom.GetId(), peerman); + BanNode(pfrom.GetId()); return; } } else if (msg_type == NetMsgType::QSIGSHARESINV) { @@ -257,12 +271,12 @@ void CSigSharesManager::ProcessMessage(const CNode& pfrom, PeerManager& peerman, vRecv >> msgs; if (msgs.size() > MAX_MSGS_CNT_QSIGSHARESINV) { LogPrint(BCLog::LLMQ_SIGS, "CSigSharesManager::%s -- too many invs in QSIGSHARESINV message. cnt=%d, max=%d, node=%d\n", __func__, msgs.size(), MAX_MSGS_CNT_QSIGSHARESINV, pfrom.GetId()); - BanNode(pfrom.GetId(), peerman); + BanNode(pfrom.GetId()); return; } if (!ranges::all_of(msgs, [this, &pfrom](const auto& inv){ return ProcessMessageSigSharesInv(pfrom, inv); })) { - BanNode(pfrom.GetId(), peerman); + BanNode(pfrom.GetId()); return; } } else if (msg_type == NetMsgType::QGETSIGSHARES) { @@ -270,12 +284,12 @@ void CSigSharesManager::ProcessMessage(const CNode& pfrom, PeerManager& peerman, vRecv >> msgs; if (msgs.size() > MAX_MSGS_CNT_QGETSIGSHARES) { LogPrint(BCLog::LLMQ_SIGS, "CSigSharesManager::%s -- too many invs in QGETSIGSHARES message. cnt=%d, max=%d, node=%d\n", __func__, msgs.size(), MAX_MSGS_CNT_QGETSIGSHARES, pfrom.GetId()); - BanNode(pfrom.GetId(), peerman); + BanNode(pfrom.GetId()); return; } if (!ranges::all_of(msgs, [this, &pfrom](const auto& inv){ return ProcessMessageGetSigShares(pfrom, inv); })) { - BanNode(pfrom.GetId(), peerman); + BanNode(pfrom.GetId()); return; } } else if (msg_type == NetMsgType::QBSIGSHARES) { @@ -287,12 +301,12 @@ void CSigSharesManager::ProcessMessage(const CNode& pfrom, PeerManager& peerman, } if (totalSigsCount > MAX_MSGS_TOTAL_BATCHED_SIGS) { LogPrint(BCLog::LLMQ_SIGS, "CSigSharesManager::%s -- too many sigs in QBSIGSHARES message. cnt=%d, max=%d, node=%d\n", __func__, msgs.size(), MAX_MSGS_TOTAL_BATCHED_SIGS, pfrom.GetId()); - BanNode(pfrom.GetId(), peerman); + BanNode(pfrom.GetId()); return; } if (!ranges::all_of(msgs, [this, &pfrom](const auto& bs){ return ProcessMessageBatchedSigShares(pfrom, bs); })) { - BanNode(pfrom.GetId(), peerman); + BanNode(pfrom.GetId()); return; } } @@ -410,7 +424,7 @@ bool CSigSharesManager::ProcessMessageBatchedSigShares(const CNode& pfrom, const return true; } - if (bool ban{false}; !PreVerifyBatchedSigShares(*Assert(m_mn_activeman), qman, sessionInfo, batchedSigShares, ban)) { + if (bool ban{false}; !PreVerifyBatchedSigShares(m_mn_activeman, qman, sessionInfo, batchedSigShares, ban)) { return !ban; } @@ -457,10 +471,8 @@ bool CSigSharesManager::ProcessMessageBatchedSigShares(const CNode& pfrom, const return true; } -void CSigSharesManager::ProcessMessageSigShare(NodeId fromId, PeerManager& peerman, const CSigShare& sigShare) +void CSigSharesManager::ProcessMessageSigShare(NodeId fromId, const CSigShare& sigShare) { - assert(m_mn_activeman); - auto quorum = qman.GetQuorum(sigShare.getLlmqType(), sigShare.getQuorumHash()); if (!quorum) { return; @@ -469,7 +481,7 @@ void CSigSharesManager::ProcessMessageSigShare(NodeId fromId, PeerManager& peerm // quorum is too old return; } - if (!quorum->IsMember(m_mn_activeman->GetProTxHash())) { + if (!quorum->IsMember(m_mn_activeman.GetProTxHash())) { // we're not a member so we can't verify it (we actually shouldn't have received it) return; } @@ -482,23 +494,32 @@ void CSigSharesManager::ProcessMessageSigShare(NodeId fromId, PeerManager& peerm if (sigShare.getQuorumMember() >= quorum->members.size()) { LogPrint(BCLog::LLMQ_SIGS, "CSigSharesManager::%s -- quorumMember out of bounds\n", __func__); - BanNode(fromId, peerman); + BanNode(fromId); return; } if (!quorum->qc->validMembers[sigShare.getQuorumMember()]) { LogPrint(BCLog::LLMQ_SIGS, "CSigSharesManager::%s -- quorumMember not valid\n", __func__); - BanNode(fromId, peerman); + BanNode(fromId); return; } + const auto signHash = sigShare.GetSignHash(); + const bool alreadyRecovered = sigman.HasRecoveredSigForId(sigShare.getLlmqType(), sigShare.getId()) || + sigman.HasRecoveredSigForSession(signHash); + { LOCK(cs); - if (sigShares.Has(sigShare.GetKey())) { + if (alreadyRecovered) { + LogPrint(BCLog::LLMQ_SIGS, /* Continued */ + "CSigSharesManager::%s -- dropping sigShare for recovered session. signHash=%s, id=%s, " + "msgHash=%s, member=%d, node=%d\n", + __func__, signHash.ToString(), sigShare.getId().ToString(), sigShare.getMsgHash().ToString(), + sigShare.getQuorumMember(), fromId); return; } - if (sigman.HasRecoveredSigForId(sigShare.getLlmqType(), sigShare.getId())) { + if (sigShares.Has(sigShare.GetKey())) { return; } @@ -507,7 +528,7 @@ void CSigSharesManager::ProcessMessageSigShare(NodeId fromId, PeerManager& peerm } LogPrint(BCLog::LLMQ_SIGS, "CSigSharesManager::%s -- signHash=%s, id=%s, msgHash=%s, member=%d, node=%d\n", __func__, - sigShare.GetSignHash().ToString(), sigShare.getId().ToString(), sigShare.getMsgHash().ToString(), sigShare.getQuorumMember(), fromId); + signHash.ToString(), sigShare.getId().ToString(), sigShare.getMsgHash().ToString(), sigShare.getQuorumMember(), fromId); } bool CSigSharesManager::PreVerifyBatchedSigShares(const CActiveMasternodeManager& mn_activeman, const CQuorumManager& quorum_manager, @@ -556,6 +577,8 @@ bool CSigSharesManager::CollectPendingSigSharesToVerify( size_t maxUniqueSessions, std::unordered_map>& retSigShares, std::unordered_map, CQuorumCPtr, StaticSaltedHasher>& retQuorums) { + bool more_work{false}; + { LOCK(cs); if (nodeStates.empty()) { @@ -594,6 +617,13 @@ bool CSigSharesManager::CollectPendingSigSharesToVerify( if (retSigShares.empty()) { return false; } + + // Determine if there is still work left in any node state after pulling this batch + more_work = std::any_of(nodeStates.begin(), nodeStates.end(), + [](const auto& entry) { + const auto& ns = entry.second; + return !ns.pendingIncomingSigShares.Empty(); + }); } // For the convenience of the caller, also build a map of quorumHash -> quorum @@ -620,17 +650,17 @@ bool CSigSharesManager::CollectPendingSigSharesToVerify( } } - return true; + return more_work; } -bool CSigSharesManager::ProcessPendingSigShares(PeerManager& peerman, const CConnman& connman) +bool CSigSharesManager::ProcessPendingSigShares() { std::unordered_map> sigSharesByNodes; std::unordered_map, CQuorumCPtr, StaticSaltedHasher> quorums; const size_t nMaxBatchSize{32}; - bool collect_status = CollectPendingSigSharesToVerify(nMaxBatchSize, sigSharesByNodes, quorums); - if (!collect_status || sigSharesByNodes.empty()) { + bool more_work = CollectPendingSigSharesToVerify(nMaxBatchSize, sigSharesByNodes, quorums); + if (sigSharesByNodes.empty()) { return false; } @@ -646,10 +676,13 @@ bool CSigSharesManager::ProcessPendingSigShares(PeerManager& peerman, const CCon continue; } + // Materialize the signature once. Get() internally validates, so if it returns an invalid signature, + // we know it's malformed. This avoids calling Get() twice (once for IsValid(), once for PushMessage). + CBLSSignature sig = sigShare.sigShare.Get(); // we didn't check this earlier because we use a lazy BLS signature and tried to avoid doing the expensive // deserialization in the message thread - if (!sigShare.sigShare.Get().IsValid()) { - BanNode(nodeId, peerman); + if (!sig.IsValid()) { + BanNode(nodeId); // don't process any additional shares from this node break; } @@ -664,7 +697,7 @@ bool CSigSharesManager::ProcessPendingSigShares(PeerManager& peerman, const CCon assert(false); } - batchVerifier.PushMessage(nodeId, sigShare.GetKey(), sigShare.GetSignHash(), sigShare.sigShare.Get(), pubKeyShare); + batchVerifier.PushMessage(nodeId, sigShare.GetKey(), sigShare.GetSignHash(), sig, pubKeyShare); verifyCount++; } } @@ -681,26 +714,25 @@ bool CSigSharesManager::ProcessPendingSigShares(PeerManager& peerman, const CCon LogPrint(BCLog::LLMQ_SIGS, "CSigSharesManager::%s -- invalid sig shares from other node, banning peer=%d\n", __func__, nodeId); // this will also cause re-requesting of the shares that were sent by this node - BanNode(nodeId, peerman); + BanNode(nodeId); continue; } - ProcessPendingSigShares(v, quorums, peerman, connman); + ProcessPendingSigShares(v, quorums); } - return sigSharesByNodes.size() >= nMaxBatchSize; + return more_work; } // It's ensured that no duplicates are passed to this method void CSigSharesManager::ProcessPendingSigShares( const std::vector& sigSharesToProcess, - const std::unordered_map, CQuorumCPtr, StaticSaltedHasher>& quorums, - PeerManager& peerman, const CConnman& connman) + const std::unordered_map, CQuorumCPtr, StaticSaltedHasher>& quorums) { cxxtimer::Timer t(true); for (const auto& sigShare : sigSharesToProcess) { auto quorumKey = std::make_pair(sigShare.getLlmqType(), sigShare.getQuorumHash()); - ProcessSigShare(peerman, sigShare, connman, quorums.at(quorumKey)); + ProcessSigShare(sigShare, quorums.at(quorumKey)); } t.stop(); @@ -709,18 +741,18 @@ void CSigSharesManager::ProcessPendingSigShares( } // sig shares are already verified when entering this method -void CSigSharesManager::ProcessSigShare(PeerManager& peerman, const CSigShare& sigShare, const CConnman& connman, - const CQuorumCPtr& quorum) +void CSigSharesManager::ProcessSigShare(const CSigShare& sigShare, const CQuorumCPtr& quorum) { - assert(m_mn_activeman); - auto llmqType = quorum->params.type; bool canTryRecovery = false; + const bool isAllMembersConnectedEnabled = IsAllMembersConnectedEnabled(llmqType, m_sporkman); + // prepare node set for direct-push in case this is our sig share - std::unordered_set quorumNodes; - if (!IsAllMembersConnectedEnabled(llmqType, m_sporkman) && sigShare.getQuorumMember() == quorum->GetMemberIndex(m_mn_activeman->GetProTxHash())) { - quorumNodes = connman.GetMasternodeQuorumNodes(sigShare.getLlmqType(), sigShare.getQuorumHash()); + std::vector quorumNodes; + if (!isAllMembersConnectedEnabled && + sigShare.getQuorumMember() == quorum->GetMemberIndex(m_mn_activeman.GetProTxHash())) { + quorumNodes = m_connman.GetMasternodeQuorumNodes(sigShare.getLlmqType(), sigShare.getQuorumHash()); } if (sigman.HasRecoveredSigForId(llmqType, sigShare.getId())) { @@ -733,7 +765,7 @@ void CSigSharesManager::ProcessSigShare(PeerManager& peerman, const CSigShare& s if (!sigShares.Add(sigShare.GetKey(), sigShare)) { return; } - if (!IsAllMembersConnectedEnabled(llmqType, m_sporkman)) { + if (!isAllMembersConnectedEnabled) { sigSharesQueuedToAnnounce.Add(sigShare.GetKey(), true); } @@ -757,29 +789,29 @@ void CSigSharesManager::ProcessSigShare(PeerManager& peerman, const CSigShare& s } if (canTryRecovery) { - TryRecoverSig(peerman, quorum, sigShare.getId(), sigShare.getMsgHash()); + TryRecoverSig(*quorum, sigShare.getId(), sigShare.getMsgHash()); } } -void CSigSharesManager::TryRecoverSig(PeerManager& peerman, const CQuorumCPtr& quorum, const uint256& id, - const uint256& msgHash) +void CSigSharesManager::TryRecoverSig(const CQuorum& quorum, const uint256& id, const uint256& msgHash) { - if (sigman.HasRecoveredSigForId(quorum->params.type, id)) { + if (sigman.HasRecoveredSigForId(quorum.params.type, id)) { return; } std::vector sigSharesForRecovery; std::vector idsForRecovery; + std::shared_ptr singleMemberRecoveredSig; { LOCK(cs); - auto signHash = SignHash(quorum->params.type, quorum->qc->quorumHash, id, msgHash).Get(); + auto signHash = SignHash(quorum.params.type, quorum.qc->quorumHash, id, msgHash).Get(); const auto* sigSharesForSignHash = sigShares.GetAllForSignHash(signHash); if (sigSharesForSignHash == nullptr) { return; } - if (quorum->params.size == 1) { + if (quorum.params.is_single_member()) { if (sigSharesForSignHash->empty()) { LogPrint(BCLog::LLMQ_SIGS, /* Continued */ "CSigSharesManager::%s -- impossible to recover single-node signature - no shares yet. id=%s, " @@ -792,26 +824,30 @@ void CSigSharesManager::TryRecoverSig(PeerManager& peerman, const CQuorumCPtr& q LogPrint(BCLog::LLMQ_SIGS, "CSigSharesManager::%s -- recover single-node signature. id=%s, msgHash=%s\n", __func__, id.ToString(), msgHash.ToString()); - auto rs = std::make_shared(quorum->params.type, quorum->qc->quorumHash, id, msgHash, + singleMemberRecoveredSig = std::make_shared(quorum.params.type, quorum.qc->quorumHash, id, msgHash, recoveredSig); - sigman.ProcessRecoveredSig(rs, peerman); - return; // end of single-quorum processing } - sigSharesForRecovery.reserve((size_t) quorum->params.threshold); - idsForRecovery.reserve((size_t) quorum->params.threshold); - for (auto it = sigSharesForSignHash->begin(); it != sigSharesForSignHash->end() && sigSharesForRecovery.size() < size_t(quorum->params.threshold); ++it) { + sigSharesForRecovery.reserve((size_t) quorum.params.threshold); + idsForRecovery.reserve((size_t) quorum.params.threshold); + for (auto it = sigSharesForSignHash->begin(); it != sigSharesForSignHash->end() && sigSharesForRecovery.size() < size_t(quorum.params.threshold); ++it) { const auto& sigShare = it->second; sigSharesForRecovery.emplace_back(sigShare.sigShare.Get()); - idsForRecovery.emplace_back(quorum->members[sigShare.getQuorumMember()]->proTxHash); + idsForRecovery.emplace_back(quorum.members[sigShare.getQuorumMember()]->proTxHash); } // check if we can recover the final signature - if (sigSharesForRecovery.size() < size_t(quorum->params.threshold)) { + if (sigSharesForRecovery.size() < size_t(quorum.params.threshold)) { return; } } + // Handle single-member quorum case after releasing the lock + if (singleMemberRecoveredSig) { + sigman.ProcessRecoveredSig(singleMemberRecoveredSig, m_peerman); + return; // end of single-quorum processing + } + // now recover it cxxtimer::Timer t(true); CBLSSignature recoveredSig; @@ -824,14 +860,14 @@ void CSigSharesManager::TryRecoverSig(PeerManager& peerman, const CQuorumCPtr& q LogPrint(BCLog::LLMQ_SIGS, "CSigSharesManager::%s -- recovered signature. id=%s, msgHash=%s, time=%d\n", __func__, id.ToString(), msgHash.ToString(), t.count()); - auto rs = std::make_shared(quorum->params.type, quorum->qc->quorumHash, id, msgHash, recoveredSig); + auto rs = std::make_shared(quorum.params.type, quorum.qc->quorumHash, id, msgHash, recoveredSig); // There should actually be no need to verify the self-recovered signatures as it should always succeed. Let's // however still verify it from time to time, so that we have a chance to catch bugs. We do only this sporadic // verification because this is unbatched and thus slow verification that happens here. if (((recoveredSigsCounter++) % 100) == 0) { auto signHash = rs->buildSignHash(); - bool valid = recoveredSig.VerifyInsecure(quorum->qc->quorumPublicKey, signHash.Get()); + bool valid = recoveredSig.VerifyInsecure(quorum.qc->quorumPublicKey, signHash.Get()); if (!valid) { // this should really not happen as we have verified all signature shares before LogPrintf("CSigSharesManager::%s -- own recovered signature is invalid. id=%s, msgHash=%s\n", __func__, @@ -840,16 +876,16 @@ void CSigSharesManager::TryRecoverSig(PeerManager& peerman, const CQuorumCPtr& q } } - sigman.ProcessRecoveredSig(rs, peerman); + sigman.ProcessRecoveredSig(rs, m_peerman); } -CDeterministicMNCPtr CSigSharesManager::SelectMemberForRecovery(const CQuorumCPtr& quorum, const uint256 &id, int attempt) +CDeterministicMNCPtr CSigSharesManager::SelectMemberForRecovery(const CQuorum& quorum, const uint256 &id, int attempt) { - assert(attempt < quorum->params.recoveryMembers); + assert(attempt < quorum.params.recoveryMembers); std::vector> v; - v.reserve(quorum->members.size()); - for (const auto& dmn : quorum->members) { + v.reserve(quorum.members.size()); + for (const auto& dmn : quorum.members) { auto h = ::SerializeHash(std::make_pair(dmn->proTxHash, id)); v.emplace_back(h, dmn); } @@ -858,6 +894,91 @@ CDeterministicMNCPtr CSigSharesManager::SelectMemberForRecovery(const CQuorumCPt return v[attempt % v.size()].second; } +bool CSigSharesManager::AsyncSignIfMember(Consensus::LLMQType llmqType, CSigningManager& sigman, const uint256& id, + const uint256& msgHash, const uint256& quorumHash, bool allowReSign, + bool allowDiffMsgHashSigning) +{ + AssertLockNotHeld(cs_pendingSigns); + + if (m_mn_activeman.GetProTxHash().IsNull()) return false; + + auto quorum = [&]() { + if (quorumHash.IsNull()) { + // This might end up giving different results on different members + // This might happen when we are on the brink of confirming a new quorum + // This gives a slight risk of not getting enough shares to recover a signature + // But at least it shouldn't be possible to get conflicting recovered signatures + // TODO fix this by re-signing when the next block arrives, but only when that block results in a change of + // the quorum list and no recovered signature has been created in the mean time + const auto& llmq_params_opt = Params().GetLLMQ(llmqType); + assert(llmq_params_opt.has_value()); + return SelectQuorumForSigning(llmq_params_opt.value(), m_chainstate.m_chain, qman, id); + } else { + return qman.GetQuorum(llmqType, quorumHash); + } + }(); + + if (!quorum) { + LogPrint(BCLog::LLMQ, "CSigningManager::%s -- failed to select quorum. id=%s, msgHash=%s\n", __func__, + id.ToString(), msgHash.ToString()); + return false; + } + + if (!quorum->IsValidMember(m_mn_activeman.GetProTxHash())) { + return false; + } + + { + auto& db = sigman.GetDb(); + bool hasVoted = db.HasVotedOnId(llmqType, id); + if (hasVoted) { + uint256 prevMsgHash; + db.GetVoteForId(llmqType, id, prevMsgHash); + if (msgHash != prevMsgHash) { + if (allowDiffMsgHashSigning) { + LogPrintf("%s -- already voted for id=%s and msgHash=%s. Signing for different " /* Continued */ + "msgHash=%s\n", + __func__, id.ToString(), prevMsgHash.ToString(), msgHash.ToString()); + hasVoted = false; + } else { + LogPrintf("%s -- already voted for id=%s and msgHash=%s. Not voting on " /* Continued */ + "conflicting msgHash=%s\n", + __func__, id.ToString(), prevMsgHash.ToString(), msgHash.ToString()); + return false; + } + } else if (allowReSign) { + LogPrint(BCLog::LLMQ, "%s -- already voted for id=%s and msgHash=%s. Resigning!\n", __func__, + id.ToString(), prevMsgHash.ToString()); + } else { + LogPrint(BCLog::LLMQ, "%s -- already voted for id=%s and msgHash=%s. Not voting again.\n", __func__, + id.ToString(), prevMsgHash.ToString()); + return false; + } + } + + if (db.HasRecoveredSigForId(llmqType, id)) { + // no need to sign it if we already have a recovered sig + return true; + } + if (!hasVoted) { + db.WriteVoteForId(llmqType, id, msgHash); + } + } + + if (allowReSign) { + // make us re-announce all known shares (other nodes might have run into a timeout) + ForceReAnnouncement(*quorum, llmqType, id, msgHash); + } + AsyncSign(std::move(quorum), id, msgHash); + + return true; +} + +void CSigSharesManager::NotifyRecoveredSig(const std::shared_ptr& sig) const +{ + m_peerman.RelayRecoveredSig(Assert(sig)->GetHash()); +} + void CSigSharesManager::CollectSigSharesToRequest(std::unordered_map>& sigSharesToRequest) { AssertLockHeld(cs); @@ -1033,7 +1154,7 @@ void CSigSharesManager::CollectSigSharesToSendConcentrated(std::unordered_map>& sigSharesToAnnounce) +void CSigSharesManager::CollectSigSharesToAnnounce(std::unordered_map>& sigSharesToAnnounce) { AssertLockHeld(cs); @@ -1059,8 +1179,8 @@ void CSigSharesManager::CollectSigSharesToAnnounce(const CConnman& connman, // TODO: remove NO_THREAD_SAFETY_ANALYSIS // using here template ForEach makes impossible to use lock annotation - sigSharesQueuedToAnnounce.ForEach([this, &connman, &quorumNodesMap, - &sigSharesToAnnounce](const SigShareKey& sigShareKey, bool) NO_THREAD_SAFETY_ANALYSIS { + sigSharesQueuedToAnnounce.ForEach([this, &quorumNodesMap, &sigSharesToAnnounce](const SigShareKey& sigShareKey, + bool) NO_THREAD_SAFETY_ANALYSIS { AssertLockHeld(cs); const auto& signHash = sigShareKey.first; auto quorumMember = sigShareKey.second; @@ -1073,7 +1193,7 @@ void CSigSharesManager::CollectSigSharesToAnnounce(const CConnman& connman, auto quorumKey = std::make_pair(sigShare->getLlmqType(), sigShare->getQuorumHash()); auto it = quorumNodesMap.find(quorumKey); if (it == quorumNodesMap.end()) { - auto nodeIds = connman.GetMasternodeQuorumNodes(quorumKey.first, quorumKey.second); + auto nodeIds = m_connman.GetMasternodeQuorumNodes(quorumKey.first, quorumKey.second); it = quorumNodesMap.emplace(std::piecewise_construct, std::forward_as_tuple(quorumKey), std::forward_as_tuple(nodeIds.begin(), nodeIds.end())).first; } @@ -1108,7 +1228,7 @@ void CSigSharesManager::CollectSigSharesToAnnounce(const CConnman& connman, sigSharesQueuedToAnnounce.Clear(); } -bool CSigSharesManager::SendMessages(CConnman& connman) +bool CSigSharesManager::SendMessages() { std::unordered_map> sigSharesToRequest; std::unordered_map> sigShareBatchesToSend; @@ -1137,12 +1257,12 @@ bool CSigSharesManager::SendMessages(CConnman& connman) return session->sendSessionId; }; - const CConnman::NodesSnapshot snap{connman, /* cond = */ CConnman::FullyConnectedOnly}; + const CConnman::NodesSnapshot snap{m_connman, /* cond = */ CConnman::FullyConnectedOnly}; { LOCK(cs); CollectSigSharesToRequest(sigSharesToRequest); CollectSigSharesToSend(sigShareBatchesToSend); - CollectSigSharesToAnnounce(connman, sigSharesToAnnounce); + CollectSigSharesToAnnounce(sigSharesToAnnounce); CollectSigSharesToSendConcentrated(sigSharesToSend, snap.Nodes()); for (auto& [nodeId, sigShareMap] : sigSharesToRequest) { @@ -1175,13 +1295,13 @@ bool CSigSharesManager::SendMessages(CConnman& connman) sigSesAnn.buildSignHash().ToString(), sigSesAnn.getSessionId(), pnode->GetId()); msgs.emplace_back(sigSesAnn); if (msgs.size() == MAX_MSGS_CNT_QSIGSESANN) { - connman.PushMessage(pnode, msgMaker.Make(NetMsgType::QSIGSESANN, msgs)); + m_connman.PushMessage(pnode, msgMaker.Make(NetMsgType::QSIGSESANN, msgs)); msgs.clear(); didSend = true; } } if (!msgs.empty()) { - connman.PushMessage(pnode, msgMaker.Make(NetMsgType::QSIGSESANN, msgs)); + m_connman.PushMessage(pnode, msgMaker.Make(NetMsgType::QSIGSESANN, msgs)); didSend = true; } } @@ -1194,13 +1314,13 @@ bool CSigSharesManager::SendMessages(CConnman& connman) signHash.ToString(), inv.ToString(), pnode->GetId()); msgs.emplace_back(inv); if (msgs.size() == MAX_MSGS_CNT_QGETSIGSHARES) { - connman.PushMessage(pnode, msgMaker.Make(NetMsgType::QGETSIGSHARES, msgs)); + m_connman.PushMessage(pnode, msgMaker.Make(NetMsgType::QGETSIGSHARES, msgs)); msgs.clear(); didSend = true; } } if (!msgs.empty()) { - connman.PushMessage(pnode, msgMaker.Make(NetMsgType::QGETSIGSHARES, msgs)); + m_connman.PushMessage(pnode, msgMaker.Make(NetMsgType::QGETSIGSHARES, msgs)); didSend = true; } } @@ -1213,7 +1333,7 @@ bool CSigSharesManager::SendMessages(CConnman& connman) LogPrint(BCLog::LLMQ_SIGS, "CSigSharesManager::SendMessages -- QBSIGSHARES signHash=%s, inv={%s}, node=%d\n", signHash.ToString(), inv.ToInvString(), pnode->GetId()); if (totalSigsCount + inv.sigShares.size() > MAX_MSGS_TOTAL_BATCHED_SIGS) { - connman.PushMessage(pnode, msgMaker.Make(NetMsgType::QBSIGSHARES, msgs)); + m_connman.PushMessage(pnode, msgMaker.Make(NetMsgType::QBSIGSHARES, msgs)); msgs.clear(); totalSigsCount = 0; didSend = true; @@ -1222,7 +1342,7 @@ bool CSigSharesManager::SendMessages(CConnman& connman) msgs.emplace_back(inv); } if (!msgs.empty()) { - connman.PushMessage(pnode, msgMaker.Make(NetMsgType::QBSIGSHARES, std::move(msgs))); + m_connman.PushMessage(pnode, msgMaker.Make(NetMsgType::QBSIGSHARES, std::move(msgs))); didSend = true; } } @@ -1235,13 +1355,13 @@ bool CSigSharesManager::SendMessages(CConnman& connman) signHash.ToString(), inv.ToString(), pnode->GetId()); msgs.emplace_back(inv); if (msgs.size() == MAX_MSGS_CNT_QSIGSHARESINV) { - connman.PushMessage(pnode, msgMaker.Make(NetMsgType::QSIGSHARESINV, msgs)); + m_connman.PushMessage(pnode, msgMaker.Make(NetMsgType::QSIGSHARESINV, msgs)); msgs.clear(); didSend = true; } } if (!msgs.empty()) { - connman.PushMessage(pnode, msgMaker.Make(NetMsgType::QSIGSHARESINV, msgs)); + m_connman.PushMessage(pnode, msgMaker.Make(NetMsgType::QSIGSHARESINV, msgs)); didSend = true; } } @@ -1254,13 +1374,13 @@ bool CSigSharesManager::SendMessages(CConnman& connman) sigShare.GetSignHash().ToString(), pnode->GetId()); msgs.emplace_back(std::move(sigShare)); if (msgs.size() == MAX_MSGS_SIG_SHARES) { - connman.PushMessage(pnode, msgMaker.Make(NetMsgType::QSIGSHARE, msgs)); + m_connman.PushMessage(pnode, msgMaker.Make(NetMsgType::QSIGSHARE, msgs)); msgs.clear(); didSend = true; } } if (!msgs.empty()) { - connman.PushMessage(pnode, msgMaker.Make(NetMsgType::QSIGSHARE, msgs)); + m_connman.PushMessage(pnode, msgMaker.Make(NetMsgType::QSIGSHARE, msgs)); didSend = true; } } @@ -1283,10 +1403,10 @@ CSigShare CSigSharesManager::RebuildSigShare(const CSigSharesNodeState::SessionI return sigShare; } -void CSigSharesManager::Cleanup(const CConnman& connman) +void CSigSharesManager::Cleanup() { - int64_t now = GetTime().count(); - if (now - lastCleanupTime < 5) { + constexpr auto CLEANUP_INTERVAL{5s}; + if (!cleanupThrottler.TryCleanup(CLEANUP_INTERVAL)) { return; } @@ -1349,6 +1469,7 @@ void CSigSharesManager::Cleanup(const CConnman& connman) // Remove sessions which timed out Uint256HashSet timeoutSessions; + int64_t now = GetTime().count(); for (const auto& [signHash, lastSeenTime] : timeSeenForSessions) { if (now - lastSeenTime >= SESSION_NEW_SHARES_TIMEOUT) { timeoutSessions.emplace(signHash); @@ -1397,9 +1518,7 @@ void CSigSharesManager::Cleanup(const CConnman& connman) nodeStatesToDelete.emplace(nodeId); } } - connman.ForEachNode([&nodeStatesToDelete](const CNode* pnode) { - nodeStatesToDelete.erase(pnode->GetId()); - }); + m_connman.ForEachNode([&nodeStatesToDelete](const CNode* pnode) { nodeStatesToDelete.erase(pnode->GetId()); }); // Now delete these node states LOCK(cs); @@ -1417,8 +1536,6 @@ void CSigSharesManager::Cleanup(const CConnman& connman) }); nodeStates.erase(nodeId); } - - lastCleanupTime = GetTime().count(); } void CSigSharesManager::RemoveSigSharesForSession(const uint256& signHash) @@ -1436,13 +1553,13 @@ void CSigSharesManager::RemoveSigSharesForSession(const uint256& signHash) timeSeenForSessions.erase(signHash); } -void CSigSharesManager::RemoveBannedNodeStates(PeerManager& peerman) +void CSigSharesManager::RemoveBannedNodeStates() { // Called regularly to cleanup local node states for banned nodes LOCK(cs); for (auto it = nodeStates.begin(); it != nodeStates.end();) { - if (peerman.IsBanned(it->first)) { + if (m_peerman.IsBanned(it->first)) { // re-request sigshares from other nodes // TODO: remove NO_THREAD_SAFETY_ANALYSIS // using here template ForEach makes impossible to use lock annotation @@ -1457,13 +1574,13 @@ void CSigSharesManager::RemoveBannedNodeStates(PeerManager& peerman) } } -void CSigSharesManager::BanNode(NodeId nodeId, PeerManager& peerman) +void CSigSharesManager::BanNode(NodeId nodeId) { if (nodeId == -1) { return; } - peerman.Misbehaving(nodeId, 100); + m_peerman.Misbehaving(nodeId, 100); LOCK(cs); auto it = nodeStates.find(nodeId); @@ -1483,22 +1600,22 @@ void CSigSharesManager::BanNode(NodeId nodeId, PeerManager& peerman) nodeState.banned = true; } -void CSigSharesManager::WorkThreadMain(CConnman& connman, PeerManager& peerman) +void CSigSharesManager::WorkThreadMain() { int64_t lastSendTime = 0; while (!workInterrupt) { - RemoveBannedNodeStates(peerman); + RemoveBannedNodeStates(); - bool fMoreWork = ProcessPendingSigShares(peerman, connman); - SignPendingSigShares(connman, peerman); + bool fMoreWork = ProcessPendingSigShares(); + SignPendingSigShares(); if (TicksSinceEpoch(SystemClock::now()) - lastSendTime > 100) { - SendMessages(connman); + SendMessages(); lastSendTime = TicksSinceEpoch(SystemClock::now()); } - Cleanup(connman); + Cleanup(); // TODO Wakeup when pending signing is needed? if (!fMoreWork && !workInterrupt.sleep_for(std::chrono::milliseconds(100))) { @@ -1507,28 +1624,28 @@ void CSigSharesManager::WorkThreadMain(CConnman& connman, PeerManager& peerman) } } -void CSigSharesManager::AsyncSign(const CQuorumCPtr& quorum, const uint256& id, const uint256& msgHash) +void CSigSharesManager::AsyncSign(CQuorumCPtr quorum, const uint256& id, const uint256& msgHash) { LOCK(cs_pendingSigns); - pendingSigns.emplace_back(quorum, id, msgHash); + pendingSigns.emplace_back(std::move(quorum), id, msgHash); } -void CSigSharesManager::SignPendingSigShares(const CConnman& connman, PeerManager& peerman) +void CSigSharesManager::SignPendingSigShares() { std::vector v; WITH_LOCK(cs_pendingSigns, v.swap(pendingSigns)); for (const auto& [pQuorum, id, msgHash] : v) { - auto opt_sigShare = CreateSigShare(pQuorum, id, msgHash); + auto opt_sigShare = CreateSigShare(*pQuorum, id, msgHash); if (opt_sigShare.has_value() && opt_sigShare->sigShare.Get().IsValid()) { - auto sigShare = *opt_sigShare; - ProcessSigShare(peerman, sigShare, connman, pQuorum); + auto& sigShare = *opt_sigShare; + ProcessSigShare(sigShare, pQuorum); if (IsAllMembersConnectedEnabled(pQuorum->params.type, m_sporkman)) { LOCK(cs); auto& session = signedSessions[sigShare.GetSignHash()]; - session.sigShare = sigShare; + session.sigShare = std::move(sigShare); session.quorum = pQuorum; session.nextAttemptTime = 0; session.attempt = 0; @@ -1537,64 +1654,72 @@ void CSigSharesManager::SignPendingSigShares(const CConnman& connman, PeerManage } } -std::optional CSigSharesManager::CreateSigShare(const CQuorumCPtr& quorum, const uint256& id, const uint256& msgHash) const +std::optional CSigSharesManager::CreateSigShareForSingleMember(const CQuorum& quorum, const uint256& id, const uint256& msgHash) const { - assert(m_mn_activeman); - cxxtimer::Timer t(true); - auto activeMasterNodeProTxHash = m_mn_activeman->GetProTxHash(); + auto activeMasterNodeProTxHash = m_mn_activeman.GetProTxHash(); - if (!quorum->IsValidMember(activeMasterNodeProTxHash)) { + int memberIdx = quorum.GetMemberIndex(activeMasterNodeProTxHash); + if (memberIdx == -1) { + // this should really not happen (IsValidMember gave true) return std::nullopt; } - if (quorum->params.size == 1) { - int memberIdx = quorum->GetMemberIndex(activeMasterNodeProTxHash); - if (memberIdx == -1) { - // this should really not happen (IsValidMember gave true) - return std::nullopt; - } + CSigShare sigShare(quorum.params.type, quorum.qc->quorumHash, id, msgHash, uint16_t(memberIdx), {}); + uint256 signHash = sigShare.buildSignHash().Get(); - CSigShare sigShare(quorum->params.type, quorum->qc->quorumHash, id, msgHash, uint16_t(memberIdx), {}); - uint256 signHash = sigShare.buildSignHash().Get(); + // TODO: This one should be SIGN by QUORUM key, not by OPERATOR key + // see TODO in CDKGSession::FinalizeSingleCommitment for details + auto bls_scheme = bls::bls_legacy_scheme.load(); + sigShare.sigShare.Set(m_mn_activeman.Sign(signHash, bls_scheme), bls_scheme); - // TODO: This one should be SIGN by QUORUM key, not by OPERATOR key - // see TODO in CDKGSession::FinalizeSingleCommitment for details - sigShare.sigShare.Set(m_mn_activeman->Sign(signHash, bls::bls_legacy_scheme.load()), bls::bls_legacy_scheme.load()); + if (!sigShare.sigShare.Get().IsValid()) { + LogPrintf("CSigSharesManager::%s -- failed to sign sigShare. signHash=%s, id=%s, msgHash=%s, time=%s\n", + __func__, signHash.ToString(), sigShare.getId().ToString(), sigShare.getMsgHash().ToString(), + t.count()); + return std::nullopt; + } - if (!sigShare.sigShare.Get().IsValid()) { - LogPrintf("CSigSharesManager::%s -- failed to sign sigShare. signHash=%s, id=%s, msgHash=%s, time=%s\n", - __func__, signHash.ToString(), sigShare.getId().ToString(), sigShare.getMsgHash().ToString(), - t.count()); - return std::nullopt; - } + sigShare.UpdateKey(); - sigShare.UpdateKey(); + LogPrint(BCLog::LLMQ_SIGS, /* Continued */ + "CSigSharesManager::%s -- created sigShare. signHash=%s, id=%s, msgHash=%s, llmqType=%d, quorum=%s, " + "time=%s\n", + __func__, signHash.ToString(), sigShare.getId().ToString(), sigShare.getMsgHash().ToString(), + ToUnderlying(quorum.params.type), quorum.qc->quorumHash.ToString(), t.count()); - LogPrint(BCLog::LLMQ_SIGS, /* Continued */ - "CSigSharesManager::%s -- created sigShare. signHash=%s, id=%s, msgHash=%s, llmqType=%d, quorum=%s, " - "time=%s\n", - __func__, signHash.ToString(), sigShare.getId().ToString(), sigShare.getMsgHash().ToString(), - ToUnderlying(quorum->params.type), quorum->qc->quorumHash.ToString(), t.count()); + return sigShare; +} + +std::optional CSigSharesManager::CreateSigShare(const CQuorum& quorum, const uint256& id, const uint256& msgHash) const +{ + auto activeMasterNodeProTxHash = m_mn_activeman.GetProTxHash(); + + if (!quorum.IsValidMember(activeMasterNodeProTxHash)) { + return std::nullopt; + } - return sigShare; + if (quorum.params.is_single_member()) { + return CreateSigShareForSingleMember(quorum, id, msgHash); } - const CBLSSecretKey& skShare = quorum->GetSkShare(); + cxxtimer::Timer t(true); + const CBLSSecretKey& skShare = quorum.GetSkShare(); if (!skShare.IsValid()) { - LogPrint(BCLog::LLMQ_SIGS, "CSigSharesManager::%s -- we don't have our skShare for quorum %s\n", __func__, quorum->qc->quorumHash.ToString()); + LogPrint(BCLog::LLMQ_SIGS, "CSigSharesManager::%s -- we don't have our skShare for quorum %s\n", __func__, quorum.qc->quorumHash.ToString()); return std::nullopt; } - int memberIdx = quorum->GetMemberIndex(activeMasterNodeProTxHash); + int memberIdx = quorum.GetMemberIndex(activeMasterNodeProTxHash); if (memberIdx == -1) { // this should really not happen (IsValidMember gave true) return std::nullopt; } - CSigShare sigShare(quorum->params.type, quorum->qc->quorumHash, id, msgHash, uint16_t(memberIdx), {}); + CSigShare sigShare(quorum.params.type, quorum.qc->quorumHash, id, msgHash, uint16_t(memberIdx), {}); uint256 signHash = sigShare.buildSignHash().Get(); - sigShare.sigShare.Set(skShare.Sign(signHash, bls::bls_legacy_scheme.load()), bls::bls_legacy_scheme.load()); + auto bls_scheme = bls::bls_legacy_scheme.load(); + sigShare.sigShare.Set(skShare.Sign(signHash, bls_scheme), bls_scheme); if (!sigShare.sigShare.Get().IsValid()) { LogPrintf("CSigSharesManager::%s -- failed to sign sigShare. signHash=%s, id=%s, msgHash=%s, time=%s\n", __func__, signHash.ToString(), sigShare.getId().ToString(), sigShare.getMsgHash().ToString(), t.count()); @@ -1604,20 +1729,20 @@ std::optional CSigSharesManager::CreateSigShare(const CQuorumCPtr& qu sigShare.UpdateKey(); LogPrint(BCLog::LLMQ_SIGS, "CSigSharesManager::%s -- created sigShare. signHash=%s, id=%s, msgHash=%s, llmqType=%d, quorum=%s, time=%s\n", __func__, - signHash.ToString(), sigShare.getId().ToString(), sigShare.getMsgHash().ToString(), ToUnderlying(quorum->params.type), quorum->qc->quorumHash.ToString(), t.count()); + signHash.ToString(), sigShare.getId().ToString(), sigShare.getMsgHash().ToString(), ToUnderlying(quorum.params.type), quorum.qc->quorumHash.ToString(), t.count()); return sigShare; } // causes all known sigShares to be re-announced -void CSigSharesManager::ForceReAnnouncement(const CQuorumCPtr& quorum, Consensus::LLMQType llmqType, const uint256& id, const uint256& msgHash) +void CSigSharesManager::ForceReAnnouncement(const CQuorum& quorum, Consensus::LLMQType llmqType, const uint256& id, const uint256& msgHash) { if (IsAllMembersConnectedEnabled(llmqType, m_sporkman)) { return; } LOCK(cs); - auto signHash = SignHash(llmqType, quorum->qc->quorumHash, id, msgHash).Get(); + auto signHash = SignHash(llmqType, quorum.qc->quorumHash, id, msgHash).Get(); if (const auto *const sigs = sigShares.GetAllForSignHash(signHash)) { for (const auto& [quorumMemberIndex, _] : *sigs) { // re-announce every sigshare to every node @@ -1638,9 +1763,9 @@ void CSigSharesManager::ForceReAnnouncement(const CQuorumCPtr& quorum, Consensus MessageProcessingResult CSigSharesManager::HandleNewRecoveredSig(const llmq::CRecoveredSig& recoveredSig) { + auto signHash = recoveredSig.buildSignHash().Get(); LOCK(cs); - RemoveSigSharesForSession(recoveredSig.buildSignHash().Get()); + RemoveSigSharesForSession(signHash); return {}; } - } // namespace llmq diff --git a/src/llmq/signing_shares.h b/src/llmq/signing_shares.h index b47a41c16a1d..24865fec98a8 100644 --- a/src/llmq/signing_shares.h +++ b/src/llmq/signing_shares.h @@ -5,17 +5,18 @@ #ifndef BITCOIN_LLMQ_SIGNING_SHARES_H #define BITCOIN_LLMQ_SIGNING_SHARES_H -#include - #include #include +#include +#include #include #include #include #include -#include #include +#include +#include #include #include @@ -27,6 +28,7 @@ #include #include +class CActiveMasternodeManager; class CNode; class CConnman; class CDeterministicMN; @@ -375,7 +377,7 @@ class CSigSharesManager : public CRecoveredSigsListener static constexpr int64_t MAX_SEND_FOR_RECOVERY_TIMEOUT{10000}; static constexpr size_t MAX_MSGS_SIG_SHARES{32}; - RecursiveMutex cs; + Mutex cs; std::thread workThread; CThreadInterrupt workInterrupt; @@ -403,51 +405,62 @@ class CSigSharesManager : public CRecoveredSigsListener FastRandomContext rnd GUARDED_BY(cs); + CConnman& m_connman; + CChainState& m_chainstate; CSigningManager& sigman; - const CActiveMasternodeManager* const m_mn_activeman; + PeerManager& m_peerman; + const CActiveMasternodeManager& m_mn_activeman; const CQuorumManager& qman; const CSporkManager& m_sporkman; - int64_t lastCleanupTime{0}; + CleanupThrottler cleanupThrottler; std::atomic recoveredSigsCounter{0}; public: - explicit CSigSharesManager(CSigningManager& _sigman, const CActiveMasternodeManager* const mn_activeman, - const CQuorumManager& _qman, const CSporkManager& sporkman) : - sigman(_sigman), - m_mn_activeman(mn_activeman), - qman(_qman), - m_sporkman(sporkman) - { - workInterrupt.reset(); - }; CSigSharesManager() = delete; - ~CSigSharesManager() override = default; + CSigSharesManager(const CSigSharesManager&) = delete; + CSigSharesManager& operator=(const CSigSharesManager&) = delete; + explicit CSigSharesManager(CConnman& connman, CChainState& chainstate, CSigningManager& _sigman, + PeerManager& peerman, const CActiveMasternodeManager& mn_activeman, + const CQuorumManager& _qman, const CSporkManager& sporkman); + ~CSigSharesManager() override; + + void StartWorkerThread() EXCLUSIVE_LOCKS_REQUIRED(!cs); + void StopWorkerThread() EXCLUSIVE_LOCKS_REQUIRED(!cs); + void RegisterAsRecoveredSigsListener() EXCLUSIVE_LOCKS_REQUIRED(!cs); + void UnregisterAsRecoveredSigsListener() EXCLUSIVE_LOCKS_REQUIRED(!cs); + void InterruptWorkerThread() EXCLUSIVE_LOCKS_REQUIRED(!cs); - void StartWorkerThread(CConnman& connman, PeerManager& peerman); - void StopWorkerThread(); - void RegisterAsRecoveredSigsListener(); - void UnregisterAsRecoveredSigsListener(); - void InterruptWorkerThread(); + void ProcessMessage(const CNode& pnode, const std::string& msg_type, CDataStream& vRecv) EXCLUSIVE_LOCKS_REQUIRED(!cs); - void ProcessMessage(const CNode& pnode, PeerManager& peerman, const CSporkManager& sporkman, - const std::string& msg_type, CDataStream& vRecv); + void AsyncSign(CQuorumCPtr quorum, const uint256& id, const uint256& msgHash) + EXCLUSIVE_LOCKS_REQUIRED(!cs_pendingSigns, !cs); + std::optional CreateSigShare(const CQuorum& quorum, const uint256& id, const uint256& msgHash) const + EXCLUSIVE_LOCKS_REQUIRED(!cs); + void ForceReAnnouncement(const CQuorum& quorum, Consensus::LLMQType llmqType, const uint256& id, + const uint256& msgHash) EXCLUSIVE_LOCKS_REQUIRED(!cs); - void AsyncSign(const CQuorumCPtr& quorum, const uint256& id, const uint256& msgHash); - std::optional CreateSigShare(const CQuorumCPtr& quorum, const uint256& id, const uint256& msgHash) const; - void ForceReAnnouncement(const CQuorumCPtr& quorum, Consensus::LLMQType llmqType, const uint256& id, const uint256& msgHash); + [[nodiscard]] MessageProcessingResult HandleNewRecoveredSig(const CRecoveredSig& recoveredSig) override + EXCLUSIVE_LOCKS_REQUIRED(!cs); - [[nodiscard]] MessageProcessingResult HandleNewRecoveredSig(const CRecoveredSig& recoveredSig) override; + static CDeterministicMNCPtr SelectMemberForRecovery(const CQuorum& quorum, const uint256& id, int attempt); - static CDeterministicMNCPtr SelectMemberForRecovery(const CQuorumCPtr& quorum, const uint256& id, int attempt); + bool AsyncSignIfMember(Consensus::LLMQType llmqType, CSigningManager& sigman, const uint256& id, + const uint256& msgHash, const uint256& quorumHash = uint256(), bool allowReSign = false, + bool allowDiffMsgHashSigning = false) EXCLUSIVE_LOCKS_REQUIRED(!cs_pendingSigns, !cs); + + void NotifyRecoveredSig(const std::shared_ptr& sig) const EXCLUSIVE_LOCKS_REQUIRED(!cs); private: + std::optional CreateSigShareForSingleMember(const CQuorum& quorum, const uint256& id, const uint256& msgHash) const; + // all of these return false when the currently processed message should be aborted (as each message actually contains multiple messages) - bool ProcessMessageSigSesAnn(const CNode& pfrom, const CSigSesAnn& ann); - bool ProcessMessageSigSharesInv(const CNode& pfrom, const CSigSharesInv& inv); - bool ProcessMessageGetSigShares(const CNode& pfrom, const CSigSharesInv& inv); - bool ProcessMessageBatchedSigShares(const CNode& pfrom, const CBatchedSigShares& batchedSigShares); - void ProcessMessageSigShare(NodeId fromId, PeerManager& peerman, const CSigShare& sigShare); + bool ProcessMessageSigSesAnn(const CNode& pfrom, const CSigSesAnn& ann) EXCLUSIVE_LOCKS_REQUIRED(!cs); + bool ProcessMessageSigSharesInv(const CNode& pfrom, const CSigSharesInv& inv) EXCLUSIVE_LOCKS_REQUIRED(!cs); + bool ProcessMessageGetSigShares(const CNode& pfrom, const CSigSharesInv& inv) EXCLUSIVE_LOCKS_REQUIRED(!cs); + bool ProcessMessageBatchedSigShares(const CNode& pfrom, const CBatchedSigShares& batchedSigShares) + EXCLUSIVE_LOCKS_REQUIRED(!cs); + void ProcessMessageSigShare(NodeId fromId, const CSigShare& sigShare) EXCLUSIVE_LOCKS_REQUIRED(!cs); static bool VerifySigSharesInv(Consensus::LLMQType llmqType, const CSigSharesInv& inv); static bool PreVerifyBatchedSigShares(const CActiveMasternodeManager& mn_activeman, const CQuorumManager& quorum_manager, @@ -455,38 +468,38 @@ class CSigSharesManager : public CRecoveredSigsListener bool CollectPendingSigSharesToVerify( size_t maxUniqueSessions, std::unordered_map>& retSigShares, - std::unordered_map, CQuorumCPtr, StaticSaltedHasher>& retQuorums); - bool ProcessPendingSigShares(PeerManager& peerman, const CConnman& connman); + std::unordered_map, CQuorumCPtr, StaticSaltedHasher>& retQuorums) + EXCLUSIVE_LOCKS_REQUIRED(!cs); + bool ProcessPendingSigShares() EXCLUSIVE_LOCKS_REQUIRED(!cs); void ProcessPendingSigShares( const std::vector& sigSharesToProcess, - const std::unordered_map, CQuorumCPtr, StaticSaltedHasher>& quorums, - PeerManager& peerman, const CConnman& connman); + const std::unordered_map, CQuorumCPtr, StaticSaltedHasher>& quorums) + EXCLUSIVE_LOCKS_REQUIRED(!cs); - void ProcessSigShare(PeerManager& peerman, const CSigShare& sigShare, const CConnman& connman, - const CQuorumCPtr& quorum); - void TryRecoverSig(PeerManager& peerman, const CQuorumCPtr& quorum, const uint256& id, const uint256& msgHash); + void ProcessSigShare(const CSigShare& sigShare, const CQuorumCPtr& quorum) EXCLUSIVE_LOCKS_REQUIRED(!cs); + void TryRecoverSig(const CQuorum& quorum, const uint256& id, const uint256& msgHash) EXCLUSIVE_LOCKS_REQUIRED(!cs); - bool GetSessionInfoByRecvId(NodeId nodeId, uint32_t sessionId, CSigSharesNodeState::SessionInfo& retInfo); + bool GetSessionInfoByRecvId(NodeId nodeId, uint32_t sessionId, CSigSharesNodeState::SessionInfo& retInfo) + EXCLUSIVE_LOCKS_REQUIRED(!cs); static CSigShare RebuildSigShare(const CSigSharesNodeState::SessionInfo& session, const std::pair& in); - void Cleanup(const CConnman& connman); + void Cleanup() EXCLUSIVE_LOCKS_REQUIRED(!cs); void RemoveSigSharesForSession(const uint256& signHash) EXCLUSIVE_LOCKS_REQUIRED(cs); - void RemoveBannedNodeStates(PeerManager& peerman); + void RemoveBannedNodeStates() EXCLUSIVE_LOCKS_REQUIRED(!cs); - void BanNode(NodeId nodeId, PeerManager& peerman); + void BanNode(NodeId nodeId) EXCLUSIVE_LOCKS_REQUIRED(!cs); - bool SendMessages(CConnman& connman); + bool SendMessages() EXCLUSIVE_LOCKS_REQUIRED(!cs); void CollectSigSharesToRequest(std::unordered_map>& sigSharesToRequest) EXCLUSIVE_LOCKS_REQUIRED(cs); void CollectSigSharesToSend(std::unordered_map>& sigSharesToSend) EXCLUSIVE_LOCKS_REQUIRED(cs); void CollectSigSharesToSendConcentrated(std::unordered_map>& sigSharesToSend, const std::vector& vNodes) EXCLUSIVE_LOCKS_REQUIRED(cs); - void CollectSigSharesToAnnounce(const CConnman& connman, - std::unordered_map>& sigSharesToAnnounce) + void CollectSigSharesToAnnounce(std::unordered_map>& sigSharesToAnnounce) EXCLUSIVE_LOCKS_REQUIRED(cs); - void SignPendingSigShares(const CConnman& connman, PeerManager& peerman); - void WorkThreadMain(CConnman& connman, PeerManager& peerman); + void SignPendingSigShares() EXCLUSIVE_LOCKS_REQUIRED(!cs_pendingSigns, !cs); + void WorkThreadMain() EXCLUSIVE_LOCKS_REQUIRED(!cs_pendingSigns, !cs); }; } // namespace llmq diff --git a/src/llmq/snapshot.cpp b/src/llmq/snapshot.cpp index 3544177dc575..cf744f6c781a 100644 --- a/src/llmq/snapshot.cpp +++ b/src/llmq/snapshot.cpp @@ -17,67 +17,6 @@ namespace llmq { static const std::string DB_QUORUM_SNAPSHOT = "llmq_S"; -UniValue CQuorumSnapshot::ToJson() const -{ - UniValue obj(UniValue::VOBJ); - UniValue activeQ(UniValue::VARR); - for (const bool h : activeQuorumMembers) { - // cppcheck-suppress useStlAlgorithm - activeQ.push_back(h); - } - obj.pushKV("activeQuorumMembers", activeQ); - obj.pushKV("mnSkipListMode", mnSkipListMode); - UniValue skipList(UniValue::VARR); - for (const auto& h : mnSkipList) { - // cppcheck-suppress useStlAlgorithm - skipList.push_back(h); - } - obj.pushKV("mnSkipList", skipList); - return obj; -} - -UniValue CQuorumRotationInfo::ToJson() const -{ - UniValue obj(UniValue::VOBJ); - obj.pushKV("extraShare", extraShare); - - obj.pushKV("quorumSnapshotAtHMinusC", quorumSnapshotAtHMinusC.ToJson()); - obj.pushKV("quorumSnapshotAtHMinus2C", quorumSnapshotAtHMinus2C.ToJson()); - obj.pushKV("quorumSnapshotAtHMinus3C", quorumSnapshotAtHMinus3C.ToJson()); - - if (extraShare) { - obj.pushKV("quorumSnapshotAtHMinus4C", quorumSnapshotAtHMinus4C.ToJson()); - } - - obj.pushKV("mnListDiffTip", mnListDiffTip.ToJson()); - obj.pushKV("mnListDiffH", mnListDiffH.ToJson()); - obj.pushKV("mnListDiffAtHMinusC", mnListDiffAtHMinusC.ToJson()); - obj.pushKV("mnListDiffAtHMinus2C", mnListDiffAtHMinus2C.ToJson()); - obj.pushKV("mnListDiffAtHMinus3C", mnListDiffAtHMinus3C.ToJson()); - - if (extraShare) { - obj.pushKV("mnListDiffAtHMinus4C", mnListDiffAtHMinus4C.ToJson()); - } - UniValue hqclists(UniValue::VARR); - for (const auto& qc : lastCommitmentPerIndex) { - hqclists.push_back(qc.ToJson()); - } - obj.pushKV("lastCommitmentPerIndex", hqclists); - - UniValue snapshotlist(UniValue::VARR); - for (const auto& snap : quorumSnapshotList) { - snapshotlist.push_back(snap.ToJson()); - } - obj.pushKV("quorumSnapshotList", snapshotlist); - - UniValue mnlistdifflist(UniValue::VARR); - for (const auto& mnlist : mnListDiffList) { - mnlistdifflist.push_back(mnlist.ToJson()); - } - obj.pushKV("mnListDiffList", mnlistdifflist); - return obj; -} - bool BuildQuorumRotationInfo(CDeterministicMNManager& dmnman, CQuorumSnapshotManager& qsnapman, const ChainstateManager& chainman, const CQuorumManager& qman, const CQuorumBlockProcessor& qblockman, const CGetQuorumRotationInfo& request, @@ -270,17 +209,16 @@ bool BuildQuorumRotationInfo(CDeterministicMNManager& dmnman, CQuorumSnapshotMan response.quorumSnapshotAtHMinus4C = std::move(snapshotHMinus4C.value()); } - CSimplifiedMNListDiff mn4c; if (!BuildSimplifiedMNListDiff(dmnman, chainman, qblockman, qman, GetLastBaseBlockHash(baseBlockIndexes, pWorkBlockHMinus4CIndex, use_legacy_construction), - pWorkBlockHMinus4CIndex->GetBlockHash(), mn4c, errorRet)) { + pWorkBlockHMinus4CIndex->GetBlockHash(), response.mnListDiffAtHMinus4C, errorRet)) { + response.mnListDiffAtHMinus4C = {}; return false; } if (!use_legacy_construction) { baseBlockIndexes.push_back(pWorkBlockHMinus4CIndex); } - response.mnListDiffAtHMinus4C = std::move(mn4c); } else { response.extraShare = false; } @@ -397,6 +335,14 @@ uint256 GetLastBaseBlockHash(Span baseBlockIndexes, const CB return hash; } +CQuorumSnapshotManager::CQuorumSnapshotManager(CEvoDB& evoDb) : + m_evoDb{evoDb}, + quorumSnapshotCache{32} +{ +} + +CQuorumSnapshotManager::~CQuorumSnapshotManager() = default; + std::optional CQuorumSnapshotManager::GetSnapshotForBlock(const Consensus::LLMQType llmqType, const CBlockIndex* pindex) { CQuorumSnapshot snapshot = {}; diff --git a/src/llmq/snapshot.h b/src/llmq/snapshot.h index 2d161ed00faf..7d64404c3610 100644 --- a/src/llmq/snapshot.h +++ b/src/llmq/snapshot.h @@ -19,6 +19,8 @@ class CBlockIndex; class CEvoDB; +struct RPCResult; + class UniValue; namespace llmq { @@ -82,6 +84,7 @@ class CQuorumSnapshot } } + [[nodiscard]] static RPCResult GetJsonHelp(const std::string& key, bool optional); [[nodiscard]] UniValue ToJson() const; }; @@ -198,6 +201,7 @@ class CQuorumRotationInfo CQuorumRotationInfo() = default; CQuorumRotationInfo(const CQuorumRotationInfo& dmn) {} + [[nodiscard]] static RPCResult GetJsonHelp(const std::string& key, bool optional); [[nodiscard]] UniValue ToJson() const; }; @@ -219,8 +223,11 @@ class CQuorumSnapshotManager Uint256LruHashMap quorumSnapshotCache GUARDED_BY(snapshotCacheCs); public: - explicit CQuorumSnapshotManager(CEvoDB& evoDb) : - m_evoDb(evoDb), quorumSnapshotCache(32) {} + CQuorumSnapshotManager() = delete; + CQuorumSnapshotManager(const CQuorumSnapshotManager&) = delete; + CQuorumSnapshotManager& operator=(const CQuorumSnapshotManager&) = delete; + explicit CQuorumSnapshotManager(CEvoDB& evoDb); + ~CQuorumSnapshotManager(); std::optional GetSnapshotForBlock(Consensus::LLMQType llmqType, const CBlockIndex* pindex); void StoreSnapshotForBlock(Consensus::LLMQType llmqType, const CBlockIndex* pindex, const CQuorumSnapshot& snapshot); diff --git a/src/llmq/utils.cpp b/src/llmq/utils.cpp index 09d2d4fddc7b..099f5f74c9b9 100644 --- a/src/llmq/utils.cpp +++ b/src/llmq/utils.cpp @@ -912,7 +912,7 @@ void AddQuorumProbeConnections(const Consensus::LLMQParams& llmqParams, CConnman if (dmn->proTxHash == myProTxHash) { continue; } - auto lastOutbound = mn_metaman.GetMetaInfo(dmn->proTxHash)->GetLastOutboundSuccess(); + auto lastOutbound = mn_metaman.GetLastOutboundSuccess(dmn->proTxHash); if (curTime - lastOutbound < 10 * 60) { // avoid re-probing nodes too often continue; diff --git a/src/logging.cpp b/src/logging.cpp index 1655206166fa..d59d1a86aa9b 100644 --- a/src/logging.cpp +++ b/src/logging.cpp @@ -395,7 +395,7 @@ std::string BCLog::Logger::LogTimestampStr(const std::string& str) if (m_started_new_line) { int64_t nTimeMicros = GetTimeMicros(); strStamped = FormatISO8601DateTime(nTimeMicros/1000000); - if (m_log_time_micros) { + if (m_log_time_micros && !strStamped.empty()) { strStamped.pop_back(); strStamped += strprintf(".%06dZ", nTimeMicros%1000000); } @@ -462,8 +462,9 @@ void BCLog::Logger::LogPrintStr(const std::string& str, const std::string& loggi } if (m_log_threadnames && m_started_new_line) { + const auto& threadname = util::ThreadGetInternalName(); // 16 chars total, "dash-" is 5 of them and another 1 is a NUL terminator - str_prefixed.insert(0, "[" + strprintf("%10s", util::ThreadGetInternalName()) + "] "); + str_prefixed.insert(0, "[" + strprintf("%10s", (threadname.empty() ? "unknown" : threadname)) + "] "); } str_prefixed = LogTimestampStr(str_prefixed); diff --git a/src/mapport.cpp b/src/mapport.cpp index 85d65e39c5c5..d45ff9b3bd4b 100644 --- a/src/mapport.cpp +++ b/src/mapport.cpp @@ -26,9 +26,9 @@ #include #include #include -// The minimum supported miniUPnPc API version is set to 10. This keeps compatibility -// with Ubuntu 16.04 LTS and Debian 8 libminiupnpc-dev packages. -static_assert(MINIUPNPC_API_VERSION >= 10, "miniUPnPc API version >= 10 assumed"); +// The minimum supported miniUPnPc API version is set to 17. This excludes +// versions with known vulnerabilities. +static_assert(MINIUPNPC_API_VERSION >= 17, "miniUPnPc API version >= 17 assumed"); #endif // USE_UPNP #include @@ -158,11 +158,7 @@ static bool ProcessUpnp() char lanaddr[64]; int error = 0; -#if MINIUPNPC_API_VERSION < 14 - devlist = upnpDiscover(2000, multicastif, minissdpdpath, 0, 0, &error); -#else devlist = upnpDiscover(2000, multicastif, minissdpdpath, 0, 0, 2, &error); -#endif struct UPNPUrls urls; struct IGDdatas data; diff --git a/src/masternode/active/context.cpp b/src/masternode/active/context.cpp index 3fdfa75bad39..c737d8a03d0b 100644 --- a/src/masternode/active/context.cpp +++ b/src/masternode/active/context.cpp @@ -7,26 +7,34 @@ #include #include #include +#include +#include #include #include #include +#include #include +#include #include ActiveContext::ActiveContext(ChainstateManager& chainman, CConnman& connman, CDeterministicMNManager& dmnman, - CDSTXManager& dstxman, CMasternodeMetaMan& mn_metaman, CMNHFManager& mnhfman, - LLMQContext& llmq_ctx, CSporkManager& sporkman, CTxMemPool& mempool, PeerManager& peerman, - const CActiveMasternodeManager& mn_activeman, const CMasternodeSync& mn_sync) : + CDSTXManager& dstxman, CGovernanceManager& govman, CMasternodeMetaMan& mn_metaman, + CMNHFManager& mnhfman, CSporkManager& sporkman, CTxMemPool& mempool, LLMQContext& llmq_ctx, + PeerManager& peerman, const CActiveMasternodeManager& mn_activeman, + const CMasternodeSync& mn_sync) : m_llmq_ctx{llmq_ctx}, - cl_signer{std::make_unique(chainman.ActiveChainstate(), *llmq_ctx.clhandler, - *llmq_ctx.sigman, *llmq_ctx.shareman, sporkman, mn_sync)}, - is_signer{std::make_unique(chainman.ActiveChainstate(), *llmq_ctx.clhandler, - *llmq_ctx.isman, *llmq_ctx.sigman, *llmq_ctx.shareman, - *llmq_ctx.qman, sporkman, mempool, mn_sync)}, cj_server{std::make_unique(chainman, connman, dmnman, dstxman, mn_metaman, mempool, peerman, mn_activeman, mn_sync, *llmq_ctx.isman)}, - ehf_sighandler{std::make_unique(chainman, mnhfman, *llmq_ctx.sigman, *llmq_ctx.shareman, - *llmq_ctx.qman)} + gov_signer{std::make_unique(connman, dmnman, govman, mn_activeman, chainman, mn_sync)}, + shareman{std::make_unique(connman, chainman.ActiveChainstate(), *llmq_ctx.sigman, peerman, + mn_activeman, *llmq_ctx.qman, sporkman)}, + ehf_sighandler{ + std::make_unique(chainman, mnhfman, *llmq_ctx.sigman, *shareman, *llmq_ctx.qman)}, + cl_signer{std::make_unique(chainman.ActiveChainstate(), *llmq_ctx.clhandler, + *llmq_ctx.sigman, *shareman, sporkman, mn_sync)}, + is_signer{std::make_unique(chainman.ActiveChainstate(), *llmq_ctx.clhandler, + *llmq_ctx.isman, *llmq_ctx.sigman, *shareman, + *llmq_ctx.qman, sporkman, mempool, mn_sync)} { m_llmq_ctx.clhandler->ConnectSigner(cl_signer.get()); m_llmq_ctx.isman->ConnectSigner(is_signer.get()); @@ -37,3 +45,22 @@ ActiveContext::~ActiveContext() m_llmq_ctx.clhandler->DisconnectSigner(); m_llmq_ctx.isman->DisconnectSigner(); } + +void ActiveContext::Interrupt() +{ + shareman->InterruptWorkerThread(); +} + +void ActiveContext::Start(CConnman& connman, PeerManager& peerman) +{ + m_llmq_ctx.qdkgsman->StartThreads(connman, peerman); + shareman->RegisterAsRecoveredSigsListener(); + shareman->StartWorkerThread(); +} + +void ActiveContext::Stop() +{ + shareman->StopWorkerThread(); + shareman->UnregisterAsRecoveredSigsListener(); + m_llmq_ctx.qdkgsman->StopThreads(); +} diff --git a/src/masternode/active/context.h b/src/masternode/active/context.h index 7dd04a507b47..c34fbae09d22 100644 --- a/src/masternode/active/context.h +++ b/src/masternode/active/context.h @@ -13,11 +13,13 @@ class CCoinJoinServer; class CConnman; class CDeterministicMNManager; class CDSTXManager; +class CGovernanceManager; class CMasternodeMetaMan; class CMasternodeSync; class CMNHFManager; class CSporkManager; class CTxMemPool; +class GovernanceSigner; class PeerManager; struct LLMQContext; namespace chainlock { @@ -28,6 +30,7 @@ class InstantSendSigner; } // namespace instantsend namespace llmq { class CEHFSignalsHandler; +class CSigSharesManager; } // namespace llmq struct ActiveContext { @@ -35,29 +38,38 @@ struct ActiveContext { // TODO: Switch to references to members when migration is finished LLMQContext& m_llmq_ctx; - /* - * Entities that are registered with LLMQContext members are not accessible - * and are managed with (Dis)connectSigner() in the (c/d)tor instead - */ - const std::unique_ptr cl_signer; - const std::unique_ptr is_signer; - public: ActiveContext() = delete; ActiveContext(const ActiveContext&) = delete; - ActiveContext(ChainstateManager& chainman, CConnman& connman, CDeterministicMNManager& dmnman, - CDSTXManager& dstxman, CMasternodeMetaMan& mn_metaman, CMNHFManager& mnhfman, LLMQContext& llmq_ctx, - CSporkManager& sporkman, CTxMemPool& mempool, PeerManager& peerman, - const CActiveMasternodeManager& mn_activeman, const CMasternodeSync& mn_sync); + ActiveContext& operator=(const ActiveContext&) = delete; + explicit ActiveContext(ChainstateManager& chainman, CConnman& connman, CDeterministicMNManager& dmnman, + CDSTXManager& dstxman, CGovernanceManager& govman, CMasternodeMetaMan& mn_metaman, + CMNHFManager& mnhfman, CSporkManager& sporkman, CTxMemPool& mempool, LLMQContext& llmq_ctx, + PeerManager& peerman, const CActiveMasternodeManager& mn_activeman, + const CMasternodeSync& mn_sync); ~ActiveContext(); + void Interrupt(); + void Start(CConnman& connman, PeerManager& peerman); + void Stop(); + /* * Entities that are only utilized when masternode mode is enabled * and are accessible in their own right * TODO: Move CActiveMasternodeManager here when dependents have been migrated */ const std::unique_ptr cj_server; + const std::unique_ptr gov_signer; + const std::unique_ptr shareman; const std::unique_ptr ehf_sighandler; + +private: + /* + * Entities that are registered with LLMQContext members are not accessible + * and are managed with (Dis)connectSigner() in the (c/d)tor instead + */ + const std::unique_ptr cl_signer; + const std::unique_ptr is_signer; }; #endif // BITCOIN_MASTERNODE_ACTIVE_CONTEXT_H diff --git a/src/masternode/active/notificationinterface.cpp b/src/masternode/active/notificationinterface.cpp index 215458a9e9dd..17340861ae6c 100644 --- a/src/masternode/active/notificationinterface.cpp +++ b/src/masternode/active/notificationinterface.cpp @@ -4,7 +4,9 @@ #include +#include #include +#include #include #include @@ -14,6 +16,8 @@ ActiveNotificationInterface::ActiveNotificationInterface(ActiveContext& active_c { } +ActiveNotificationInterface::~ActiveNotificationInterface() = default; + void ActiveNotificationInterface::UpdatedBlockTip(const CBlockIndex* pindexNew, const CBlockIndex* pindexFork, bool fInitialDownload) { @@ -22,6 +26,12 @@ void ActiveNotificationInterface::UpdatedBlockTip(const CBlockIndex* pindexNew, m_mn_activeman.UpdatedBlockTip(pindexNew, pindexFork, fInitialDownload); m_active_ctx.ehf_sighandler->UpdatedBlockTip(pindexNew); + m_active_ctx.gov_signer->UpdatedBlockTip(pindexNew); +} + +void ActiveNotificationInterface::NotifyRecoveredSig(const std::shared_ptr& sig) +{ + m_active_ctx.shareman->NotifyRecoveredSig(sig); } std::unique_ptr g_active_notification_interface; diff --git a/src/masternode/active/notificationinterface.h b/src/masternode/active/notificationinterface.h index ecb3f9fa962c..905371e41b7a 100644 --- a/src/masternode/active/notificationinterface.h +++ b/src/masternode/active/notificationinterface.h @@ -7,19 +7,26 @@ #include +#include + class CActiveMasternodeManager; struct ActiveContext; +namespace llmq { +class CRecoveredSig; +} // namespace llmq class ActiveNotificationInterface final : public CValidationInterface { public: ActiveNotificationInterface() = delete; ActiveNotificationInterface(const ActiveNotificationInterface&) = delete; + ActiveNotificationInterface& operator=(const ActiveNotificationInterface&) = delete; explicit ActiveNotificationInterface(ActiveContext& active_ctx, CActiveMasternodeManager& mn_activeman); - virtual ~ActiveNotificationInterface() = default; + virtual ~ActiveNotificationInterface(); protected: // CValidationInterface + void NotifyRecoveredSig(const std::shared_ptr& sig) override; void UpdatedBlockTip(const CBlockIndex* pindexNew, const CBlockIndex* pindexFork, bool fInitialDownload) override; private: diff --git a/src/masternode/meta.cpp b/src/masternode/meta.cpp index adb2aaa30259..48d106b968da 100644 --- a/src/masternode/meta.cpp +++ b/src/masternode/meta.cpp @@ -8,13 +8,26 @@ #include #include -const std::string MasternodeMetaStore::SERIALIZATION_VERSION_STRING = "CMasternodeMetaMan-Version-4"; +const std::string MasternodeMetaStore::SERIALIZATION_VERSION_STRING = "CMasternodeMetaMan-Version-5"; + +static constexpr int MASTERNODE_MAX_FAILED_OUTBOUND_ATTEMPTS{5}; +static constexpr int MASTERNODE_MAX_MIXING_TXES{5}; + +namespace { +static const CMasternodeMetaInfo default_meta_info{}; +} // anonymous namespace CMasternodeMetaMan::CMasternodeMetaMan() : m_db{std::make_unique("mncache.dat", "magicMasternodeCache")} { } +CMasternodeMetaMan::~CMasternodeMetaMan() +{ + if (!is_valid) return; + m_db->Store(*this); +} + bool CMasternodeMetaMan::LoadCache(bool load_cache) { assert(m_db != nullptr); @@ -22,37 +35,26 @@ bool CMasternodeMetaMan::LoadCache(bool load_cache) return is_valid; } -CMasternodeMetaMan::~CMasternodeMetaMan() -{ - if (!is_valid) return; - m_db->Store(*this); -} - UniValue CMasternodeMetaInfo::ToJson() const { - UniValue ret(UniValue::VOBJ); - int64_t now = GetTime().count(); - ret.pushKV("lastDSQ", nLastDsq.load()); - ret.pushKV("mixingTxCount", nMixingTxCount.load()); - ret.pushKV("outboundAttemptCount", outboundAttemptCount.load()); - ret.pushKV("lastOutboundAttempt", lastOutboundAttempt.load()); - ret.pushKV("lastOutboundAttemptElapsed", now - lastOutboundAttempt.load()); - ret.pushKV("lastOutboundSuccess", lastOutboundSuccess.load()); - ret.pushKV("lastOutboundSuccessElapsed", now - lastOutboundSuccess.load()); - { - LOCK(cs); - ret.pushKV("is_platform_banned", m_platform_ban); - ret.pushKV("platform_ban_height_updated", m_platform_ban_updated); - } + UniValue ret(UniValue::VOBJ); + ret.pushKV("lastDSQ", m_last_dsq); + ret.pushKV("mixingTxCount", m_mixing_tx_count); + ret.pushKV("outboundAttemptCount", outboundAttemptCount); + ret.pushKV("lastOutboundAttempt", lastOutboundAttempt); + ret.pushKV("lastOutboundAttemptElapsed", now - lastOutboundAttempt); + ret.pushKV("lastOutboundSuccess", lastOutboundSuccess); + ret.pushKV("lastOutboundSuccessElapsed", now - lastOutboundSuccess); + ret.pushKV("is_platform_banned", m_platform_ban); + ret.pushKV("platform_ban_height_updated", m_platform_ban_updated); return ret; } void CMasternodeMetaInfo::AddGovernanceVote(const uint256& nGovernanceObjectHash) { - LOCK(cs); // Insert a zero value, or not. Then increment the value regardless. This // ensures the value is in the map. const auto& pair = mapGovernanceObjectsVotedOn.emplace(nGovernanceObjectHash, 0); @@ -61,65 +63,81 @@ void CMasternodeMetaInfo::AddGovernanceVote(const uint256& nGovernanceObjectHash void CMasternodeMetaInfo::RemoveGovernanceObject(const uint256& nGovernanceObjectHash) { - LOCK(cs); // Whether or not the govobj hash exists in the map first is irrelevant. mapGovernanceObjectsVotedOn.erase(nGovernanceObjectHash); } -CMasternodeMetaInfoPtr CMasternodeMetaMan::GetMetaInfo(const uint256& proTxHash, bool fCreate) +const CMasternodeMetaInfo& CMasternodeMetaMan::GetMetaInfoOrDefault(const uint256& protx_hash) const +{ + const auto it = metaInfos.find(protx_hash); + if (it == metaInfos.end()) return default_meta_info; + return it->second; +} + +CMasternodeMetaInfo CMasternodeMetaMan::GetInfo(const uint256& proTxHash) const { LOCK(cs); + return GetMetaInfoOrDefault(proTxHash); +} + +CMasternodeMetaInfo& CMasternodeMetaMan::GetMetaInfo(const uint256& proTxHash) +{ auto it = metaInfos.find(proTxHash); if (it != metaInfos.end()) { return it->second; } - if (!fCreate) { - return nullptr; - } - it = metaInfos.emplace(proTxHash, std::make_shared(proTxHash)).first; + it = metaInfos.emplace(proTxHash, CMasternodeMetaInfo{proTxHash}).first; return it->second; } -// We keep track of dsq (mixing queues) count to avoid using same masternodes for mixing too often. -// This threshold is calculated as the last dsq count this specific masternode was used in a mixing -// session plus a margin of 20% of masternode count. In other words we expect at least 20% of unique -// masternodes before we ever see a masternode that we know already mixed someone's funds earlier. -int64_t CMasternodeMetaMan::GetDsqThreshold(const uint256& proTxHash, int nMnCount) +bool CMasternodeMetaMan::IsMixingThresholdExceeded(const uint256& protx_hash, int mn_count) const { - auto metaInfo = GetMetaInfo(proTxHash); - if (metaInfo == nullptr) { - // return a threshold which is slightly above nDsqCount i.e. a no-go - return nDsqCount + 1; + LOCK(cs); + auto it = metaInfos.find(protx_hash); + if (it == metaInfos.end()) { + LogPrint(BCLog::COINJOIN, "DSQUEUE -- node %s is logged\n", protx_hash.ToString()); + return false; } - return metaInfo->GetLastDsq() + nMnCount / 5; + const auto& meta_info = it->second; + int64_t last_dsq = meta_info.m_last_dsq; + int64_t threshold = last_dsq + mn_count / 5; + + LogPrint(BCLog::COINJOIN, "DSQUEUE -- mn: %s last_dsq: %d dsq_threshold: %d nDsqCount: %d\n", + protx_hash.ToString(), last_dsq, threshold, nDsqCount); + return last_dsq != 0 && threshold > nDsqCount; } void CMasternodeMetaMan::AllowMixing(const uint256& proTxHash) { - auto mm = GetMetaInfo(proTxHash); - nDsqCount++; - mm->nLastDsq = nDsqCount.load(); - mm->nMixingTxCount = 0; + LOCK(cs); + auto& mm = GetMetaInfo(proTxHash); + mm.m_last_dsq = ++nDsqCount; + mm.m_mixing_tx_count = 0; } void CMasternodeMetaMan::DisallowMixing(const uint256& proTxHash) { - auto mm = GetMetaInfo(proTxHash); - mm->nMixingTxCount++; + LOCK(cs); + GetMetaInfo(proTxHash).m_mixing_tx_count++; +} + +bool CMasternodeMetaMan::IsValidForMixingTxes(const uint256& protx_hash) const +{ + LOCK(cs); + return GetMetaInfoOrDefault(protx_hash).m_mixing_tx_count <= MASTERNODE_MAX_MIXING_TXES; } -bool CMasternodeMetaMan::AddGovernanceVote(const uint256& proTxHash, const uint256& nGovernanceObjectHash) +void CMasternodeMetaMan::AddGovernanceVote(const uint256& proTxHash, const uint256& nGovernanceObjectHash) { - auto mm = GetMetaInfo(proTxHash); - mm->AddGovernanceVote(nGovernanceObjectHash); - return true; + LOCK(cs); + GetMetaInfo(proTxHash).AddGovernanceVote(nGovernanceObjectHash); } void CMasternodeMetaMan::RemoveGovernanceObject(const uint256& nGovernanceObjectHash) { LOCK(cs); - for(const auto& p : metaInfos) { - p.second->RemoveGovernanceObject(nGovernanceObjectHash); + for (auto& [_, meta_info] : metaInfos) { + meta_info.RemoveGovernanceObject(nGovernanceObjectHash); } } @@ -130,6 +148,65 @@ std::vector CMasternodeMetaMan::GetAndClearDirtyGovernanceObjectHashes( return vecTmp; } +void CMasternodeMetaMan::SetLastOutboundAttempt(const uint256& protx_hash, int64_t t) +{ + LOCK(cs); + GetMetaInfo(protx_hash).SetLastOutboundAttempt(t); +} + +void CMasternodeMetaMan::SetLastOutboundSuccess(const uint256& protx_hash, int64_t t) +{ + LOCK(cs); + GetMetaInfo(protx_hash).SetLastOutboundSuccess(t); +} + +int64_t CMasternodeMetaMan::GetLastOutboundAttempt(const uint256& protx_hash) const +{ + LOCK(cs); + return GetMetaInfoOrDefault(protx_hash).lastOutboundAttempt; +} + +int64_t CMasternodeMetaMan::GetLastOutboundSuccess(const uint256& protx_hash) const +{ + LOCK(cs); + return GetMetaInfoOrDefault(protx_hash).lastOutboundSuccess; +} + +bool CMasternodeMetaMan::OutboundFailedTooManyTimes(const uint256& protx_hash) const +{ + LOCK(cs); + return GetMetaInfoOrDefault(protx_hash).outboundAttemptCount > MASTERNODE_MAX_FAILED_OUTBOUND_ATTEMPTS; +} + +bool CMasternodeMetaMan::IsPlatformBanned(const uint256& protx_hash) const +{ + LOCK(cs); + return GetMetaInfoOrDefault(protx_hash).m_platform_ban; +} + +bool CMasternodeMetaMan::ResetPlatformBan(const uint256& protx_hash, int height) +{ + LOCK(cs); + + auto it = metaInfos.find(protx_hash); + if (it == metaInfos.end()) return false; + + return it->second.SetPlatformBan(false, height); +} + +bool CMasternodeMetaMan::SetPlatformBan(const uint256& inv_hash, PlatformBanMessage&& ban_msg) +{ + LOCK(cs); + + const uint256& protx_hash = ban_msg.m_protx_hash; + + bool ret = GetMetaInfo(protx_hash).SetPlatformBan(true, ban_msg.m_requested_height); + if (ret) { + m_seen_platform_bans.emplace(inv_hash, std::move(ban_msg)); + } + return ret; +} + bool CMasternodeMetaMan::AlreadyHavePlatformBan(const uint256& inv_hash) const { LOCK(cs); @@ -147,16 +224,44 @@ std::optional CMasternodeMetaMan::GetPlatformBan(const uint2 return ret; } -void CMasternodeMetaMan::RememberPlatformBan(const uint256& inv_hash, PlatformBanMessage&& msg) +void CMasternodeMetaMan::AddUsedMasternode(const uint256& proTxHash) +{ + LOCK(cs); + // Only add if not already present (prevents duplicates) + if (m_used_masternodes_set.insert(proTxHash).second) { + m_used_masternodes.push_back(proTxHash); + } +} + +void CMasternodeMetaMan::RemoveUsedMasternodes(size_t count) +{ + LOCK(cs); + size_t removed = 0; + while (removed < count && !m_used_masternodes.empty()) { + // Remove from both the set and the deque + m_used_masternodes_set.erase(m_used_masternodes.front()); + m_used_masternodes.pop_front(); + ++removed; + } +} + +size_t CMasternodeMetaMan::GetUsedMasternodesCount() const +{ + LOCK(cs); + return m_used_masternodes.size(); +} + +bool CMasternodeMetaMan::IsUsedMasternode(const uint256& proTxHash) const { LOCK(cs); - m_seen_platform_bans.insert(inv_hash, std::move(msg)); + return m_used_masternodes_set.find(proTxHash) != m_used_masternodes_set.end(); } std::string MasternodeMetaStore::ToString() const { LOCK(cs); - return strprintf("Masternodes: meta infos object count: %d, nDsqCount: %d", metaInfos.size(), nDsqCount); + return strprintf("Masternodes: meta infos object count: %d, nDsqCount: %d, used masternodes count: %d", + metaInfos.size(), nDsqCount, m_used_masternodes.size()); } uint256 PlatformBanMessage::GetHash() const { return ::SerializeHash(*this); } diff --git a/src/masternode/meta.h b/src/masternode/meta.h index e06a10cceed9..5e7729a9390f 100644 --- a/src/masternode/meta.h +++ b/src/masternode/meta.h @@ -13,97 +13,65 @@ #include #include -#include +#include #include -#include #include #include -class CConnman; class UniValue; template class CFlatDB; -static constexpr int MASTERNODE_MAX_MIXING_TXES{5}; -static constexpr int MASTERNODE_MAX_FAILED_OUTBOUND_ATTEMPTS{5}; - // Holds extra (non-deterministic) information about masternodes // This is mostly local information, e.g. about mixing and governance class CMasternodeMetaInfo { - friend class CMasternodeMetaMan; - -private: - mutable RecursiveMutex cs; - - uint256 proTxHash GUARDED_BY(cs); +public: + uint256 m_protx_hash; - //the dsq count from the last dsq broadcast of this node - std::atomic nLastDsq{0}; - std::atomic nMixingTxCount{0}; + //! the dsq count from the last dsq broadcast of this node + int64_t m_last_dsq{0}; + int m_mixing_tx_count{0}; // KEEP TRACK OF GOVERNANCE ITEMS EACH MASTERNODE HAS VOTE UPON FOR RECALCULATION - std::map mapGovernanceObjectsVotedOn GUARDED_BY(cs); + std::map mapGovernanceObjectsVotedOn; - std::atomic outboundAttemptCount{0}; - std::atomic lastOutboundAttempt{0}; - std::atomic lastOutboundSuccess{0}; + int outboundAttemptCount{0}; + int64_t lastOutboundAttempt{0}; + int64_t lastOutboundSuccess{0}; //! bool flag is node currently under platform ban by p2p message - bool m_platform_ban GUARDED_BY(cs){false}; + bool m_platform_ban{false}; //! height at which platform ban has been applied or removed - int m_platform_ban_updated GUARDED_BY(cs){0}; + int m_platform_ban_updated{0}; public: CMasternodeMetaInfo() = default; - explicit CMasternodeMetaInfo(const uint256& _proTxHash) : proTxHash(_proTxHash) {} - CMasternodeMetaInfo(const CMasternodeMetaInfo& ref) : - proTxHash(ref.proTxHash), - nLastDsq(ref.nLastDsq.load()), - nMixingTxCount(ref.nMixingTxCount.load()), - mapGovernanceObjectsVotedOn(ref.mapGovernanceObjectsVotedOn), - lastOutboundAttempt(ref.lastOutboundAttempt.load()), - lastOutboundSuccess(ref.lastOutboundSuccess.load()), - m_platform_ban(ref.m_platform_ban), - m_platform_ban_updated(ref.m_platform_ban_updated) + explicit CMasternodeMetaInfo(const uint256& protx_hash) : + m_protx_hash(protx_hash) { } + CMasternodeMetaInfo(const CMasternodeMetaInfo& ref) = default; SERIALIZE_METHODS(CMasternodeMetaInfo, obj) { - LOCK(obj.cs); - READWRITE(obj.proTxHash, obj.nLastDsq, obj.nMixingTxCount, obj.mapGovernanceObjectsVotedOn, + READWRITE(obj.m_protx_hash, obj.m_last_dsq, obj.m_mixing_tx_count, obj.mapGovernanceObjectsVotedOn, obj.outboundAttemptCount, obj.lastOutboundAttempt, obj.lastOutboundSuccess, obj.m_platform_ban, obj.m_platform_ban_updated); } UniValue ToJson() const; -public: - const uint256 GetProTxHash() const - { - LOCK(cs); - return proTxHash; - } - int64_t GetLastDsq() const { return nLastDsq; } - int GetMixingTxCount() const { return nMixingTxCount; } - - bool IsValidForMixingTxes() const { return GetMixingTxCount() <= MASTERNODE_MAX_MIXING_TXES; } - // KEEP TRACK OF EACH GOVERNANCE ITEM IN CASE THIS NODE GOES OFFLINE, SO WE CAN RECALCULATE THEIR STATUS void AddGovernanceVote(const uint256& nGovernanceObjectHash); - void RemoveGovernanceObject(const uint256& nGovernanceObjectHash); - bool OutboundFailedTooManyTimes() const { return outboundAttemptCount > MASTERNODE_MAX_FAILED_OUTBOUND_ATTEMPTS; } void SetLastOutboundAttempt(int64_t t) { lastOutboundAttempt = t; ++outboundAttemptCount; } - int64_t GetLastOutboundAttempt() const { return lastOutboundAttempt; } void SetLastOutboundSuccess(int64_t t) { lastOutboundSuccess = t; outboundAttemptCount = 0; } - int64_t GetLastOutboundSuccess() const { return lastOutboundSuccess; } + bool SetPlatformBan(bool is_banned, int height) { - LOCK(cs); if (height < m_platform_ban_updated) { return false; } @@ -114,63 +82,70 @@ class CMasternodeMetaInfo m_platform_ban_updated = height; return true; } - bool IsPlatformBanned() const - { - LOCK(cs); - return m_platform_ban; - } }; -using CMasternodeMetaInfoPtr = std::shared_ptr; class MasternodeMetaStore { protected: static const std::string SERIALIZATION_VERSION_STRING; - mutable RecursiveMutex cs; - std::map metaInfos GUARDED_BY(cs); + mutable Mutex cs; + std::map metaInfos GUARDED_BY(cs); // keep track of dsq count to prevent masternodes from gaming coinjoin queue - std::atomic nDsqCount{0}; + int64_t nDsqCount GUARDED_BY(cs){0}; + // keep track of the used Masternodes for CoinJoin across all wallets + // Using deque for efficient FIFO removal and unordered_set for O(1) lookups + std::deque m_used_masternodes GUARDED_BY(cs); + Uint256HashSet m_used_masternodes_set GUARDED_BY(cs); public: template - void Serialize(Stream &s) const + void Serialize(Stream &s) const EXCLUSIVE_LOCKS_REQUIRED(!cs) { LOCK(cs); std::vector tmpMetaInfo; for (const auto& p : metaInfos) { - tmpMetaInfo.emplace_back(*p.second); + tmpMetaInfo.emplace_back(p.second); } - s << SERIALIZATION_VERSION_STRING << tmpMetaInfo << nDsqCount; + // Convert deque to vector for serialization - unordered_set will be rebuilt on deserialization + std::vector tmpUsedMasternodes(m_used_masternodes.begin(), m_used_masternodes.end()); + s << SERIALIZATION_VERSION_STRING << tmpMetaInfo << nDsqCount << tmpUsedMasternodes; } template - void Unserialize(Stream &s) + void Unserialize(Stream &s) EXCLUSIVE_LOCKS_REQUIRED(!cs) { - Clear(); - LOCK(cs); + + metaInfos.clear(); std::string strVersion; s >> strVersion; if (strVersion != SERIALIZATION_VERSION_STRING) { return; } std::vector tmpMetaInfo; - s >> tmpMetaInfo >> nDsqCount; - metaInfos.clear(); + std::vector tmpUsedMasternodes; + s >> tmpMetaInfo >> nDsqCount >> tmpUsedMasternodes; for (auto& mm : tmpMetaInfo) { - metaInfos.emplace(mm.GetProTxHash(), std::make_shared(std::move(mm))); + metaInfos.emplace(mm.m_protx_hash, CMasternodeMetaInfo{std::move(mm)}); } + + // Convert vector to deque and build unordered_set for O(1) lookups + m_used_masternodes.assign(tmpUsedMasternodes.begin(), tmpUsedMasternodes.end()); + m_used_masternodes_set.clear(); + m_used_masternodes_set.insert(tmpUsedMasternodes.begin(), tmpUsedMasternodes.end()); } - void Clear() + void Clear() EXCLUSIVE_LOCKS_REQUIRED(!cs) { LOCK(cs); metaInfos.clear(); + m_used_masternodes.clear(); + m_used_masternodes_set.clear(); } - std::string ToString() const; + std::string ToString() const EXCLUSIVE_LOCKS_REQUIRED(!cs); }; /** @@ -225,30 +200,53 @@ class CMasternodeMetaMan : public MasternodeMetaStore mutable unordered_lru_cache m_seen_platform_bans GUARDED_BY(cs){ SeenBanInventorySize}; + CMasternodeMetaInfo& GetMetaInfo(const uint256& proTxHash) EXCLUSIVE_LOCKS_REQUIRED(cs); + const CMasternodeMetaInfo& GetMetaInfoOrDefault(const uint256& proTxHash) const EXCLUSIVE_LOCKS_REQUIRED(cs); + public: - explicit CMasternodeMetaMan(); + CMasternodeMetaMan(const CMasternodeMetaMan&) = delete; + CMasternodeMetaMan& operator=(const CMasternodeMetaMan&) = delete; + CMasternodeMetaMan(); ~CMasternodeMetaMan(); bool LoadCache(bool load_cache); bool IsValid() const { return is_valid; } - CMasternodeMetaInfoPtr GetMetaInfo(const uint256& proTxHash, bool fCreate = true); + CMasternodeMetaInfo GetInfo(const uint256& proTxHash) const EXCLUSIVE_LOCKS_REQUIRED(!cs); - int64_t GetDsqCount() const { return nDsqCount; } - int64_t GetDsqThreshold(const uint256& proTxHash, int nMnCount); + // We keep track of dsq (mixing queues) count to avoid using same masternodes for mixing too often. + // MN's threshold is calculated as the last dsq count this specific masternode was used in a mixing + // session plus a margin of 20% of masternode count. In other words we expect at least 20% of unique + // masternodes before we ever see a masternode that we know already mixed someone's funds earlier. + bool IsMixingThresholdExceeded(const uint256& protx_hash, int mn_count) const EXCLUSIVE_LOCKS_REQUIRED(!cs); - void AllowMixing(const uint256& proTxHash); - void DisallowMixing(const uint256& proTxHash); + void AllowMixing(const uint256& proTxHash) EXCLUSIVE_LOCKS_REQUIRED(!cs); + void DisallowMixing(const uint256& proTxHash) EXCLUSIVE_LOCKS_REQUIRED(!cs); + bool IsValidForMixingTxes(const uint256& protx_hash) const EXCLUSIVE_LOCKS_REQUIRED(!cs); - bool AddGovernanceVote(const uint256& proTxHash, const uint256& nGovernanceObjectHash); - void RemoveGovernanceObject(const uint256& nGovernanceObjectHash); + void AddGovernanceVote(const uint256& proTxHash, const uint256& nGovernanceObjectHash); + void RemoveGovernanceObject(const uint256& nGovernanceObjectHash) EXCLUSIVE_LOCKS_REQUIRED(!cs); + + std::vector GetAndClearDirtyGovernanceObjectHashes() EXCLUSIVE_LOCKS_REQUIRED(!cs); + + void SetLastOutboundAttempt(const uint256& protx_hash, int64_t t) EXCLUSIVE_LOCKS_REQUIRED(!cs); + void SetLastOutboundSuccess(const uint256& protx_hash, int64_t t) EXCLUSIVE_LOCKS_REQUIRED(!cs); + int64_t GetLastOutboundAttempt(const uint256& protx_hash) const EXCLUSIVE_LOCKS_REQUIRED(!cs); + int64_t GetLastOutboundSuccess(const uint256& protx_hash) const EXCLUSIVE_LOCKS_REQUIRED(!cs); + bool OutboundFailedTooManyTimes(const uint256& protx_hash) const EXCLUSIVE_LOCKS_REQUIRED(!cs); - std::vector GetAndClearDirtyGovernanceObjectHashes(); + bool IsPlatformBanned(const uint256& protx_hash) const EXCLUSIVE_LOCKS_REQUIRED(!cs); + bool ResetPlatformBan(const uint256& protx_hash, int height) EXCLUSIVE_LOCKS_REQUIRED(!cs); + bool SetPlatformBan(const uint256& inv_hash, PlatformBanMessage&& msg) EXCLUSIVE_LOCKS_REQUIRED(!cs); + bool AlreadyHavePlatformBan(const uint256& inv_hash) const EXCLUSIVE_LOCKS_REQUIRED(!cs); + std::optional GetPlatformBan(const uint256& inv_hash) const EXCLUSIVE_LOCKS_REQUIRED(!cs); - bool AlreadyHavePlatformBan(const uint256& inv_hash) const; - std::optional GetPlatformBan(const uint256& inv_hash) const; - void RememberPlatformBan(const uint256& inv_hash, PlatformBanMessage&& msg); + // CoinJoin masternode tracking + void AddUsedMasternode(const uint256& proTxHash) EXCLUSIVE_LOCKS_REQUIRED(!cs); + void RemoveUsedMasternodes(size_t count) EXCLUSIVE_LOCKS_REQUIRED(!cs); + size_t GetUsedMasternodesCount() const EXCLUSIVE_LOCKS_REQUIRED(!cs); + bool IsUsedMasternode(const uint256& proTxHash) const EXCLUSIVE_LOCKS_REQUIRED(!cs); }; #endif // BITCOIN_MASTERNODE_META_H diff --git a/src/masternode/node.cpp b/src/masternode/node.cpp index 5399ab47ba14..7c48ce7f4fba 100644 --- a/src/masternode/node.cpp +++ b/src/masternode/node.cpp @@ -49,8 +49,9 @@ bool GetLocal(CService& addr, const CNetAddr* paddrPeer) } } // anonymous namespace -CActiveMasternodeManager::CActiveMasternodeManager(const CBLSSecretKey& sk, CConnman& connman, const std::unique_ptr& dmnman) : - m_info(sk, sk.GetPublicKey()), +CActiveMasternodeManager::CActiveMasternodeManager(const CBLSSecretKey& sk, CConnman& connman, + const std::unique_ptr& dmnman) : + m_info{sk, sk.GetPublicKey()}, m_connman{connman}, m_dmnman{dmnman} { @@ -60,6 +61,8 @@ CActiveMasternodeManager::CActiveMasternodeManager(const CBLSSecretKey& sk, CCon m_info.blsPubKeyOperator.ToString(/*specificLegacyScheme=*/ false)); } +CActiveMasternodeManager::~CActiveMasternodeManager() = default; + std::string CActiveMasternodeManager::GetStateString() const { switch (WITH_READ_LOCK(cs, return m_state)) { @@ -276,6 +279,14 @@ template bool CActiveMasternodeManager::Decrypt(const CBLSIESMultiRecipientObjec return WITH_READ_LOCK(cs, return m_info.blsKeyOperator.Sign(hash, is_legacy)); } +[[nodiscard]] std::vector CActiveMasternodeManager::SignBasic(const uint256& hash) const +{ + AssertLockNotHeld(cs); + auto sig = Sign(hash, /*is_legacy=*/false); + assert(sig.IsValid()); + return sig.ToByteVector(/*specificLegacyScheme=*/false); +} + // We need to pass a copy as opposed to a const ref because CBLSPublicKeyVersionWrapper // does not accept a const ref in its construction args [[nodiscard]] CBLSPublicKey CActiveMasternodeManager::GetPubKey() const diff --git a/src/masternode/node.h b/src/masternode/node.h index 931233c42f72..980a2f96814d 100644 --- a/src/masternode/node.h +++ b/src/masternode/node.h @@ -11,6 +11,7 @@ #include #include +class CConnman; class CDeterministicMNManager; struct CActiveMasternodeInfo { @@ -50,7 +51,11 @@ class CActiveMasternodeManager const std::unique_ptr& m_dmnman; public: + CActiveMasternodeManager() = delete; + CActiveMasternodeManager(const CActiveMasternodeManager&) = delete; + CActiveMasternodeManager& operator=(const CActiveMasternodeManager&) = delete; explicit CActiveMasternodeManager(const CBLSSecretKey& sk, CConnman& connman, const std::unique_ptr& dmnman); + ~CActiveMasternodeManager(); void UpdatedBlockTip(const CBlockIndex* pindexNew, const CBlockIndex* pindexFork, bool fInitialDownload) EXCLUSIVE_LOCKS_REQUIRED(!cs); @@ -66,6 +71,7 @@ class CActiveMasternodeManager [[nodiscard]] bool Decrypt(const EncryptedObj& obj, size_t idx, Obj& ret_obj, int version) const EXCLUSIVE_LOCKS_REQUIRED(!cs); [[nodiscard]] CBLSSignature Sign(const uint256& hash, const bool is_legacy) const EXCLUSIVE_LOCKS_REQUIRED(!cs); + [[nodiscard]] std::vector SignBasic(const uint256& hash) const EXCLUSIVE_LOCKS_REQUIRED(!cs); /* TODO: Reconsider external locking */ [[nodiscard]] COutPoint GetOutPoint() const { READ_LOCK(cs); return m_info.outpoint; } diff --git a/src/masternode/sync.cpp b/src/masternode/sync.cpp index b9bebb07cb64..674e6d7994c1 100644 --- a/src/masternode/sync.cpp +++ b/src/masternode/sync.cpp @@ -15,13 +15,15 @@ #include CMasternodeSync::CMasternodeSync(CConnman& _connman, CNetFulfilledRequestManager& netfulfilledman) : - nTimeAssetSyncStarted(GetTime()), - nTimeLastBumped(GetTime()), - connman(_connman), - m_netfulfilledman(netfulfilledman) + nTimeAssetSyncStarted{GetTime()}, + nTimeLastBumped{GetTime()}, + connman{_connman}, + m_netfulfilledman{netfulfilledman} { } +CMasternodeSync::~CMasternodeSync() = default; + void CMasternodeSync::Reset(bool fForce, bool fNotifyReset) { // Avoid resetting the sync process if we just "recently" received a new block diff --git a/src/masternode/sync.h b/src/masternode/sync.h index dc12376c7518..2af331c64e36 100644 --- a/src/masternode/sync.h +++ b/src/masternode/sync.h @@ -53,7 +53,11 @@ class CMasternodeSync CNetFulfilledRequestManager& m_netfulfilledman; public: + CMasternodeSync() = delete; + CMasternodeSync(const CMasternodeSync&) = delete; + CMasternodeSync& operator=(const CMasternodeSync&) = delete; explicit CMasternodeSync(CConnman& _connman, CNetFulfilledRequestManager& netfulfilledman); + ~CMasternodeSync(); void SendGovernanceSyncRequest(CNode* pnode) const; diff --git a/src/masternode/utils.cpp b/src/masternode/utils.cpp index 2988b3ffe801..4ed51031db27 100644 --- a/src/masternode/utils.cpp +++ b/src/masternode/utils.cpp @@ -3,30 +3,21 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include -#include -#ifdef ENABLE_WALLET -#include -#endif -#include #include #include #include -#include -void CMasternodeUtils::DoMaintenance(CConnman& connman, CDeterministicMNManager& dmnman, - const CMasternodeSync& mn_sync, const CJContext& cj_ctx) +#include +#include +#include + +void CMasternodeUtils::DoMaintenance(CConnman& connman, CDeterministicMNManager& dmnman, const CMasternodeSync& mn_sync, + CJWalletManager* const cj_walletman) { if (!mn_sync.IsBlockchainSynced()) return; if (ShutdownRequested()) return; - std::vector vecDmns; // will be empty when no wallet -#ifdef ENABLE_WALLET - cj_ctx.walletman->ForEachCJClientMan([&vecDmns](const std::unique_ptr& clientman) { - clientman->GetMixingMasternodesInfo(vecDmns); - }); -#endif // ENABLE_WALLET - // Don't disconnect masternode connections when we have less then the desired amount of outbound nodes int nonMasternodeCount = 0; connman.ForEachNode(CConnman::AllNodes, [&](const CNode* pnode) { @@ -45,6 +36,7 @@ void CMasternodeUtils::DoMaintenance(CConnman& connman, CDeterministicMNManager& return; } + auto mixing_masternodes = cj_walletman ? cj_walletman->getMixingMasternodes() : std::vector{}; connman.ForEachNode(CConnman::AllNodes, [&](CNode* pnode) { if (pnode->m_masternode_probe_connection) { // we're not disconnecting masternode probes for at least PROBE_WAIT_INTERVAL seconds @@ -75,12 +67,10 @@ void CMasternodeUtils::DoMaintenance(CConnman& connman, CDeterministicMNManager& } } -#ifdef ENABLE_WALLET - bool fFound = ranges::any_of(vecDmns, [&pnode](const auto& dmn) { + bool fFound = ranges::any_of(mixing_masternodes, [&pnode](const auto& dmn) { return pnode->addr == dmn->pdmnState->netInfo->GetPrimary(); }); if (fFound) return; // do NOT disconnect mixing masternodes -#endif // ENABLE_WALLET if (fLogIPs) { LogPrint(BCLog::NET_NETCONN, "Closing Masternode connection: peer=%d, addr=%s\n", pnode->GetId(), pnode->addr.ToStringAddrPort()); diff --git a/src/masternode/utils.h b/src/masternode/utils.h index eb50990985c1..e1e7b586a912 100644 --- a/src/masternode/utils.h +++ b/src/masternode/utils.h @@ -8,13 +8,13 @@ class CConnman; class CDeterministicMNManager; class CMasternodeSync; -struct CJContext; +class CJWalletManager; class CMasternodeUtils { public: - static void DoMaintenance(CConnman &connman, CDeterministicMNManager& dmnman, - const CMasternodeSync& mn_sync, const CJContext& cj_ctx); + static void DoMaintenance(CConnman& connman, CDeterministicMNManager& dmnman, const CMasternodeSync& mn_sync, + CJWalletManager* const cj_walletman); }; #endif // BITCOIN_MASTERNODE_UTILS_H diff --git a/src/msg_result.h b/src/msg_result.h new file mode 100644 index 000000000000..646d2142443c --- /dev/null +++ b/src/msg_result.h @@ -0,0 +1,72 @@ +// Copyright (c) 2024-2025 The Dash Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_MSG_RESULT_H +#define BITCOIN_MSG_RESULT_H + +#include + +#include +#include + +#include +#include +#include +#include +#include + +struct MisbehavingError +{ + int score; + std::string message; + + MisbehavingError(int s) : score{s} {} + + // Constructor does a perfect forwarding reference + template + MisbehavingError(int s, T&& msg) : + score{s}, + message{std::forward(msg)} + {} +}; + +/** + * This struct is a helper to return values from handlers that are processing + * network messages but implemented outside of net_processing.cpp, + * for example llmq's messages. + * + * These handlers do not supposed to know anything about PeerManager to avoid + * circular dependencies. + * + * See `PeerManagerImpl::PostProcessMessage` to see how each type of return code + * is processed. + */ +struct MessageProcessingResult +{ + //! @m_error triggers Misbehaving error with score and optional message if not nullopt + std::optional m_error; + + //! @m_inventory will relay these inventories to connected peers + std::vector m_inventory; + + //! @m_dsq will relay DSQs to connected peers + std::vector m_dsq; + + //! @m_transactions will relay transactions to peers which is ready to accept it (some peers does not accept transactions) + std::vector m_transactions; + + //! @m_to_erase triggers EraseObjectRequest from PeerManager for this inventory if not nullopt + std::optional m_to_erase; + + MessageProcessingResult() = default; + MessageProcessingResult(CInv inv) : + m_inventory({inv}) + { + } + MessageProcessingResult(MisbehavingError error) : + m_error(error) + {} +}; + +#endif // BITCOIN_MSG_RESULT_H diff --git a/src/net.cpp b/src/net.cpp index b339dd451460..69c279eace73 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -128,7 +128,7 @@ static const uint64_t RANDOMIZER_ID_ADDRCACHE = 0x1cf2e4ddd306dda9ULL; // SHA256 // bool fDiscover = true; bool fListen = true; -Mutex g_maplocalhost_mutex; +GlobalMutex g_maplocalhost_mutex; std::map mapLocalHost GUARDED_BY(g_maplocalhost_mutex); std::string strSubVersion; @@ -338,56 +338,15 @@ bool IsLocal(const CService& addr) return mapLocalHost.count(addr) > 0; } -CNode* CConnman::FindNode(const CNetAddr& ip, bool fExcludeDisconnecting) +bool CConnman::AlreadyConnectedToAddress(const CAddress& addr) const { - LOCK(m_nodes_mutex); - for (CNode* pnode : m_nodes) { - if (fExcludeDisconnecting && pnode->fDisconnect) { - continue; - } - if (static_cast(pnode->addr) == ip) { - return pnode; - } - } - return nullptr; -} - -CNode* CConnman::FindNode(const std::string& addrName, bool fExcludeDisconnecting) -{ - LOCK(m_nodes_mutex); - for (CNode* pnode : m_nodes) { - if (fExcludeDisconnecting && pnode->fDisconnect) { - continue; - } - if (pnode->m_addr_name == addrName) { - return pnode; - } - } - return nullptr; -} - -CNode* CConnman::FindNode(const CService& addr, bool fExcludeDisconnecting) -{ - LOCK(m_nodes_mutex); - for (CNode* pnode : m_nodes) { - if (fExcludeDisconnecting && pnode->fDisconnect) { - continue; - } - if (static_cast(pnode->addr) == addr) { - return pnode; - } - } - return nullptr; + READ_LOCK(m_nodes_mutex); + return FindNode(static_cast(addr)) != nullptr; } -bool CConnman::AlreadyConnectedToAddress(const CAddress& addr) +bool CConnman::CheckIncomingNonce(uint64_t nonce) const { - return FindNode(addr.ToStringAddrPort()); -} - -bool CConnman::CheckIncomingNonce(uint64_t nonce) -{ - LOCK(m_nodes_mutex); + READ_LOCK(m_nodes_mutex); for (const CNode* pnode : m_nodes) { if (!pnode->fSuccessfullyConnected && !pnode->IsInboundConn() && pnode->GetLocalNonce() == nonce) return false; @@ -420,9 +379,7 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo } // Look for an existing connection - CNode* pnode = FindNode(static_cast(addrConnect)); - if (pnode) - { + if (ExistsNode(static_cast(addrConnect))) { LogPrintf("Failed to open new connection, already connected\n"); return nullptr; } @@ -457,9 +414,7 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo } // It is possible that we already have a connection to the IP/port pszDest resolved to. // In that case, drop the connection that was just created. - LOCK(m_nodes_mutex); - CNode* pnode = FindNode(static_cast(addrConnect)); - if (pnode) { + if (ExistsNode(static_cast(addrConnect))) { LogPrintf("Not opening a connection to %s, already connected to %s\n", pszDest, addrConnect.ToStringAddrPort()); return nullptr; } @@ -637,7 +592,7 @@ bool CNode::IsConnectedThroughPrivacyNet() const #undef X #define X(name) stats.name = name -void CNode::CopyStats(CNodeStats& stats) +void CNode::CopyStats(CNodeStats& stats) const { stats.nodeid = this->GetId(); X(addr); @@ -1783,6 +1738,56 @@ std::pair CConnman::SocketSendData(CNode& node) const return {nSentSize, data_left}; } +std::vector CConnman::GetEvictionCandidates() const +{ + std::vector vEvictionCandidates; + READ_LOCK(m_nodes_mutex); + + for (const CNode* node : m_nodes) { + if (node->fDisconnect) + continue; + + if (m_active_masternode) { + // This handles eviction protected nodes. Nodes are always protected for a short time after the connection + // was accepted. This short time is meant for the VERSION/VERACK exchange and the possible MNAUTH that might + // follow when the incoming connection is from another masternode. When a message other than MNAUTH + // is received after VERSION/VERACK, the protection is lifted immediately. + bool isProtected = GetTime() - node->m_connected < INBOUND_EVICTION_PROTECTION_TIME; + if (node->nTimeFirstMessageReceived.load() != 0s && !node->fFirstMessageIsMNAUTH) { + isProtected = false; + } + // if MNAUTH was valid, the node is always protected (and at the same time not accounted when + // checking incoming connection limits) + if (!node->GetVerifiedProRegTxHash().IsNull()) { + isProtected = true; + } + if (isProtected) { + continue; + } + } + + NodeEvictionCandidate candidate{ + .id = node->GetId(), + .m_connected = node->m_connected, + .m_min_ping_time = node->m_min_ping_time, + .m_last_block_time = node->m_last_block_time, + .m_last_tx_time = node->m_last_tx_time, + .fRelevantServices = node->m_has_all_wanted_services, + .m_relay_txs = node->m_relays_txs.load(), + .fBloomFilter = node->m_bloom_filter_loaded.load(), + .nKeyedNetGroup = node->nKeyedNetGroup, + .prefer_evict = node->m_prefer_evict, + .m_is_local = node->addr.IsLocal(), + .m_network = node->ConnectedThroughNetwork(), + .m_noban = node->HasPermission(NetPermissionFlags::NoBan), + .m_conn_type = node->m_conn_type, + }; + vEvictionCandidates.push_back(candidate); + } + + return vEvictionCandidates; +} + /** Try to find a connection to evict when the node is full. * Extreme care must be taken to avoid opening the node to attacker * triggered network partitioning. @@ -1793,65 +1798,16 @@ std::pair CConnman::SocketSendData(CNode& node) const */ bool CConnman::AttemptToEvictConnection() { - std::vector vEvictionCandidates; - { - LOCK(m_nodes_mutex); - - for (const CNode* node : m_nodes) { - if (node->fDisconnect) - continue; - - if (m_active_masternode) { - // This handles eviction protected nodes. Nodes are always protected for a short time after the connection - // was accepted. This short time is meant for the VERSION/VERACK exchange and the possible MNAUTH that might - // follow when the incoming connection is from another masternode. When a message other than MNAUTH - // is received after VERSION/VERACK, the protection is lifted immediately. - bool isProtected = GetTime() - node->m_connected < INBOUND_EVICTION_PROTECTION_TIME; - if (node->nTimeFirstMessageReceived.load() != 0s && !node->fFirstMessageIsMNAUTH) { - isProtected = false; - } - // if MNAUTH was valid, the node is always protected (and at the same time not accounted when - // checking incoming connection limits) - if (!node->GetVerifiedProRegTxHash().IsNull()) { - isProtected = true; - } - if (isProtected) { - continue; - } - } - - NodeEvictionCandidate candidate{ - .id = node->GetId(), - .m_connected = node->m_connected, - .m_min_ping_time = node->m_min_ping_time, - .m_last_block_time = node->m_last_block_time, - .m_last_tx_time = node->m_last_tx_time, - .fRelevantServices = node->m_has_all_wanted_services, - .m_relay_txs = node->m_relays_txs.load(), - .fBloomFilter = node->m_bloom_filter_loaded.load(), - .nKeyedNetGroup = node->nKeyedNetGroup, - .prefer_evict = node->m_prefer_evict, - .m_is_local = node->addr.IsLocal(), - .m_network = node->ConnectedThroughNetwork(), - .m_noban = node->HasPermission(NetPermissionFlags::NoBan), - .m_conn_type = node->m_conn_type, - }; - vEvictionCandidates.push_back(candidate); - } - } + std::vector vEvictionCandidates = GetEvictionCandidates(); const std::optional node_id_to_evict = SelectNodeToEvict(std::move(vEvictionCandidates)); if (!node_id_to_evict) { return false; } - LOCK(m_nodes_mutex); - for (CNode* pnode : m_nodes) { - if (pnode->GetId() == *node_id_to_evict) { - LogPrint(BCLog::NET_NETCONN, "selected %s connection for eviction peer=%d; disconnecting\n", pnode->ConnectionTypeAsString(), pnode->GetId()); - pnode->fDisconnect = true; - return true; - } - } - return false; + return WithNodeMutable(*node_id_to_evict, [](CNode* pnode){ + LogPrint(BCLog::NET_NETCONN, "selected %s connection for eviction peer=%d; disconnecting\n", pnode->ConnectionTypeAsString(), pnode->GetId()); + pnode->fDisconnect = true; + return true; + }).value_or(false); } void CConnman::AcceptConnection(const ListenSocket& hListenSocket, CMasternodeSync& mn_sync) { @@ -1901,8 +1857,9 @@ void CConnman::CreateNodeFromAcceptedSocket(std::unique_ptr&& sock, NetPermissions::AddFlag(permission_flags, NetPermissionFlags::NoBan); } + { - LOCK(m_nodes_mutex); + READ_LOCK(m_nodes_mutex); for (const CNode* pnode : m_nodes) { if (pnode->IsInboundConn()) { nInbound++; @@ -1911,7 +1868,6 @@ void CConnman::CreateNodeFromAcceptedSocket(std::unique_ptr&& sock, } } } - } std::string strDropped; @@ -2060,7 +2016,7 @@ bool CConnman::AddConnection(const std::string& address, ConnectionType conn_typ } // no default case, so the compiler can warn about missing cases // Count existing connections - int existing_connections = WITH_LOCK(m_nodes_mutex, + int existing_connections = WITH_READ_LOCK(m_nodes_mutex, return std::count_if(m_nodes.begin(), m_nodes.end(), [conn_type](CNode* node) { return node->m_conn_type == conn_type; });); // Max connections of specified type already exist @@ -2083,7 +2039,29 @@ void CConnman::DisconnectNodes() // m_reconnections_mutex while holding m_nodes_mutex. decltype(m_reconnections) reconnections_to_add; - { + // Quick check without exclusive lock to avoid unnecessary locking + // Note: This is a best-effort optimization. If network is active and no nodes + // are marked for disconnect, we can skip the expensive exclusive lock. + // If network is inactive or nodes need cleanup, we must take the lock. + bool has_to_disconnect = false; + if (fNetworkActive) { + { + READ_LOCK(m_nodes_mutex); + for (CNode* pnode : m_nodes) { + if (pnode->fDisconnect) { + has_to_disconnect = true; + break; + } + } + } + // Only return early if network is active AND no nodes need disconnection + // AND no disconnected nodes need cleanup (checked below) + if (!has_to_disconnect && m_nodes_disconnected.empty()) { + return; + } + } + + if (has_to_disconnect || !fNetworkActive) { LOCK(m_nodes_mutex); if (!fNetworkActive) { @@ -2096,7 +2074,7 @@ void CConnman::DisconnectNodes() } } - // Disconnect unused nodes + // Disconnect unused nodes, if we have any for (auto it = m_nodes.begin(); it != m_nodes.end(); ) { CNode* pnode = *it; @@ -2201,11 +2179,7 @@ void CConnman::DisconnectNodes() void CConnman::NotifyNumConnectionsChanged(CMasternodeSync& mn_sync) { - size_t nodes_size; - { - LOCK(m_nodes_mutex); - nodes_size = m_nodes.size(); - } + size_t nodes_size = WITH_READ_LOCK(m_nodes_mutex, return m_nodes.size();); // If we had zero connections before and new connections now or if we just dropped // to zero connections reset the sync process if its outdated. @@ -2373,7 +2347,8 @@ void CConnman::SocketHandler(CMasternodeSync& mn_sync) bool only_poll = [this]() { // Check if we have work to do and thus should avoid waiting for events - LOCK2(m_nodes_mutex, cs_sendable_receivable_nodes); + READ_LOCK(m_nodes_mutex); // We acquire this to avoid the pointers stored in mapSendableNodes and mapReceivableNodes being invalidated by ThreadSocketHandler + LOCK(cs_sendable_receivable_nodes); if (!mapReceivableNodes.empty()) { return true; } @@ -2584,7 +2559,7 @@ size_t CConnman::SocketRecvData(CNode *pnode) { bool notify = false; if (!pnode->ReceiveMsgBytes(Span(pchBuf, nBytes), notify)) { - LOCK(m_nodes_mutex); + READ_LOCK(m_nodes_mutex); // is this here for lock ordering? pnode->CloseSocketDisconnect(this); } RecordBytesRecv(nBytes); @@ -2599,7 +2574,7 @@ size_t CConnman::SocketRecvData(CNode *pnode) if (!pnode->fDisconnect) { LogPrint(BCLog::NET, "socket closed for peer=%d\n", pnode->GetId()); } - LOCK(m_nodes_mutex); + READ_LOCK(m_nodes_mutex); // is this here for lock ordering? pnode->fOtherSideDisconnected = true; // avoid lingering pnode->CloseSocketDisconnect(this); } @@ -2612,7 +2587,7 @@ size_t CConnman::SocketRecvData(CNode *pnode) if (!pnode->fDisconnect){ LogPrint(BCLog::NET, "socket recv error for peer=%d: %s\n", pnode->GetId(), NetworkErrorString(nErr)); } - LOCK(m_nodes_mutex); + READ_LOCK(m_nodes_mutex); // is this here for lock ordering? pnode->fOtherSideDisconnected = true; // avoid lingering pnode->CloseSocketDisconnect(this); } @@ -2703,7 +2678,7 @@ void CConnman::ThreadDNSAddressSeed() int nRelevant = 0; { - LOCK(m_nodes_mutex); + READ_LOCK(m_nodes_mutex); for (const CNode* pnode : m_nodes) { if (pnode->fSuccessfullyConnected && !pnode->IsFullOutboundConn() && !pnode->m_masternode_probe_connection) ++nRelevant; } @@ -2828,7 +2803,7 @@ int CConnman::GetExtraFullOutboundCount() const { int full_outbound_peers = 0; { - LOCK(m_nodes_mutex); + READ_LOCK(m_nodes_mutex); for (const CNode* pnode : m_nodes) { // don't count outbound masternodes if (pnode->m_masternode_connection) { @@ -2846,7 +2821,7 @@ int CConnman::GetExtraBlockRelayCount() const { int block_relay_peers = 0; { - LOCK(m_nodes_mutex); + READ_LOCK(m_nodes_mutex); for (const CNode* pnode : m_nodes) { if (pnode->fSuccessfullyConnected && !pnode->fDisconnect && pnode->IsBlockOnlyConn()) { ++block_relay_peers; @@ -2871,7 +2846,7 @@ std::unordered_set CConnman::GetReachableEmptyNetworks() const bool CConnman::MultipleManualOrFullOutboundConns(Network net) const { - AssertLockHeld(m_nodes_mutex); + AssertSharedLockHeld(m_nodes_mutex); return m_network_conn_counts[net] > 1; } @@ -2880,7 +2855,7 @@ bool CConnman::MaybePickPreferredNetwork(std::optional& network) std::array nets{NET_IPV4, NET_IPV6, NET_ONION, NET_I2P, NET_CJDNS}; Shuffle(nets.begin(), nets.end(), FastRandomContext()); - LOCK(m_nodes_mutex); + READ_LOCK(m_nodes_mutex); for (const auto net : nets) { if (g_reachable_nets.Contains(net) && m_network_conn_counts[net] == 0 && addrman.Size(net) != 0) { network = net; @@ -3003,7 +2978,7 @@ void CConnman::ThreadOpenConnections(const std::vector connect, CDe std::set> outbound_ipv46_peer_netgroups; if (!Params().AllowMultipleAddressesFromGroup()) { - LOCK(m_nodes_mutex); + READ_LOCK(m_nodes_mutex); for (const CNode* pnode : m_nodes) { if (pnode->IsFullOutboundConn() && !pnode->m_masternode_connection) nOutboundFullRelay++; if (pnode->IsBlockOnlyConn()) nOutboundBlockRelay++; @@ -3042,8 +3017,8 @@ void CConnman::ThreadOpenConnections(const std::vector connect, CDe std::set setConnectedMasternodes; { - LOCK(m_nodes_mutex); - for (CNode* pnode : m_nodes) { + READ_LOCK(m_nodes_mutex); + for (const CNode* pnode : m_nodes) { auto verifiedProRegTxHash = pnode->GetVerifiedProRegTxHash(); if (!verifiedProRegTxHash.IsNull()) { setConnectedMasternodes.emplace(verifiedProRegTxHash); @@ -3272,7 +3247,7 @@ void CConnman::ThreadOpenConnections(const std::vector connect, CDe std::vector CConnman::GetCurrentBlockRelayOnlyConns() const { std::vector ret; - LOCK(m_nodes_mutex); + READ_LOCK(m_nodes_mutex); for (const CNode* pnode : m_nodes) { if (pnode->IsBlockRelayOnly()) { ret.push_back(pnode->addr); @@ -3298,7 +3273,7 @@ std::vector CConnman::GetAddedNodeInfo(bool include_connected) co std::map mapConnected; std::map> mapConnectedByName; { - LOCK(m_nodes_mutex); + READ_LOCK(m_nodes_mutex); for (const CNode* pnode : m_nodes) { if (pnode->addr.IsValid()) { mapConnected[pnode->addr] = pnode->IsInboundConn(); @@ -3415,40 +3390,47 @@ void CConnman::ThreadOpenMasternodeConnections(CDeterministicMNManager& dmnman, MasternodeProbeConn isProbe = MasternodeProbeConn::IsNotConnection; - const auto getPendingQuorumNodes = [&]() EXCLUSIVE_LOCKS_REQUIRED(cs_vPendingMasternodes) { + const auto getPendingQuorumNodes = [&]() SHARED_LOCKS_REQUIRED(m_nodes_mutex) EXCLUSIVE_LOCKS_REQUIRED(cs_vPendingMasternodes) { + AssertSharedLockHeld(m_nodes_mutex); AssertLockHeld(cs_vPendingMasternodes); std::vector ret; for (const auto& group : masternodeQuorumNodes) { for (const auto& proRegTxHash : group.second) { + if (connectedProRegTxHashes.count(proRegTxHash)) { + continue; + } auto dmn = mnList.GetMN(proRegTxHash); if (!dmn) { continue; } const auto addr2 = dmn->pdmnState->netInfo->GetPrimary(); - if (connectedNodes.count(addr2) && !connectedProRegTxHashes.count(proRegTxHash)) { + CNode* pnode = FindNodeMutable(addr2, /*fExcludeDisconnecting=*/false); + if (pnode && (pnode->m_masternode_connection || pnode->fDisconnect)) { + // node is either a masternode or disconnecting, skip it + continue; + } + if (connectedNodes.count(addr2)) { // we probably connected to it before it became a masternode // or maybe we are still waiting for mnauth - (void)ForNode(addr2, [&](CNode* pnode) { - if (pnode->nTimeFirstMessageReceived.load() != 0s && GetTime() - pnode->nTimeFirstMessageReceived.load() > 5s) { - // clearly not expecting mnauth to take that long even if it wasn't the first message - // we received (as it should normally), disconnect - LogPrint(BCLog::NET_NETCONN, "CConnman::%s -- dropping non-mnauth connection to %s, service=%s\n", _func_, proRegTxHash.ToString(), addr2.ToStringAddrPort()); - pnode->fDisconnect = true; - return true; - } - return false; - }); + bool slow_handshake = pnode && pnode->nTimeFirstMessageReceived.load() != 0s && + GetTime() - pnode->nTimeFirstMessageReceived.load() > 5s; + if (slow_handshake) { + // clearly not expecting mnauth to take that long even if it wasn't the first message + // we received (as it should normally), disconnect + LogPrint(BCLog::NET_NETCONN, "CConnman::%s -- dropping non-mnauth connection to %s, service=%s\n", + _func_, proRegTxHash.ToString(), addr2.ToStringAddrPort()); + pnode->fDisconnect = true; + } // either way - it's not ready, skip it for now continue; } - if (!connectedNodes.count(addr2) && !IsMasternodeOrDisconnectRequested(addr2) && !connectedProRegTxHashes.count(proRegTxHash)) { - int64_t lastAttempt = mn_metaman.GetMetaInfo(dmn->proTxHash)->GetLastOutboundAttempt(); - // back off trying connecting to an address if we already tried recently - if (nANow - lastAttempt < chainParams.LLMQConnectionRetryTimeout()) { - continue; - } - ret.emplace_back(dmn); + // back off connecting to an address if we already tried recently + int64_t last_attempt = mn_metaman.GetLastOutboundAttempt(dmn->proTxHash); + if (nANow - last_attempt < chainParams.LLMQConnectionRetryTimeout()) { + continue; } + // all checks passed + ret.emplace_back(dmn); } } return ret; @@ -3466,14 +3448,14 @@ void CConnman::ThreadOpenMasternodeConnections(CDeterministicMNManager& dmnman, bool connectedAndOutbound = connectedProRegTxHashes.count(dmn->proTxHash) && !connectedProRegTxHashes[dmn->proTxHash]; if (connectedAndOutbound) { // we already have an outbound connection to this MN so there is no theed to probe it again - mn_metaman.GetMetaInfo(dmn->proTxHash)->SetLastOutboundSuccess(nANow); + mn_metaman.SetLastOutboundSuccess(dmn->proTxHash, nANow); it = masternodePendingProbes.erase(it); continue; } ++it; - int64_t lastAttempt = mn_metaman.GetMetaInfo(dmn->proTxHash)->GetLastOutboundAttempt(); + int64_t lastAttempt = mn_metaman.GetLastOutboundAttempt(dmn->proTxHash); // back off trying connecting to an address if we already tried recently if (nANow - lastAttempt < chainParams.LLMQConnectionRetryTimeout()) { continue; @@ -3485,14 +3467,22 @@ void CConnman::ThreadOpenMasternodeConnections(CDeterministicMNManager& dmnman, auto getConnectToDmn = [&]() -> CDeterministicMNCPtr { // don't hold lock while calling OpenMasternodeConnection as cs_main is locked deep inside - LOCK2(m_nodes_mutex, cs_vPendingMasternodes); + READ_LOCK(m_nodes_mutex); + LOCK(cs_vPendingMasternodes); if (!vPendingMasternodes.empty()) { auto dmn = mnList.GetValidMN(vPendingMasternodes.front()); vPendingMasternodes.erase(vPendingMasternodes.begin()); - if (dmn && !connectedNodes.count(dmn->pdmnState->netInfo->GetPrimary()) && !IsMasternodeOrDisconnectRequested(dmn->pdmnState->netInfo->GetPrimary())) { - LogPrint(BCLog::NET_NETCONN, "CConnman::%s -- opening pending masternode connection to %s, service=%s\n", _func_, dmn->proTxHash.ToString(), dmn->pdmnState->netInfo->GetPrimary().ToStringAddrPort()); - return dmn; + // Check if we should connect to this masternode + // We already hold m_nodes_mutex here, so check m_masternode_connection directly + if (dmn && !connectedNodes.count(dmn->pdmnState->netInfo->GetPrimary())) { + const CNode* pnode = FindNode(dmn->pdmnState->netInfo->GetPrimary(), /*fExcludeDisconnecting=*/false); + if (pnode == nullptr || (!pnode->m_masternode_connection && !pnode->fDisconnect)) { + LogPrint(BCLog::NET_NETCONN, "CConnman::%s -- opening pending masternode connection to %s, service=%s\n", + _func_, dmn->proTxHash.ToString(), + dmn->pdmnState->netInfo->GetPrimary().ToStringAddrPort()); + return dmn; + } } } @@ -3524,11 +3514,11 @@ void CConnman::ThreadOpenMasternodeConnections(CDeterministicMNManager& dmnman, didConnect = true; - mn_metaman.GetMetaInfo(connectToDmn->proTxHash)->SetLastOutboundAttempt(nANow); + mn_metaman.SetLastOutboundAttempt(connectToDmn->proTxHash, nANow); OpenMasternodeConnection(CAddress(connectToDmn->pdmnState->netInfo->GetPrimary(), NODE_NETWORK), /*use_v2transport=*/GetLocalServices() & NODE_P2P_V2, isProbe); // should be in the list now if connection was opened - bool connected = ForNode(connectToDmn->pdmnState->netInfo->GetPrimary(), CConnman::AllNodes, [&](CNode* pnode) { + bool connected = ForNode(connectToDmn->pdmnState->netInfo->GetPrimary(), CConnman::AllNodes, [&](const CNode* pnode) { if (pnode->fDisconnect) { return false; } @@ -3537,7 +3527,7 @@ void CConnman::ThreadOpenMasternodeConnections(CDeterministicMNManager& dmnman, if (!connected) { LogPrint(BCLog::NET_NETCONN, "CConnman::%s -- connection failed for masternode %s, service=%s\n", __func__, connectToDmn->proTxHash.ToString(), connectToDmn->pdmnState->netInfo->GetPrimary().ToStringAddrPort()); // Will take a few consequent failed attempts to PoSe-punish a MN. - if (mn_metaman.GetMetaInfo(connectToDmn->proTxHash)->OutboundFailedTooManyTimes()) { + if (mn_metaman.OutboundFailedTooManyTimes(connectToDmn->proTxHash)) { LogPrint(BCLog::NET_NETCONN, "CConnman::%s -- failed to connect to masternode %s too many times\n", __func__, connectToDmn->proTxHash.ToString()); } } @@ -3578,8 +3568,9 @@ void CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFai if (addrConnect.GetPort() == GetListenPort() && IsLocal(addrConnect)) { return; } - } else if (FindNode(std::string(pszDest))) + } else if (ExistsNode(std::string(pszDest))) { return; + } LogPrint(BCLog::NET_NETCONN, "CConnman::%s -- connecting to %s\n", __func__, getIpStr()); CNode* pnode = ConnectNode(addrConnect, pszDest, fCountFailure, conn_type, use_v2transport); @@ -4064,7 +4055,7 @@ bool CConnman::Start(CDeterministicMNManager& dmnman, CMasternodeMetaMan& mn_met class CNetCleanup { public: - CNetCleanup() {} + CNetCleanup() = default; ~CNetCleanup() { @@ -4348,25 +4339,28 @@ Uint256HashSet CConnman::GetMasternodeQuorums(Consensus::LLMQType llmqType) cons return result; } -std::unordered_set CConnman::GetMasternodeQuorumNodes(Consensus::LLMQType llmqType, const uint256& quorumHash) const +std::vector CConnman::GetMasternodeQuorumNodes(Consensus::LLMQType llmqType, const uint256& quorumHash) const { - LOCK2(m_nodes_mutex, cs_vPendingMasternodes); + READ_LOCK(m_nodes_mutex); + LOCK(cs_vPendingMasternodes); auto it = masternodeQuorumNodes.find(std::make_pair(llmqType, quorumHash)); if (it == masternodeQuorumNodes.end()) { return {}; } const auto& proRegTxHashes = it->second; - std::unordered_set nodes; - for (const auto pnode : m_nodes) { - if (pnode->fDisconnect) { - continue; - } - auto verifiedProRegTxHash = pnode->GetVerifiedProRegTxHash(); - if (!pnode->qwatch && (verifiedProRegTxHash.IsNull() || !proRegTxHashes.count(verifiedProRegTxHash))) { - continue; - } - nodes.emplace(pnode->GetId()); + std::vector nodes; + + auto IsMasternodeQuorumNode = [&](const CNode* n) { + if (n->fDisconnect) return false; + const auto h = n->GetVerifiedProRegTxHash(); + return n->qwatch || (!h.IsNull() && proRegTxHashes.contains(h)); + }; + + for (NodeId id : m_nodes + | std::views::filter(IsMasternodeQuorumNode) + | std::views::transform([](const CNode* n){ return n->GetId(); })) { + nodes.push_back(id); } return nodes; } @@ -4429,7 +4423,7 @@ void CConnman::AddPendingProbeConnections(const std::set &proTxHashes) size_t CConnman::GetNodeCount(ConnectionDirection flags) const { - LOCK(m_nodes_mutex); + READ_LOCK(m_nodes_mutex); int nNum = 0; for (const auto& pnode : m_nodes) { @@ -4468,9 +4462,9 @@ size_t CConnman::GetMaxOutboundOnionNodeCount() void CConnman::GetNodeStats(std::vector& vstats) const { vstats.clear(); - LOCK(m_nodes_mutex); + READ_LOCK(m_nodes_mutex); vstats.reserve(m_nodes.size()); - for (CNode* pnode : m_nodes) { + for (const CNode* pnode : m_nodes) { if (pnode->fDisconnect) { continue; } @@ -4482,19 +4476,17 @@ void CConnman::GetNodeStats(std::vector& vstats) const bool CConnman::DisconnectNode(const std::string& strNode) { - LOCK(m_nodes_mutex); - if (CNode* pnode = FindNode(strNode)) { + return WithNodeMutable(strNode, [&](CNode* pnode){ LogPrint(BCLog::NET_NETCONN, "disconnect by address%s matched peer=%d; disconnecting\n", (fLogIPs ? strprintf("=%s", strNode) : ""), pnode->GetId()); pnode->fDisconnect = true; return true; - } - return false; + }).value_or(false); } bool CConnman::DisconnectNode(const CSubNet& subnet) { bool disconnected = false; - LOCK(m_nodes_mutex); + READ_LOCK(m_nodes_mutex); for (CNode* pnode : m_nodes) { if (subnet.Match(pnode->addr)) { LogPrint(BCLog::NET_NETCONN, "disconnect by subnet%s matched peer=%d; disconnecting\n", (fLogIPs ? strprintf("=%s", subnet.ToString()) : ""), pnode->GetId()); @@ -4512,15 +4504,11 @@ bool CConnman::DisconnectNode(const CNetAddr& addr) bool CConnman::DisconnectNode(NodeId id) { - LOCK(m_nodes_mutex); - for(CNode* pnode : m_nodes) { - if (id == pnode->GetId()) { - LogPrint(BCLog::NET_NETCONN, "disconnect by id peer=%d; disconnecting\n", pnode->GetId()); - pnode->fDisconnect = true; - return true; - } - } - return false; + return WithNodeMutable(id, [&](CNode* pnode){ + LogPrint(BCLog::NET_NETCONN, "disconnect by id peer=%d; disconnecting\n", pnode->GetId()); + pnode->fDisconnect = true; + return true; + }).value_or(false); } void CConnman::RecordBytesRecv(uint64_t bytes) @@ -4685,31 +4673,79 @@ void CNode::MarkReceivedMsgsForProcessing() { AssertLockNotHeld(m_msg_process_queue_mutex); - size_t nSizeAdded = 0; - for (const auto& msg : vRecvMsg) { + size_t nQuorumSizeAdded = 0; + size_t nNormalSizeAdded = 0; + std::list quorumMsgs; + std::list normalMsgs; + + // Classify messages into quorum-priority and normal queues + for (auto it = vRecvMsg.begin(); it != vRecvMsg.end();) { + auto& msg = *it; // vRecvMsg contains only completed CNetMessage // the single possible partially deserialized message are held by TransportDeserializer - nSizeAdded += msg.m_raw_message_size; + if (IsQuorumPriorityMessage(msg.m_type)) { + quorumMsgs.splice(quorumMsgs.end(), vRecvMsg, it++); + nQuorumSizeAdded += msg.m_raw_message_size; + } else { + normalMsgs.splice(normalMsgs.end(), vRecvMsg, it++); + nNormalSizeAdded += msg.m_raw_message_size; + } } LOCK(m_msg_process_queue_mutex); - m_msg_process_queue.splice(m_msg_process_queue.end(), vRecvMsg); - m_msg_process_queue_size += nSizeAdded; - fPauseRecv = m_msg_process_queue_size > m_recv_flood_size; + // Splice classified messages into appropriate queues + m_msg_quorum_queue.splice(m_msg_quorum_queue.end(), quorumMsgs); + m_msg_quorum_queue_size += nQuorumSizeAdded; + m_msg_process_queue.splice(m_msg_process_queue.end(), normalMsgs); + m_msg_process_queue_size += nNormalSizeAdded; + // Compute backpressure over combined size of both queues + fPauseRecv = (m_msg_quorum_queue_size + m_msg_process_queue_size) > m_recv_flood_size; } std::optional> CNode::PollMessage() { LOCK(m_msg_process_queue_mutex); + + // Ratio-based processing: process N quorum messages for every 1 normal message + // This ensures forward progress for both queues while strongly prioritizing quorum messages + // However, if normal queue is empty, process quorum messages in bursts (like old algorithm) + constexpr size_t QUORUM_TO_NORMAL_RATIO = 100; + + // Check if we should process normal queue for forward progress + // Only apply ratio when both queues have messages to allow burst processing when normal queue is empty + bool skip_quorum_processing = !m_msg_process_queue.empty() && + m_quorum_msg_count_since_normal >= QUORUM_TO_NORMAL_RATIO; + + // Prioritize quorum queue: pop from it first if non-empty and ratio not reached + // If normal queue is empty, process quorum messages without ratio limit (burst mode) + if (!m_msg_quorum_queue.empty() && !skip_quorum_processing) { + std::list msgs; + // Just take one message from quorum queue + msgs.splice(msgs.begin(), m_msg_quorum_queue, m_msg_quorum_queue.begin()); + m_msg_quorum_queue_size -= msgs.front().m_raw_message_size; + // Only increment counter if normal queue has messages (to track ratio) + // If normal queue is empty, don't increment so we can process bursts quickly + if (!m_msg_process_queue.empty()) { + ++m_quorum_msg_count_since_normal; + } + // Compute backpressure over combined size of both queues + fPauseRecv = (m_msg_quorum_queue_size + m_msg_process_queue_size) > m_recv_flood_size; + // Return true for 'more' if either queue has remaining messages + return std::make_pair(std::move(msgs.front()), !m_msg_quorum_queue.empty() || !m_msg_process_queue.empty()); + } + + // Process normal queue (either because quorum queue is empty or ratio reached) if (m_msg_process_queue.empty()) return std::nullopt; std::list msgs; // Just take one message msgs.splice(msgs.begin(), m_msg_process_queue, m_msg_process_queue.begin()); m_msg_process_queue_size -= msgs.front().m_raw_message_size; - fPauseRecv = m_msg_process_queue_size > m_recv_flood_size; + m_quorum_msg_count_since_normal = 0; // Reset counter after processing normal message + // Compute backpressure over combined size of both queues + fPauseRecv = (m_msg_quorum_queue_size + m_msg_process_queue_size) > m_recv_flood_size; - return std::make_pair(std::move(msgs.front()), !m_msg_process_queue.empty()); + return std::make_pair(std::move(msgs.front()), !m_msg_quorum_queue.empty() || !m_msg_process_queue.empty()); } bool CConnman::NodeFullyConnected(const CNode* pnode) @@ -4770,32 +4806,35 @@ void CConnman::PushMessage(CNode* pnode, CSerializedNetMsg&& msg) bool CConnman::ForNode(const CService& addr, std::function cond, std::function func) { - CNode* found = nullptr; - LOCK(m_nodes_mutex); - for (auto&& pnode : m_nodes) { - if((CService)pnode->addr == addr) { - found = pnode; - break; - } - } + READ_LOCK(m_nodes_mutex); + CNode* found = FindNodeMutable(addr, false); + return found != nullptr && cond(found) && func(found); +} + +bool CConnman::ForNode(const CService& addr, std::function cond, std::function func) const +{ + READ_LOCK(m_nodes_mutex); + const CNode* found = FindNode(addr, false); return found != nullptr && cond(found) && func(found); } bool CConnman::ForNode(NodeId id, std::function cond, std::function func) { - CNode* found = nullptr; - LOCK(m_nodes_mutex); - for (auto&& pnode : m_nodes) { - if(pnode->GetId() == id) { - found = pnode; - break; - } - } + READ_LOCK(m_nodes_mutex); + CNode* found = FindNodeMutable(id, false); + return found != nullptr && cond(found) && func(found); +} + +bool CConnman::ForNode(NodeId id, std::function cond, std::function func) const +{ + READ_LOCK(m_nodes_mutex); + const CNode* found = FindNode(id, false); return found != nullptr && cond(found) && func(found); } -bool CConnman::IsMasternodeOrDisconnectRequested(const CService& addr) { - return ForNode(addr, AllNodes, [](CNode* pnode){ +bool CConnman::IsMasternodeOrDisconnectRequested(const CService& addr) const +{ + return ForNode(addr, AllNodes, [](const CNode* pnode){ return pnode->m_masternode_connection || pnode->fDisconnect; }); } @@ -4804,7 +4843,7 @@ CConnman::NodesSnapshot::NodesSnapshot(const CConnman& connman, std::function #include #include +#include #include #include @@ -61,6 +62,7 @@ class CMasternodeSync; class CNode; class CScheduler; struct bilingual_str; +struct NodeEvictionCandidate; /** Default for -whitelistrelay. */ static const bool DEFAULT_WHITELISTRELAY = true; @@ -199,7 +201,7 @@ struct LocalServiceInfo { uint16_t nPort; }; -extern Mutex g_maplocalhost_mutex; +extern GlobalMutex g_maplocalhost_mutex; extern std::map mapLocalHost GUARDED_BY(g_maplocalhost_mutex); extern const std::string NET_MESSAGE_TYPE_OTHER; @@ -730,9 +732,9 @@ class CNode /** Messages still to be fed to m_transport->SetMessageToSend. */ std::deque vSendMsg GUARDED_BY(cs_vSend); std::atomic nSendMsgSize{0}; - Mutex cs_vSend; + mutable Mutex cs_vSend; Mutex m_sock_mutex; - Mutex cs_vRecv; + mutable Mutex cs_vRecv; uint64_t nRecvBytes GUARDED_BY(cs_vRecv){0}; @@ -755,7 +757,7 @@ class CNode const bool m_inbound_onion; std::atomic nNumWarningsSkipped{0}; std::atomic nVersion{0}; - Mutex m_subver_mutex; + mutable Mutex m_subver_mutex; /** * cleanSubVer is a sanitized string of the user agent byte array we read * from the wire. This cleaned string can safely be logged or displayed. @@ -1027,7 +1029,7 @@ class CNode void CloseSocketDisconnect(CConnman* connman) EXCLUSIVE_LOCKS_REQUIRED(!m_sock_mutex); - void CopyStats(CNodeStats& stats) EXCLUSIVE_LOCKS_REQUIRED(!m_subver_mutex, !m_addr_local_mutex, !cs_vSend, !cs_vRecv); + void CopyStats(CNodeStats& stats) const EXCLUSIVE_LOCKS_REQUIRED(!m_subver_mutex, !m_addr_local_mutex, !cs_vSend, !cs_vRecv, !cs_mnauth); std::string ConnectionTypeAsString() const { return ::ConnectionTypeAsString(m_conn_type); } @@ -1041,42 +1043,42 @@ class CNode bool CanRelay() const { return !m_masternode_connection || m_masternode_iqr_connection; } - uint256 GetSentMNAuthChallenge() const { + uint256 GetSentMNAuthChallenge() const EXCLUSIVE_LOCKS_REQUIRED(!cs_mnauth) { LOCK(cs_mnauth); return sentMNAuthChallenge; } - uint256 GetReceivedMNAuthChallenge() const { + uint256 GetReceivedMNAuthChallenge() const EXCLUSIVE_LOCKS_REQUIRED(!cs_mnauth) { LOCK(cs_mnauth); return receivedMNAuthChallenge; } - uint256 GetVerifiedProRegTxHash() const { + uint256 GetVerifiedProRegTxHash() const EXCLUSIVE_LOCKS_REQUIRED(!cs_mnauth) { LOCK(cs_mnauth); return verifiedProRegTxHash; } - uint256 GetVerifiedPubKeyHash() const { + uint256 GetVerifiedPubKeyHash() const EXCLUSIVE_LOCKS_REQUIRED(!cs_mnauth) { LOCK(cs_mnauth); return verifiedPubKeyHash; } - void SetSentMNAuthChallenge(const uint256& newSentMNAuthChallenge) { + void SetSentMNAuthChallenge(const uint256& newSentMNAuthChallenge) EXCLUSIVE_LOCKS_REQUIRED(!cs_mnauth) { LOCK(cs_mnauth); sentMNAuthChallenge = newSentMNAuthChallenge; } - void SetReceivedMNAuthChallenge(const uint256& newReceivedMNAuthChallenge) { + void SetReceivedMNAuthChallenge(const uint256& newReceivedMNAuthChallenge) EXCLUSIVE_LOCKS_REQUIRED(!cs_mnauth) { LOCK(cs_mnauth); receivedMNAuthChallenge = newReceivedMNAuthChallenge; } - void SetVerifiedProRegTxHash(const uint256& newVerifiedProRegTxHash) { + void SetVerifiedProRegTxHash(const uint256& newVerifiedProRegTxHash) EXCLUSIVE_LOCKS_REQUIRED(!cs_mnauth) { LOCK(cs_mnauth); verifiedProRegTxHash = newVerifiedProRegTxHash; } - void SetVerifiedPubKeyHash(const uint256& newVerifiedPubKeyHash) { + void SetVerifiedPubKeyHash(const uint256& newVerifiedPubKeyHash) EXCLUSIVE_LOCKS_REQUIRED(!cs_mnauth) { LOCK(cs_mnauth); verifiedPubKeyHash = newVerifiedPubKeyHash; } @@ -1092,6 +1094,9 @@ class CNode Mutex m_msg_process_queue_mutex; std::list m_msg_process_queue GUARDED_BY(m_msg_process_queue_mutex); size_t m_msg_process_queue_size GUARDED_BY(m_msg_process_queue_mutex){0}; + std::list m_msg_quorum_queue GUARDED_BY(m_msg_process_queue_mutex); + size_t m_msg_quorum_queue_size GUARDED_BY(m_msg_process_queue_mutex){0}; + size_t m_quorum_msg_count_since_normal GUARDED_BY(m_msg_process_queue_mutex){0}; // Our address, as reported by the peer CService addrLocal GUARDED_BY(m_addr_local_mutex); @@ -1244,8 +1249,8 @@ friend class CNode; EXCLUSIVE_LOCKS_REQUIRED(!m_total_bytes_sent_mutex, !m_added_nodes_mutex, !m_addr_fetches_mutex, !mutexMsgProc); void StopThreads(); - void StopNodes(); - void Stop() + void StopNodes() EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex, !cs_mapSocketToNode, !cs_sendable_receivable_nodes); + void Stop() EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex, !cs_mapSocketToNode, !cs_sendable_receivable_nodes) { StopThreads(); StopNodes(); @@ -1274,13 +1279,13 @@ friend class CNode; const char* strDest, ConnectionType conn_type, bool use_v2transport, MasternodeConn masternode_connection = MasternodeConn::IsNotConnection, MasternodeProbeConn masternode_probe_connection = MasternodeProbeConn::IsNotConnection) - EXCLUSIVE_LOCKS_REQUIRED(!m_unused_i2p_sessions_mutex, !mutexMsgProc); + EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex, !m_unused_i2p_sessions_mutex, !mutexMsgProc, !cs_mapSocketToNode); void OpenMasternodeConnection(const CAddress& addrConnect, bool use_v2transport, MasternodeProbeConn probe = MasternodeProbeConn::IsConnection) - EXCLUSIVE_LOCKS_REQUIRED(!m_unused_i2p_sessions_mutex, !mutexMsgProc); - bool CheckIncomingNonce(uint64_t nonce); + EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex, !m_unused_i2p_sessions_mutex, !mutexMsgProc, !cs_mapSocketToNode); + bool CheckIncomingNonce(uint64_t nonce) const EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex); // alias for thread safety annotations only, not defined - RecursiveMutex& GetNodesMutex() const LOCK_RETURNED(m_nodes_mutex); + SharedMutex& GetNodesMutex() const LOCK_RETURNED(m_nodes_mutex); struct CFullyConnectedOnly { bool operator() (const CNode* pnode) const { @@ -1296,39 +1301,41 @@ friend class CNode; constexpr static const CAllNodes AllNodes{}; - bool ForNode(NodeId id, std::function cond, std::function func); - bool ForNode(const CService& addr, std::function cond, std::function func); + bool ForNode(NodeId id, std::function cond, std::function func) EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex); + bool ForNode(NodeId id, std::function cond, std::function func) const EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex); + bool ForNode(const CService& addr, std::function cond, std::function func) EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex); + bool ForNode(const CService& addr, std::function cond, std::function func) const EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex); template - bool ForNode(const CService& addr, Callable&& func) + bool ForNode(const CService& addr, Callable&& func) EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex) { return ForNode(addr, FullyConnectedOnly, func); } template - bool ForNode(NodeId id, Callable&& func) + bool ForNode(NodeId id, Callable&& func) EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex) { return ForNode(id, FullyConnectedOnly, func); } using NodeFn = std::function; - bool IsConnected(const CService& addr, std::function cond) + bool IsConnected(const CService& addr, std::function cond) EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex) { - return ForNode(addr, cond, [](CNode* pnode){ + return ForNode(addr, cond, [](const CNode* pnode){ return true; }); } - bool IsMasternodeOrDisconnectRequested(const CService& addr); + bool IsMasternodeOrDisconnectRequested(const CService& addr) const EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex); void PushMessage(CNode* pnode, CSerializedNetMsg&& msg) EXCLUSIVE_LOCKS_REQUIRED(!mutexMsgProc, !m_total_bytes_sent_mutex); template - bool ForEachNodeContinueIf(const Condition& cond, Callable&& func) + bool ForEachNodeContinueIf(const Condition& cond, Callable&& func) EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex) { - LOCK(m_nodes_mutex); + READ_LOCK(m_nodes_mutex); for (auto&& node : m_nodes) if (cond(node)) if(!func(node)) @@ -1337,15 +1344,15 @@ friend class CNode; }; template - bool ForEachNodeContinueIf(Callable&& func) + bool ForEachNodeContinueIf(Callable&& func) EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex) { return ForEachNodeContinueIf(FullyConnectedOnly, func); } template - bool ForEachNodeContinueIf(const Condition& cond, Callable&& func) const + bool ForEachNodeContinueIf(const Condition& cond, Callable&& func) const EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex) { - LOCK(m_nodes_mutex); + READ_LOCK(m_nodes_mutex); for (const auto& node : m_nodes) if (cond(node)) if(!func(node)) @@ -1354,62 +1361,41 @@ friend class CNode; }; template - bool ForEachNodeContinueIf(Callable&& func) const + bool ForEachNodeContinueIf(Callable&& func) const EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex) { return ForEachNodeContinueIf(FullyConnectedOnly, func); } - template - void ForEachNode(const Condition& cond, Callable&& func) - { - LOCK(m_nodes_mutex); - for (auto&& node : m_nodes) { - if (cond(node)) - func(node); - } - }; - - void ForEachNode(const NodeFn& fn) + void ForEachNode(const NodeFn& fn) EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex) { ForEachNode(FullyConnectedOnly, fn); } template - void ForEachNode(const Condition& cond, Callable&& func) const + void ForEachNode(const Condition& cond, Callable&& func) const EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex) { - LOCK(m_nodes_mutex); + READ_LOCK(m_nodes_mutex); for (auto&& node : m_nodes) { if (cond(node)) func(node); } }; - void ForEachNode(const NodeFn& fn) const + void ForEachNode(const NodeFn& fn) const EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex) { ForEachNode(FullyConnectedOnly, fn); } - template - void ForEachNodeThen(const Condition& cond, Callable&& pre, CallableAfter&& post) - { - LOCK(m_nodes_mutex); - for (auto&& node : m_nodes) { - if (cond(node)) - pre(node); - } - post(); - }; - template - void ForEachNodeThen(Callable&& pre, CallableAfter&& post) + void ForEachNodeThen(Callable&& pre, CallableAfter&& post) EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex) { ForEachNodeThen(FullyConnectedOnly, pre, post); } template - void ForEachNodeThen(const Condition& cond, Callable&& pre, CallableAfter&& post) const + void ForEachNodeThen(const Condition& cond, Callable&& pre, CallableAfter&& post) const EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex) { - LOCK(m_nodes_mutex); + READ_LOCK(m_nodes_mutex); for (auto&& node : m_nodes) { if (cond(node)) pre(node); @@ -1418,7 +1404,7 @@ friend class CNode; }; template - void ForEachNodeThen(Callable&& pre, CallableAfter&& post) const + void ForEachNodeThen(Callable&& pre, CallableAfter&& post) const EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex) { ForEachNodeThen(FullyConnectedOnly, pre, post); } @@ -1454,14 +1440,15 @@ friend class CNode; // return a value less than (num_outbound_connections - num_outbound_slots) // in cases where some outbound connections are not yet fully connected, or // not yet fully disconnected. - int GetExtraFullOutboundCount() const; + int GetExtraFullOutboundCount() const EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex); // Count the number of block-relay-only peers we have over our limit. - int GetExtraBlockRelayCount() const; + int GetExtraBlockRelayCount() const EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex); bool AddNode(const AddedNodeParams& add) EXCLUSIVE_LOCKS_REQUIRED(!m_added_nodes_mutex); bool RemoveAddedNode(const std::string& node) EXCLUSIVE_LOCKS_REQUIRED(!m_added_nodes_mutex); bool AddedNodesContain(const CAddress& addr) const EXCLUSIVE_LOCKS_REQUIRED(!m_added_nodes_mutex); - std::vector GetAddedNodeInfo(bool include_connected) const EXCLUSIVE_LOCKS_REQUIRED(!m_added_nodes_mutex); + std::vector GetAddedNodeInfo(bool include_connected) const + EXCLUSIVE_LOCKS_REQUIRED(!m_added_nodes_mutex, !m_nodes_mutex); /** * Attempts to open a connection. Currently only used from tests. @@ -1477,29 +1464,29 @@ friend class CNode; * - Max connection capacity for type is filled */ bool AddConnection(const std::string& address, ConnectionType conn_type, bool use_v2transport) - EXCLUSIVE_LOCKS_REQUIRED(!m_unused_i2p_sessions_mutex, !mutexMsgProc); + EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex, !m_unused_i2p_sessions_mutex, !mutexMsgProc, !cs_mapSocketToNode); bool AddPendingMasternode(const uint256& proTxHash); void SetMasternodeQuorumNodes(Consensus::LLMQType llmqType, const uint256& quorumHash, const Uint256HashSet& proTxHashes); - void SetMasternodeQuorumRelayMembers(Consensus::LLMQType llmqType, const uint256& quorumHash, const Uint256HashSet& proTxHashes); + void SetMasternodeQuorumRelayMembers(Consensus::LLMQType llmqType, const uint256& quorumHash, const Uint256HashSet& proTxHashes) EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex); bool HasMasternodeQuorumNodes(Consensus::LLMQType llmqType, const uint256& quorumHash) const; Uint256HashSet GetMasternodeQuorums(Consensus::LLMQType llmqType) const; // also returns QWATCH nodes - std::unordered_set GetMasternodeQuorumNodes(Consensus::LLMQType llmqType, const uint256& quorumHash) const; + std::vector GetMasternodeQuorumNodes(Consensus::LLMQType llmqType, const uint256& quorumHash) const EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex); void RemoveMasternodeQuorumNodes(Consensus::LLMQType llmqType, const uint256& quorumHash); bool IsMasternodeQuorumNode(const CNode* pnode, const CDeterministicMNList& tip_mn_list) const; bool IsMasternodeQuorumRelayMember(const uint256& protxHash); void AddPendingProbeConnections(const std::set& proTxHashes); - size_t GetNodeCount(ConnectionDirection) const; + size_t GetNodeCount(ConnectionDirection) const EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex); std::map getNetLocalAddresses() const; size_t GetMaxOutboundNodeCount(); size_t GetMaxOutboundOnionNodeCount(); - void GetNodeStats(std::vector& vstats) const; - bool DisconnectNode(const std::string& node); - bool DisconnectNode(const CSubNet& subnet); - bool DisconnectNode(const CNetAddr& addr); - bool DisconnectNode(NodeId id); + void GetNodeStats(std::vector& vstats) const EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex); + bool DisconnectNode(const std::string& node) EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex); + bool DisconnectNode(const CSubNet& subnet) EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex); + bool DisconnectNode(const CNetAddr& addr) EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex); + bool DisconnectNode(NodeId id) EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex); //! Used to convey which local services we are offering peers during node //! connection. @@ -1534,7 +1521,7 @@ friend class CNode; /** Return true if we should disconnect the peer for failing an inactivity check. */ bool ShouldRunInactivityChecks(const CNode& node, std::chrono::seconds now) const; - bool MultipleManualOrFullOutboundConns(Network net) const EXCLUSIVE_LOCKS_REQUIRED(m_nodes_mutex); + bool MultipleManualOrFullOutboundConns(Network net) const SHARED_LOCKS_REQUIRED(m_nodes_mutex); /** * RAII helper to atomically create a copy of `m_nodes` and add a reference @@ -1544,7 +1531,8 @@ friend class CNode; { public: explicit NodesSnapshot(const CConnman& connman, std::function cond = AllNodes, - bool shuffle = false); + bool shuffle = false) + EXCLUSIVE_LOCKS_REQUIRED(!connman.m_nodes_mutex); ~NodesSnapshot(); const std::vector& Nodes() const @@ -1579,16 +1567,19 @@ friend class CNode; bool InitBinds(const Options& options); void ThreadOpenAddedConnections() - EXCLUSIVE_LOCKS_REQUIRED(!m_added_nodes_mutex, !m_unused_i2p_sessions_mutex, !m_reconnections_mutex, !mutexMsgProc); + EXCLUSIVE_LOCKS_REQUIRED(!m_added_nodes_mutex, !m_nodes_mutex, !m_reconnections_mutex, + !m_unused_i2p_sessions_mutex, !mutexMsgProc, !cs_mapSocketToNode); 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, !mutexMsgProc); + EXCLUSIVE_LOCKS_REQUIRED(!m_addr_fetches_mutex, !m_nodes_mutex, !m_unused_i2p_sessions_mutex, + !mutexMsgProc, !cs_mapSocketToNode); void ThreadOpenConnections(const std::vector connect, CDeterministicMNManager& dmnman) - EXCLUSIVE_LOCKS_REQUIRED(!m_addr_fetches_mutex, !m_added_nodes_mutex, !m_nodes_mutex, !m_unused_i2p_sessions_mutex, !m_reconnections_mutex, !mutexMsgProc); - void ThreadMessageHandler() EXCLUSIVE_LOCKS_REQUIRED(!mutexMsgProc); - void ThreadI2PAcceptIncoming(CMasternodeSync& mn_sync) EXCLUSIVE_LOCKS_REQUIRED(!mutexMsgProc); + EXCLUSIVE_LOCKS_REQUIRED(!m_addr_fetches_mutex, !m_added_nodes_mutex, !m_nodes_mutex, !m_reconnections_mutex, + !m_unused_i2p_sessions_mutex, !mutexMsgProc, !cs_mapSocketToNode); + void ThreadMessageHandler() EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex, !mutexMsgProc); + void ThreadI2PAcceptIncoming(CMasternodeSync& mn_sync) EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex, !mutexMsgProc, !cs_mapSocketToNode); void AcceptConnection(const ListenSocket& hListenSocket, CMasternodeSync& mn_sync) - EXCLUSIVE_LOCKS_REQUIRED(!mutexMsgProc); + EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex, !mutexMsgProc, !cs_mapSocketToNode); /** * Create a `CNode` object from a socket that has just been accepted and add the node to @@ -1602,11 +1593,12 @@ friend class CNode; NetPermissionFlags permission_flags, const CAddress& addr_bind, const CAddress& addr, - CMasternodeSync& mn_sync) EXCLUSIVE_LOCKS_REQUIRED(!mutexMsgProc); + CMasternodeSync& mn_sync) + EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex, !mutexMsgProc, !cs_mapSocketToNode); void DisconnectNodes() EXCLUSIVE_LOCKS_REQUIRED(!m_reconnections_mutex, !m_nodes_mutex); - void NotifyNumConnectionsChanged(CMasternodeSync& mn_sync); - void CalculateNumConnectionsChangedStats(); + void NotifyNumConnectionsChanged(CMasternodeSync& mn_sync) EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex); + void CalculateNumConnectionsChangedStats() EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex); /** Return true if the peer is inactive and should be disconnected. */ bool InactivityCheck(const CNode& node) const; @@ -1620,43 +1612,98 @@ friend class CNode; /** * Check connected and listening sockets for IO readiness and process them accordingly. */ - void SocketHandler(CMasternodeSync& mn_sync) EXCLUSIVE_LOCKS_REQUIRED(!m_total_bytes_sent_mutex, !mutexMsgProc); + void SocketHandler(CMasternodeSync& mn_sync) EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex, !m_total_bytes_sent_mutex, !mutexMsgProc, !cs_mapSocketToNode, !cs_sendable_receivable_nodes); /** * Do the read/write for connected sockets that are ready for IO. * @param[in] events_per_sock Sockets that are ready for IO. */ void SocketHandlerConnected(const Sock::EventsPerSock& events_per_sock) - EXCLUSIVE_LOCKS_REQUIRED(!m_total_bytes_sent_mutex, !mutexMsgProc); + EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex, !m_total_bytes_sent_mutex, !mutexMsgProc, !cs_sendable_receivable_nodes, !cs_mapSocketToNode); /** * Accept incoming connections, one from each read-ready listening socket. * @param[in] events_per_sock Sockets that are ready for IO. */ void SocketHandlerListening(const Sock::EventsPerSock& events_per_sock, CMasternodeSync& mn_sync) - EXCLUSIVE_LOCKS_REQUIRED(!mutexMsgProc); + EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex, !mutexMsgProc, !cs_mapSocketToNode); void ThreadSocketHandler(CMasternodeSync& mn_sync) - EXCLUSIVE_LOCKS_REQUIRED(!m_total_bytes_sent_mutex, !mutexMsgProc, !m_nodes_mutex, !m_reconnections_mutex); + EXCLUSIVE_LOCKS_REQUIRED(!m_total_bytes_sent_mutex, !mutexMsgProc, !m_nodes_mutex, !m_reconnections_mutex, !cs_mapSocketToNode, !cs_sendable_receivable_nodes); void ThreadDNSAddressSeed() EXCLUSIVE_LOCKS_REQUIRED(!m_addr_fetches_mutex, !m_nodes_mutex); void ThreadOpenMasternodeConnections(CDeterministicMNManager& dmnman, CMasternodeMetaMan& mn_metaman, CMasternodeSync& mn_sync) - EXCLUSIVE_LOCKS_REQUIRED(!m_addr_fetches_mutex, !m_nodes_mutex, !m_unused_i2p_sessions_mutex, !mutexMsgProc); + EXCLUSIVE_LOCKS_REQUIRED(!m_addr_fetches_mutex, !m_nodes_mutex, !m_unused_i2p_sessions_mutex, !mutexMsgProc, !cs_mapSocketToNode); uint64_t CalculateKeyedNetGroup(const CAddress& ad) const; - CNode* FindNode(const CNetAddr& ip, bool fExcludeDisconnecting = true); - CNode* FindNode(const std::string& addrName, bool fExcludeDisconnecting = true); - CNode* FindNode(const CService& addr, bool fExcludeDisconnecting = true); + // Type-agnostic node matching helpers + static inline bool NodeMatches(const CNode* p, const CService& addr) + { + return static_cast(p->addr) == addr; + } + static inline bool NodeMatches(const CNode* p, const CNetAddr& ip) + { + return static_cast(p->addr) == ip; + } + static inline bool NodeMatches(const CNode* p, const std::string& addrName) + { + return p->m_addr_name == addrName; + } + static inline bool NodeMatches(const CNode* p, const NodeId id) + { + return p->GetId() == id; + } + + template + const CNode* FindNode(const Key& key, bool fExcludeDisconnecting = true) const SHARED_LOCKS_REQUIRED(m_nodes_mutex) + { + AssertSharedLockHeld(m_nodes_mutex); + for (const CNode* pnode : m_nodes) { + if (fExcludeDisconnecting && pnode->fDisconnect) continue; + if (NodeMatches(pnode, key)) return pnode; + } + return nullptr; + } + + template + CNode* FindNodeMutable(const Key& key, bool fExcludeDisconnecting = true) SHARED_LOCKS_REQUIRED(m_nodes_mutex) + { + AssertSharedLockHeld(m_nodes_mutex); + for (CNode* pnode : m_nodes) { + if (fExcludeDisconnecting && pnode->fDisconnect) continue; + if (NodeMatches(pnode, key)) return pnode; + } + return nullptr; + } + + // Callback helpers with explicit lock semantics (templated on key type) + // Lambda-based shared accessor returning optional result (nullopt = not found) + template + std::optional> WithNodeMutable(const Key& key, Callable&& fn) EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex) + { + READ_LOCK(m_nodes_mutex); + if (CNode* p = FindNodeMutable(key)) return std::optional>{fn(p)}; + return std::nullopt; + } + + // Fast existence check under shared lock + template + bool ExistsNode(const Key& key) const EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex) + { + READ_LOCK(m_nodes_mutex); + return FindNode(key) != nullptr; + } /** * Determine whether we're already connected to a given address, in order to * avoid initiating duplicate connections. */ - bool AlreadyConnectedToAddress(const CAddress& addr); + bool AlreadyConnectedToAddress(const CAddress& addr) const EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex); - bool AttemptToEvictConnection(); - CNode* ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure, ConnectionType conn_type, bool use_v2transport) EXCLUSIVE_LOCKS_REQUIRED(!m_unused_i2p_sessions_mutex); + std::vector GetEvictionCandidates() const EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex); + bool AttemptToEvictConnection() EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex); + CNode* ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure, ConnectionType conn_type, bool use_v2transport) EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex, !m_unused_i2p_sessions_mutex); void AddWhitelistPermissionFlags(NetPermissionFlags& flags, const CNetAddr &addr) const; void DeleteNode(CNode* pnode); @@ -1666,7 +1713,7 @@ friend class CNode; /** (Try to) send data from node's vSendMsg. Returns (bytes_sent, data_left). */ std::pair SocketSendData(CNode& node) const EXCLUSIVE_LOCKS_REQUIRED(node.cs_vSend); - size_t SocketRecvData(CNode* pnode) EXCLUSIVE_LOCKS_REQUIRED(!mutexMsgProc); + size_t SocketRecvData(CNode* pnode) EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex, !mutexMsgProc); void DumpAddresses(); @@ -1683,7 +1730,7 @@ friend class CNode; /** * Return vector of current BLOCK_RELAY peers. */ - std::vector GetCurrentBlockRelayOnlyConns() const; + std::vector GetCurrentBlockRelayOnlyConns() const EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex); /** * Search for a "preferred" network, a reachable network to which we @@ -1695,7 +1742,7 @@ friend class CNode; * * @return bool Whether a preferred network was found. */ - bool MaybePickPreferredNetwork(std::optional& network); + bool MaybePickPreferredNetwork(std::optional& network) EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex); // Whether the node should be passed out in ForEach* callbacks static bool NodeFullyConnected(const CNode* pnode); @@ -1735,12 +1782,12 @@ friend class CNode; mutable Mutex m_added_nodes_mutex; std::vector m_nodes GUARDED_BY(m_nodes_mutex); std::list m_nodes_disconnected; - mutable RecursiveMutex m_nodes_mutex; + mutable SharedMutex m_nodes_mutex; std::atomic nLastNodeId{0}; unsigned int nPrevNodeCount{0}; // Stores number of full-tx connections (outbound and manual) per network - std::array m_network_conn_counts GUARDED_BY(m_nodes_mutex) = {}; + std::array m_network_conn_counts GUARDED_BY(m_nodes_mutex) = {}; // TODO consider moving this to seperate mutex std::vector vPendingMasternodes; mutable RecursiveMutex cs_vPendingMasternodes; @@ -1934,7 +1981,7 @@ friend class CNode; std::list m_reconnections GUARDED_BY(m_reconnections_mutex); /** Attempt reconnections, if m_reconnections non-empty. */ - void PerformReconnections() EXCLUSIVE_LOCKS_REQUIRED(!mutexMsgProc, !m_reconnections_mutex, !m_unused_i2p_sessions_mutex); + void PerformReconnections() EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex, !mutexMsgProc, !m_reconnections_mutex, !m_unused_i2p_sessions_mutex, !cs_mapSocketToNode); /** * Cap on the size of `m_unused_i2p_sessions`, to ensure it does not @@ -1958,4 +2005,24 @@ class CExplicitNetCleanup static void callCleanup(); }; +// Helper function to determine if a message type should be prioritized in the quorum queue +inline bool IsQuorumPriorityMessage(const std::string& msg_type) +{ + // LLMQ signing/data messages + if (msg_type == NetMsgType::QSIGSHARE || + msg_type == NetMsgType::QBSIGSHARES || + msg_type == NetMsgType::QSIGSHARESINV || + msg_type == NetMsgType::QGETSIGSHARES || + msg_type == NetMsgType::QSIGSESANN || + msg_type == NetMsgType::QSIGREC) { + return true; + } + // High-level lock messages (ChainLocks, InstantSend locks) + if (msg_type == NetMsgType::CLSIG || + msg_type == NetMsgType::ISDLOCK) { + return true; + } + return false; +} + #endif // BITCOIN_NET_H diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 7e474e4cdd2a..9808fb9f646a 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -14,11 +14,11 @@ #include #include #include -#include +#include #include -#include -#include #include +#include +#include #include #include #include @@ -31,42 +31,24 @@ #include #include #include -#include #include #include #include -#include #include -#include +#include #include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#ifdef ENABLE_WALLET -#include -#endif // ENABLE_WALLET -#include -#include +#include +#include #include +#include +#include #include #include #include -#include +#include #include +#include #include #include #include @@ -77,9 +59,23 @@ #include #include #include - +#include +#include +#include +#include +#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include + using node::ReadBlockFromDisk; using node::fImporting; using node::fPruneMode; @@ -324,7 +320,7 @@ struct Peer { /** * (Bitcoin) Initializes a TxRelay struct for this peer. Can be called at most once for a peer. * (Dash) Enables the flag that allows GetTxRelay() to return m_tx_relay */ - TxRelay* SetTxRelay() LOCKS_EXCLUDED(m_tx_relay_mutex) + TxRelay* SetTxRelay() EXCLUSIVE_LOCKS_REQUIRED(!m_tx_relay_mutex) { LOCK(m_tx_relay_mutex); Assume(!m_can_tx_relay); @@ -332,17 +328,17 @@ struct Peer { return m_tx_relay.get(); }; - TxRelay* GetInvRelay() LOCKS_EXCLUDED(m_tx_relay_mutex) + TxRelay* GetInvRelay() EXCLUSIVE_LOCKS_REQUIRED(!m_tx_relay_mutex) { return WITH_LOCK(m_tx_relay_mutex, return m_tx_relay.get()); } - TxRelay* GetTxRelay() LOCKS_EXCLUDED(m_tx_relay_mutex) + TxRelay* GetTxRelay() EXCLUSIVE_LOCKS_REQUIRED(!m_tx_relay_mutex) { LOCK(m_tx_relay_mutex); return m_can_tx_relay ? m_tx_relay.get() : nullptr; }; - const TxRelay* GetTxRelay() const LOCKS_EXCLUDED(m_tx_relay_mutex) + const TxRelay* GetTxRelay() const EXCLUSIVE_LOCKS_REQUIRED(!m_tx_relay_mutex) { LOCK(m_tx_relay_mutex); return m_can_tx_relay ? m_tx_relay.get() : nullptr; @@ -416,7 +412,7 @@ struct Peer { std::deque m_getdata_requests GUARDED_BY(m_getdata_requests_mutex); /** Time of the last getheaders message to this peer */ - std::atomic m_last_getheaders_timestamp GUARDED_BY(NetEventsInterface::g_msgproc_mutex){0s}; + NodeClock::time_point m_last_getheaders_timestamp GUARDED_BY(NetEventsInterface::g_msgproc_mutex){}; explicit Peer(NodeId id, ServiceFlags our_services) : m_id(id) @@ -592,15 +588,17 @@ class PeerManagerImpl final : public PeerManager { public: PeerManagerImpl(const CChainParams& chainparams, CConnman& connman, AddrMan& addrman, BanMan* banman, - ChainstateManager& chainman, CTxMemPool& pool, - CMasternodeMetaMan& mn_metaman, CMasternodeSync& mn_sync, - CGovernanceManager& govman, CSporkManager& sporkman, - const CActiveMasternodeManager* const mn_activeman, + CDSTXManager& dstxman, ChainstateManager& chainman, CTxMemPool& pool, + CMasternodeMetaMan& mn_metaman, CMasternodeSync& mn_sync, CGovernanceManager& govman, + CSporkManager& sporkman, const CActiveMasternodeManager* const mn_activeman, const std::unique_ptr& dmnman, - const std::unique_ptr& active_ctx, - const std::unique_ptr& cj_ctx, - const std::unique_ptr& llmq_ctx, - bool ignore_incoming_txs); + const std::unique_ptr& active_ctx, CJWalletManager* const cj_walletman, + const std::unique_ptr& llmq_ctx, bool ignore_incoming_txs); + + ~PeerManagerImpl() + { + RemoveHandlers(); + } /** Overridden from CValidationInterface. */ void BlockConnected(const std::shared_ptr& pblock, const CBlockIndex* pindexConnected) override @@ -611,15 +609,16 @@ class PeerManagerImpl final : public PeerManager EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); void BlockChecked(const CBlock& block, const BlockValidationState& state) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); - void NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr& pblock) override; + void NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr& pblock) override + 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); bool ProcessMessages(CNode* pfrom, std::atomic& interrupt) override - EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, !m_recent_confirmed_transactions_mutex, g_msgproc_mutex); + EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, !m_recent_confirmed_transactions_mutex, !m_most_recent_block_mutex, g_msgproc_mutex); bool SendMessages(CNode* pto) override - EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, !m_recent_confirmed_transactions_mutex, g_msgproc_mutex); + EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, !m_recent_confirmed_transactions_mutex, !m_most_recent_block_mutex, g_msgproc_mutex); /** Implement PeerManager */ void StartScheduledTasks(CScheduler& scheduler) override; @@ -639,24 +638,39 @@ class PeerManagerImpl final : public PeerManager void Misbehaving(const NodeId pnode, const int howmuch, const std::string& message = "") override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); void ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRecv, const std::chrono::microseconds time_received, const std::atomic& interruptMsgProc) override - EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, !m_recent_confirmed_transactions_mutex, g_msgproc_mutex); + EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, !m_recent_confirmed_transactions_mutex, !m_most_recent_block_mutex, g_msgproc_mutex); void UpdateLastBlockAnnounceTime(NodeId node, int64_t time_in_seconds) override; bool IsBanned(NodeId pnode) override EXCLUSIVE_LOCKS_REQUIRED(cs_main, !m_peer_mutex); size_t GetRequestedObjectCount(NodeId nodeid) const override EXCLUSIVE_LOCKS_REQUIRED(::cs_main); + + /** Implements external handlers logic */ + void AddExtraHandler(std::unique_ptr&& handler) override; + void RemoveHandlers() override; + void StartHandlers() override; + void StopHandlers() override; + void InterruptHandlers() override; + + /** Implement PeerManagerInternal */ + void PeerMisbehaving(const NodeId pnode, const int howmuch, const std::string& message = "") override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); + void PeerEraseObjectRequest(const NodeId nodeid, const CInv& inv) override EXCLUSIVE_LOCKS_REQUIRED(::cs_main); + void PeerRelayInv(const CInv& inv) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); + void PeerRelayInvFiltered(const CInv& inv, const CTransaction& relatedTx) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); + void PeerRelayInvFiltered(const CInv& inv, const uint256& relatedTxHash) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); + void PeerAskPeersForTransaction(const uint256& txid) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); private: - void _RelayTransaction(const uint256& txid) EXCLUSIVE_LOCKS_REQUIRED(cs_main); + void _RelayTransaction(const uint256& txid) EXCLUSIVE_LOCKS_REQUIRED(cs_main, !m_peer_mutex); /** Ask peers that have a transaction in their inventory to relay it to us. */ void AskPeersForTransaction(const uint256& txid) EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); /** Relay inventories to peers that find it relevant */ - void RelayInvFiltered(const CInv& inv, const CTransaction& relatedTx, const int minProtoVersion) EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); + void RelayInvFiltered(const CInv& inv, const CTransaction& relatedTx) EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); /** * This overload will not update node filters, use it only for the cases * when other messages will update related transaction data in filters */ - void RelayInvFiltered(const CInv& inv, const uint256& relatedTxHash, const int minProtoVersion) EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); + void RelayInvFiltered(const CInv& inv, const uint256& relatedTxHash) EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); void EraseObjectRequest(NodeId nodeid, const CInv& inv) EXCLUSIVE_LOCKS_REQUIRED(::cs_main); @@ -789,12 +803,14 @@ class PeerManagerImpl final : public PeerManager AddrMan& m_addrman; /** Pointer to this node's banman. May be nullptr - check existence before dereferencing. */ BanMan* const m_banman; + CDSTXManager& m_dstxman; ChainstateManager& m_chainman; CTxMemPool& m_mempool; std::unique_ptr m_txreconciliation; const std::unique_ptr& m_dmnman; const std::unique_ptr& m_active_ctx; - const std::unique_ptr& m_cj_ctx; + /** Pointer to this node's CJWalletManager. May be nullptr - check existence before dereferencing. */ + CJWalletManager* const m_cj_walletman; const std::unique_ptr& m_llmq_ctx; CMasternodeMetaMan& m_mn_metaman; CMasternodeSync& m_mn_sync; @@ -819,7 +835,7 @@ class PeerManagerImpl final : public PeerManager /** Protects m_peer_map. This mutex must not be locked while holding a lock * on any of the mutexes inside a Peer object. */ - mutable Mutex m_peer_mutex; + mutable SharedMutex m_peer_mutex; /** * Map of all Peer objects, keyed by peer id. This map is protected * by the m_peer_mutex. Once a shared pointer reference is @@ -852,7 +868,7 @@ class PeerManagerImpl final : public PeerManager */ 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, llmq::CInstantSendManager& isman); + void ProcessGetBlockData(CNode& pfrom, Peer& peer, const CInv& inv, llmq::CInstantSendManager& isman) EXCLUSIVE_LOCKS_REQUIRED(!m_most_recent_block_mutex); /** * Validation logic for compact filters request handling. @@ -1034,7 +1050,8 @@ class PeerManagerImpl final : public PeerManager /** Determine whether or not a peer can request a transaction, and return it (or nullptr if not found or not allowed). */ CTransactionRef FindTxForGetData(const CNode* peer, const uint256& txid, const std::chrono::seconds mempool_req, const std::chrono::seconds now) LOCKS_EXCLUDED(cs_main); - void ProcessGetData(CNode& pfrom, Peer& peer, const std::atomic& interruptMsgProc) EXCLUSIVE_LOCKS_REQUIRED(peer.m_getdata_requests_mutex) LOCKS_EXCLUDED(::cs_main); + void ProcessGetData(CNode& pfrom, Peer& peer, const std::atomic& interruptMsgProc) + EXCLUSIVE_LOCKS_REQUIRED(!m_most_recent_block_mutex, peer.m_getdata_requests_mutex) LOCKS_EXCLUDED(::cs_main); /** Process a new block. Perform any post-processing housekeeping */ void ProcessBlock(CNode& from, const std::shared_ptr& pblock, bool force_processing); @@ -1070,6 +1087,8 @@ class PeerManagerImpl final : public PeerManager std::vector> vExtraTxnForCompact GUARDED_BY(g_msgproc_mutex); /** Offset into vExtraTxnForCompact to insert the next tx */ size_t vExtraTxnForCompactIt GUARDED_BY(g_msgproc_mutex) = 0; + + std::vector> m_handlers; }; // Keeps track of the time (in microseconds) when transactions were requested last time @@ -1169,6 +1188,13 @@ static void PushInv(Peer& peer, const CInv& inv) return; } + // Skip ISDLOCK inv announcements for peers that want recsigs, as they can reconstruct + // the islock from the recsig + if (inv.type == MSG_ISDLOCK && peer.m_wants_recsigs) { + LogPrint(BCLog::NET, "%s -- skipping ISDLOCK inv (peer wants recsigs): %s peer=%d\n", __func__, inv.ToString(), peer.m_id); + return; + } + LOCK(inv_relay->m_tx_inventory_mutex); if (inv_relay->m_tx_inventory_known_filter.contains(inv.hash)) { LogPrint(BCLog::NET, "%s -- skipping known inv: %s peer=%d\n", __func__, inv.ToString(), peer.m_id); @@ -1299,23 +1325,23 @@ void PeerManagerImpl::MaybeSetPeerAsAnnouncingHeaderAndIDs(NodeId nodeid) } m_connman.ForNode(nodeid, [this](CNode* pfrom) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) { AssertLockHeld(::cs_main); - if (lNodesAnnouncingHeaderAndIDs.size() >= 3) { - // As per BIP152, we only get 3 of our peers to announce - // blocks using compact encodings. - m_connman.ForNode(lNodesAnnouncingHeaderAndIDs.front(), [this](CNode* pnodeStop){ - m_connman.PushMessage(pnodeStop, CNetMsgMaker(pnodeStop->GetCommonVersion()).Make(NetMsgType::SENDCMPCT, /*high_bandwidth=*/false, /*version=*/CMPCTBLOCKS_VERSION)); - // save BIP152 bandwidth state: we select peer to be low-bandwidth - pnodeStop->m_bip152_highbandwidth_to = false; - return true; - }); - lNodesAnnouncingHeaderAndIDs.pop_front(); - } m_connman.PushMessage(pfrom, CNetMsgMaker(pfrom->GetCommonVersion()).Make(NetMsgType::SENDCMPCT, /*high_bandwidth=*/true, /*version=*/CMPCTBLOCKS_VERSION)); // save BIP152 bandwidth state: we select peer to be high-bandwidth pfrom->m_bip152_highbandwidth_to = true; lNodesAnnouncingHeaderAndIDs.push_back(pfrom->GetId()); return true; }); + if (lNodesAnnouncingHeaderAndIDs.size() > 3) { + // As per BIP152, we only get 3 of our peers to announce + // blocks using compact encodings. + m_connman.ForNode(lNodesAnnouncingHeaderAndIDs.front(), [this](CNode* pnodeStop){ + m_connman.PushMessage(pnodeStop, CNetMsgMaker(pnodeStop->GetCommonVersion()).Make(NetMsgType::SENDCMPCT, /*high_bandwidth=*/false, /*version=*/CMPCTBLOCKS_VERSION)); + // save BIP152 bandwidth state: we select peer to be low-bandwidth + pnodeStop->m_bip152_highbandwidth_to = false; + return true; + }); + lNodesAnnouncingHeaderAndIDs.pop_front(); + } } bool PeerManagerImpl::TipMayBeStale() @@ -1628,6 +1654,46 @@ size_t PeerManagerImpl::GetRequestedObjectCount(NodeId nodeid) const return state->m_object_download.m_object_process_time.size(); } +void PeerManagerImpl::AddExtraHandler(std::unique_ptr&& handler) +{ + assert(handler != nullptr); + if (auto i = dynamic_cast(handler.get()); i != nullptr) { + RegisterValidationInterface(i); + } + m_handlers.emplace_back(std::move(handler)); +} + +void PeerManagerImpl::RemoveHandlers() +{ + InterruptHandlers(); + StopHandlers(); + m_handlers.clear(); +} + +void PeerManagerImpl::StartHandlers() +{ + for (auto& handler : m_handlers) { + handler->Start(); + } +} + +void PeerManagerImpl::StopHandlers() +{ + for (auto& handler : m_handlers) { + if (auto i = dynamic_cast(handler.get()); i != nullptr) { + UnregisterValidationInterface(i); + } + handler->Stop(); + } +} + +void PeerManagerImpl::InterruptHandlers() +{ + for (auto& handler : m_handlers) { + handler->Interrupt(); + } +} + void PeerManagerImpl::UpdateLastBlockAnnounceTime(NodeId node, int64_t time_in_seconds) { LOCK(cs_main); @@ -1728,7 +1794,7 @@ void PeerManagerImpl::FinalizeNode(const CNode& node) { PeerRef PeerManagerImpl::GetPeerRef(NodeId id) const { - LOCK(m_peer_mutex); + READ_LOCK(m_peer_mutex); auto it = m_peer_map.find(id); return it != m_peer_map.end() ? it->second : nullptr; } @@ -1938,6 +2004,8 @@ std::optional PeerManagerImpl::FetchBlock(NodeId peer_id, const CBl LOCK(cs_main); // Mark block as in-flight unless it already is (for this peer). + // If the peer does not send us a block, vBlocksInFlight remains non-empty, + // causing us to timeout and disconnect. // If a block was already in-flight for a different peer, its BLOCKTXN // response will be dropped. if (!BlockRequested(peer_id, block_index)) return "Already requested from this peer"; @@ -1960,38 +2028,38 @@ std::optional PeerManagerImpl::FetchBlock(NodeId peer_id, const CBl return std::nullopt; } -std::unique_ptr PeerManager::make(const CChainParams& chainparams, CConnman& connman, AddrMan& addrman, BanMan* banman, - ChainstateManager& chainman, CTxMemPool& pool, - CMasternodeMetaMan& mn_metaman, CMasternodeSync& mn_sync, - CGovernanceManager& govman, CSporkManager& sporkman, +std::unique_ptr PeerManager::make(const CChainParams& chainparams, CConnman& connman, AddrMan& addrman, + BanMan* banman, CDSTXManager& dstxman, ChainstateManager& chainman, + CTxMemPool& pool, CMasternodeMetaMan& mn_metaman, + CMasternodeSync& mn_sync, CGovernanceManager& govman, + CSporkManager& sporkman, const CActiveMasternodeManager* const mn_activeman, const std::unique_ptr& dmnman, const std::unique_ptr& active_ctx, - const std::unique_ptr& cj_ctx, + CJWalletManager* const cj_walletman, const std::unique_ptr& llmq_ctx, bool ignore_incoming_txs) { - return std::make_unique(chainparams, connman, addrman, banman, chainman, pool, mn_metaman, mn_sync, govman, sporkman, mn_activeman, dmnman, active_ctx, cj_ctx, llmq_ctx, ignore_incoming_txs); + return std::make_unique(chainparams, connman, addrman, banman, dstxman, chainman, pool, mn_metaman, mn_sync, govman, sporkman, mn_activeman, dmnman, active_ctx, cj_walletman, llmq_ctx, ignore_incoming_txs); } PeerManagerImpl::PeerManagerImpl(const CChainParams& chainparams, CConnman& connman, AddrMan& addrman, BanMan* banman, - ChainstateManager& chainman, CTxMemPool& pool, - CMasternodeMetaMan& mn_metaman, CMasternodeSync& mn_sync, - CGovernanceManager& govman, CSporkManager& sporkman, - const CActiveMasternodeManager* const mn_activeman, + CDSTXManager& dstxman, ChainstateManager& chainman, CTxMemPool& pool, + CMasternodeMetaMan& mn_metaman, CMasternodeSync& mn_sync, CGovernanceManager& govman, + CSporkManager& sporkman, const CActiveMasternodeManager* const mn_activeman, const std::unique_ptr& dmnman, const std::unique_ptr& active_ctx, - const std::unique_ptr& cj_ctx, - const std::unique_ptr& llmq_ctx, - bool ignore_incoming_txs) + CJWalletManager* const cj_walletman, + const std::unique_ptr& llmq_ctx, bool ignore_incoming_txs) : m_chainparams(chainparams), m_connman(connman), m_addrman(addrman), m_banman(banman), + m_dstxman(dstxman), m_chainman(chainman), m_mempool(pool), m_dmnman(dmnman), m_active_ctx(active_ctx), - m_cj_ctx(cj_ctx), + m_cj_walletman(cj_walletman), m_llmq_ctx(llmq_ctx), m_mn_metaman(mn_metaman), m_mn_sync(mn_sync), @@ -2242,7 +2310,7 @@ bool PeerManagerImpl::AlreadyHave(const CInv& inv) m_llmq_ctx->isman->IsLocked(inv.hash); return (!fIgnoreRecentRejects && m_recent_rejects.contains(inv.hash)) || - (inv.IsMsgDstx() && static_cast(m_cj_ctx->dstxman->GetDSTX(inv.hash))) || + (inv.IsMsgDstx() && static_cast(m_dstxman.GetDSTX(inv.hash))) || m_mempool.exists(inv.hash) || (g_txindex != nullptr && g_txindex->HasTx(inv.hash)); } @@ -2280,11 +2348,7 @@ bool PeerManagerImpl::AlreadyHave(const CInv& inv) case MSG_ISDLOCK: return m_llmq_ctx->isman->AlreadyHave(inv); case MSG_DSQ: - return -#ifdef ENABLE_WALLET - (m_cj_ctx->queueman && m_cj_ctx->queueman->HasQueue(inv.hash)) || -#endif // ENABLE_WALLET - (m_active_ctx && m_active_ctx->cj_server->HasQueue(inv.hash)); + return (m_cj_walletman && m_cj_walletman->hasQueue(inv.hash)) || (m_active_ctx && m_active_ctx->cj_server->HasQueue(inv.hash)); case MSG_PLATFORM_BAN: return m_mn_metaman.AlreadyHavePlatformBan(inv.hash); } @@ -2301,7 +2365,7 @@ bool PeerManagerImpl::AlreadyHaveBlock(const uint256& block_hash) void PeerManagerImpl::SendPings() { - LOCK(m_peer_mutex); + READ_LOCK(m_peer_mutex); for(auto& it : m_peer_map) it.second->m_ping_queued = true; } @@ -2311,7 +2375,7 @@ void PeerManagerImpl::AskPeersForTransaction(const uint256& txid) peersToAsk.reserve(4); { - LOCK(m_peer_mutex); + READ_LOCK(m_peer_mutex); // TODO consider prioritizing MNs again, once that flag is moved into Peer for (const auto& [_, peer] : m_peer_map) { if (peersToAsk.size() >= 4) { @@ -2367,7 +2431,7 @@ void PeerManagerImpl::RelayInv(const CInv& inv, const int minProtoVersion) void PeerManagerImpl::RelayInv(const CInv& inv) { - LOCK(m_peer_mutex); + READ_LOCK(m_peer_mutex); for (const auto& [_, peer] : m_peer_map) { if (!peer->GetInvRelay()) continue; PushInv(*peer, inv); @@ -2379,7 +2443,7 @@ void PeerManagerImpl::RelayDSQ(const CCoinJoinQueue& queue) CInv inv{MSG_DSQ, queue.GetHash()}; std::vector nodes_send_all; { - LOCK(m_peer_mutex); + READ_LOCK(m_peer_mutex); for (const auto& [nodeid, peer] : m_peer_map) { switch (peer->m_wants_dsq) { case Peer::WantsDSQ::NONE: @@ -2402,15 +2466,17 @@ void PeerManagerImpl::RelayDSQ(const CCoinJoinQueue& queue) } } -void PeerManagerImpl::RelayInvFiltered(const CInv& inv, const CTransaction& relatedTx, const int minProtoVersion) +void PeerManagerImpl::RelayInvFiltered(const CInv& inv, const CTransaction& relatedTx) { // TODO: Migrate to iteration through m_peer_map m_connman.ForEachNode([&](CNode* pnode) { + if (!pnode->CanRelay()) return; + PeerRef peer = GetPeerRef(pnode->GetId()); if (peer == nullptr) return; auto tx_relay = peer->GetTxRelay(); - if (pnode->nVersion < minProtoVersion || !pnode->CanRelay() || tx_relay == nullptr) { + if (tx_relay == nullptr) { return; } @@ -2427,7 +2493,7 @@ void PeerManagerImpl::RelayInvFiltered(const CInv& inv, const CTransaction& rela }); } -void PeerManagerImpl::RelayInvFiltered(const CInv& inv, const uint256& relatedTxHash, const int minProtoVersion) +void PeerManagerImpl::RelayInvFiltered(const CInv& inv, const uint256& relatedTxHash) { // TODO: Migrate to iteration through m_peer_map m_connman.ForEachNode([&](CNode* pnode) { @@ -2435,7 +2501,7 @@ void PeerManagerImpl::RelayInvFiltered(const CInv& inv, const uint256& relatedTx if (peer == nullptr) return; auto tx_relay = peer->GetTxRelay(); - if (pnode->nVersion < minProtoVersion || !pnode->CanRelay() || tx_relay == nullptr) { + if (!pnode->CanRelay() || tx_relay == nullptr) { return; } @@ -2459,8 +2525,8 @@ void PeerManagerImpl::RelayTransaction(const uint256& txid) void PeerManagerImpl::_RelayTransaction(const uint256& txid) { - const CInv inv{m_cj_ctx->dstxman->GetDSTX(txid) ? MSG_DSTX : MSG_TX, txid}; - LOCK(m_peer_mutex); + const CInv inv{m_dstxman.GetDSTX(txid) ? MSG_DSTX : MSG_TX, txid}; + READ_LOCK(m_peer_mutex); for(auto& it : m_peer_map) { Peer& peer = *it.second; auto tx_relay = peer.GetTxRelay(); @@ -2473,7 +2539,7 @@ void PeerManagerImpl::_RelayTransaction(const uint256& txid) void PeerManagerImpl::RelayRecoveredSig(const uint256& sigHash) { const CInv inv{MSG_QUORUM_RECOVERED_SIG, sigHash}; - LOCK(m_peer_mutex); + READ_LOCK(m_peer_mutex); for (const auto& [_, peer] : m_peer_map) { if (peer->m_wants_recsigs) { PushInv(*peer, inv); @@ -2511,7 +2577,7 @@ void PeerManagerImpl::RelayAddress(NodeId originator, std::array, 2> best{{{0, nullptr}, {0, nullptr}}}; assert(nRelayNodes <= best.size()); - LOCK(m_peer_mutex); + READ_LOCK(m_peer_mutex); for (auto& [id, peer] : m_peer_map) { if (peer->m_addr_relay_enabled && id != originator && IsAddrCompatible(*peer, addr)) { @@ -2751,7 +2817,7 @@ void PeerManagerImpl::ProcessGetData(CNode& pfrom, Peer& peer, const std::atomic if (tx) { CCoinJoinBroadcastTx dstx; if (inv.IsMsgDstx()) { - dstx = m_cj_ctx->dstxman->GetDSTX(inv.hash); + dstx = m_dstxman.GetDSTX(inv.hash); } if (dstx) { m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::DSTX, dstx)); @@ -2765,9 +2831,9 @@ void PeerManagerImpl::ProcessGetData(CNode& pfrom, Peer& peer, const std::atomic std::vector parent_ids_to_add; { LOCK(m_mempool.cs); - auto txiter = m_mempool.GetIter(tx->GetHash()); - if (txiter) { - const CTxMemPoolEntry::Parents& parents = (*txiter)->GetMemPoolParentsConst(); + auto tx_iter = m_mempool.GetIter(tx->GetHash()); + if (tx_iter) { + const CTxMemPoolEntry::Parents& parents = (*tx_iter)->GetMemPoolParentsConst(); parent_ids_to_add.reserve(parents.size()); for (const CTxMemPoolEntry& parent : parents) { if (parent.GetTime() > now - UNCONDITIONAL_RELAY_DELAY) { @@ -2890,11 +2956,9 @@ void PeerManagerImpl::ProcessGetData(CNode& pfrom, Peer& peer, const std::atomic } if (!push && inv.type == MSG_DSQ) { auto opt_dsq = m_active_ctx ? m_active_ctx->cj_server->GetQueueFromHash(inv.hash) : std::nullopt; -#ifdef ENABLE_WALLET - if (m_cj_ctx->queueman && !opt_dsq.has_value()) { - opt_dsq = m_cj_ctx->queueman->GetQueueFromHash(inv.hash); + if (m_cj_walletman && !opt_dsq.has_value()) { + opt_dsq = m_cj_walletman->getQueueFromHash(inv.hash); } -#endif if (opt_dsq.has_value()) { m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::DSQUEUE, *opt_dsq)); push = true; @@ -3017,10 +3081,11 @@ bool PeerManagerImpl::MaybeSendGetHeaders(CNode& pfrom, const std::string& msg_t const CNetMsgMaker msgMaker(pfrom.GetCommonVersion()); - const auto current_time = GetTime(); + const auto current_time = NodeClock::now(); + // Only allow a new getheaders message to go out if we don't have a recent // one already in-flight - if (peer.m_last_getheaders_timestamp.load() < current_time - HEADERS_RESPONSE_TIME) { + if (current_time - peer.m_last_getheaders_timestamp > HEADERS_RESPONSE_TIME) { m_connman.PushMessage(&pfrom, msgMaker.Make(msg_type, locator, uint256())); peer.m_last_getheaders_timestamp = current_time; return true; @@ -3477,7 +3542,7 @@ std::pair static ValidateDSTX(CDeterministicMN return {false, true}; } - if (!mn_metaman.GetMetaInfo(dmn->proTxHash)->IsValidForMixingTxes()) { + if (!mn_metaman.IsValidForMixingTxes(dmn->proTxHash)) { LogPrint(BCLog::COINJOIN, "DSTX -- Masternode %s is sending too many transactions %s\n", dstx.masternodeOutpoint.ToStringShort(), hashTx.ToString()); return {true, true}; // TODO: Not an error? Could it be that someone is relaying old DSTXes @@ -3522,18 +3587,8 @@ void PeerManagerImpl::PostProcessMessage(MessageProcessingResult&& result, NodeI for (const auto& inv : result.m_inventory) { RelayInv(inv); } - if (result.m_inv_filter) { - const auto& [inv, filter] = result.m_inv_filter.value(); - if (std::holds_alternative(filter)) { - RelayInvFiltered(inv, *std::get(filter), ISDLOCK_PROTO_VERSION); - } else if (std::holds_alternative(filter)) { - RelayInvFiltered(inv, std::get(filter), ISDLOCK_PROTO_VERSION); - } else { - assert(false); - } - } - if (result.m_request_tx) { - AskPeersForTransaction(result.m_request_tx.value()); + for (const auto& dsq : result.m_dsq) { + RelayDSQ(dsq); } } @@ -3605,10 +3660,8 @@ MessageProcessingResult PeerManagerImpl::ProcessPlatformBanMessage(NodeId node, } // At this point, the outgoing message serialization version can't change. - const auto meta_info = m_mn_metaman.GetMetaInfo(ban_msg.m_protx_hash); - if (meta_info->SetPlatformBan(true, ban_msg.m_requested_height)) { - LogPrintf("PLATFORMBAN -- forward message to other nodes\n"); - m_mn_metaman.RememberPlatformBan(hash, std::move(ban_msg)); + if (m_mn_metaman.SetPlatformBan(hash, std::move(ban_msg))) { + LogPrintf("PLATFORMBAN -- hash: %s forward message to other nodes\n", hash.ToString()); ret.m_inventory.emplace_back(MSG_PLATFORM_BAN, hash); } return ret; @@ -4565,7 +4618,7 @@ void PeerManagerImpl::ProcessMessage( if (nInvType == MSG_DSTX) { // Validate DSTX and return bRet if we need to return from here uint256 hashTx = tx.GetHash(); - const auto& [bRet, bDoReturn] = ValidateDSTX(*m_dmnman, *(m_cj_ctx->dstxman), m_chainman, m_mn_metaman, m_mempool, dstx, hashTx); + const auto& [bRet, bDoReturn] = ValidateDSTX(*m_dmnman, m_dstxman, m_chainman, m_mn_metaman, m_mempool, dstx, hashTx); if (bDoReturn) { return; } @@ -4597,7 +4650,7 @@ void PeerManagerImpl::ProcessMessage( if (nInvType == MSG_DSTX) { LogPrint(BCLog::COINJOIN, "DSTX -- Masternode transaction accepted, txid=%s, peer=%d\n", tx.GetHash().ToString(), pfrom.GetId()); - m_cj_ctx->dstxman->AddDSTX(dstx); + m_dstxman.AddDSTX(dstx); } _RelayTransaction(tx.GetHash()); @@ -4706,6 +4759,7 @@ void PeerManagerImpl::ProcessMessage( vRecv >> cmpctblock; bool received_new_header = false; + const auto blockhash = cmpctblock.header.GetHash(); { LOCK(cs_main); @@ -4719,7 +4773,7 @@ void PeerManagerImpl::ProcessMessage( return; } - if (!m_chainman.m_blockman.LookupBlockIndex(cmpctblock.header.GetHash())) { + if (!m_chainman.m_blockman.LookupBlockIndex(blockhash)) { received_new_header = true; } } @@ -4733,6 +4787,11 @@ void PeerManagerImpl::ProcessMessage( } } + if (received_new_header) { + LogPrintfCategory(BCLog::NET, "Saw new cmpctblock header hash=%s peer=%d\n", + blockhash.ToString(), pfrom.GetId()); + } + // When we succeed in decoding a block's txids from a cmpctblock // message we typically jump to the BLOCKTXN handling code, with a // dummy (empty) BLOCKTXN message, to re-use the logic there in @@ -4775,7 +4834,7 @@ void PeerManagerImpl::ProcessMessage( // We requested this block for some reason, but our mempool will probably be useless // so we just grab the block via normal getdata std::vector vInv(1); - vInv[0] = CInv(MSG_BLOCK, cmpctblock.header.GetHash()); + vInv[0] = CInv(MSG_BLOCK, blockhash); m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETDATA, vInv)); } return; @@ -4810,7 +4869,7 @@ void PeerManagerImpl::ProcessMessage( } else if (status == READ_STATUS_FAILED) { // Duplicate txindexes, the block is now in-flight, so just request it std::vector vInv(1); - vInv[0] = CInv(MSG_BLOCK, cmpctblock.header.GetHash()); + vInv[0] = CInv(MSG_BLOCK, blockhash); m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETDATA, vInv)); return; } @@ -4823,7 +4882,7 @@ void PeerManagerImpl::ProcessMessage( if (req.indexes.empty()) { // Dirty hack to jump to BLOCKTXN code (TODO: move message handling into their own functions) BlockTransactions txn; - txn.blockhash = cmpctblock.header.GetHash(); + txn.blockhash = blockhash; blockTxnMsg << txn; fProcessBLOCKTXN = true; } else { @@ -4853,7 +4912,7 @@ void PeerManagerImpl::ProcessMessage( // We requested this block, but its far into the future, so our // mempool will probably be useless - request the block normally std::vector vInv(1); - vInv[0] = CInv(MSG_BLOCK, cmpctblock.header.GetHash()); + vInv[0] = CInv(MSG_BLOCK, blockhash); m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETDATA, vInv)); return; } else { @@ -4988,7 +5047,7 @@ void PeerManagerImpl::ProcessMessage( // 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 = 0s; + peer->m_last_getheaders_timestamp = {}; std::vector headers; @@ -5361,25 +5420,20 @@ void PeerManagerImpl::ProcessMessage( if (found) { //probably one the extensions -#ifdef ENABLE_WALLET - if (m_cj_ctx->queueman) { - PostProcessMessage(m_cj_ctx->queueman->ProcessMessage(pfrom.GetId(), m_connman, *this, msg_type, vRecv), pfrom.GetId()); + if (m_cj_walletman) { + PostProcessMessage(m_cj_walletman->processMessage(pfrom, m_chainman.ActiveChainstate(), m_connman, m_mempool, msg_type, vRecv), pfrom.GetId()); } - m_cj_ctx->walletman->ForEachCJClientMan([this, &pfrom, &msg_type, &vRecv](std::unique_ptr& clientman) { - clientman->ProcessMessage(pfrom, m_chainman.ActiveChainstate(), m_connman, m_mempool, msg_type, vRecv); - }); -#endif // ENABLE_WALLET if (m_active_ctx) { PostProcessMessage(m_active_ctx->cj_server->ProcessMessage(pfrom, msg_type, vRecv), pfrom.GetId()); + m_active_ctx->shareman->ProcessMessage(pfrom, msg_type, vRecv); } PostProcessMessage(m_sporkman.ProcessMessage(pfrom, m_connman, msg_type, vRecv), pfrom.GetId()); m_mn_sync.ProcessMessage(pfrom, msg_type, vRecv); - PostProcessMessage(m_govman.ProcessMessage(pfrom, m_connman, *this, msg_type, vRecv), pfrom.GetId()); + PostProcessMessage(m_govman.ProcessMessage(pfrom, m_connman, msg_type, vRecv), pfrom.GetId()); PostProcessMessage(CMNAuth::ProcessMessage(pfrom, peer->m_their_services, m_connman, m_mn_metaman, m_mn_activeman, m_mn_sync, m_dmnman->GetListAtChainTip(), msg_type, vRecv), pfrom.GetId()); PostProcessMessage(m_llmq_ctx->quorum_block_processor->ProcessMessage(pfrom, msg_type, vRecv), pfrom.GetId()); PostProcessMessage(m_llmq_ctx->qdkgsman->ProcessMessage(pfrom, is_masternode, msg_type, vRecv), pfrom.GetId()); PostProcessMessage(m_llmq_ctx->qman->ProcessMessage(pfrom, m_connman, msg_type, vRecv), pfrom.GetId()); - m_llmq_ctx->shareman->ProcessMessage(pfrom, *this, m_sporkman, msg_type, vRecv); PostProcessMessage(m_llmq_ctx->sigman->ProcessMessage(pfrom.GetId(), msg_type, vRecv), pfrom.GetId()); PostProcessMessage(ProcessPlatformBanMessage(pfrom.GetId(), msg_type, vRecv), pfrom.GetId()); @@ -5394,7 +5448,9 @@ void PeerManagerImpl::ProcessMessage( return; // CLSIG } - PostProcessMessage(m_llmq_ctx->isman->ProcessMessage(pfrom.GetId(), msg_type, vRecv), pfrom.GetId()); + for (const auto& handler : m_handlers) { + handler->ProcessMessage(pfrom, msg_type, vRecv); + } return; } @@ -6199,16 +6255,19 @@ bool PeerManagerImpl::SendMessages(CNode* pto) tx_relay->m_tx_inventory_to_send.erase(hash); if (tx_relay->m_bloom_filter && !tx_relay->m_bloom_filter->IsRelevantAndUpdate(*txinfo.tx)) continue; - int nInvType = m_cj_ctx->dstxman->GetDSTX(hash) ? MSG_DSTX : MSG_TX; + int nInvType = m_dstxman.GetDSTX(hash) ? MSG_DSTX : MSG_TX; tx_relay->m_tx_inventory_known_filter.insert(hash); queueAndMaybePushInv(CInv(nInvType, hash)); const auto islock = m_llmq_ctx->isman->GetInstantSendLockByTxid(hash); if (islock == nullptr) continue; - if (pto->nVersion < ISDLOCK_PROTO_VERSION) continue; uint256 isLockHash{::SerializeHash(*islock)}; tx_relay->m_tx_inventory_known_filter.insert(isLockHash); - queueAndMaybePushInv(CInv(MSG_ISDLOCK, isLockHash)); + // Skip ISDLOCK inv announcements for peers that want recsigs, as they can reconstruct + // the islock from the recsig + if (!peer->m_wants_recsigs) { + queueAndMaybePushInv(CInv(MSG_ISDLOCK, isLockHash)); + } } // Send an inv for the best ChainLock we have @@ -6275,7 +6334,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto) g_relay_expiration.emplace_back(current_time + RELAY_TX_CACHE_TIME, ret.first); } } - int nInvType = m_cj_ctx->dstxman->GetDSTX(hash) ? MSG_DSTX : MSG_TX; + int nInvType = m_dstxman.GetDSTX(hash) ? MSG_DSTX : MSG_TX; tx_relay->m_tx_inventory_known_filter.insert(hash); queueAndMaybePushInv(CInv(nInvType, hash)); } @@ -6471,3 +6530,33 @@ bool PeerManagerImpl::SendMessages(CNode* pto) } // release cs_main return true; } + +void PeerManagerImpl::PeerMisbehaving(const NodeId pnode, const int howmuch, const std::string& message) +{ + Misbehaving(pnode, howmuch, message); +} + +void PeerManagerImpl::PeerEraseObjectRequest(const NodeId nodeid, const CInv& inv) +{ + EraseObjectRequest(nodeid, inv); +} + +void PeerManagerImpl::PeerRelayInv(const CInv& inv) +{ + RelayInv(inv); +} + +void PeerManagerImpl::PeerRelayInvFiltered(const CInv& inv, const CTransaction& relatedTx) +{ + RelayInvFiltered(inv, relatedTx); +} + +void PeerManagerImpl::PeerRelayInvFiltered(const CInv& inv, const uint256& relatedTxHash) +{ + RelayInvFiltered(inv, relatedTxHash); +} + +void PeerManagerImpl::PeerAskPeersForTransaction(const uint256& txid) +{ + AskPeersForTransaction(txid); +} diff --git a/src/net_processing.h b/src/net_processing.h index 56efc63adce8..d15298401c24 100644 --- a/src/net_processing.h +++ b/src/net_processing.h @@ -10,23 +10,26 @@ #include #include +#include + #include -class CActiveMasternodeManager; class AddrMan; -class CTxMemPool; +class CActiveMasternodeManager; class CCoinJoinQueue; -class CDeterministicMNManager; -class CMasternodeMetaMan; -class CMasternodeSync; -class ChainstateManager; class CCoinJoinServer; +class CDeterministicMNManager; +class CDSTXManager; class CGovernanceManager; +class ChainstateManager; class CInv; +class CJWalletManager; +class CMasternodeMetaMan; +class CMasternodeSync; class CSporkManager; class CTransaction; +class CTxMemPool; struct ActiveContext; -struct CJContext; struct LLMQContext; /** Default for -maxorphantxsize, maximum size in megabytes the orphan map can grow before entries are removed */ @@ -52,17 +55,46 @@ struct CNodeStateStats { ServiceFlags their_services; }; -class PeerManager : public CValidationInterface, public NetEventsInterface +class PeerManagerInternal +{ +public: + virtual void PeerMisbehaving(const NodeId pnode, const int howmuch, const std::string& message = "") = 0; + virtual void PeerEraseObjectRequest(const NodeId nodeid, const CInv& inv) = 0; + virtual void PeerRelayInv(const CInv& inv) = 0; + virtual void PeerRelayInvFiltered(const CInv& inv, const CTransaction& relatedTx) = 0; + virtual void PeerRelayInvFiltered(const CInv& inv, const uint256& relatedTxHash) = 0; + virtual void PeerAskPeersForTransaction(const uint256& txid) = 0; +}; + +class NetHandler +{ +public: + NetHandler(PeerManagerInternal* peer_manager) : m_peer_manager{Assert(peer_manager)} {} + virtual ~NetHandler() { + Interrupt(); + Stop(); + } + + virtual void Start() {} + virtual void Stop() {} + virtual void Interrupt() {} + virtual void ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRecv) {} +protected: + PeerManagerInternal* m_peer_manager; +}; + + +class PeerManager : public CValidationInterface, public NetEventsInterface, public PeerManagerInternal { public: static std::unique_ptr make(const CChainParams& chainparams, CConnman& connman, AddrMan& addrman, - BanMan* banman, ChainstateManager& chainman, + BanMan* banman, CDSTXManager& dstxman, ChainstateManager& chainman, CTxMemPool& pool, CMasternodeMetaMan& mn_metaman, CMasternodeSync& mn_sync, CGovernanceManager& govman, CSporkManager& sporkman, const CActiveMasternodeManager* const mn_activeman, const std::unique_ptr& dmnman, const std::unique_ptr& active_ctx, - const std::unique_ptr& cj_ctx, + CJWalletManager* const cj_walletman, const std::unique_ptr& llmq_ctx, bool ignore_incoming_txs); virtual ~PeerManager() { } @@ -130,6 +162,12 @@ class PeerManager : public CValidationInterface, public NetEventsInterface virtual bool IsBanned(NodeId pnode) = 0; virtual size_t GetRequestedObjectCount(NodeId nodeid) const = 0; + + virtual void AddExtraHandler(std::unique_ptr&& handler) = 0; + virtual void RemoveHandlers() = 0; + virtual void StartHandlers() = 0; + virtual void StopHandlers() = 0; + virtual void InterruptHandlers() = 0; }; #endif // BITCOIN_NET_PROCESSING_H diff --git a/src/netaddress.cpp b/src/netaddress.cpp index cea9e194e9d4..76fe1f2e8e82 100644 --- a/src/netaddress.cpp +++ b/src/netaddress.cpp @@ -99,7 +99,7 @@ bool fAllowPrivateNet = DEFAULT_ALLOWPRIVATENET; * * @note This address is considered invalid by CNetAddr::IsValid() */ -CNetAddr::CNetAddr() {} +CNetAddr::CNetAddr() = default; void CNetAddr::SetIP(const CNetAddr& ipIn) { diff --git a/src/netaddress.h b/src/netaddress.h index 053b3369fc61..eb5a822a38a3 100644 --- a/src/netaddress.h +++ b/src/netaddress.h @@ -9,7 +9,6 @@ #include #endif -#include #include #include #include diff --git a/src/netbase.cpp b/src/netbase.cpp index 64034b919b50..b1a4f7750076 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -29,7 +29,7 @@ #endif // Settings -static Mutex g_proxyinfo_mutex; +static GlobalMutex g_proxyinfo_mutex; static Proxy proxyInfo[NET_MAX] GUARDED_BY(g_proxyinfo_mutex); static Proxy nameProxy GUARDED_BY(g_proxyinfo_mutex); int nConnectTimeout = DEFAULT_CONNECT_TIMEOUT; @@ -390,7 +390,7 @@ bool Socks5(const std::string& strDest, uint16_t port, const ProxyCredentials* a return error("Error sending to proxy"); } uint8_t pchRet1[2]; - if ((recvr = InterruptibleRecv(pchRet1, 2, g_socks5_recv_timeout, sock)) != IntrRecvError::OK) { + if (InterruptibleRecv(pchRet1, 2, g_socks5_recv_timeout, sock) != IntrRecvError::OK) { LogPrintf("Socks5() connect to %s:%d failed: InterruptibleRecv() timeout or other failure\n", strDest, port); return false; } @@ -413,7 +413,7 @@ bool Socks5(const std::string& strDest, uint16_t port, const ProxyCredentials* a } LogPrint(BCLog::PROXY, "SOCKS5 sending proxy authentication %s:%s\n", auth->username, auth->password); uint8_t pchRetA[2]; - if ((recvr = InterruptibleRecv(pchRetA, 2, g_socks5_recv_timeout, sock)) != IntrRecvError::OK) { + if (InterruptibleRecv(pchRetA, 2, g_socks5_recv_timeout, sock) != IntrRecvError::OK) { return error("Error reading proxy authentication response"); } if (pchRetA[0] != 0x01 || pchRetA[1] != 0x00) { @@ -479,7 +479,7 @@ bool Socks5(const std::string& strDest, uint16_t port, const ProxyCredentials* a if (recvr != IntrRecvError::OK) { return error("Error reading from proxy"); } - if ((recvr = InterruptibleRecv(pchRet3, 2, g_socks5_recv_timeout, sock)) != IntrRecvError::OK) { + if (InterruptibleRecv(pchRet3, 2, g_socks5_recv_timeout, sock) != IntrRecvError::OK) { return error("Error reading from proxy"); } LogPrint(BCLog::NET, "SOCKS5 connected %s\n", strDest); diff --git a/src/netfulfilledman.cpp b/src/netfulfilledman.cpp index 8e68dca02db7..43b981405911 100644 --- a/src/netfulfilledman.cpp +++ b/src/netfulfilledman.cpp @@ -12,6 +12,12 @@ CNetFulfilledRequestManager::CNetFulfilledRequestManager() : { } +CNetFulfilledRequestManager::~CNetFulfilledRequestManager() +{ + if (!is_valid) return; + m_db->Store(*this); +} + bool CNetFulfilledRequestManager::LoadCache(bool load_cache) { assert(m_db != nullptr); @@ -22,12 +28,6 @@ bool CNetFulfilledRequestManager::LoadCache(bool load_cache) return is_valid; } -CNetFulfilledRequestManager::~CNetFulfilledRequestManager() -{ - if (!is_valid) return; - m_db->Store(*this); -} - void CNetFulfilledRequestManager::AddFulfilledRequest(const CService& addr, const std::string& strRequest) { LOCK(cs_mapFulfilledRequests); diff --git a/src/netfulfilledman.h b/src/netfulfilledman.h index 1a4471f3ccee..b3518f4fc9ab 100644 --- a/src/netfulfilledman.h +++ b/src/netfulfilledman.h @@ -50,7 +50,9 @@ class CNetFulfilledRequestManager : public NetFulfilledRequestStore bool is_valid{false}; public: - explicit CNetFulfilledRequestManager(); + CNetFulfilledRequestManager(const CNetFulfilledRequestManager&) = delete; + CNetFulfilledRequestManager& operator=(const CNetFulfilledRequestManager&) = delete; + CNetFulfilledRequestManager(); ~CNetFulfilledRequestManager(); bool LoadCache(bool load_cache); diff --git a/src/node/blockstorage.cpp b/src/node/blockstorage.cpp index 0a5ca022fa73..76fd09843ac7 100644 --- a/src/node/blockstorage.cpp +++ b/src/node/blockstorage.cpp @@ -448,7 +448,7 @@ void CleanupBlockRevFiles() // Remove the rev files immediately and insert the blk file paths into an // ordered map keyed by block file index. LogPrintf("Removing unusable blk?????.dat and rev?????.dat files for -reindex with -prune\n"); - fs::path blocksdir = gArgs.GetBlocksDirPath(); + const fs::path& blocksdir = gArgs.GetBlocksDirPath(); for (fs::directory_iterator it(blocksdir); it != fs::directory_iterator(); it++) { const std::string path = fs::PathToString(it->path().filename()); if (fs::is_regular_file(*it) && @@ -505,7 +505,7 @@ static bool UndoWriteToDisk(const CBlockUndo& blockundo, FlatFilePos& pos, const fileout << blockundo; // calculate & write checksum - CHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION); + HashWriter hasher{}; hasher << hashBlock; hasher << blockundo; fileout << hasher.GetHash(); @@ -589,12 +589,14 @@ void UnlinkPrunedFiles(const std::set& setFilesToPrune) static FlatFileSeq BlockFileSeq() { - return FlatFileSeq(gArgs.GetBlocksDirPath(), "blk", gArgs.GetBoolArg("-fastprune", false) ? 0x4000 /* 16kb */ : BLOCKFILE_CHUNK_SIZE); + return FlatFileSeq(gArgs.GetBlocksDirPath(), "blk", + gArgs.GetBoolArg("-fastprune", false) ? 0x4000 /* 16kb */ : + (gArgs.GetBoolArg("-tinyblk", false) ? 0x10000 /* 64kb */ : BLOCKFILE_CHUNK_SIZE)); } static FlatFileSeq UndoFileSeq() { - return FlatFileSeq(gArgs.GetBlocksDirPath(), "rev", UNDOFILE_CHUNK_SIZE); + return FlatFileSeq(gArgs.GetBlocksDirPath(), "rev", gArgs.GetBoolArg("-tinyblk", false) ? 0x10000 /* 64kb */ : UNDOFILE_CHUNK_SIZE); } FILE* OpenBlockFile(const FlatFilePos& pos, bool fReadOnly) diff --git a/src/node/chainstate.cpp b/src/node/chainstate.cpp index 555cef21a831..8812f7b64829 100644 --- a/src/node/chainstate.cpp +++ b/src/node/chainstate.cpp @@ -4,19 +4,35 @@ #include +#include +#include #include #include #include #include +#include +#include +#include +#include +#include +#include +#include #include +#include #include #include #include #include #include +#include #include +#include +#include +#include +#include + namespace node { std::optional LoadChainstate(bool fReset, ChainstateManager& chainman, @@ -32,6 +48,7 @@ std::optional LoadChainstate(bool fReset, std::unique_ptr& mnhf_manager, std::unique_ptr& llmq_ctx, CTxMemPool* mempool, + const fs::path& data_dir, bool fPruneMode, bool is_addrindex_enabled, bool is_governance_enabled, @@ -46,6 +63,7 @@ std::optional LoadChainstate(bool fReset, int64_t nCoinCacheUsage, bool block_tree_db_in_memory, bool coins_db_in_memory, + bool dash_dbs_in_memory, std::function shutdown_requested, std::function coins_error_cb) { @@ -55,9 +73,8 @@ std::optional LoadChainstate(bool fReset, LOCK(cs_main); - int64_t nEvoDbCache{64 * 1024 * 1024}; // TODO evodb.reset(); - evodb = std::make_unique(nEvoDbCache, false, fReset || fReindexChainState); + evodb = std::make_unique(util::DbWrapperParams{.path = data_dir, .memory = dash_dbs_in_memory, .wipe = fReset || fReindexChainState}); mnhf_manager.reset(); mnhf_manager = std::make_unique(*evodb); @@ -73,8 +90,8 @@ std::optional LoadChainstate(bool fReset, pblocktree.reset(new CBlockTreeDB(nBlockTreeDBCache, block_tree_db_in_memory, fReset)); DashChainstateSetup(chainman, govman, mn_metaman, mn_sync, sporkman, mn_activeman, chain_helper, cpoolman, - dmnman, evodb, mnhf_manager, llmq_ctx, mempool, fReset, fReindexChainState, - consensus_params); + dmnman, evodb, mnhf_manager, llmq_ctx, mempool, data_dir, dash_dbs_in_memory, + /*llmq_dbs_wipe=*/fReset || fReindexChainState, consensus_params); if (fReset) { pblocktree->WriteReindexing(true); @@ -148,9 +165,9 @@ std::optional LoadChainstate(bool fReset, for (CChainState* chainstate : chainman.GetAll()) { chainstate->InitCoinsDB( - /* cache_size_bytes */ nCoinDBCache, - /* in_memory */ coins_db_in_memory, - /* should_wipe */ fReset || fReindexChainState); + /*cache_size_bytes=*/nCoinDBCache, + /*in_memory=*/coins_db_in_memory, + /*should_wipe=*/fReset || fReindexChainState); if (coins_error_cb) { chainstate->CoinsErrorCatcher().AddReadErrCallback(coins_error_cb); @@ -213,8 +230,9 @@ void DashChainstateSetup(ChainstateManager& chainman, std::unique_ptr& mnhf_manager, std::unique_ptr& llmq_ctx, CTxMemPool* mempool, - bool fReset, - bool fReindexChainState, + const fs::path& data_dir, + bool llmq_dbs_in_memory, + bool llmq_dbs_wipe, const Consensus::Params& consensus_params) { // Same logic as pblocktree @@ -230,7 +248,8 @@ void DashChainstateSetup(ChainstateManager& chainman, } llmq_ctx.reset(); llmq_ctx = std::make_unique(chainman, *dmnman, *evodb, mn_metaman, *mnhf_manager, sporkman, - *mempool, mn_activeman.get(), mn_sync, /*unit_tests=*/false, /*wipe=*/fReset || fReindexChainState); + *mempool, mn_activeman.get(), mn_sync, + util::DbWrapperParams{.path = data_dir, .memory = llmq_dbs_in_memory, .wipe = llmq_dbs_wipe}); mempool->ConnectManagers(dmnman.get(), llmq_ctx->isman.get()); // Enable CMNHFManager::{Process, Undo}Block mnhf_manager->ConnectManagers(&chainman, llmq_ctx->qman.get()); diff --git a/src/node/chainstate.h b/src/node/chainstate.h index 3279d52b90ec..aba1ccaa5fc6 100644 --- a/src/node/chainstate.h +++ b/src/node/chainstate.h @@ -27,7 +27,10 @@ struct LLMQContext; namespace Consensus { struct Params; -} +} // namespace Consensus +namespace fs { +class path; +} // namespace fs namespace node { enum class ChainstateLoadingError { @@ -90,6 +93,7 @@ std::optional LoadChainstate(bool fReset, std::unique_ptr& mnhf_manager, std::unique_ptr& llmq_ctx, CTxMemPool* mempool, + const fs::path& data_dir, bool fPruneMode, bool is_addrindex_enabled, bool is_governance_enabled, @@ -104,6 +108,7 @@ std::optional LoadChainstate(bool fReset, int64_t nCoinCacheUsage, bool block_tree_db_in_memory, bool coins_db_in_memory, + bool dash_dbs_in_memory, std::function shutdown_requested = nullptr, std::function coins_error_cb = nullptr); @@ -121,8 +126,9 @@ void DashChainstateSetup(ChainstateManager& chainman, std::unique_ptr& mnhf_manager, std::unique_ptr& llmq_ctx, CTxMemPool* mempool, - bool fReset, - bool fReindexChainState, + const fs::path& data_dir, + bool llmq_dbs_in_memory, + bool llmq_dbs_wipe, const Consensus::Params& consensus_params); void DashChainstateSetupClose(std::unique_ptr& chain_helper, diff --git a/src/node/context.cpp b/src/node/context.cpp index 22296e423a92..a13ef83414e1 100644 --- a/src/node/context.cpp +++ b/src/node/context.cpp @@ -6,7 +6,8 @@ #include #include -#include +#include +#include #include #include #include @@ -31,6 +32,6 @@ #include namespace node { -NodeContext::NodeContext() {} -NodeContext::~NodeContext() {} +NodeContext::NodeContext() = default; +NodeContext::~NodeContext() = default; } // namespace node diff --git a/src/node/context.h b/src/node/context.h index fc04830e72d6..15845e6ce2ce 100644 --- a/src/node/context.h +++ b/src/node/context.h @@ -18,10 +18,12 @@ class CBlockPolicyEstimator; class CConnman; class CCreditPoolManager; class CDeterministicMNManager; +class CDSTXManager; class CChainstateHelper; class ChainstateManager; class CEvoDB; class CGovernanceManager; +class CJWalletManager; class CMasternodeMetaMan; class CMasternodeSync; class CNetFulfilledRequestManager; @@ -32,7 +34,6 @@ class CMNHFManager; class NetGroupManager; class PeerManager; struct ActiveContext; -struct CJContext; struct LLMQContext; namespace interfaces { @@ -80,6 +81,8 @@ struct NodeContext { //! Dash managers std::unique_ptr mn_activeman; std::unique_ptr cpoolman; + std::unique_ptr cj_walletman; + std::unique_ptr dstxman; std::unique_ptr evodb; std::unique_ptr chain_helper; std::unique_ptr dmnman; @@ -91,7 +94,6 @@ struct NodeContext { std::unique_ptr sporkman; //! Dash contexts std::unique_ptr active_ctx; - std::unique_ptr cj_ctx; std::unique_ptr llmq_ctx; //! Declare default constructor and destructor that are not inline, so code diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp index 420dd9f6baf3..f2fc6401e329 100644 --- a/src/node/interfaces.cpp +++ b/src/node/interfaces.cpp @@ -12,7 +12,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -147,9 +149,9 @@ class GOVImpl : public GOV } bool processVoteAndRelay(const CGovernanceVote& vote, std::string& error) override { - if (context().govman != nullptr && context().connman != nullptr && context().peerman != nullptr) { + if (context().govman != nullptr && context().connman != nullptr) { CGovernanceException exception; - bool result = context().govman->ProcessVoteAndRelay(vote, exception, *context().connman, *context().peerman); + bool result = context().govman->ProcessVoteAndRelay(vote, exception, *context().connman); if (!result) { error = exception.GetMessage(); } @@ -234,12 +236,11 @@ class GOVImpl : public GOV } } if (!Assert(context().govman)->MasternodeRateCheck(govobj)) { error = "Object creation rate limit exceeded"; return false; } - PeerManager& peerman = EnsurePeerman(context()); if (fMissingConfirmations) { context().govman->AddPostponedObject(govobj); - govobj.Relay(peerman, *Assert(context().mn_sync)); + context().govman->RelayObject(govobj); } else { - context().govman->AddGovernanceObject(govobj, peerman); + context().govman->AddGovernanceObject(govobj); } out_object_hash = govobj.GetHash().ToString(); return true; @@ -398,6 +399,17 @@ class CoinJoinOptionsImpl : public CoinJoin::Options } }; +#ifdef ENABLE_EXTERNAL_SIGNER +class ExternalSignerImpl : public interfaces::ExternalSigner +{ +public: + ExternalSignerImpl(::ExternalSigner signer) : m_signer(std::move(signer)) {} + std::string getName() override { return m_signer.m_name; } +private: + ::ExternalSigner m_signer; +}; +#endif + class NodeImpl : public Node { private: @@ -444,6 +456,46 @@ class NodeImpl : public Node } } bool shutdownRequested() override { return ShutdownRequested(); } + bool isSettingIgnored(const std::string& name) override + { + bool ignored = false; + gArgs.LockSettings([&](util::Settings& settings) { + if (auto* options = util::FindKey(settings.command_line_options, name)) { + ignored = !options->empty(); + } + }); + return ignored; + } + util::SettingsValue getPersistentSetting(const std::string& name) override { return gArgs.GetPersistentSetting(name); } + void updateRwSetting(const std::string& name, const util::SettingsValue& value) override + { + gArgs.LockSettings([&](util::Settings& settings) { + if (value.isNull()) { + settings.rw_settings.erase(name); + } else { + settings.rw_settings[name] = value; + } + }); + gArgs.WriteSettingsFile(); + } + void forceSetting(const std::string& name, const util::SettingsValue& value) override + { + gArgs.LockSettings([&](util::Settings& settings) { + if (value.isNull()) { + settings.forced_settings.erase(name); + } else { + settings.forced_settings[name] = value; + } + }); + } + void resetSettings() override + { + gArgs.WriteSettingsFile(/*errors=*/nullptr, /*backup=*/true); + gArgs.LockSettings([&](util::Settings& settings) { + settings.rw_settings.clear(); + }); + gArgs.WriteSettingsFile(); + } void mapPort(bool use_upnp, bool use_natpmp) override { StartMapPort(use_upnp, use_natpmp); } bool getProxy(Network net, Proxy& proxy_info) override { return GetProxy(net, proxy_info); } size_t getNodeCount(ConnectionDirection flags) override @@ -515,6 +567,28 @@ class NodeImpl : public Node } return false; } + std::vector> listExternalSigners() override + { +#ifdef ENABLE_EXTERNAL_SIGNER + std::vector signers = {}; + const std::string command = gArgs.GetArg("-signer", ""); + if (command == "") return {}; + ExternalSigner::Enumerate(command, signers, Params().NetworkIDString()); + std::vector> result; + for (auto& signer : signers) { + result.emplace_back(std::make_unique(std::move(signer))); + } + return result; +#else + // This result is undistinguisable from a succesful call that returns + // no signers. For the current GUI this doesn't matter, because the wallet + // creation dialog disables the external signer checkbox in both + // cases. The return type could be changed to std::optional + // (or something that also includes error messages) if this distinction + // becomes important. + return {}; +#endif // ENABLE_EXTERNAL_SIGNER + } int64_t getTotalBytesRecv() override { return m_context->connman ? m_context->connman->GetTotalBytesRecv() : 0; } 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; } @@ -828,7 +902,7 @@ class ChainImpl : public Chain std::optional getHeight() override { LOCK(::cs_main); - const CChain& active = Assert(m_node.chainman)->ActiveChain(); + const CChain& active = chainman().ActiveChain(); int height = active.Height(); if (height >= 0) { return height; @@ -838,7 +912,7 @@ class ChainImpl : public Chain uint256 getBlockHash(int height) override { LOCK(::cs_main); - const CChain& active = Assert(m_node.chainman)->ActiveChain(); + const CChain& active = chainman().ActiveChain(); CBlockIndex* block = active[height]; assert(block != nullptr); return block->GetBlockHash(); @@ -846,7 +920,7 @@ class ChainImpl : public Chain bool haveBlockOnDisk(int height) override { LOCK(::cs_main); - const CChain& active = Assert(m_node.chainman)->ActiveChain(); + const CChain& active = chainman().ActiveChain(); CBlockIndex* block = active[height]; return block && ((block->nStatus & BLOCK_HAVE_DATA) != 0) && block->nTx > 0; } @@ -883,7 +957,7 @@ class ChainImpl : public Chain std::optional findLocatorFork(const CBlockLocator& locator) override { LOCK(::cs_main); - const CChainState& active = Assert(m_node.chainman)->ActiveChainstate(); + const CChainState& active = chainman().ActiveChainstate(); if (const CBlockIndex* fork = active.FindForkInGlobalIndex(locator)) { return fork->nHeight; } @@ -918,20 +992,20 @@ class ChainImpl : public Chain bool findBlock(const uint256& hash, const FoundBlock& block) override { WAIT_LOCK(cs_main, lock); - const CChain& active = Assert(m_node.chainman)->ActiveChain(); - return FillBlock(m_node.chainman->m_blockman.LookupBlockIndex(hash), block, lock, active); + const CChain& active = chainman().ActiveChain(); + return FillBlock(chainman().m_blockman.LookupBlockIndex(hash), block, lock, active); } bool findFirstBlockWithTimeAndHeight(int64_t min_time, int min_height, const FoundBlock& block) override { WAIT_LOCK(cs_main, lock); - const CChain& active = Assert(m_node.chainman)->ActiveChain(); + const CChain& active = chainman().ActiveChain(); return FillBlock(active.FindEarliestAtLeast(min_time, min_height), block, lock, active); } bool findAncestorByHeight(const uint256& block_hash, int ancestor_height, const FoundBlock& ancestor_out) override { WAIT_LOCK(cs_main, lock); - const CChain& active = Assert(m_node.chainman)->ActiveChain(); - if (const CBlockIndex* block = m_node.chainman->m_blockman.LookupBlockIndex(block_hash)) { + const CChain& active = chainman().ActiveChain(); + if (const CBlockIndex* block = chainman().m_blockman.LookupBlockIndex(block_hash)) { if (const CBlockIndex* ancestor = block->GetAncestor(ancestor_height)) { return FillBlock(ancestor, ancestor_out, lock, active); } @@ -941,18 +1015,18 @@ class ChainImpl : public Chain bool findAncestorByHash(const uint256& block_hash, const uint256& ancestor_hash, const FoundBlock& ancestor_out) override { WAIT_LOCK(cs_main, lock); - const CChain& active = Assert(m_node.chainman)->ActiveChain(); - const CBlockIndex* block = m_node.chainman->m_blockman.LookupBlockIndex(block_hash); - const CBlockIndex* ancestor = m_node.chainman->m_blockman.LookupBlockIndex(ancestor_hash); + const CChain& active = chainman().ActiveChain(); + const CBlockIndex* block = chainman().m_blockman.LookupBlockIndex(block_hash); + const CBlockIndex* ancestor = chainman().m_blockman.LookupBlockIndex(ancestor_hash); if (block && ancestor && block->GetAncestor(ancestor->nHeight) != ancestor) ancestor = nullptr; return FillBlock(ancestor, ancestor_out, lock, active); } bool findCommonAncestor(const uint256& block_hash1, const uint256& block_hash2, const FoundBlock& ancestor_out, const FoundBlock& block1_out, const FoundBlock& block2_out) override { WAIT_LOCK(cs_main, lock); - const CChain& active = Assert(m_node.chainman)->ActiveChain(); - const CBlockIndex* block1 = m_node.chainman->m_blockman.LookupBlockIndex(block_hash1); - const CBlockIndex* block2 = m_node.chainman->m_blockman.LookupBlockIndex(block_hash2); + const CChain& active = chainman().ActiveChain(); + const CBlockIndex* block1 = chainman().m_blockman.LookupBlockIndex(block_hash1); + const CBlockIndex* block2 = chainman().m_blockman.LookupBlockIndex(block_hash2); const CBlockIndex* ancestor = block1 && block2 ? LastCommonAncestor(block1, block2) : nullptr; // Using & instead of && below to avoid short circuiting and leaving // output uninitialized. Cast bool to int to avoid -Wbitwise-instead-of-logical @@ -1055,7 +1129,7 @@ class ChainImpl : public Chain bool havePruned() override { LOCK(::cs_main); - return m_node.chainman->m_blockman.m_have_pruned; + return chainman().m_blockman.m_have_pruned; } bool isReadyToBroadcast() override { return !node::fImporting && !node::fReindex && !isInitialBlockDownload(); } bool isInitialBlockDownload() override { @@ -1077,7 +1151,7 @@ class ChainImpl : public Chain { if (!old_tip.IsNull()) { LOCK(::cs_main); - const CChain& active = Assert(m_node.chainman)->ActiveChain(); + const CChain& active = chainman().ActiveChain(); if (old_tip == active.Tip()->GetBlockHash()) return; } SyncWithValidationInterfaceQueue(); @@ -1130,7 +1204,7 @@ class ChainImpl : public Chain } bool hasAssumedValidChain() override { - return Assert(m_node.chainman)->IsSnapshotActive(); + return chainman().IsSnapshotActive(); } NodeContext& m_node; diff --git a/src/node/miner.cpp b/src/node/miner.cpp index 8b2626570da1..d99aeb8aee74 100644 --- a/src/node/miner.cpp +++ b/src/node/miner.cpp @@ -173,7 +173,7 @@ static bool CalcCbTxBestChainlock(const llmq::CChainLocksHandler& chainlock_hand // Inserting our best CL bestCLHeightDiff = pindexPrev->nHeight - best_clsig.getHeight(); - bestCLSignature = chainlock_handler.GetBestChainLock().getSig(); + bestCLSignature = best_clsig.getSig(); return true; } diff --git a/src/node/miner.h b/src/node/miner.h index 188416d3ff44..eea4d69884bd 100644 --- a/src/node/miner.h +++ b/src/node/miner.h @@ -135,7 +135,7 @@ struct update_for_parent_inclusion void operator() (CTxMemPoolModifiedEntry &e) { - e.nModFeesWithAncestors -= iter->GetFee(); + e.nModFeesWithAncestors -= iter->GetModifiedFee(); e.nSizeWithAncestors -= iter->GetTxSize(); e.nSigOpCountWithAncestors -= iter->GetSigOpCount(); } diff --git a/src/node/minisketchwrapper.cpp b/src/node/minisketchwrapper.cpp index 67e823cb6827..96707f7a0a95 100644 --- a/src/node/minisketchwrapper.cpp +++ b/src/node/minisketchwrapper.cpp @@ -23,17 +23,17 @@ static constexpr uint32_t BITS = 32; uint32_t FindBestImplementation() { - std::optional> best; + std::optional> best; uint32_t max_impl = Minisketch::MaxImplementation(); for (uint32_t impl = 0; impl <= max_impl; ++impl) { - std::vector benches; + std::vector benches; uint64_t offset = 0; /* Run a little benchmark with capacity 32, adding 184 entries, and decoding 11 of them once. */ for (int b = 0; b < 11; ++b) { if (!Minisketch::ImplementationSupported(BITS, impl)) break; Minisketch sketch(BITS, impl, 32); - auto start = GetTimeMicros(); + auto start = SteadyClock::now(); for (uint64_t e = 0; e < 100; ++e) { sketch.Add(e*1337 + b*13337 + offset); } @@ -41,7 +41,7 @@ uint32_t FindBestImplementation() sketch.Add(e*1337 + b*13337 + offset); } offset += (*sketch.Decode(32))[0]; - auto stop = GetTimeMicros(); + auto stop = SteadyClock::now(); benches.push_back(stop - start); } /* Remember which implementation has the best median benchmark time. */ diff --git a/src/node/transaction.h b/src/node/transaction.h index 3156e841e594..9617c1f99b92 100644 --- a/src/node/transaction.h +++ b/src/node/transaction.h @@ -5,7 +5,6 @@ #ifndef BITCOIN_NODE_TRANSACTION_H #define BITCOIN_NODE_TRANSACTION_H -#include #include #include #include diff --git a/src/node/txreconciliation.cpp b/src/node/txreconciliation.cpp index 03d4258a84aa..ed04a78cecfa 100644 --- a/src/node/txreconciliation.cpp +++ b/src/node/txreconciliation.cpp @@ -15,7 +15,7 @@ namespace { /** Static salt component used to compute short txids for sketch construction, see BIP-330. */ const std::string RECON_STATIC_SALT = "Tx Relay Salting"; -const CHashWriter RECON_SALT_HASHER = TaggedHash(RECON_STATIC_SALT); +const HashWriter RECON_SALT_HASHER = TaggedHash(RECON_STATIC_SALT); /** * Salt (specified by BIP-330) constructed from contributions from both peers. It is used diff --git a/src/outputtype.cpp b/src/outputtype.cpp index 440372c0b5ea..2a48c1e3c776 100644 --- a/src/outputtype.cpp +++ b/src/outputtype.cpp @@ -18,7 +18,7 @@ static const std::string OUTPUT_TYPE_STRING_LEGACY = "legacy"; static const std::string OUTPUT_TYPE_STRING_UNKNOWN = "unknown"; -const std::array OUTPUT_TYPES = {OutputType::LEGACY, OutputType::UNKNOWN}; +const std::array OUTPUT_TYPES = {OutputType::LEGACY}; bool ParseOutputType(const std::string& type, OutputType& output_type) { diff --git a/src/outputtype.h b/src/outputtype.h index db05dd5ee7e3..5789f8a222c3 100644 --- a/src/outputtype.h +++ b/src/outputtype.h @@ -18,7 +18,7 @@ enum class OutputType { UNKNOWN, }; -extern const std::array OUTPUT_TYPES; +extern const std::array OUTPUT_TYPES; [[nodiscard]] bool ParseOutputType(const std::string& str, OutputType& output_type); const std::string& FormatOutputType(OutputType type); diff --git a/src/policy/feerate.cpp b/src/policy/feerate.cpp index bde00572071b..c05c02f423e7 100644 --- a/src/policy/feerate.cpp +++ b/src/policy/feerate.cpp @@ -7,6 +7,8 @@ #include #include +#include + CFeeRate::CFeeRate(const CAmount& nFeePaid, uint32_t num_bytes) { const int64_t nSize{num_bytes}; @@ -22,7 +24,9 @@ CAmount CFeeRate::GetFee(uint32_t num_bytes) const { const int64_t nSize{num_bytes}; - CAmount nFee = nSatoshisPerK * nSize / 1000; + // Be explicit that we're converting from a double to int64_t (CAmount) here. + // We've previously had issues with the silent double->int64_t conversion. + CAmount nFee{static_cast(std::ceil(nSatoshisPerK * nSize / 1000.0))}; if (nFee == 0 && nSize != 0) { if (nSatoshisPerK > 0) nFee = CAmount(1); diff --git a/src/policy/feerate.h b/src/policy/feerate.h index 0fa18a1a2e6b..7b7e6c5d38dd 100644 --- a/src/policy/feerate.h +++ b/src/policy/feerate.h @@ -54,6 +54,7 @@ class CFeeRate /** * Return the fee in satoshis for the given size in vbytes. + * If the calculated fee would have fractional satoshis, then the returned fee will always be rounded up to the nearest satoshi. */ CAmount GetFee(uint32_t num_bytes) const; diff --git a/src/policy/fees.cpp b/src/policy/fees.cpp index 489c9944519e..e0586637450a 100644 --- a/src/policy/fees.cpp +++ b/src/policy/fees.cpp @@ -163,13 +163,13 @@ class TxConfirmStats unsigned int GetMaxConfirms() const { return scale * confAvg.size(); } /** Write state of estimation data to a file*/ - void Write(CAutoFile& fileout) const; + void Write(AutoFile& fileout) const; /** * Read saved state of estimation data from a file and replace all internal data structures and * variables with this state. */ - void Read(CAutoFile& filein, int nFileVersion, size_t numBuckets); + void Read(AutoFile& filein, int nFileVersion, size_t numBuckets); }; @@ -405,7 +405,7 @@ double TxConfirmStats::EstimateMedianVal(int confTarget, double sufficientTxVal, return median; } -void TxConfirmStats::Write(CAutoFile& fileout) const +void TxConfirmStats::Write(AutoFile& fileout) const { fileout << Using(decay); fileout << scale; @@ -415,7 +415,7 @@ void TxConfirmStats::Write(CAutoFile& fileout) const fileout << Using>>(failAvg); } -void TxConfirmStats::Read(CAutoFile& filein, int nFileVersion, size_t numBuckets) +void TxConfirmStats::Read(AutoFile& filein, int nFileVersion, size_t numBuckets) { // Read data file and do some very basic sanity checking // buckets and bucketMap are not updated yet, so don't access them @@ -562,15 +562,13 @@ CBlockPolicyEstimator::CBlockPolicyEstimator() // If the fee estimation file is present, read recorded estimations fs::path est_filepath = gArgs.GetDataDirNet() / FEE_ESTIMATES_FILENAME; - CAutoFile est_file(fsbridge::fopen(est_filepath, "rb"), SER_DISK, CLIENT_VERSION); + AutoFile est_file{fsbridge::fopen(est_filepath, "rb")}; if (est_file.IsNull() || !Read(est_file)) { LogPrintf("Failed to read fee estimates from %s. Continue anyway.\n", fs::PathToString(est_filepath)); } } -CBlockPolicyEstimator::~CBlockPolicyEstimator() -{ -} +CBlockPolicyEstimator::~CBlockPolicyEstimator() = default; void CBlockPolicyEstimator::processTransaction(const CTxMemPoolEntry& entry, bool validFeeEstimate) { @@ -922,13 +920,13 @@ void CBlockPolicyEstimator::Flush() { FlushUnconfirmed(); fs::path est_filepath = gArgs.GetDataDirNet() / FEE_ESTIMATES_FILENAME; - CAutoFile est_file(fsbridge::fopen(est_filepath, "wb"), SER_DISK, CLIENT_VERSION); + AutoFile est_file{fsbridge::fopen(est_filepath, "wb")}; if (est_file.IsNull() || !Write(est_file)) { LogPrintf("Failed to write fee estimates to %s. Continue anyway.\n", fs::PathToString(est_filepath)); } } -bool CBlockPolicyEstimator::Write(CAutoFile& fileout) const +bool CBlockPolicyEstimator::Write(AutoFile& fileout) const { try { LOCK(m_cs_fee_estimator); @@ -953,7 +951,7 @@ bool CBlockPolicyEstimator::Write(CAutoFile& fileout) const return true; } -bool CBlockPolicyEstimator::Read(CAutoFile& filein) +bool CBlockPolicyEstimator::Read(AutoFile& filein) { try { LOCK(m_cs_fee_estimator); diff --git a/src/policy/fees.h b/src/policy/fees.h index 753d983cf8b0..3a0ed2dc1b11 100644 --- a/src/policy/fees.h +++ b/src/policy/fees.h @@ -19,7 +19,7 @@ #include #include -class CAutoFile; +class AutoFile; class CTxMemPoolEntry; class TxConfirmStats; @@ -218,11 +218,11 @@ class CBlockPolicyEstimator EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator); /** Write estimation data to a file */ - bool Write(CAutoFile& fileout) const + bool Write(AutoFile& fileout) const EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator); /** Read estimation data from a file */ - bool Read(CAutoFile& filein) + bool Read(AutoFile& filein) EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator); /** Empty mempool transactions on shutdown to record failure to confirm for txs still in mempool */ diff --git a/src/policy/packages.h b/src/policy/packages.h index 47c6717b0330..997056a61471 100644 --- a/src/policy/packages.h +++ b/src/policy/packages.h @@ -5,7 +5,6 @@ #ifndef BITCOIN_POLICY_PACKAGES_H #define BITCOIN_POLICY_PACKAGES_H -#include #include #include #include diff --git a/src/policy/policy.h b/src/policy/policy.h index c83bab928dbb..838f35306498 100644 --- a/src/policy/policy.h +++ b/src/policy/policy.h @@ -33,7 +33,7 @@ static constexpr unsigned int MAX_P2SH_SIGOPS{15}; static constexpr unsigned int MAX_STANDARD_TX_SIGOPS{4000}; /** Default for -maxmempool, maximum megabytes of mempool memory usage */ static constexpr unsigned int DEFAULT_MAX_MEMPOOL_SIZE{300}; -/** Default for -incrementalrelayfee, which sets the minimum feerate increase for mempool limiting or BIP 125 replacement **/ +/** Default for -incrementalrelayfee, which sets the minimum feerate increase for mempool limiting **/ static constexpr unsigned int DEFAULT_INCREMENTAL_RELAY_FEE{1000}; /** Default for -bytespersigop */ static constexpr unsigned int DEFAULT_BYTES_PER_SIGOP{20}; diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h index f3062ce00740..b45e81fa6e88 100644 --- a/src/primitives/transaction.h +++ b/src/primitives/transaction.h @@ -12,13 +12,12 @@ #include #include -#include +#include #include -#include +#include #include #include #include -#include #include #include diff --git a/src/protocol.h b/src/protocol.h index 75456d161fb7..ed1b71705b80 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -7,7 +7,6 @@ #define BITCOIN_PROTOCOL_H #include -#include #include #include #include @@ -568,60 +567,4 @@ class CInv uint256 hash; }; -struct MisbehavingError -{ - int score; - std::string message; - - MisbehavingError(int s) : score{s} {} - - // Constructor does a perfect forwarding reference - template - MisbehavingError(int s, T&& msg) : - score{s}, - message{std::forward(msg)} - {} -}; - -/** - * This struct is a helper to return values from handlers that are processing - * network messages but implemented outside of net_processing.cpp, - * for example llmq's messages. - * - * These handlers do not supposed to know anything about PeerManager to avoid - * circular dependencies. - * - * See `PeerManagerImpl::PostProcessMessage` to see how each type of return code - * is processed. - */ -struct MessageProcessingResult -{ - //! @m_error triggers Misbehaving error with score and optional message if not nullopt - std::optional m_error; - - //! @m_inventory will relay these inventories to connected peers - std::vector m_inventory; - - //! @m_inv_filter will relay this inventory if filter matches to connected peers if not nullopt - std::optional>> m_inv_filter; - - //! @m_request_tx will ask connected peers to relay transaction if not nullopt - std::optional m_request_tx; - - //! @m_transactions will relay transactions to peers which is ready to accept it (some peers does not accept transactions) - std::vector m_transactions; - - //! @m_to_erase triggers EraseObjectRequest from PeerManager for this inventory if not nullopt - std::optional m_to_erase; - - MessageProcessingResult() = default; - MessageProcessingResult(MisbehavingError error) : - m_error(error) - {} - MessageProcessingResult(CInv inv) : - m_inventory({inv}) - { - } -}; - #endif // BITCOIN_PROTOCOL_H diff --git a/src/psbt.cpp b/src/psbt.cpp index 90285c414ee8..bea409f2c281 100644 --- a/src/psbt.cpp +++ b/src/psbt.cpp @@ -205,7 +205,7 @@ void UpdatePSBTOutput(const SigningProvider& provider, PartiallySignedTransactio // Construct a would-be spend of this output, to update sigdata with. // Note that ProduceSignature is used to fill in metadata (not actual signatures), // so provider does not need to provide any private keys (it can be a HidingSigningProvider). - MutableTransactionSignatureCreator creator(&tx, /*input_idx=*/0, out.nValue, SIGHASH_ALL); + MutableTransactionSignatureCreator creator(tx, /*input_idx=*/0, out.nValue, SIGHASH_ALL); ProduceSignature(provider, creator, out.scriptPubKey, sigdata); // Put redeem_script, key paths, into PSBTOutput. @@ -267,7 +267,7 @@ bool SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction& if (txdata == nullptr) { sig_complete = ProduceSignature(provider, DUMMY_SIGNATURE_CREATOR, utxo.scriptPubKey, sigdata); } else { - MutableTransactionSignatureCreator creator(&tx, index, utxo.nValue, txdata, sighash); + MutableTransactionSignatureCreator creator(tx, index, utxo.nValue, txdata, sighash); sig_complete = ProduceSignature(provider, creator, utxo.scriptPubKey, sigdata); } diff --git a/src/psbt.h b/src/psbt.h index d3d778d8952a..7069a58e61f0 100644 --- a/src/psbt.h +++ b/src/psbt.h @@ -5,7 +5,6 @@ #ifndef BITCOIN_PSBT_H #define BITCOIN_PSBT_H -#include #include #include #include diff --git a/src/pubkey.cpp b/src/pubkey.cpp index a1c13e902a6f..8de5143dbb0b 100644 --- a/src/pubkey.cpp +++ b/src/pubkey.cpp @@ -309,6 +309,7 @@ void CExtPubKey::DecodeWithVersion(const unsigned char code[BIP32_EXTKEY_WITH_VE } bool CExtPubKey::Derive(CExtPubKey &out, unsigned int _nChild) const { + if (nDepth == std::numeric_limits::max()) return false; out.nDepth = nDepth + 1; CKeyID id = pubkey.GetID(); memcpy(out.vchFingerprint, &id, 4); diff --git a/src/pubkey.h b/src/pubkey.h index 09b53ead9f63..990a33ccef99 100644 --- a/src/pubkey.h +++ b/src/pubkey.h @@ -208,7 +208,7 @@ class CPubKey bool Decompress(); //! Derive BIP32 child pubkey. - bool Derive(CPubKey& pubkeyChild, ChainCode &ccChild, unsigned int nChild, const ChainCode& cc) const; + [[nodiscard]] bool Derive(CPubKey& pubkeyChild, ChainCode &ccChild, unsigned int nChild, const ChainCode& cc) const; }; /** An ElligatorSwift-encoded public key. */ @@ -281,7 +281,7 @@ struct CExtPubKey { void Decode(const unsigned char code[BIP32_EXTKEY_SIZE]); void EncodeWithVersion(unsigned char code[BIP32_EXTKEY_WITH_VERSION_SIZE]) const; void DecodeWithVersion(const unsigned char code[BIP32_EXTKEY_WITH_VERSION_SIZE]); - bool Derive(CExtPubKey& out, unsigned int nChild) const; + [[nodiscard]] bool Derive(CExtPubKey& out, unsigned int nChild) const; void Serialize(CSizeComputer& s) const { diff --git a/src/qt/Makefile b/src/qt/Makefile new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/src/qt/addressbookpage.cpp b/src/qt/addressbookpage.cpp index 441531bb9207..31ebe8f4a676 100644 --- a/src/qt/addressbookpage.cpp +++ b/src/qt/addressbookpage.cpp @@ -21,6 +21,11 @@ #include #include #include +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) +#include +#else +#include +#endif class AddressBookSortFilterProxyModel final : public QSortFilterProxyModel { @@ -48,12 +53,13 @@ class AddressBookSortFilterProxyModel final : public QSortFilterProxyModel auto address = model->index(row, AddressTableModel::Address, parent); - if (filterRegExp().indexIn(model->data(address).toString()) < 0 && - filterRegExp().indexIn(model->data(label).toString()) < 0) { - return false; - } - - return true; +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + const auto pattern = filterRegularExpression(); +#else + const auto pattern = filterRegExp(); +#endif + return (model->data(address).toString().contains(pattern) || + model->data(label).toString().contains(pattern)); } }; diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp index d40a3deef6eb..f9eaf6d904b2 100644 --- a/src/qt/addresstablemodel.cpp +++ b/src/qt/addresstablemodel.cpp @@ -30,7 +30,7 @@ struct AddressTableEntry QString label; QString address; - AddressTableEntry() {} + AddressTableEntry() = default; AddressTableEntry(Type _type, const QString &_label, const QString &_address): type(_type), label(_label), address(_address) {} }; diff --git a/src/qt/bantablemodel.cpp b/src/qt/bantablemodel.cpp index ba0e7b8480b2..107b7e797579 100644 --- a/src/qt/bantablemodel.cpp +++ b/src/qt/bantablemodel.cpp @@ -89,10 +89,7 @@ BanTableModel::BanTableModel(interfaces::Node& node, QObject* parent) : refresh(); } -BanTableModel::~BanTableModel() -{ - // Intentionally left empty -} +BanTableModel::~BanTableModel() = default; int BanTableModel::rowCount(const QModelIndex &parent) const { diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index 394d1d97165c..e78adbb79884 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -49,6 +49,7 @@ #include #include +#include #include #include #include diff --git a/src/qt/bitcoinamountfield.cpp b/src/qt/bitcoinamountfield.cpp index 37ac0c91d4ae..d71e08fd2ee8 100644 --- a/src/qt/bitcoinamountfield.cpp +++ b/src/qt/bitcoinamountfield.cpp @@ -38,12 +38,12 @@ static CAmount parse(const QString &text, BitcoinUnit nUnit, bool *valid_out= nu class AmountValidator : public QValidator { Q_OBJECT - BitcoinUnit currentUnit; + BitcoinUnit currentUnit{BitcoinUnit::DASH}; public: explicit AmountValidator(QObject *parent) : - QValidator(parent), - currentUnit(BitcoinUnit::DASH) {} + QValidator(parent) + {} State validate(QString &input, int &pos) const override { @@ -70,8 +70,7 @@ class AmountLineEdit: public QLineEdit AmountValidator* amountValidator; public: explicit AmountLineEdit(QWidget *parent): - QLineEdit(parent), - currentUnit(BitcoinUnit::DASH) + QLineEdit(parent) { setAlignment(Qt::AlignLeft); amountValidator = new AmountValidator(this); diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 3b440e87e2d3..3921618469ea 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -44,6 +44,7 @@ #include #include +#include #include #include #include @@ -393,6 +394,8 @@ void BitcoinGUI::createActions() backupWalletAction->setStatusTip(tr("Backup wallet to another location")); changePassphraseAction = new QAction(tr("&Change Passphrase…"), this); changePassphraseAction->setStatusTip(tr("Change the passphrase used for wallet encryption")); + showMnemonicAction = new QAction(tr("&Show Recovery Phrase…"), this); + showMnemonicAction->setStatusTip(tr("Show the recovery phrase (mnemonic seed) for this wallet")); unlockWalletAction = new QAction(tr("&Unlock Wallet…"), this); unlockWalletAction->setToolTip(tr("Unlock wallet")); lockWalletAction = new QAction(tr("&Lock Wallet"), this); @@ -501,6 +504,7 @@ void BitcoinGUI::createActions() connect(encryptWalletAction, &QAction::triggered, walletFrame, &WalletFrame::encryptWallet); connect(backupWalletAction, &QAction::triggered, walletFrame, &WalletFrame::backupWallet); connect(changePassphraseAction, &QAction::triggered, walletFrame, &WalletFrame::changePassphrase); + connect(showMnemonicAction, &QAction::triggered, walletFrame, &WalletFrame::showMnemonic); connect(unlockWalletAction, &QAction::triggered, walletFrame, &WalletFrame::unlockWallet); connect(lockWalletAction, &QAction::triggered, walletFrame, &WalletFrame::lockWallet); connect(signMessageAction, &QAction::triggered, [this]{ showNormalIfMinimized(); }); @@ -619,6 +623,7 @@ void BitcoinGUI::createMenuBar() { settings->addAction(encryptWalletAction); settings->addAction(changePassphraseAction); + settings->addAction(showMnemonicAction); settings->addAction(unlockWalletAction); settings->addAction(lockWalletAction); settings->addSeparator(); @@ -1039,6 +1044,7 @@ void BitcoinGUI::setWalletActionsEnabled(bool enabled) encryptWalletAction->setEnabled(enabled); backupWalletAction->setEnabled(enabled); changePassphraseAction->setEnabled(enabled); + showMnemonicAction->setEnabled(enabled); unlockWalletAction->setEnabled(enabled); lockWalletAction->setEnabled(enabled); signMessageAction->setEnabled(enabled); @@ -1935,6 +1941,7 @@ void BitcoinGUI::setEncryptionStatus(int status) encryptWalletAction->setChecked(false); changePassphraseAction->setEnabled(false); encryptWalletAction->setEnabled(false); + showMnemonicAction->setEnabled(false); break; case WalletModel::Unencrypted: labelWalletEncryptionIcon->show(); diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index e165738a8a32..08543872943e 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -157,6 +157,7 @@ class BitcoinGUI : public QMainWindow QAction* encryptWalletAction = nullptr; QAction* backupWalletAction = nullptr; QAction* changePassphraseAction = nullptr; + QAction* showMnemonicAction = nullptr; QAction* unlockWalletAction = nullptr; QAction* lockWalletAction = nullptr; QAction* aboutQtAction = nullptr; diff --git a/src/qt/bitcoinunits.cpp b/src/qt/bitcoinunits.cpp index 2d5d6d265f62..65ddc1bda5f8 100644 --- a/src/qt/bitcoinunits.cpp +++ b/src/qt/bitcoinunits.cpp @@ -182,7 +182,7 @@ bool BitcoinUnits::parse(Unit unit, const QString& value, CAmount* val_out) { return false; // More than one dot } - QString whole = parts[0]; + const QString& whole = parts[0]; QString decimals; if(parts.size() > 1) diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h index f4f39a4f61f1..241639e2cd14 100644 --- a/src/qt/clientmodel.h +++ b/src/qt/clientmodel.h @@ -123,7 +123,7 @@ class ClientModel : public QObject std::unique_ptr mnListCached GUARDED_BY(cs_mnlist){}; const CBlockIndex* mnListTip{nullptr}; - void TipChanged(SynchronizationState sync_state, interfaces::BlockTip tip, double verification_progress, bool header); + void TipChanged(SynchronizationState sync_state, interfaces::BlockTip tip, double verification_progress, bool header) EXCLUSIVE_LOCKS_REQUIRED(!m_cached_tip_mutex); void subscribeToCoreSignals(); void unsubscribeFromCoreSignals(); diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index d9bafaafdc3c..9c486d100713 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -638,7 +638,7 @@ void CoinControlDialog::updateView() ui->treeWidget->setEnabled(false); // performance, otherwise updateLabels would be called for every checked checkbox ui->treeWidget->setAlternatingRowColors(!treeMode); QFlags flgCheckbox = Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable; - QFlags flgTristate = Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable | Qt::ItemIsTristate; + QFlags flgTristate = Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable | Qt::ItemIsAutoTristate; BitcoinUnit nDisplayUnit = model->getOptionsModel()->getDisplayUnit(); diff --git a/src/qt/createwalletdialog.cpp b/src/qt/createwalletdialog.cpp index 5b7a7b353b4b..8b19e927ba72 100644 --- a/src/qt/createwalletdialog.cpp +++ b/src/qt/createwalletdialog.cpp @@ -6,12 +6,14 @@ #include #endif +#include #include #include #include #include +#include CreateWalletDialog::CreateWalletDialog(QWidget* parent) : QDialog(parent, GUIUtil::dialog_flags), @@ -22,19 +24,56 @@ CreateWalletDialog::CreateWalletDialog(QWidget* parent) : ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); ui->wallet_name_line_edit->setFocus(Qt::ActiveWindowFocusReason); + // Hide advanced options by default and provide a compact toggle control. + ui->groupBox->setVisible(false); + ui->groupBox->setTitle(QString()); + ui->advanced_toggle_button->setChecked(false); + ui->advanced_toggle_button->setArrowType(Qt::RightArrow); + ui->advanced_toggle_button->setFocusPolicy(Qt::NoFocus); + connect(ui->advanced_toggle_button, &QToolButton::toggled, this, [this](bool checked) { + ui->groupBox->setVisible(checked); + ui->advanced_toggle_button->setArrowType(checked ? Qt::DownArrow : Qt::RightArrow); + }); + connect(ui->wallet_name_line_edit, &QLineEdit::textEdited, [this](const QString& text) { ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(!text.isEmpty()); }); connect(ui->encrypt_wallet_checkbox, &QCheckBox::toggled, [this](bool checked) { - // Disable the disable_privkeys_checkbox when isEncryptWalletChecked is + // Disable the disable_privkeys_checkbox and external_signer_checkbox when isEncryptWalletChecked is // set to true, enable it when isEncryptWalletChecked is false. ui->disable_privkeys_checkbox->setEnabled(!checked); - +#ifdef ENABLE_EXTERNAL_SIGNER + ui->external_signer_checkbox->setEnabled(m_has_signers && !checked); +#endif // When the disable_privkeys_checkbox is disabled, uncheck it. if (!ui->disable_privkeys_checkbox->isEnabled()) { ui->disable_privkeys_checkbox->setChecked(false); } + + // When the external_signer_checkbox box is disabled, uncheck it. + if (!ui->external_signer_checkbox->isEnabled()) { + ui->external_signer_checkbox->setChecked(false); + } + + }); + + connect(ui->external_signer_checkbox, &QCheckBox::toggled, [this](bool checked) { + ui->encrypt_wallet_checkbox->setEnabled(!checked); + ui->blank_wallet_checkbox->setEnabled(!checked); + ui->disable_privkeys_checkbox->setEnabled(!checked); + ui->descriptor_checkbox->setEnabled(!checked); + + // The external signer checkbox is only enabled when a device is detected. + // In that case it is checked by default. Toggling it restores the other + // options to their default. + ui->descriptor_checkbox->setChecked(checked); + ui->encrypt_wallet_checkbox->setChecked(false); + ui->disable_privkeys_checkbox->setChecked(checked); + // The blank check box is ambiguous. This flag is always true for a + // watch-only wallet, even though we immedidately fetch keys from the + // external signer. + ui->blank_wallet_checkbox->setChecked(checked); }); connect(ui->disable_privkeys_checkbox, &QCheckBox::toggled, [this](bool checked) { // Disable the encrypt_wallet_checkbox when isDisablePrivateKeysChecked is @@ -62,11 +101,22 @@ CreateWalletDialog::CreateWalletDialog(QWidget* parent) : ui->descriptor_checkbox->setToolTip(tr("Compiled without sqlite support (required for descriptor wallets)")); ui->descriptor_checkbox->setEnabled(false); ui->descriptor_checkbox->setChecked(false); + ui->external_signer_checkbox->setEnabled(false); + ui->external_signer_checkbox->setChecked(false); #endif + #ifndef USE_BDB ui->descriptor_checkbox->setEnabled(false); ui->descriptor_checkbox->setChecked(true); #endif + +#ifndef ENABLE_EXTERNAL_SIGNER + //: "External signing" means using devices such as hardware wallets. + ui->external_signer_checkbox->setToolTip(tr("Compiled without external signing support (required for external signing)")); + ui->external_signer_checkbox->setEnabled(false); + ui->external_signer_checkbox->setChecked(false); +#endif + } CreateWalletDialog::~CreateWalletDialog() @@ -74,6 +124,27 @@ CreateWalletDialog::~CreateWalletDialog() delete ui; } +void CreateWalletDialog::setSigners(const std::vector>& signers) +{ + m_has_signers = !signers.empty(); + if (m_has_signers) { + ui->external_signer_checkbox->setEnabled(true); + ui->external_signer_checkbox->setChecked(true); + ui->encrypt_wallet_checkbox->setEnabled(false); + ui->encrypt_wallet_checkbox->setChecked(false); + // The order matters, because connect() is called when toggling a checkbox: + ui->blank_wallet_checkbox->setEnabled(false); + ui->blank_wallet_checkbox->setChecked(false); + ui->disable_privkeys_checkbox->setEnabled(false); + ui->disable_privkeys_checkbox->setChecked(true); + const std::string label = signers[0]->getName(); + ui->wallet_name_line_edit->setText(QString::fromStdString(label)); + ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true); + } else { + ui->external_signer_checkbox->setEnabled(false); + } +} + QString CreateWalletDialog::walletName() const { return ui->wallet_name_line_edit->text(); @@ -98,3 +169,8 @@ bool CreateWalletDialog::isDescriptorWalletChecked() const { return ui->descriptor_checkbox->isChecked(); } + +bool CreateWalletDialog::isExternalSignerChecked() const +{ + return ui->external_signer_checkbox->isChecked(); +} diff --git a/src/qt/createwalletdialog.h b/src/qt/createwalletdialog.h index 5fca441eba47..939b82ff78c4 100644 --- a/src/qt/createwalletdialog.h +++ b/src/qt/createwalletdialog.h @@ -7,6 +7,12 @@ #include +#include + +namespace interfaces { +class ExternalSigner; +} // namespace interfaces + class WalletModel; namespace Ui { @@ -23,14 +29,18 @@ class CreateWalletDialog : public QDialog explicit CreateWalletDialog(QWidget* parent); virtual ~CreateWalletDialog(); + void setSigners(const std::vector>& signers); + QString walletName() const; bool isEncryptWalletChecked() const; bool isDisablePrivateKeysChecked() const; bool isMakeBlankWalletChecked() const; bool isDescriptorWalletChecked() const; + bool isExternalSignerChecked() const; private: Ui::CreateWalletDialog *ui; + bool m_has_signers = false; }; #endif // BITCOIN_QT_CREATEWALLETDIALOG_H diff --git a/src/qt/dashstrings.cpp b/src/qt/dashstrings.cpp index 59a3ec2a47f1..772330ce8ba8 100644 --- a/src/qt/dashstrings.cpp +++ b/src/qt/dashstrings.cpp @@ -17,6 +17,8 @@ QT_TRANSLATE_NOOP("dash-core", "" "%s file contains all private keys from this wallet. Do not share it with " "anyone!"), QT_TRANSLATE_NOOP("dash-core", "" +"%s is set very high! Fees this large could be paid on a single transaction."), +QT_TRANSLATE_NOOP("dash-core", "" "%s request to listen on port %u. This port is considered \"bad\" and thus it " "is unlikely that any Dash Core peers connect to it. See doc/p2p-bad-ports.md " "for details and a full list."), @@ -24,9 +26,6 @@ QT_TRANSLATE_NOOP("dash-core", "" "%s uses exact denominated amounts to send funds, you might simply need to " "mix some more coins."), QT_TRANSLATE_NOOP("dash-core", "" -"-maxtxfee is set very high! Fees this large could be paid on a single " -"transaction."), -QT_TRANSLATE_NOOP("dash-core", "" "-reindex-chainstate option is not compatible with -blockfilterindex. Please " "temporarily disable blockfilterindex while using -reindex-chainstate, or " "replace -reindex-chainstate with -reindex to fully rebuild all indexes."), @@ -47,9 +46,6 @@ QT_TRANSLATE_NOOP("dash-core", "" "Cannot provide specific connections and have addrman find outgoing " "connections at the same time."), QT_TRANSLATE_NOOP("dash-core", "" -"Cannot upgrade a non HD wallet from version %i to version %i which is non-HD " -"wallet. Use upgradetohd RPC"), -QT_TRANSLATE_NOOP("dash-core", "" "Distributed under the MIT software license, see the accompanying file %s or " "%s"), QT_TRANSLATE_NOOP("dash-core", "" @@ -78,7 +74,7 @@ QT_TRANSLATE_NOOP("dash-core", "" "again."), QT_TRANSLATE_NOOP("dash-core", "" "Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable " -"-fallbackfee."), +"%s."), QT_TRANSLATE_NOOP("dash-core", "" "File %s already exists. If you are sure this is what you want, move it out " "of the way first."), @@ -94,8 +90,8 @@ QT_TRANSLATE_NOOP("dash-core", "" QT_TRANSLATE_NOOP("dash-core", "" "Invalid -socketevents ('%s') specified. Only these modes are supported: %s"), QT_TRANSLATE_NOOP("dash-core", "" -"Invalid amount for -maxtxfee=: '%s' (must be at least the minrelay " -"fee of %s to prevent stuck transactions)"), +"Invalid amount for %s=: '%s' (must be at least the minrelay fee of " +"%s to prevent stuck transactions)"), QT_TRANSLATE_NOOP("dash-core", "" "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 " @@ -115,6 +111,9 @@ QT_TRANSLATE_NOOP("dash-core", "" "No wallet file format provided. To use createfromdump, -format= must " "be provided."), QT_TRANSLATE_NOOP("dash-core", "" +"Outbound connections restricted to CJDNS (-onlynet=cjdns) but " +"-cjdnsreachable is not provided"), +QT_TRANSLATE_NOOP("dash-core", "" "Outbound connections restricted to Tor (-onlynet=onion) but the proxy for " "reaching the Tor network is explicitly forbidden: -onion=0"), QT_TRANSLATE_NOOP("dash-core", "" @@ -122,6 +121,9 @@ QT_TRANSLATE_NOOP("dash-core", "" "reaching the Tor network is not provided: none of -proxy, -onion or " "-listenonion is given"), QT_TRANSLATE_NOOP("dash-core", "" +"Outbound connections restricted to i2p (-onlynet=i2p) but -i2psam is not " +"provided"), +QT_TRANSLATE_NOOP("dash-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("dash-core", "" @@ -139,18 +141,11 @@ QT_TRANSLATE_NOOP("dash-core", "" "SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is " "supported"), QT_TRANSLATE_NOOP("dash-core", "" -"The -txindex upgrade started by a previous version cannot be completed. " -"Restart with the previous version or run a full -reindex."), -QT_TRANSLATE_NOOP("dash-core", "" "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"), QT_TRANSLATE_NOOP("dash-core", "" -"The block index db contains a legacy 'txindex'. To clear the occupied disk " -"space, run a full -reindex, otherwise ignore this error. This error message " -"will not be displayed again."), -QT_TRANSLATE_NOOP("dash-core", "" "The transaction amount is too small to send after the fee has been deducted"), QT_TRANSLATE_NOOP("dash-core", "" "This error could occur if this wallet was not shutdown cleanly and was last " @@ -175,8 +170,8 @@ QT_TRANSLATE_NOOP("dash-core", "" "Either start with -disablegovernance command line switch or enable " "transaction index."), QT_TRANSLATE_NOOP("dash-core", "" -"Transaction needs a change address, but we can't generate it. Please call " -"keypoolrefill first."), +"Transaction requires one destination of non-0 value, a non-0 feerate, or a " +"pre-selected input"), QT_TRANSLATE_NOOP("dash-core", "" "Unable to replay blocks. You will need to rebuild the database using " "-reindex-chainstate."), @@ -187,6 +182,9 @@ QT_TRANSLATE_NOOP("dash-core", "" "Unsupported category-specific logging level -loglevel=%s. Expected " "-loglevel=:. Valid categories: %s. Valid loglevels: %s."), QT_TRANSLATE_NOOP("dash-core", "" +"Unsupported chainstate database format found. Please restart with -reindex-" +"chainstate. This will rebuild the chainstate database."), +QT_TRANSLATE_NOOP("dash-core", "" "WARNING! Failed to replenish keypool, please unlock your wallet to do so."), QT_TRANSLATE_NOOP("dash-core", "" "Wallet is locked, can't replenish keypool! Automatic backups and mixing are " @@ -215,12 +213,17 @@ QT_TRANSLATE_NOOP("dash-core", "-devnet can only be specified once"), QT_TRANSLATE_NOOP("dash-core", "-maxmempool must be at least %d MB"), QT_TRANSLATE_NOOP("dash-core", "-port must be specified when -devnet and -listen are specified"), QT_TRANSLATE_NOOP("dash-core", "-rpcport must be specified when -devnet and -server are specified"), +QT_TRANSLATE_NOOP("dash-core", "-statsbatchsize cannot be configured with a negative value."), +QT_TRANSLATE_NOOP("dash-core", "-statsduration cannot be configured with a negative value."), QT_TRANSLATE_NOOP("dash-core", "A fatal internal error occurred, see debug.log for details"), QT_TRANSLATE_NOOP("dash-core", "Already have that input."), QT_TRANSLATE_NOOP("dash-core", "Automatic backups disabled"), QT_TRANSLATE_NOOP("dash-core", "Can't find random Masternode."), QT_TRANSLATE_NOOP("dash-core", "Can't mix while sync in progress."), QT_TRANSLATE_NOOP("dash-core", "Can't mix: no compatible inputs found!"), +QT_TRANSLATE_NOOP("dash-core", "Cannot create socket (socket() returned error %s)"), +QT_TRANSLATE_NOOP("dash-core", "Cannot get socket address for %s"), +QT_TRANSLATE_NOOP("dash-core", "Cannot init Statsd client"), QT_TRANSLATE_NOOP("dash-core", "Cannot resolve -%s address: '%s'"), QT_TRANSLATE_NOOP("dash-core", "Cannot set -peerblockfilters without -blockfilterindex."), QT_TRANSLATE_NOOP("dash-core", "Cannot write to data directory '%s'; check permissions."), @@ -249,8 +252,6 @@ QT_TRANSLATE_NOOP("dash-core", "Error loading block database"), QT_TRANSLATE_NOOP("dash-core", "Error opening block database"), QT_TRANSLATE_NOOP("dash-core", "Error reading from database, shutting down."), QT_TRANSLATE_NOOP("dash-core", "Error reading next record from wallet database"), -QT_TRANSLATE_NOOP("dash-core", "Error upgrading Evo database"), -QT_TRANSLATE_NOOP("dash-core", "Error upgrading chainstate database"), QT_TRANSLATE_NOOP("dash-core", "Error upgrading evo database for EHF"), QT_TRANSLATE_NOOP("dash-core", "Error: Couldn't create cursor into database"), QT_TRANSLATE_NOOP("dash-core", "Error: Disk space is low for %s"), @@ -262,7 +263,6 @@ QT_TRANSLATE_NOOP("dash-core", "Error: Missing checksum"), QT_TRANSLATE_NOOP("dash-core", "Error: No addresses available."), QT_TRANSLATE_NOOP("dash-core", "Error: Unable to parse version %u as a uint32_t"), QT_TRANSLATE_NOOP("dash-core", "Error: Unable to write record to new wallet"), -QT_TRANSLATE_NOOP("dash-core", "Exceeded max tries."), QT_TRANSLATE_NOOP("dash-core", "Failed to clear fulfilled requests cache at %s"), QT_TRANSLATE_NOOP("dash-core", "Failed to clear governance cache at %s"), QT_TRANSLATE_NOOP("dash-core", "Failed to clear masternode cache at %s"), @@ -278,10 +278,13 @@ QT_TRANSLATE_NOOP("dash-core", "Failed to load masternode cache from %s"), QT_TRANSLATE_NOOP("dash-core", "Failed to load sporks cache from %s"), QT_TRANSLATE_NOOP("dash-core", "Failed to rescan the wallet during initialization"), QT_TRANSLATE_NOOP("dash-core", "Failed to start a new mixing queue"), +QT_TRANSLATE_NOOP("dash-core", "Failed to upgrade Evo database"), QT_TRANSLATE_NOOP("dash-core", "Failed to verify database"), +QT_TRANSLATE_NOOP("dash-core", "Fee needed > fee paid"), QT_TRANSLATE_NOOP("dash-core", "Fee rate (%s) is lower than the minimum fee rate setting (%s)"), QT_TRANSLATE_NOOP("dash-core", "Found enough users, signing ( waiting %s )"), QT_TRANSLATE_NOOP("dash-core", "Found enough users, signing…"), +QT_TRANSLATE_NOOP("dash-core", "Host %s on unsupported network"), QT_TRANSLATE_NOOP("dash-core", "Ignoring duplicate -wallet %s."), QT_TRANSLATE_NOOP("dash-core", "Importing…"), QT_TRANSLATE_NOOP("dash-core", "Incompatible mode."), @@ -298,13 +301,13 @@ QT_TRANSLATE_NOOP("dash-core", "Invalid -i2psam address or hostname: '%s'"), QT_TRANSLATE_NOOP("dash-core", "Invalid -onion address or hostname: '%s'"), QT_TRANSLATE_NOOP("dash-core", "Invalid -proxy address or hostname: '%s'"), QT_TRANSLATE_NOOP("dash-core", "Invalid P2P permission: '%s'"), +QT_TRANSLATE_NOOP("dash-core", "Invalid amount for %s=: '%s' (must be at least %s)"), +QT_TRANSLATE_NOOP("dash-core", "Invalid amount for %s=: '%s'"), QT_TRANSLATE_NOOP("dash-core", "Invalid amount for -%s=: '%s'"), -QT_TRANSLATE_NOOP("dash-core", "Invalid amount for -discardfee=: '%s'"), -QT_TRANSLATE_NOOP("dash-core", "Invalid amount for -fallbackfee=: '%s'"), -QT_TRANSLATE_NOOP("dash-core", "Invalid amount for -paytxfee=: '%s' (must be at least %s)"), QT_TRANSLATE_NOOP("dash-core", "Invalid masternodeblsprivkey. Please see documentation."), QT_TRANSLATE_NOOP("dash-core", "Invalid minimum number of spork signers specified with -minsporkkeys"), QT_TRANSLATE_NOOP("dash-core", "Invalid netmask specified in -whitelist: '%s'"), +QT_TRANSLATE_NOOP("dash-core", "Invalid port specified in %s: '%s'"), QT_TRANSLATE_NOOP("dash-core", "Invalid script detected."), QT_TRANSLATE_NOOP("dash-core", "Invalid spork address specified with -sporkaddr"), QT_TRANSLATE_NOOP("dash-core", "Last queue was created too recently."), @@ -318,17 +321,22 @@ QT_TRANSLATE_NOOP("dash-core", "Lock is already in place."), QT_TRANSLATE_NOOP("dash-core", "Masternode queue is full."), QT_TRANSLATE_NOOP("dash-core", "Masternode:"), QT_TRANSLATE_NOOP("dash-core", "Missing input transaction information."), +QT_TRANSLATE_NOOP("dash-core", "Missing solving data for estimating transaction size"), QT_TRANSLATE_NOOP("dash-core", "Mixing in progress…"), QT_TRANSLATE_NOOP("dash-core", "Need to specify a port with -whitebind: '%s'"), QT_TRANSLATE_NOOP("dash-core", "No Masternodes detected."), QT_TRANSLATE_NOOP("dash-core", "No addresses available"), QT_TRANSLATE_NOOP("dash-core", "No compatible Masternode found."), QT_TRANSLATE_NOOP("dash-core", "No errors detected."), +QT_TRANSLATE_NOOP("dash-core", "No host specified"), +QT_TRANSLATE_NOOP("dash-core", "No host specified, malformed URL"), QT_TRANSLATE_NOOP("dash-core", "No matching denominations found for mixing."), +QT_TRANSLATE_NOOP("dash-core", "No text before the scheme delimiter, malformed URL"), QT_TRANSLATE_NOOP("dash-core", "Not compatible with existing transactions."), QT_TRANSLATE_NOOP("dash-core", "Not enough file descriptors available."), QT_TRANSLATE_NOOP("dash-core", "Not enough funds to mix."), QT_TRANSLATE_NOOP("dash-core", "Not in the Masternode list."), +QT_TRANSLATE_NOOP("dash-core", "Port must be between %d and %d, supplied %d"), QT_TRANSLATE_NOOP("dash-core", "Prune cannot be configured with a negative value."), QT_TRANSLATE_NOOP("dash-core", "Prune mode is incompatible with -disablegovernance=false."), QT_TRANSLATE_NOOP("dash-core", "Prune mode is incompatible with -txindex."), @@ -344,6 +352,7 @@ QT_TRANSLATE_NOOP("dash-core", "Section [%s] is not recognized."), QT_TRANSLATE_NOOP("dash-core", "Session not complete!"), QT_TRANSLATE_NOOP("dash-core", "Session timed out."), QT_TRANSLATE_NOOP("dash-core", "Signing transaction failed"), +QT_TRANSLATE_NOOP("dash-core", "Socket not initialized, cannot send message"), QT_TRANSLATE_NOOP("dash-core", "Specified -walletdir \"%s\" does not exist"), QT_TRANSLATE_NOOP("dash-core", "Specified -walletdir \"%s\" is a relative path"), QT_TRANSLATE_NOOP("dash-core", "Specified -walletdir \"%s\" is not a directory"), @@ -369,6 +378,7 @@ QT_TRANSLATE_NOOP("dash-core", "Transaction created successfully."), QT_TRANSLATE_NOOP("dash-core", "Transaction fees are too high."), QT_TRANSLATE_NOOP("dash-core", "Transaction has too long of a mempool chain"), QT_TRANSLATE_NOOP("dash-core", "Transaction must have at least one recipient"), +QT_TRANSLATE_NOOP("dash-core", "Transaction needs a change address, but we can't generate it."), QT_TRANSLATE_NOOP("dash-core", "Transaction not valid."), QT_TRANSLATE_NOOP("dash-core", "Transaction too large"), QT_TRANSLATE_NOOP("dash-core", "Trying to connect…"), @@ -378,8 +388,10 @@ QT_TRANSLATE_NOOP("dash-core", "Unable to create the PID file '%s': %s"), QT_TRANSLATE_NOOP("dash-core", "Unable to generate initial keys"), QT_TRANSLATE_NOOP("dash-core", "Unable to locate enough mixed funds for this transaction."), QT_TRANSLATE_NOOP("dash-core", "Unable to locate enough non-denominated funds for this transaction."), +QT_TRANSLATE_NOOP("dash-core", "Unable to lookup host %s"), QT_TRANSLATE_NOOP("dash-core", "Unable to open %s for writing"), -QT_TRANSLATE_NOOP("dash-core", "Unable to parse -maxuploadtarget: '%s' (possible integer overflow?)"), +QT_TRANSLATE_NOOP("dash-core", "Unable to parse -maxuploadtarget: '%s'"), +QT_TRANSLATE_NOOP("dash-core", "Unable to send message to %s (::sendto() returned error %s)"), QT_TRANSLATE_NOOP("dash-core", "Unable to sign spork message, wrong key?"), QT_TRANSLATE_NOOP("dash-core", "Unable to start HTTP server. See debug log for details."), QT_TRANSLATE_NOOP("dash-core", "Unknown -blockfilterindex value %s."), @@ -387,9 +399,9 @@ QT_TRANSLATE_NOOP("dash-core", "Unknown network specified in -onlynet: '%s'"), QT_TRANSLATE_NOOP("dash-core", "Unknown new rules activated (versionbit %i)"), QT_TRANSLATE_NOOP("dash-core", "Unknown response."), QT_TRANSLATE_NOOP("dash-core", "Unknown state: id = %u"), +QT_TRANSLATE_NOOP("dash-core", "Unsupported URL scheme, must begin with udp://"), QT_TRANSLATE_NOOP("dash-core", "Unsupported global logging level -loglevel=%s. Valid values: %s."), QT_TRANSLATE_NOOP("dash-core", "Unsupported logging category %s=%s."), -QT_TRANSLATE_NOOP("dash-core", "Upgrading UTXO database"), QT_TRANSLATE_NOOP("dash-core", "User Agent comment (%s) contains unsafe characters."), QT_TRANSLATE_NOOP("dash-core", "Verifying blocks…"), QT_TRANSLATE_NOOP("dash-core", "Verifying wallet(s)…"), diff --git a/src/qt/forms/createwalletdialog.ui b/src/qt/forms/createwalletdialog.ui index 49f66c25e418..48310006fc36 100644 --- a/src/qt/forms/createwalletdialog.ui +++ b/src/qt/forms/createwalletdialog.ui @@ -17,6 +17,9 @@ true + + 8 + @@ -71,11 +74,54 @@ + + + Advanced Options + + + Qt::ToolButtonTextBesideIcon + + + true + + + Qt::NoFocus + + + true + + + false + + + Qt::RightArrow + + + + - Advanced Options + + + + false + + 0 + + + 8 + + + 8 + + + 8 + + + 4 + @@ -109,6 +155,16 @@ + + + + Use an external signing device such as a hardware wallet. Configure the external signer script in wallet preferences first. + + + External signer + + + @@ -142,6 +198,7 @@ encrypt_wallet_checkbox disable_privkeys_checkbox blank_wallet_checkbox + external_signer_checkbox diff --git a/src/qt/forms/mnemonicverificationdialog.ui b/src/qt/forms/mnemonicverificationdialog.ui new file mode 100644 index 000000000000..af07af8b3299 --- /dev/null +++ b/src/qt/forms/mnemonicverificationdialog.ui @@ -0,0 +1,206 @@ + + + MnemonicVerificationDialog + + + Save Your Mnemonic + + + + + + 0 + + + + + + + WARNING: If you lose your mnemonic seed phrase, you will lose access to your wallet forever. + + + Qt::RichText + + + true + + + + + + + Please write down these words in order. You will need them to restore your wallet. + + + true + + + + + + + QFrame::NoFrame + + + true + + + + + + + + + + + + Show + + + + + + + Hide + + + + + + + Qt::Horizontal + + + + 20 + 20 + + + + + + + + I have written down my mnemonic + + + + + + + + + + + + + To verify you've saved your mnemonic, please enter the following words: + + + true + + + + + + + + + Word #1: + + + + + + + + + + + + + + + + + Word #2: + + + + + + + + + + + + + + + + + Word #3: + + + + + + + + + + + + + + + + + + + + + Back + + + + + + + Qt::Horizontal + + + + + + + + + + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + MnemonicVerificationDialog + accept() + + + buttonBox + rejected() + MnemonicVerificationDialog + reject() + + + + diff --git a/src/qt/forms/optionsdialog.ui b/src/qt/forms/optionsdialog.ui index bca7379c75f5..b46cf51b7ce1 100644 --- a/src/qt/forms/optionsdialog.ui +++ b/src/qt/forms/optionsdialog.ui @@ -409,6 +409,36 @@ + + + + External Signer (e.g. hardware wallet) + + + + + + + + &External signer script path + + + externalSignerPath + + + + + + + Full path to a Dash Core compatible script (e.g. C:\Downloads\hwi.exe or /Users/you/Downloads/hwi.py). Beware: malware can steal your coins! + + + + + + + + diff --git a/src/qt/forms/proposalwizard.ui b/src/qt/forms/proposalwizard.ui index d8b749cc65d4..992929f64ed3 100644 --- a/src/qt/forms/proposalwizard.ui +++ b/src/qt/forms/proposalwizard.ui @@ -33,21 +33,6 @@ - - 0 - - - 8 - - - 0 - - - 0 - - - 8 - @@ -110,7 +95,7 @@ - short-unique-name + short-unique-name 24 @@ -136,7 +121,7 @@ - https://example.com/my-proposal + https://example.com/my-proposal 24 @@ -255,7 +240,7 @@ - 0 + 0 @@ -330,6 +315,9 @@ 120 + + true + @@ -337,12 +325,15 @@ Hex-encoded JSON + + true + - - + - @@ -377,19 +368,6 @@ - - - - Validate - - - - 0 - 28 - - - - @@ -427,7 +405,7 @@ - TxID: + TxID: @@ -437,7 +415,7 @@ true - - + - 24 @@ -661,7 +639,7 @@ true - - + - 24 @@ -762,7 +740,6 @@ plainJson editHex btnBack1 - btnValidate btnNext2 editTxid btnCopyTxid diff --git a/src/qt/forms/receiverequestdialog.ui b/src/qt/forms/receiverequestdialog.ui index 7d95a8bc907c..70a7cf71de9b 100644 --- a/src/qt/forms/receiverequestdialog.ui +++ b/src/qt/forms/receiverequestdialog.ui @@ -254,6 +254,19 @@ + + + + &Verify + + + Verify this address on e.g. a hardware wallet screen + + + false + + + diff --git a/src/qt/governancelist.cpp b/src/qt/governancelist.cpp index 35567f47eb2b..37f61fca4a06 100644 --- a/src/qt/governancelist.cpp +++ b/src/qt/governancelist.cpp @@ -43,23 +43,23 @@ Proposal::Proposal(ClientModel* _clientModel, const CGovernanceObject& _govObj, { UniValue prop_data; if (prop_data.read(govObj.GetDataAsPlainString())) { - if (UniValue titleValue = prop_data.find_value("name"); titleValue.isStr()) { + if (const UniValue& titleValue = prop_data.find_value("name"); titleValue.isStr()) { m_title = QString::fromStdString(titleValue.get_str()); } - if (UniValue paymentStartValue = prop_data.find_value("start_epoch"); paymentStartValue.isNum()) { + if (const UniValue& paymentStartValue = prop_data.find_value("start_epoch"); paymentStartValue.isNum()) { m_startDate = QDateTime::fromSecsSinceEpoch(paymentStartValue.getInt()); } - if (UniValue paymentEndValue = prop_data.find_value("end_epoch"); paymentEndValue.isNum()) { + if (const UniValue& paymentEndValue = prop_data.find_value("end_epoch"); paymentEndValue.isNum()) { m_endDate = QDateTime::fromSecsSinceEpoch(paymentEndValue.getInt()); } - if (UniValue amountValue = prop_data.find_value("payment_amount"); amountValue.isNum()) { + if (const UniValue& amountValue = prop_data.find_value("payment_amount"); amountValue.isNum()) { m_paymentAmount = amountValue.get_real(); } - if (UniValue urlValue = prop_data.find_value("url"); urlValue.isStr()) { + if (const UniValue& urlValue = prop_data.find_value("url"); urlValue.isStr()) { m_url = QString::fromStdString(urlValue.get_str()); } } @@ -595,18 +595,17 @@ void GovernanceList::voteForProposal(vote_outcome_enum_t outcome) // Show results QString message; - if (nSuccessful > 0 && nFailed == 0) { - message = tr("Voted successfully %1 time(s).").arg(nSuccessful); - } else if (nSuccessful > 0 && nFailed > 0) { - message = tr("Voted successfully %1 time(s) and failed %2 time(s).").arg(nSuccessful).arg(nFailed); - if (!failedMessages.isEmpty()) { - message += tr("\n\nFailed votes:\n%1").arg(failedMessages.join("\n")); - } - } else { - message = tr("Failed to vote %1 time(s).").arg(nFailed); - if (!failedMessages.isEmpty()) { - message += tr("\n\nErrors:\n%1").arg(failedMessages.join("\n")); + if (nSuccessful > 0) { + message += tr("Voted successfully %n time(s)", "", nSuccessful); + } + if (nFailed > 0) { + if (nSuccessful > 0) { + message += QString("\n"); } + message += tr("Failed to vote %n time(s)", "", nFailed); + } + if (!failedMessages.isEmpty()) { + message += QString("\n\n") + tr("Errors:") + QString("\n") + failedMessages.join("\n"); } QMessageBox::information(this, tr("Voting Results"), message); diff --git a/src/qt/governancelist.h b/src/qt/governancelist.h index 1f696d7f1669..dd79fe51e571 100644 --- a/src/qt/governancelist.h +++ b/src/qt/governancelist.h @@ -5,13 +5,14 @@ #ifndef BITCOIN_QT_GOVERNANCELIST_H #define BITCOIN_QT_GOVERNANCELIST_H -#include -#include #include +#include #include #include #include +#include + #include #include #include @@ -28,12 +29,14 @@ namespace Ui { class GovernanceList; } -class CDeterministicMNList; class ClientModel; class ProposalModel; class WalletModel; class ProposalWizard; +class CDeterministicMNList; +enum vote_outcome_enum_t : int; + /** Governance Manager page widget */ class GovernanceList : public QWidget { diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index ae9f29e2cd4c..9ae4964330f2 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -62,6 +62,7 @@ #include #include #include +#include #include #include // for Qt::mightBeRichText #include @@ -70,6 +71,7 @@ #include #include +#include #include #include #include @@ -175,7 +177,7 @@ static const std::map themedDarkColors = { }; static const std::map themedStyles = { - { ThemedStyle::TS_INVALID, "background:#a84832;" }, + { ThemedStyle::TS_INVALID, "border: 3px solid #a84832;" }, { ThemedStyle::TS_ERROR, "color:#a84832;" }, { ThemedStyle::TS_WARNING, "color:#999900;" }, { ThemedStyle::TS_SUCCESS, "color:#5e8c41;" }, @@ -185,7 +187,7 @@ static const std::map themedStyles = { }; static const std::map themedDarkStyles = { - { ThemedStyle::TS_INVALID, "background:#a84832;" }, + { ThemedStyle::TS_INVALID, "border: 3px solid #a84832;" }, { ThemedStyle::TS_ERROR, "color:#a84832;" }, { ThemedStyle::TS_WARNING, "color:#999900;" }, { ThemedStyle::TS_SUCCESS, "color:#5e8c41;" }, @@ -886,7 +888,7 @@ bool isStyleSheetDirectoryCustom() return stylesheetDirectory != defaultStylesheetDirectory; } -const std::vector listStyleSheets() +std::vector listStyleSheets() { std::vector vecStylesheets; for (const auto& it : mapThemeToStyle) { @@ -895,7 +897,7 @@ const std::vector listStyleSheets() return vecStylesheets; } -const std::vector listThemes() +std::vector listThemes() { std::vector vecThemes; for (const auto& it : mapThemeToStyle) { @@ -905,7 +907,7 @@ const std::vector listThemes() return vecThemes; } -const QString getDefaultTheme() +QString getDefaultTheme() { return defaultTheme; } @@ -957,7 +959,6 @@ void loadStyleSheet(bool fForceUpdate) QString strStyle = QLatin1String(qFile.readAll()); // Process all groups in the stylesheet first - QRegularExpressionMatch osStyleMatch; QRegularExpression osStyleExp( "^" "()" // group 1 @@ -965,29 +966,44 @@ void loadStyleSheet(bool fForceUpdate) "(?)" // group 3 "$"); osStyleExp.setPatternOptions(QRegularExpression::MultilineOption); - QRegularExpressionMatchIterator it = osStyleExp.globalMatch(strStyle); - // For all sections - while (it.hasNext() && (osStyleMatch = it.next()).isValid()) { - QStringList listMatches = osStyleMatch.capturedTexts(); - - // Full match + 3 group matches - if (listMatches.size() % 4) { - throw std::runtime_error(strprintf("%s: Invalid section in file %s", __func__, file.toStdString())); + // Collect matches first to avoid modifying the string while iterating + QList matches; + { + QRegularExpressionMatchIterator it = osStyleExp.globalMatch(strStyle); + while (it.hasNext()) { + QRegularExpressionMatch m = it.next(); + if (m.hasMatch()) { + matches.append(m); + } } + } - for (int i = 0; i < listMatches.size(); i += 4) { - if (!listMatches[i + 1].contains(QString::fromStdString(platformName))) { - // If os is not supported for this styles - // just remove the full match - strStyle.replace(listMatches[i], ""); - } else { - // If its supported remove the tags - strStyle.replace(listMatches[i + 1], ""); - strStyle.replace(listMatches[i + 3], ""); - } + // Build replacement operations using absolute positions + struct Replacement { int start; int end; QString replacement; }; + QVector replacements; + for (const auto& m : matches) { + const QString openTag = m.captured(1); + const QString inner = m.captured(2); + Q_UNUSED(inner); + // Remove entire block if OS doesn't match, otherwise drop only the tags + if (!openTag.contains(QString::fromStdString(platformName))) { + replacements.push_back({m.capturedStart(0), m.capturedEnd(0), QString()}); + } else { + // Remove opening and closing tags, keep inner content + replacements.push_back({m.capturedStart(1), m.capturedEnd(1), QString()}); + replacements.push_back({m.capturedStart(3), m.capturedEnd(3), QString()}); } } + + // Apply replacements from end to start so offsets stay valid + std::sort(replacements.begin(), replacements.end(), [](const Replacement& a, const Replacement& b) { + return a.start > b.start; + }); + for (const auto& r : replacements) { + strStyle.replace(r.start, r.end - r.start, r.replacement); + } + stylesheet->append(strStyle); } return true; diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h index c3fd6a37a8cf..de3b1109ec9f 100644 --- a/src/qt/guiutil.h +++ b/src/qt/guiutil.h @@ -293,13 +293,13 @@ namespace GUIUtil bool isStyleSheetDirectoryCustom(); /** Return a list of all required css files */ - const std::vector listStyleSheets(); + std::vector listStyleSheets(); /** Return a list of all theme css files */ - const std::vector listThemes(); + std::vector listThemes(); /** Return the name of the default theme `*/ - const QString getDefaultTheme(); + QString getDefaultTheme(); /** Check if the given theme name is valid or not */ bool isValidTheme(const QString& strTheme); diff --git a/src/qt/locale/dash_ar.ts b/src/qt/locale/dash_ar.ts index 4eace44ef83b..74616178f2b5 100644 --- a/src/qt/locale/dash_ar.ts +++ b/src/qt/locale/dash_ar.ts @@ -65,14 +65,6 @@ C&hoose اختر - - Sending addresses - عناوين إرسال - - - Receiving addresses - عناوين الاستقبال - These are your Dash addresses for sending payments. Always check the amount and the receiving address before sending coins. هذه هي عناوين داش التابعة لك من أجل إرسال الدفعات. تحقق دائما من المبلغ و عنوان المرسل المستقبل قبل إرسال العملات @@ -94,8 +86,8 @@ تعديل - &Show address QR code - & إظهار رمز الاستجابة السريعة العنوان + Show address &QR code + عرض رمز &QR للعنوان QR code @@ -105,6 +97,24 @@ Export Address List تصدير قائمة العناوين + + Comma separated file + Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values. + ملف مفصول بفواصل + + + There was an error trying to save the address list to %1. Please try again. + An error message. %1 is a stand-in argument for the name of the file we attempted to save to. + حدث خطأ أثناء محاولة حفظ قائمة العناوين إلى %1. يرجى المحاولة مرة أخرى. + + + Sending addresses - %1 + عناوين الإرسال - %1 + + + Receiving addresses - %1 + عناوين الاستقبال - %1 + Exporting Failed فشل التصدير @@ -274,10 +284,22 @@ The passphrase entered for the wallet decryption was incorrect. كلمة المرور التي تم إدخالها لفك تشفير المحفظة غير صحيحة + + 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 23.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. + عبارة المرور المدخلة لفك تشفير المحفظة غير صحيحة. تحتوي على حرف فارغ (أي بايت صفري). إذا تم تعيين عبارة المرور بإصدار من هذا البرنامج قبل 23.0، يرجى المحاولة مرة أخرى بالأحرف فقط حتى — ولكن ليس بما في ذلك — الحرف الفارغ الأول. إذا نجح هذا، يرجى تعيين عبارة مرور جديدة لتجنب هذه المشكلة في المستقبل. + Wallet passphrase was successfully changed. لقد تم تغير عبارة مرور المحفظة بنجاح + + Passphrase change failed + فشل تغيير عبارة المرور + + + 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 23.0, please try again with only the characters up to — but not including — the first null character. + عبارة المرور القديمة المدخلة لفك تشفير المحفظة غير صحيحة. تحتوي على حرف فارغ (أي بايت صفري). إذا تم تعيين عبارة المرور بإصدار من هذا البرنامج قبل 23.0، يرجى المحاولة مرة أخرى بالأحرف فقط حتى — ولكن ليس بما في ذلك — الحرف الفارغ الأول. + Warning: The Caps Lock key is on! تحذير: مفتاح الحروف الكبيرة مفعل @@ -303,7 +325,23 @@ BitcoinApplication - + + Runaway exception + استثناء هارب + + + A fatal error occurred. %1 can no longer continue safely and will quit. + حدث خطأ فادح. لا يمكن لـ %1 المتابعة بأمان وسيتم الإنهاء. + + + Internal error + خطأ داخلي + + + An internal error occurred. %1 will attempt to continue safely. This is an unexpected bug which can be reported as described below. + حدث خطأ داخلي. سيحاول %1 المتابعة بأمان. هذا خطأ غير متوقع يمكن الإبلاغ عنه كما هو موضح أدناه. + + BitcoinGUI @@ -330,6 +368,10 @@ Request payments (generates QR codes and dash: URIs) أطلب دفعات (يولد كودات الرمز المربع وبيت كوين: العناوين المعطاة) + + Ctrl+Q + Ctrl+Q + &Options… خيارات @@ -358,6 +400,10 @@ &Verify message… التحقق من الرسالة + + &Load PSBT from file… + &تحميل PSBT من ملف… + &Sending addresses &عناوين الإرسال @@ -390,10 +436,6 @@ &Window &نافذة - - Minimize - تصغير - Zoom تكبير @@ -446,14 +488,6 @@ Modify configuration options for %1 تغيير خيارات الإعداد لأساس ل %1 - - &Show / Hide - عرض / اخفاء - - - Show or hide the main Window - عرض او اخفاء النافذة الرئيسية - Encrypt the private keys that belong to your wallet تشفير المفتاح الخاص بمحفظتك @@ -518,10 +552,6 @@ Show wallet repair options عرض خيارات إصلاح المحفظة - - Open Wallet &Configuration File - فتح ملف المحفظة والتهيئة - Open configuration file افتح ملف التهيئة @@ -576,10 +606,40 @@ Show information about %1 إظهار معلومات حول%1 + + Load PSBT from &clipboard… + تحميل PSBT من &الحافظة… + + + Open debugging and diagnostic console + فتح وحدة تحكم التصحيح والتشخيص + + + Open &wallet configuration file + فتح &ملف تكوين المحفظة + + + Open a dash: URI + فتح dash: URI + Create a new wallet أنشئ محفظة جديدة + + Restore Wallet… + Name of the menu item that restores wallet from a backup file. + استعادة المحفظة… + + + Restore a wallet from a backup file + Status tip for Restore Wallet menu item + استعادة محفظة من ملف نسخ احتياطي + + + Close all wallets + إغلاق جميع المحافظ + %1 &information %1 معلومات @@ -588,10 +648,42 @@ Show the %1 basic information عرض %1 المعلومات الرئيسية + + &Discreet mode + &الوضع السري + + + Mask the values in the Overview tab + إخفاء القيم في علامة التبويب نظرة عامة + + + Wallet Data + Name of the wallet data file format. + بيانات المحفظة + + + Load Wallet Backup + The title for Restore Wallet File Windows + تحميل نسخة احتياطية للمحفظة + + + Restore Wallet + Title of pop-up window shown when the user is attempting to restore a wallet. + استعادة المحفظة + + + Wallet Name + Label of the input field where the name of the wallet is entered. + اسم المحفظة + &Settings الإعدادات + + &Minimize + &تصغير + &Help مساعدة @@ -608,8 +700,17 @@ View Governance Proposals عرض مقترحات الحوكمة + + &Hide + &إخفاء + + + S&how + إ&ظهار + %n active connection(s) to Dash network + A substring of the tooltip. %n اتصالات نشطة بشبكة داش%n اتصالات نشطة بشبكة داش%n اتصالات نشطة بشبكة داش%n اتصالات نشطة بشبكة داش%n اتصالات نشطة بشبكة داش%n اتصالات نشطة بشبكة داش @@ -628,10 +729,50 @@ Close Wallet… إغلاق المحفظة … + + Load Partially Signed Blockchain Transaction + تحميل معاملة بلوكتشين موقعة جزئياً + + + Load Partially Signed Blockchain Transaction from clipboard + تحميل معاملة بلوكتشين موقعة جزئياً من الحافظة + Create Wallet… إنشاء المحفظة … + + Close All Wallets… + إغلاق جميع المحافظ… + + + Ctrl+Shift+D + Ctrl+Shift+D + + + Ctrl+M + Ctrl+M + + + Click for more actions. + A substring of the tooltip. "More actions" are available via the context menu. + انقر للمزيد من الإجراءات. + + + Show Peers tab + A context menu item. The "Peers tab" is an element of the "Node window". + إظهار علامة تبويب النظراء + + + Disable network activity + A context menu item. + تعطيل نشاط الشبكة + + + Enable network activity + A context menu item. The network activity was disabled previously. + تفعيل نشاط الشبكة + Syncing Headers (%1%)… مزامنة الرؤوس (%1%) … @@ -648,10 +789,6 @@ Processing blocks on disk… معالجة الكتل على القرص… - - Reindexing blocks on disk… - إعادة الفهرسة الكتل على القرص … - Connecting to peers… اتصال إلي القرناء… @@ -805,10 +942,6 @@ Coin Selection اختيار عملة - - Dust: - غبار: - After Fee: بعد الرسوم: @@ -866,28 +999,32 @@ تم تأكيد - Copy address - نسخ عنوان + Copy amount + مبلغ النسخ + + + &Copy address + &نسخ العنوان - Copy label - نسخ التسمية + Copy &label + نسخ &التسمية - Copy amount - مبلغ النسخ + Copy &amount + نسخ &المبلغ - Copy transaction ID - نسخ معرف المعاملة + Copy transaction &ID and output index + نسخ معرف &المعاملة ومؤشر المخرجات - Lock unspent - قفل غير منفقة + L&ock unspent + ق&فل غير المنفق - Unlock unspent - إلغاء فتح + &Unlock unspent + &فتح قفل غير المنفق Copy quantity @@ -905,10 +1042,6 @@ Copy bytes نسخ وحدات البايت - - Copy dust - نسخ الغبار - Copy change نسخ التغيير @@ -921,18 +1054,6 @@ (%1 locked) (%1 مقفل) - - yes - نعم - - - no - لا - - - This label turns red if any recipient receives an amount smaller than the current dust threshold. - يتحول هذا التصنيف إلى اللون الأحمر إذا تلقى أي مستلم مبلغا أصغر من عتبة الغبار الحالية. - Can vary +/- %1 duff(s) per input. يمكن أن تختلف +/-%1 داف (ق) لكل مدخلات. @@ -976,8 +1097,14 @@ CreateWalletActivity + + Create Wallet + Title of window indicating the progress of creation of a new wallet. + إنشاء المحفظة + Creating Wallet <b>%1</b>… + Descriptive text of the create wallet progress window which indicates to the user which wallet is currently being created. جاري إنشاء المحفظة<b>%1</b> … @@ -999,6 +1126,10 @@ Wallet Name اسم المحفظة + + Wallet + المحفظة + Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice. تشفير المحفظة. سيتم تشفير المحفظة بعبارة مرور من اختيارك. @@ -1007,6 +1138,10 @@ Encrypt Wallet تشفير المحفظة + + Advanced Options + خيارات متقدمة + 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. تعطيل المفاتيح الخاصة لهذه المحفظة. لن تحتوي المحافظ التي تحتوي على مفاتيح خاصة معطلة على مفاتيح خاصة ولا يمكن أن تحتوي على مفتاح HD أو مفاتيح خاصة مستوردة. هذا مثالي لمحافظ الساعات فقط. @@ -1023,11 +1158,23 @@ Make Blank Wallet اصنع محفظة فارغة + + Use descriptors for scriptPubKey management. This feature is well-tested but still considered experimental and not recommended for use yet. + استخدم الواصفات لإدارة scriptPubKey. هذه الميزة مختبرة جيدًا ولكنها لا تزال تعتبر تجريبية ولا يُنصح باستخدامها بعد. + + + Descriptor Wallet (EXPERIMENTAL) + محفظة الواصف (تجريبية) + Create انشاء - + + Compiled without sqlite support (required for descriptor wallets) + تم التجميع بدون دعم sqlite (مطلوب لمحافظ الواصف) + + EditAddressDialog @@ -1116,18 +1263,106 @@ Filter List: قائمة تصفية: + + Filter proposal list + تصفية قائمة المقترحات + + + Masternode Count: + عدد العقد الرئيسية: + + + Number of masternodes this wallet can vote with (masternodes for which this wallet holds the voting key) + عدد العقد الرئيسية التي يمكن لهذه المحفظة التصويت بها (العقد الرئيسية التي تحتفظ بها هذه المحفظة بمفتاح التصويت) + Proposal Count: عدد الاقتراح: + + Create Proposal + إنشاء مقترح + Filter by Title تصفية حسب العنوان + + Unavailable + غير متوفر + + + A synced node and an unlocked wallet are required. + مطلوب عقدة متزامنة ومحفظة غير مقفلة. + + + Vote Yes + صوت نعم + + + Vote No + صوت لا + + + Vote Abstain + صوت امتناع + Proposal Info: %1 معلومات الاقتراح:%1 + + Voting Failed + فشل التصويت + + + No wallet available. + لا توجد محفظة متاحة. + + + No masternode voting keys found in wallet. + لم يتم العثور على مفاتيح تصويت العقد الرئيسية في المحفظة. + + + Please select a proposal to vote on. + يرجى اختيار مقترح للتصويت عليه. + + + Unable to unlock wallet. + غير قادر على فتح قفل المحفظة. + + + Unable to get masternode list. Please try again later. + غير قادر على الحصول على قائمة العقد الرئيسية. يرجى المحاولة مرة أخرى لاحقًا. + + + Masternode %1 not found + لم يتم العثور على العقدة الرئيسية %1 + + + Failed to sign vote for masternode %1 + فشل توقيع التصويت للعقدة الرئيسية %1 + + + Masternode %1: %2 + العقدة الرئيسية %1: %2 + + + Voted successfully %n time(s) + تم التصويت بنجاح %n مرةتم التصويت بنجاح %n مرةتم التصويت بنجاح %n مرتينتم التصويت بنجاح %n مراتتم التصويت بنجاح %n مرةتم التصويت بنجاح %n مرة + + + Failed to vote %n time(s) + فشل التصويت %n مرةفشل التصويت %n مرةفشل التصويت %n مرتينفشل التصويت %n مراتفشل التصويت %n مرةفشل التصويت %n مرة + + + Errors: + الأخطاء: + + + Voting Results + نتائج التصويت + HelpMessageDialog @@ -1149,7 +1384,7 @@ <h3>%1 Basics</h3> %1 gives you true financial privacy by obscuring the origins of your funds. All the Dash in your wallet is comprised of different "inputs" which you can think of as separate, discrete coins.<br> %1 uses an innovative process to mix your inputs with the inputs of two or more other people, without having your coins ever leave your wallet. You retain control of your money at all times.<hr> <b>The %1 process works like this:</b><ol type="1"> <li>%1 begins by breaking your transaction inputs down into standard denominations. These denominations are 0.001 DASH, 0.01 DASH, 0.1 DASH, 1 DASH and 10 DASH -- sort of like the paper money you use every day.</li> <li>Your wallet then sends requests to specially configured software nodes on the network, called "masternodes." These masternodes are informed then that you are interested in mixing a certain denomination. No identifiable information is sent to the masternodes, so they never know "who" you are.</li> <li>When two or more other people send similar messages, indicating that they wish to mix the same denomination, a mixing session begins. The masternode mixes up the inputs and instructs all three users' wallets to pay the now-transformed input back to themselves. Your wallet pays that denomination directly to itself, but in a different address (called a change address).</li> <li>In order to fully obscure your funds, your wallet must repeat this process a number of times with each denomination. Each time the process is completed, it's called a "round." Each round of %1 makes it exponentially more difficult to determine where your funds originated.</li> <li>This mixing process happens in the background without any intervention on your part. When you wish to make a transaction, your funds will already be mixed. No additional waiting is required.</li> </ol> <hr><b>IMPORTANT:</b> Your wallet only contains 1000 of these "change addresses." Every time a mixing event happens, up to 9 of your addresses are used up. This means those 1000 addresses last for about 100 mixing events. When 900 of them are used, your wallet must create more addresses. It can only do this, however, if you have automatic backups enabled.<br> Consequently, users who have backups disabled will also have %1 disabled. <hr>For more information, see the <a style="%2" href="%3">%1 documentation</a>. - %1 يمنحك <h3>%1 أساسيات</h3> خصوصية مالية حقيقية من خلال حجب أصول أموالك. تتكون كل الداش في محفظتك من "مدخلات" مختلفة يمكنك التفكير فيها على أنها عملات معدنية منفصلة ومنفصلة.<br> %1 يستخدم عملية مبتكرة لخلط مدخلاتك مع مدخلات شخصين آخرين أو أكثر ، دون أن تترك عملاتك محفظتك. أنت تحتفظ بالسيطرة على أموالك في جميع الأوقات.<hr><b> تعمل %1 عملية على النحو التالي:</b><ol type="1"><li> يبدأ بتقسيم إدخالات معاملتك إلى فئات قياسية. هذه الفئات هي 0.001 داش و 0.01 داش و 0.1 داش و 1 داش و 10 داش - نوع من النقود الورقية التي تستخدمها كل يوم.</li><li> ثم ترسل محفظتك طلبات إلى عقد البرامج التي تم تكوينها خصيصًا على الشبكة ، والتي تسمى "العقد الرئيسية". يتم إبلاغ هذه الرموز الرئيسية بعد ذلك أنك مهتم بخلط فئة معينة. لا يتم إرسال أي معلومات يمكن التعرف عليها إلى رموز ماسترنود ، لذلك فهم لا يعرفون أبدًا "من أنت".</li><li> عندما يرسل شخصان آخران أو أكثر رسائل متشابهة ، للإشارة إلى رغبتهم في مزج نفس الفئة ، تبدأ جلسة خلط. يخلط الرمز الرئيسي بين المدخلات ويوجه جميع محافظ المستخدمين الثلاثة لدفع المدخلات التي تم تحويلها الآن لأنفسهم. تدفع محفظتك تلك الفئة مباشرة لنفسها ، ولكن في عنوان مختلف (يسمى تغيير العنوان). </li><li>من أجل إخفاء أموالك بالكامل ، يجب أن تكرر محفظتك هذه العملية عدة مرات مع كل فئة. في كل مرة يتم فيها الانتهاء من العملية ، يطلق عليها "جولة". كل جولة 1% تجعل تحديد مصدر أموالك أكثر صعوبة.</li><li> تحدث عملية الخلط هذه في الخلفية دون أي تدخل من جانبك. عندما ترغب في إجراء معاملة ، ستكون أموالك مختلطة بالفعل. لا حاجة إلى انتظار إضافي.</li></ol><hr><b> هام: </b>تحتوي محفظتك فقط على 1000 من "عناوين التغيير" هذه. في كل مرة يحدث فيها اختلاط ، يتم استخدام ما يصل إلى 9 عناوين. هذا يعني أن تلك العناوين الـ 1000 تدوم لحوالي 100 حدث خلط. عندما يتم استخدام 900 منهم ، يجب أن تنشئ محفظتك المزيد من العناوين. لا يمكنه القيام بذلك إلا إذا تم تمكين النسخ الاحتياطية التلقائية. <br>وبالتالي ، فإن المستخدمين الذين تم تعطيل النسخ الاحتياطية لديهم %1 سيتم أيضًا تعطيل.<hr> لمزيد من المعلومات ، <a style="%2" href="%3"> %1 راجع وثائق</a>. + %1 يمنحك <h3>%1 أساسيات</h3> خصوصية مالية حقيقية من خلال حجب أصول أموالك. تتكون كل الداش في محفظتك من "مدخلات" مختلفة يمكنك التفكير فيها على أنها عملات معدنية منفصلة ومنفصلة.<br> %1 يستخدم عملية مبتكرة لخلط مدخلاتك مع مدخلات شخصين آخرين أو أكثر ، دون أن تترك عملاتك محفظتك. أنت تحتفظ بالسيطرة على أموالك في جميع الأوقات.<hr><b> تعمل %1 عملية على النحو التالي:</b><ol type="1"><li> يبدأ بتقسيم إدخالات معاملتك إلى فئات قياسية. هذه الفئات هي 0.001 داش و 0.01 داش و 0.1 داش و 1 داش و 10 داش - نوع من النقود الورقية التي تستخدمها كل يوم.</li><li> ثم ترسل محفظتك طلبات إلى عقد البرامج التي تم تكوينها خصيصًا على الشبكة ، والتي تسمى "العقد الرئيسية". يتم إبلاغ هذه الرموز الرئيسية بعد ذلك أنك مهتم بخلط فئة معينة. لا يتم إرسال أي معلومات يمكن التعرف عليها إلى رموز ماسترنود ، لذلك فهم لا يعرفون أبدًا "من أنت".</li><li> عندما يرسل شخصان آخران أو أكثر رسائل متشابهة ، للإشارة إلى رغبتهم في مزج نفس الفئة ، تبدأ جلسة خلط. يخلط الرمز الرئيسي بين المدخلات ويوجه جميع محافظ المستخدمين الثلاثة لدفع المدخلات التي تم تحويلها الآن لأنفسهم. تدفع محفظتك تلك الفئة مباشرة لنفسها ، ولكن في عنوان مختلف (يسمى تغيير العنوان). </li><li>من أجل إخفاء أموالك بالكامل ، يجب أن تكرر محفظتك هذه العملية عدة مرات مع كل فئة. في كل مرة يتم فيها الانتهاء من العملية ، يطلق عليها "جولة". كل جولة %1 تجعل تحديد مصدر أموالك أكثر صعوبة.</li><li> تحدث عملية الخلط هذه في الخلفية دون أي تدخل من جانبك. عندما ترغب في إجراء معاملة ، ستكون أموالك مختلطة بالفعل. لا حاجة إلى انتظار إضافي.</li></ol><hr><b> هام: </b>تحتوي محفظتك فقط على 1000 من "عناوين التغيير" هذه. في كل مرة يحدث فيها اختلاط ، يتم استخدام ما يصل إلى 9 عناوين. هذا يعني أن تلك العناوين الـ 1000 تدوم لحوالي 100 حدث خلط. عندما يتم استخدام 900 منهم ، يجب أن تنشئ محفظتك المزيد من العناوين. لا يمكنه القيام بذلك إلا إذا تم تمكين النسخ الاحتياطية التلقائية. <br>وبالتالي ، فإن المستخدمين الذين تم تعطيل النسخ الاحتياطية لديهم %1 سيتم أيضًا تعطيل.<hr> لمزيد من المعلومات ، <a style="%2" href="%3"> %1 راجع وثائق</a>. @@ -1166,10 +1401,26 @@ As this is the first time the program is launched, you can choose where %1 will store its data. بما انه هذه اول مرة لانطلاق هذا البرنامج, فيمكنك ان تختار اين سيخزن %1 بياناته + + Limit block chain storage to + حد تخزين سلسلة الكتل إلى + + + 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. + يتطلب التراجع عن هذا الإعداد إعادة تنزيل البلوكتشين بالكامل. من الأسرع تنزيل السلسلة الكاملة أولاً ثم تقليمها لاحقًا. يعطل بعض الميزات المتقدمة. + + + GB + جيجابايت + 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. تُعد هذه المزامنة الأولية أمرًا شاقًا للغاية، وقد تعرض جهاز الكمبيوتر الخاص بك للمشاكل الذي لم يلاحظها أحد سابقًا. في كل مرة تقوم فيها بتشغيل %1، سيتابع التحميل من حيث تم التوقف. + + 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. + عند النقر فوق موافق، سيبدأ %1 في تنزيل ومعالجة سلسلة الكتل %4 الكاملة (%2 جيجابايت) بدءًا من أقدم المعاملات في %3 عند إطلاق %4 في البداية. + 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. إذا كنت قد اخترت تقييد تخزين سلسلة الكتل (التجريد)، فيجب تحميل البيانات القديمة ومعالجتها، ولكن سيتم حذفها بعد ذلك للحفاظ على انخفاض استخدام القرص. @@ -1182,6 +1433,18 @@ Use a custom data directory: استخدام دليل بيانات مخصص: + + %n GB of space available + %n جيجابايت من المساحة المتاحة%n جيجابايت من المساحة المتاحة%n جيجابايت من المساحة المتاحة%n جيجابايت من المساحة المتاحة%n جيجابايت من المساحة المتاحة%n جيجابايت من المساحة المتاحة + + + (of %n GB needed) + (من %n جيجابايت مطلوب)(من %n جيجابايت مطلوب)(من %n جيجابايت مطلوب)(من %n جيجابايت مطلوب)(من %n جيجابايت مطلوب)(من %n جيجابايت مطلوب) + + + (%n GB needed for full chain) + (%n جيجابايت مطلوب للسلسلة الكاملة)(%n جيجابايت مطلوب للسلسلة الكاملة)(%n جيجابايت مطلوب للسلسلة الكاملة)(%n جيجابايت مطلوب للسلسلة الكاملة)(%n جيجابايت مطلوب للسلسلة الكاملة)(%n جيجابايت مطلوب للسلسلة الكاملة) + At least %1 GB of data will be stored in this directory, and it will grow over time. سيتم تخزين %1 جيجابايت على الأقل من البيانات في هذا الدليل، وستنمو مع الوقت. @@ -1190,6 +1453,11 @@ Approximately %1 GB of data will be stored in this directory. سيتم تخزين %1 جيجابايت تقريباً من البيانات في هذا الدليل. + + (sufficient to restore backups %n day(s) old) + Explanatory text on the capability of the current prune target. + (كافٍ لاستعادة النسخ الاحتياطية القديمة بيوم واحد)(كافٍ لاستعادة النسخ الاحتياطية القديمة بيوم واحد)(كافٍ لاستعادة النسخ الاحتياطية القديمة بيومين)(كافٍ لاستعادة النسخ الاحتياطية القديمة بـ %n أيام)(كافٍ لاستعادة النسخ الاحتياطية القديمة بـ %n يوم)(كافٍ لاستعادة النسخ الاحتياطية القديمة بـ %n يوم) + %1 will download and store a copy of the Dash block chain. سيقوم %1 بتنزيل نسخة من سلسلة كتل بتكوين وتخزينها. @@ -1207,6 +1475,13 @@ خطأ + + LoadWalletsActivity + + Loading wallets… + تحميل المحافظ… + + MasternodeList @@ -1241,6 +1516,10 @@ Service الخدمات + + Type + النوع + PoSe Score نقاط PoSe @@ -1376,6 +1655,10 @@ Hide إخفاء + + %1 is currently syncing. It will download headers and blocks from peers and validate them until reaching the tip of the block chain. + %1 تتم المزامنة حاليًا. سيقوم بتنزيل الرؤوس والكتل من النظراء والتحقق من صحتها حتى الوصول إلى طرف سلسلة الكتل. + Unknown. Syncing Headers (%1, %2%)… مجهول. مزامنة الرؤوس (%1،%2) … @@ -1391,6 +1674,11 @@ URI: العنوان: + + Paste address from clipboard + Tooltip text for button that allows you to paste an address that is in your clipboard. + لصق العنوان من الحافظة + OpenWalletActivity @@ -1406,8 +1694,14 @@ default wallet المحفظة الافتراضية + + Open Wallet + Title of window indicating the progress of opening of a wallet. + فتح المحفظة + Opening Wallet <b>%1</b>… + Descriptive text of the open wallet progress window which indicates to the user which wallet is currently being opened. جاري فتح المحفظة<b>%1</b> … @@ -1441,6 +1735,14 @@ &Appearance &مظهر خارجي + + Show the icon in the system tray. + إظهار الرمز في علبة النظام. + + + &Show tray icon + &إظهار رمز الصينية + Prune &block storage to تقليم وحظر التخزين إلى ملفات @@ -1453,10 +1755,58 @@ Reverting this setting requires re-downloading the entire blockchain. تتطلب العودة إلى هذا الإعداد إعادة تنزيل بلوكشين بالكامل. + + 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. + Tooltip text for Options window setting that sets the size of the database cache. Explains the corresponding effects of increasing/decreasing this value. + الحد الأقصى لحجم ذاكرة التخزين المؤقت لقاعدة البيانات. يمكن أن تساهم ذاكرة التخزين المؤقت الأكبر في مزامنة أسرع، وبعد ذلك تكون الفائدة أقل وضوحًا لمعظم حالات الاستخدام. سيؤدي خفض حجم ذاكرة التخزين المؤقت إلى تقليل استخدام الذاكرة. يتم مشاركة ذاكرة mempool غير المستخدمة لهذه الذاكرة المؤقتة. + MiB MiB + + Set the number of script verification threads. Negative values correspond to the number of cores you want to leave free to the system. + 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. + تعيين عدد مؤشرات ترابط التحقق من البرنامج النصي. تتوافق القيم السالبة مع عدد النوى التي تريد تركها حرة للنظام. + + + This allows you or a third party tool to communicate with the node through command-line and JSON-RPC commands. + Tooltip text for Options window setting that enables the RPC server. + يتيح لك هذا أو لأداة طرف ثالث التواصل مع العقدة من خلال سطر الأوامر وأوامر JSON-RPC. + + + Enable R&PC server + An Options window setting to enable the RPC server. + تمكين خادم R&PC + + + Whether to set subtract fee from amount as default or not. + Tooltip text for Options window setting that sets subtracting the fee from a sending amount as default. + ما إذا كان سيتم تعيين خصم الرسوم من المبلغ كإعداد افتراضي أم لا. + + + Subtract &fee from amount by default + An Options window setting to set subtracting the fee from a sending amount as default. + خصم &الرسوم من المبلغ افتراضياً + + + Enable &PSBT controls + An options window setting to enable PSBT controls. + تمكين عناصر التحكم &PSBT + + + Whether to show PSBT controls. + Tooltip text for options window setting that enables PSBT controls. + ما إذا كان سيتم إظهار عناصر تحكم PSBT. + + + Whether to keep the specified custom change address or not. + ما إذا كان سيتم الاحتفاظ بعنوان الفكة المخصص المحدد أم لا. + + + Keep custom change &address + الاحتفاظ بعنوان &الفكة المخصص + Show additional tab listing all your masternodes in first sub-tab<br/>and all masternodes on the network in second sub-tab. عرض علامة تبويب إضافية تسرد جميع رموزك في أول علامة تبويب فرعية <br/>وجميع ماسترنود على الشبكة في علامة التبويب الفرعية الثانية. @@ -1513,6 +1863,14 @@ Enable &multi-session تمكين الإرسال متعدد الجلسات + + Use this many separate masternodes in parallel to mix funds.<br/>Note: You must use this feature carefully.<br/>Make sure you always have recent wallet (auto)backup in a safe place! + استخدم هذا العدد من العقد الرئيسية المنفصلة بالتوازي لخلط الأموال.<br/>ملاحظة: يجب عليك استخدام هذه الميزة بحذر.<br/>تأكد من أن لديك دائمًا نسخة احتياطية حديثة (تلقائية) للمحفظة في مكان آمن! + + + Parallel sessions + جلسات متوازية + Mixing rounds جولات الخلط @@ -1525,6 +1883,30 @@ Target balance الهدف رصيد + + How many inputs of each denominated amount are created.<br/>Lower these numbers if you want fewer smaller denominations. + كم عدد المدخلات من كل فئة يتم إنشاؤها.<br/>قلل هذه الأرقام إذا كنت تريد عددًا أقل من الفئات الصغيرة. + + + Inputs per denomination + مدخلات لكل فئة + + + Try to create at least this many inputs for each denominated amount.<br/>Lower this number if you want fewer smaller denominations. + حاول إنشاء هذا العدد على الأقل من المدخلات لكل فئة.<br/>قلل هذا الرقم إذا كنت تريد عددًا أقل من الفئات الصغيرة. + + + Target + الهدف + + + Create up to this many inputs for each denominated amount.<br/>Lower this number if you want fewer smaller denominations. + إنشاء ما يصل إلى هذا العدد من المدخلات لكل فئة.<br/>قلل هذا الرقم إذا كنت تريد عددًا أقل من الفئات الصغيرة. + + + Maximum + الحد الأقصى + Automatically open the Dash Core client port on the router. This only works when your router supports UPnP and it is enabled. فتح منفذ عميل داش كور تلقائيًا على جهاز التوجيه. هذا يعمل فقط عندما يدعم جهاز التوجيه الخاص بك UPnP وتمكينه. @@ -1554,20 +1936,26 @@ يظهر ما إذا كان وكيل SOCKS5 الافتراضي المقدم مستخدمًا للوصول إلى الأقران عبر هذا النوع من الشبكة. - Options set in this dialog are overridden by the command line or in the configuration file: - يتم تجاوز الخيارات المعينة في مربع الحوار هذا بواسطة سطر الأوامر أو في ملف التكوين: + Language missing or translation incomplete? Help contributing translations here: +https://explore.transifex.com/dash/dash/ + اللغة مفقودة أو الترجمة غير مكتملة؟ ساعد في المساهمة في الترجمات هنا: +https://explore.transifex.com/dash/dash/ - 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. - التصغير بدلاً من الخروج من التطبيق عند إغلاق النافذة. عند تفعيل هذا الخيار، سيتم إغلاق التطبيق فقط بعد اختيار الخروج من القائمة. + Third-party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items.<br/>%s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |. + عناوين URL لجهات خارجية (مثل مستكشف الكتل) تظهر في علامة تبويب المعاملات كعناصر قائمة السياق.<br/> يتم استبدال %s في عنوان URL بتجزئة المعاملة. يتم فصل عناوين URL متعددة بشريط عمودي |. + + + &Third-party transaction URLs + &عناوين URL للمعاملات من جهات خارجية - Third party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items.<br/>%s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |. - عناوين التابعة لجهات خارجية (مثل مستكشف كتلة) التي تظهر في علامة شريط المعاملات كعناصر قائمة السياق <br/> يتم استبدال %s في عنوان بتجزئة المعاملة. عناوين متعددة مفصولة بشريط عمودي. + Options set in this dialog are overridden by the command line or in the configuration file: + يتم تجاوز الخيارات المعينة في مربع الحوار هذا بواسطة سطر الأوامر أو في ملف التكوين: - &Third party transaction URLs - & عناوين URL لمعاملات الطرف الثالث + 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. + التصغير بدلاً من الخروج من التطبيق عند إغلاق النافذة. عند تفعيل هذا الخيار، سيتم إغلاق التطبيق فقط بعد اختيار الخروج من القائمة. Whether to show coin control features or not. @@ -1605,6 +1993,10 @@ Map port using &UPnP ميناء الخريطة باستخدام UPnP + + Automatically open the Dash Core client port on the router. This only works when your router supports NAT-PMP and it is enabled. The external port could be random. + فتح منفذ عميل Dash Core تلقائيًا على جهاز التوجيه. هذا يعمل فقط عندما يدعم جهاز التوجيه الخاص بك NAT-PMP وتمكينه. قد يكون المنفذ الخارجي عشوائيًا. + Proxy &IP: بروكسي &اي بي: @@ -1654,8 +2046,16 @@ &عرض - User Interface &language: - لغة واجهة المستخدم: + Connect to the Dash network through a separate SOCKS5 proxy for Tor onion services. + الاتصال بشبكة Dash من خلال وكيل SOCKS5 منفصل لخدمات Tor onion. + + + Use separate SOCKS&5 proxy to reach peers via Tor onion services: + استخدام وكيل SOCKS&5 منفصل للوصول إلى الأقران عبر خدمات Tor onion: + + + User Interface &language: + لغة واجهة المستخدم: The user interface language can be set here. This setting will take effect after restarting %1. @@ -1699,14 +2099,22 @@ Confirm options reset + Window title text of pop-up window shown when the user has chosen to reset options. تأكيد استعادة الخيارات Client restart required to activate changes. + Text explaining that the settings changed will not come into effect until the client is restarted. يتطلب إعادة تشغيل العميل لتفعيل التغييرات. + + Current settings will be backed up at "%1". + 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. + سيتم نسخ الإعدادات الحالية احتياطياً في "%1". + Client will be shut down. Do you want to proceed? + Text asking the user to confirm if they would like to proceed with a client shutdown. سوف يتم إيقاف العميل تماماً. هل تريد الإستمرار؟ @@ -1844,6 +2252,10 @@ %1 Balance %1 الرصيد + + Discreet mode activated for the Overview tab. To unmask the values, uncheck Settings->Discreet mode. + تم تفعيل الوضع المخفي لعلامة التبويب النظرة العامة. لإظهار القيم، قم بإلغاء تحديد الإعدادات->الوضع المخفي. + %n Rounds %n جولات%n جولات%n جولات%n جولات%n جولات%n جولات @@ -1943,7 +2355,140 @@ PSBTOperationsDialog - + + Dialog + حوار + + + Sign Tx + توقيع المعاملة + + + Broadcast Tx + بث المعاملة + + + Copy to Clipboard + نسخ إلى الحافظة + + + Save… + حفظ… + + + Close + إغلاق + + + Failed to load transaction: %1 + فشل تحميل المعاملة: %1 + + + Failed to sign transaction: %1 + فشل توقيع المعاملة: %1 + + + Cannot sign inputs while wallet is locked. + لا يمكن توقيع المدخلات أثناء قفل المحفظة. + + + Could not sign any more inputs. + لا يمكن توقيع المزيد من المدخلات. + + + Signed %1 inputs, but more signatures are still required. + تم توقيع %1 مدخلات، ولكن لا يزال يتطلب المزيد من التوقيعات. + + + Signed transaction successfully. Transaction is ready to broadcast. + تم توقيع المعاملة بنجاح. المعاملة جاهزة للبث. + + + Unknown error processing transaction. + خطأ غير معروف أثناء معالجة المعاملة. + + + Transaction broadcast successfully! Transaction ID: %1 + تم بث المعاملة بنجاح! معرف المعاملة: %1 + + + Transaction broadcast failed: %1 + فشل بث المعاملة: %1 + + + PSBT copied to clipboard. + تم نسخ PSBT إلى الحافظة. + + + Save Transaction Data + حفظ بيانات المعاملة + + + Partially Signed Transaction (Binary) + Expanded name of the binary PSBT file format. See: BIP 174. + معاملة موقعة جزئياً (ثنائية) + + + PSBT saved to disk. + تم حفظ PSBT على القرص. + + + * Sends %1 to %2 + * يرسل %1 إلى %2 + + + own address + عنوان خاص + + + Unable to calculate transaction fee or total transaction amount. + غير قادر على حساب رسوم المعاملة أو إجمالي مبلغ المعاملة. + + + Pays transaction fee: + يدفع رسوم المعاملة: + + + Total Amount + المبلغ الإجمالي + + + or + أو + + + Transaction has %1 unsigned inputs. + المعاملة لديها %1 مدخلات غير موقعة. + + + Transaction is missing some information about inputs. + المعاملة تفتقد بعض المعلومات حول المدخلات. + + + Transaction still needs signature(s). + المعاملة لا تزال بحاجة إلى توقيع (توقيعات). + + + (But no wallet is loaded.) + (ولكن لم يتم تحميل محفظة.) + + + (But this wallet cannot sign transactions.) + (ولكن هذه المحفظة لا يمكنها توقيع المعاملات.) + + + (But this wallet does not have the right keys.) + (ولكن هذه المحفظة لا تملك المفاتيح الصحيحة.) + + + Transaction is fully signed and ready for broadcast. + المعاملة موقعة بالكامل وجاهزة للبث. + + + Transaction status is unknown. + حالة المعاملة غير معروفة. + + PaymentServer @@ -1962,6 +2507,12 @@ 'dash://' is not a valid URI. Use 'dash:' instead. 'dash: //' ليس URI صالحًا. استخدم "شرطة:" بدلاً من ذلك. + + Cannot process payment request as BIP70 is no longer supported. +Due to discontinued support, you should request the merchant to provide you with a BIP21 compatible URI or use a wallet that does continue to support BIP70. + لا يمكن معالجة طلب الدفع لأن BIP70 لم يعد مدعومًا. +بسبب التوقف عن الدعم، يجب عليك أن تطلب من التاجر أن يزودك بـ URI متوافق مع BIP21 أو استخدام محفظة تستمر في دعم BIP70. + URI cannot be parsed! This can be caused by an invalid Dash address or malformed URI parameters. لا يمكن تحليل العنوان! يمكن أن يكون ذلك بسبب عنوان داش غير صالح أو معلمات العنوان غير صحيحة. @@ -1983,6 +2534,26 @@ Title of Peers Table column which indicates the current latency of the connection with the peer. رنين + + Peer + Title of Peers Table column which contains a unique number used to identify a connection. + النظير + + + Age + Title of Peers Table column which indicates the duration (length of time) since the peer connection started. + العمر + + + Direction + Title of Peers Table column which indicates the direction the peer connection was initiated from. + الاتجاه + + + Type + Title of Peers Table column which describes the type of peer connection. The "type" describes why the connection exists. + النوع + Sent Title of Peers Table column which indicates the total amount of network information we have sent to the peer. @@ -1993,7 +2564,27 @@ Title of Peers Table column which indicates the total amount of network information we have received from the peer. وصلت - + + Address + Title of Peers Table column which contains the IP/Onion/I2P address of the connected peer. + العنوان + + + Network + Title of Peers Table column which states the network the peer connected through. + الشبكة + + + Inbound + An Inbound Connection from a Peer. + وارد + + + Outbound + An Outbound Connection to a Peer. + صادر + + Proposal @@ -2044,8 +2635,193 @@ الحالة. + + ProposalWizard + + Create Governance Proposal + إنشاء مقترح الحوكمة + + + Enter proposal details + أدخل تفاصيل المقترح + + + A fee will be burned when you prepare the proposal. + سيتم حرق رسوم عند تحضير المقترح. + + + Proposal &name + &اسم المقترح + + + &Description URL + &رابط الوصف + + + Payment &address + &عنوان الدفع + + + Payment &amount + &مبلغ الدفع + + + The amount to request in a single payment + المبلغ المطلوب في دفعة واحدة + + + &First payment + &الدفعة الأولى + + + Pa&yments + ال&دفعات + + + To&tal amount + المبلغ الإ&جمالي + + + Proposal &fee + &رسوم المقترح + + + Next + التالي + + + Review proposal JSON and validate. + مراجعة JSON المقترح والتحقق من صحته. + + + Hex-encoded JSON + JSON مشفر بنظام ست عشري + + + Back + رجوع + + + Validate + التحقق + + + Prepare (burn fee) and wait for confirmations. + التحضير (حرق الرسوم) والانتظار للتأكيدات. + + + Copy + نسخ + + + At 1/6 confirmations: can be relayed and queued. At 6/6: accepted and processed. + عند 1/6 تأكيدات: يمكن الترحيل والانتظار في قائمة الانتظار. عند 6/6: مقبول ومعالج. + + + Confirmations progress + تقدم التأكيدات + + + Shows progress toward the required number of confirmations for the proposal fee transaction. + يظهر التقدم نحو العدد المطلوب من التأكيدات لمعاملة رسوم المقترح. + + + Estimated time remaining: - + الوقت المقدر المتبقي: - + + + Prepare Proposal + تحضير المقترح + + + You can submit after 1 confirmation. At 6 confirmations it is accepted and processed. + يمكنك الإرسال بعد تأكيد واحد. عند 6 تأكيدات يتم قبوله ومعالجته. + + + Proposal ID: + معرف المقترح: + + + Submit Proposal + إرسال المقترح + + + Close + إغلاق + + + Valid + صالح + + + Invalid: %1 + غير صالح: %1 + + + Burn %1 + حرق %1 + + + Burn %1 to create the fee transaction? + حرق %1 لإنشاء معاملة الرسوم؟ + + + Prepare failed + فشل التحضير + + + Confirmations: %1 / %2 required + التأكيدات: %1 / %2 مطلوب + + + Estimated time remaining: Ready + الوقت المقدر المتبقي: جاهز + + + Estimated time remaining: %n minute(s) + الوقت المقدر المتبقي: دقيقة واحدةالوقت المقدر المتبقي: دقيقة واحدةالوقت المقدر المتبقي: دقيقتانالوقت المقدر المتبقي: %n دقائقالوقت المقدر المتبقي: %n دقيقةالوقت المقدر المتبقي: %n دقيقة + + + Your proposal was submitted successfully. + تم إرسال مقترحك بنجاح. + + + Already submitted + تم الإرسال بالفعل + + + This proposal has already been submitted. + تم إرسال هذا المقترح بالفعل. + + + Submission failed + فشل الإرسال + + + Proposal submitted + تم إرسال المقترح + + + A fee of %1 will be burned when you prepare the proposal. + سيتم حرق رسوم %1 عندما تحضر المقترح. + + + Prepare (burn %1) and wait for %2 confirmations. + التحضير (حرق %1) والانتظار لـ %2 تأكيدات. + + QObject + + Do you want to reset settings to default values, or to abort without making changes? + Explanatory text shown on startup when the settings file cannot be read. Prompts user to make a choice between resetting or aborting. + هل تريد إعادة تعيين الإعدادات إلى القيم الافتراضية، أم الإلغاء دون إجراء تغييرات؟ + + + A fatal error occurred. Check that settings file is writable, or try running with -nosettings. + 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. + حدث خطأ فادح. تحقق من أن ملف الإعدادات قابل للكتابة، أو حاول التشغيل بـ -nosettings. + Choose data directory on startup (default: %u) اختر دليل البيانات عند بدء التشغير (افتراضي: %u) @@ -2146,6 +2922,53 @@ This can also be adjusted later in the "Appearance" tab of the preferences. يمكن أيضًا تعديل هذا لاحقًا في علامة التبويب "المظهر" في التفضيلات. + + Ctrl+W + Ctrl+W + + + Unroutable + غير قابل للتوجيه + + + Internal + داخلي + + + Inbound + An inbound connection from a peer. An inbound connection is a connection initiated by a peer. + وارد + + + Outbound + An outbound connection to a peer. An outbound connection is a connection initiated by us. + صادر + + + Full Relay + Peer connection type that relays all network information. + ترحيل كامل + + + Block Relay + Peer connection type that relays network information about blocks and not transactions or addresses. + ترحيل الكتل + + + Manual + Peer connection type established manually through one of several methods. + يدوي + + + Feeler + Short-lived peer connection type that tests the aliveness of known addresses. + مستشعر + + + Address Fetch + Short-lived peer connection type that solicits known addresses from a peer. + جلب العناوين + %1 d %1 يوم @@ -2207,8 +3030,8 @@ %1 B - %1 KB - %1 KB + %1 kB + %1 kB %1 MB @@ -2264,7 +3087,12 @@ Save QR Code حفظ رمز الاستجابة السريعة QR - + + PNG Image + Expanded name of the PNG file format. See: https://en.wikipedia.org/wiki/Portable_Network_Graphics. + صورة PNG + + RPCConsole @@ -2371,6 +3199,14 @@ Version الإصدار + + High bandwidth BIP152 compact block relay: %1 + ترحيل الكتل المدمجة BIP152 بنطاق ترددي عالي: %1 + + + High Bandwidth + نطاق ترددي عالي + Starting Block كتلة البداية @@ -2383,6 +3219,51 @@ Synced Blocks كتل متزامنة + + Elapsed time since a novel block passing initial validity checks was received from this peer. + الوقت المنقضي منذ استلام كتلة جديدة تجاوزت فحوصات الصلاحية الأولية من هذا النظير. + + + Last Block + آخر كتلة + + + Elapsed time since a novel transaction accepted into our mempool was received from this peer. + Tooltip text for the Last Transaction field in the peer details area. + الوقت المنقضي منذ استلام معاملة جديدة تم قبولها في مجمع الذاكرة من هذا النظير. + + + Last Transaction + آخر معاملة + + + The mapped Autonomous System used for diversifying peer selection. + النظام المستقل المعين المستخدم لتنويع اختيار الأقران. + + + Mapped AS + نظام مستقل معين + + + Whether we relay addresses to this peer. + Tooltip text for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No). + ما إذا كنا نرحل العناوين إلى هذا النظير. + + + Address Relay + Text title for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No). + ترحيل العنوان + + + Addresses Processed + 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). + العناوين المعالجة + + + Addresses Rate-Limited + 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. + العناوين المحدودة بالمعدل + Rescan blockchain files 1 إعادة فحص ملفات بلوكشين1 @@ -2423,6 +3304,22 @@ To specify a non-default location of the blocks directory use the '%1' option. لتحديد موقع غير افتراضي لدليل الكتل ، استخدم الخيار "%1". + + Local Addresses + العناوين المحلية + + + Network addresses that your Dash node is currently using to communicate with other nodes. + عناوين الشبكة التي تستخدمها عقدة Dash الخاصة بك حالياً للتواصل مع العقد الأخرى. + + + Number of regular Masternodes + عدد الماسترنود العادية + + + Number of EvoNodes + عدد العقد التطورية + Current block height ارتفاع الكتلة الحالي @@ -2471,10 +3368,50 @@ PoSe Score نقاط PoSe + + The transport layer version: %1 + إصدار طبقة النقل: %1 + + + Transport + النقل + + + The BIP324 session ID string in hex. + سلسلة معرف جلسة BIP324 بنظام ست عشري. + + + Session ID + معرف الجلسة + + + The network protocol this peer is connected through: IPv4, IPv6, Onion, I2P, or CJDNS. + بروتوكول الشبكة الذي يتصل من خلاله هذا النظير: IPv4 أو IPv6 أو Onion أو I2P أو CJDNS. + + + Permissions + الأذونات + + + The direction and type of peer connection: %1 + اتجاه ونوع اتصال النظير: %1 + + + Direction/Type + الاتجاه/النوع + Services خدمات + + Whether we relay transactions to this peer. + ما إذا كنا نرحل المعاملات إلى هذا النظير. + + + Transaction Relay + ترحيل المعاملات + Connection Time مدة الاتصال @@ -2511,6 +3448,16 @@ &Wallet Repair إصلاح المحفظة + + The total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting). + 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). + العدد الإجمالي للعناوين المستلمة من هذا النظير التي تمت معالجتها (باستثناء العناوين التي تم إسقاطها بسبب تحديد المعدل). + + + The total number of addresses received from this peer that were dropped (not processed) due to rate-limiting. + 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. + العدد الإجمالي للعناوين المستلمة من هذا النظير التي تم إسقاطها (لم تتم معالجتها) بسبب تحديد المعدل. + Wallet repair options. خيارات إصلاح المحفظة. @@ -2524,52 +3471,82 @@ إعادة بناء فهرس سلسلة كتلة من الملفات الحالية blk000 ؟؟. - &Disconnect - قطع الاتصال + Inbound: initiated by peer + Explanatory text for an inbound peer connection. + وارد: بدأه النظير - Ban for - حظر ل + Outbound Full Relay: default + Explanatory text for an outbound peer connection that relays all network information. This is the default behavior for outbound connections. + صادر بترحيل كامل: افتراضي - 1 &hour - 1 &ساعة + Outbound Block Relay: does not relay transactions or addresses + Explanatory text for an outbound peer connection that relays network information about blocks and not transactions or addresses. + صادر بترحيل الكتل: لا يرحل المعاملات أو العناوين - 1 &day - 1 & يوم + Outbound Manual: added using RPC %1 or %2/%3 configuration options + 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. + صادر يدوي: تمت الإضافة باستخدام RPC %1 أو خيارات التكوين %2/%3 - 1 &week - 1 & اسبوع + Outbound Feeler: short-lived, for testing addresses + Explanatory text for a short-lived outbound peer connection that is used to test the aliveness of known addresses. + صادر مستشعر: قصير المدة، لاختبار العناوين - 1 &year - 1 & سنة + Outbound Address Fetch: short-lived, for soliciting addresses + Explanatory text for a short-lived outbound peer connection that is used to request addresses from a peer. + صادر لجلب العناوين: قصير المدة، لطلب العناوين - &Unban - رفع الحظر + To + إلى + + + we selected the peer for high bandwidth relay + اخترنا النظير للترحيل بنطاق ترددي عالي + + + From + من - Welcome to the %1 RPC console. - مرحبًا بك في وحدة التحكم %1 RPC. + the peer selected us for high bandwidth relay + اختارنا النظير للترحيل بنطاق ترددي عالي + + + No + لا + + + no high bandwidth relay selected + لم يتم اختيار ترحيل بنطاق ترددي عالي + + + &Disconnect + قطع الاتصال + + + Ban for + حظر ل - Use up and down arrows to navigate history, and %1 to clear screen. - استخدم السهمين لأعلى ولأسفل للتنقل في المحفوظات ، و%1 لمسح الشاشة. + 1 &hour + 1 &ساعة - Type %1 for an overview of available commands. - اكتب %1 للحصول على نظرة عامة حول الأوامر المتوفرة. + 1 &week + 1 & اسبوع - For more information on using this console type %1. - لمزيد من المعلومات حول استخدام نوع وحدة التحكم هذه %1. + 1 &year + 1 & سنة - WARNING: Scammers have been active, telling users to type commands here, stealing their wallet contents. Do not use this console without fully understanding the ramifications of a command. - تحذير: كان المحتالون نشطين ، ويخبرون المستخدمين بكتابة الأوامر هنا ، وسرقة محتويات محفظتهم. لا تستخدم وحدة التحكم هذه دون فهم تداعيات الأمر بشكل كامل. + &Unban + رفع الحظر In: @@ -2583,6 +3560,10 @@ Network activity disabled تم إلغاء تفعيل الشبكه + + None + لا شيء + Total: %1 (Enabled: %2) الإجمالي: %1 (ممكّن: %2) @@ -2591,10 +3572,105 @@ Executing command without any wallet تنفيذ الأمر بدون أي محفظة + + Ctrl++ + Main shortcut to increase the RPC console font size. + Ctrl++ + + + Ctrl+= + Secondary shortcut to increase the RPC console font size. + Ctrl+= + + + Ctrl+- + Main shortcut to decrease the RPC console font size. + Ctrl+- + + + Ctrl+_ + Secondary shortcut to decrease the RPC console font size. + Ctrl+_ + + + Ctrl+Shift+I + Ctrl+Shift+I + + + Ctrl+Shift+C + Ctrl+Shift+C + + + Ctrl+Shift+G + Ctrl+Shift+G + + + Ctrl+Shift+P + Ctrl+Shift+P + + + Ctrl+Shift+R + Ctrl+Shift+R + Executing command using "%1" wallet تنفيذ الأمر باستخدام المحفظة "%1" + + detecting: peer could be v1 or v2 + Explanatory text for "detecting" transport type. + الكشف: النظير يمكن أن يكون v1 أو v2 + + + v1: unencrypted, plaintext transport protocol + Explanatory text for v1 transport type. + v1: بروتوكول نقل غير مشفر، نص عادي + + + v2: BIP324 encrypted transport protocol + Explanatory text for v2 transport type. + v2: بروتوكول نقل مشفر BIP324 + + + &Copy address + Context menu action to copy the address of a peer + &نسخ العنوان + + + 1 d&ay + يوم &واحد + + + &Copy IP/Netmask + 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 + &نسخ IP/Netmask + + + 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 + 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. + مرحباً بك في وحدة تحكم %1 RPC. +استخدم أسهم الأعلى والأسفل للتنقل في السجل، و %2 لمسح الشاشة. +استخدم %3 و %4 لزيادة أو تقليل حجم الخط. +اكتب %5 للحصول على نظرة عامة على الأوامر المتاحة. +لمزيد من المعلومات حول استخدام وحدة التحكم هذه، اكتب %6. + +%7تحذير: المحتالون نشطون، يطلبون من المستخدمين كتابة أوامر هنا، لسرقة محتويات محفظتهم. لا تستخدم وحدة التحكم هذه دون فهم كامل لتبعات الأمر.%8 + + + Executing… + A console message indicating an entered command is currently being executed. + جارٍ التنفيذ… + + + (peer: %1) + (نظير: %1) + via %1 خلال %1 @@ -2611,11 +3687,19 @@ Verified Masternode التحقق من Masternode + + Yes + نعم + Unknown غير معروف - + + Never + أبداً + + ReceiveCoinsDialog @@ -2634,6 +3718,10 @@ An optional message to attach to the payment request, which will be displayed when the request is opened.<br>Note: The message will not be sent with the payment over the Dash network. رسالة اختيارية لإرفاقها بطلب الدفع ، والتي سيتم عرضها عند فتح الطلب.<br> ملاحظة: لن يتم إرسال الرسالة مع الدفع عبر شبكة داش. + + 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. + تسمية اختيارية لربطها بعنوان الاستلام الجديد (تستخدمها لتحديد الفاتورة). كما أنها مرفقة بطلب الدفع. + Use this form to request payments. All fields are <b>optional</b>. استخدم هذا النموذج لطلب الدفعات. جميع الحقول <b>اختيارية</b>. @@ -2691,28 +3779,60 @@ أدخل رسالة لإرفاقها بطلب الدفع - Copy URI - نسخ العنوان + Copy &URI + نسخ &URI - Copy address - انسخ عنوان + &Copy address + &نسخ العنوان - Copy label - انسخ التسمية + Copy &label + نسخ &التسمية - Copy message - انسخ الرسالة + Copy &message + نسخ &الرسالة - Copy amount - نسخ الكمية + Copy &amount + نسخ &المبلغ + + + Could not unlock wallet. + تعذر فتح المحفظة. - + + Could not generate new address + تعذر إنشاء عنوان جديد + + ReceiveRequestDialog + + Request payment to … + طلب الدفع إلى … + + + Address: + العنوان: + + + Amount: + المبلغ: + + + Label: + التسمية: + + + Message: + الرسالة: + + + Wallet: + المحفظة: + Copy &URI نسخ &URI @@ -2765,6 +3885,34 @@ تم الطلب + + RestoreWalletActivity + + Restore Wallet + Title of progress window which is displayed when wallets are being restored. + استعادة المحفظة + + + Restoring Wallet <b>%1</b>… + Descriptive text of the restore wallets progress window which indicates to the user that wallets are currently being restored. + جارٍ استعادة المحفظة <b>%1</b>… + + + Restore wallet failed + Title of message box which is displayed when the wallet could not be restored. + فشلت استعادة المحفظة + + + Restore wallet warning + Title of message box which is displayed when the wallet is restored with some warning. + تحذير استعادة المحفظة + + + Restore wallet message + Title of message box which is displayed when the wallet is successfully restored. + رسالة استعادة المحفظة + + SendCoinsDialog @@ -2799,10 +3947,6 @@ Fee: رسوم : - - Dust: - غبار: - Inputs… مدخلات… @@ -2827,6 +3971,14 @@ Transaction Fee: رسوم المعاملة: + + 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 dash transactions than the network can process. + عندما يكون حجم المعاملات أقل من المساحة في الكتل، قد يفرض المعدنون وكذلك العقد المرحلة حداً أدنى من الرسوم. دفع هذا الحد الأدنى من الرسوم فقط أمر جيد، ولكن كن على دراية بأن هذا قد يؤدي إلى معاملة لن يتم تأكيدها أبداً بمجرد أن يكون هناك طلب أكبر على معاملات Dash مما يمكن للشبكة معالجته. + + + A too low fee might result in a never confirming transaction (read the tooltip) + قد تؤدي الرسوم المنخفضة جداً إلى معاملة لن يتم تأكيدها أبداً (اقرأ تلميح الأداة) + (Smart fee not initialized yet. This usually takes a few blocks…) (الرسوم الذكية لم يتم تهيئتها بعد. عادة ما يستغرق ذلك بضع كتل …) @@ -2919,10 +4071,6 @@ Copy bytes نسخ البايتات - - Copy dust - نسخ الغبار - Copy change نسخ التعديل @@ -2939,10 +4087,6 @@ %1 to %2 %1 الى %2 - - Are you sure you want to send? - هل أنت متأكد من أنك تريد أن ترسل؟ - <b>(%1 of %2 entries displayed)</b> <b>( %1 على %2 المداخلات المعروضة)</b> @@ -2955,6 +4099,18 @@ Confirm the %1 send action قم بتأكيد إجراء إرسال%1 + + Cr&eate Unsigned + إ&نشاء غير موقع + + + from wallet '%1' + من المحفظة '%1' + + + %1 to '%2' + %1 إلى '%2' + %1 funds only %1 أموال فقط @@ -3003,6 +4159,51 @@ Confirm send coins تأكيد الإرسال Coins + + Save Transaction Data + حفظ بيانات المعاملة + + + PSBT saved + تم حفظ PSBT + + + Watch-only balance: + رصيد المراقبة فقط: + + + Creates a Partially Signed Blockchain Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet. + ينشئ معاملة بلوكشين موقعة جزئياً (PSBT) للاستخدام مع محفظة %1 غير متصلة بالإنترنت على سبيل المثال، أو محفظة أجهزة متوافقة مع PSBT. + + + Do you want to create this transaction? + 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. + هل تريد إنشاء هذه المعاملة؟ + + + Please, review your transaction proposal. This will produce a Partially Signed Blockchain Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet. + 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. + يرجى مراجعة مقترح المعاملة الخاص بك. سينتج عن هذا معاملة بلوكشين موقعة جزئياً (PSBT) يمكنك حفظها أو نسخها ثم التوقيع عليها باستخدام محفظة %1 غير متصلة بالإنترنت على سبيل المثال، أو محفظة أجهزة متوافقة مع PSBT. + + + Please, review your transaction. You can create and send this transaction or create a Partially Signed Blockchain Transaction (PSBT), which you can save or copy and then sign with, e.g., an offline %1 wallet, or a PSBT-compatible hardware wallet. + 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. + يرجى مراجعة معاملتك. يمكنك إنشاء هذه المعاملة وإرسالها أو إنشاء معاملة بلوكشين موقعة جزئياً (PSBT)، والتي يمكنك حفظها أو نسخها ثم التوقيع عليها باستخدام محفظة %1 غير متصلة بالإنترنت على سبيل المثال، أو محفظة أجهزة متوافقة مع PSBT. + + + Please, review your transaction. + Text to prompt a user to review the details of the transaction they are attempting to send. + يرجى مراجعة معاملتك. + + + To review recipient list click "Show Details…" + لمراجعة قائمة المستلمين انقر على "إظهار التفاصيل…" + + + Partially Signed Transaction (Binary) + Expanded name of the binary PSBT file format. See: BIP 174. + معاملة موقعة جزئياً (ثنائية) + The recipient address is not valid. Please recheck. عنوان المستلم غير صالح. يرجى إعادة الفحص. @@ -3122,21 +4323,16 @@ A message that was attached to the dash: URI which will be stored with the transaction for your reference. Note: This message will not be sent over the Dash network. رسالة تم إرفاقها بخط العطف: عنوان الذي سيتم تخزينه مع المعاملة كمرجع لك. ملاحظة: لن يتم إرسال هذه الرسالة عبر شبكة داش. + + + SendConfirmationDialog - This is an unauthenticated payment request. - هذا طلب دفع لم يتم مصادقته. - - - This is an authenticated payment request. - هذا طلب دفع تمت مصادقته. - - - Pay To: - ادفع &الى : + Send + إرسال - Memo: - مذكرة: + Create Unsigned + إنشاء غير موقع @@ -3276,6 +4472,10 @@ Wallet unlock was cancelled. تم الغاء عملية فتح المحفظة + + No error + لا يوجد خطأ + Private key for the entered address is not available. المفتاح الخاص للعنوان المدخل غير متاح. @@ -3309,11 +4509,22 @@ تم تأكيد الرسالة. + + SplashScreen + + (press q to shutdown and continue later) + (اضغط q للإيقاف والمتابعة لاحقاً) + + + press q to shutdown + اضغط q للإيقاف + + TrafficGraphWidget - KB/s - كيلوبايت/ث + kB/s + كيلوبايت/ثانية Total @@ -3330,20 +4541,9 @@ TransactionDesc - - Open for %n more block(s) - فتح لـ %n كتل إضافيةفتح لـ %n كتل إضافيةفتح لـ %n كتل إضافيةفتح لـ %n كتل إضافيةفتح لـ %n كتل إضافيةفتح لـ %n كتل إضافية - - - Open until %1 - مفتوح حتى %1 - - - conflicted - يتعارض - 0/unconfirmed, %1 + 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. 0/غير مؤكد ،%1 @@ -3356,22 +4556,32 @@ abandoned + 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. مهجور + + conflicted with a transaction with %1 confirmations + 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. + تعارض مع معاملة لها %1 تأكيدات + %1/unconfirmed + 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, and still not locked via ChainLocks. غير مؤكدة/%1 %1 confirmations + 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 or locked via ChainLocks. تأكيد %1 locked via ChainLocks + 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 and has been locked by ChainLocks. مغلق عبر ChainLocks verified via InstantSend + 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 has been locked by InstantSend. محقق من فبل الإرسال الفوري @@ -3390,6 +4600,10 @@ Generated تم اصداره. + + Platform Transfer + نقل المنصة + From من @@ -3520,14 +4734,6 @@ Address / Label تسمية / عنوان - - Open for %n more block(s) - فتح لـ %n كتل إضافيةفتح لـ %n كتل إضافيةفتح لـ %n كتل إضافيةفتح لـ %n كتل إضافيةفتح لـ %n كتل إضافيةفتح لـ %n كتل إضافية - - - Open until %1 - مفتوح حتى %1 - Unconfirmed غير مؤكد @@ -3588,6 +4794,10 @@ Mined Mined + + Platform Transfer + نقل المنصة + %1 Mixing %1 خلط @@ -3715,6 +4925,10 @@ Mined Mined + + Platform Transfer + نقل المنصة + Other اخرى @@ -3728,49 +4942,63 @@ الحد الأدنى - Abandon transaction - التخلي عن المعاملة + &Copy address + &نسخ العنوان - Copy address - انسخ عنوان + Copy &label + نسخ &التسمية - Copy label - انسخ التسمية + Copy &amount + نسخ &المبلغ - Copy amount - نسخ الكمية + Copy transaction &ID + نسخ &معرف المعاملة + + + Copy &raw transaction + نسخ المعاملة ال&خام + + + Copy full transaction &details + نسخ &تفاصيل المعاملة الكاملة - Copy transaction ID - نسخ رقم العملية + &Show transaction details + &إظهار تفاصيل المعاملة - Copy raw transaction - نسخ المعاملة الخام + A&bandon transaction + &التخلي عن المعاملة - Copy full transaction details - نسخ كامل تفاصيل المعاملة + Rese&nd transaction + إعا&دة إرسال المعاملة - Edit address label - تحرير تسمية العنوان + &Edit address label + &تعديل تسمية العنوان - Show transaction details - عرض تفاصيل المعاملة + Show address &QR code + عرض رمز &QR للعنوان - Show address QR code - إظهار رمز الاستجابة السريعة العنوان + Show in %1 + 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. + عرض في %1 Export Transaction History تصدير تفاصيل المعاملات + + Comma separated file + Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values. + ملف مفصول بفواصل + Confirmed تأكيد @@ -3849,10 +5077,54 @@ Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled. قد يؤدي إغلاق المحفظة لفترة طويلة إلى الاضطرار إلى إعادة مزامنة السلسلة بأكملها إذا تم تمكين التقليم. - + + Close all wallets + إغلاق جميع المحافظ + + + Are you sure you wish to close all wallets? + هل أنت متأكد من أنك تريد إغلاق جميع المحافظ؟ + + WalletFrame - + + No wallet has been loaded. +Go to File > Open Wallet to load a wallet. +- OR - + لم يتم تحميل أي محفظة. +انتقل إلى ملف > فتح محفظة لتحميل محفظة. +- أو - + + + Create a new wallet + إنشاء محفظة جديدة + + + Error + خطأ + + + Unable to decode PSBT from clipboard (invalid base64) + غير قادر على فك تشفير PSBT من الحافظة (base64 غير صالح) + + + Load Transaction Data + تحميل بيانات المعاملة + + + Partially Signed Transaction (*.psbt) + معاملة موقعة جزئياً (*.psbt) + + + PSBT file must be smaller than 100 MiB + يجب أن يكون ملف PSBT أصغر من 100 ميبيبايت + + + Unable to decode PSBT + غير قادر على فك تشفير PSBT + + WalletModel @@ -3878,6 +5150,11 @@ Selected amount: المبلغ المحدد: + + Wallet Data + Name of the wallet data file format. + بيانات المحفظة + Backup Wallet نسخ احتياط للمحفظة @@ -3905,14 +5182,6 @@ dash-core - - Error: Listening for incoming connections failed (listen returned error %s) - خطأ: فشل الاستماع إلى الاتصالات الواردة (تم إرجاع الخطأ %s) - - - Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee. - فشل تقدير الرسوم. تم تعطيل الرسوم الاحتياطية. انتظر بضع كتل أو قم بتمكين -رسوم التراجع. - 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 يمكن أن يحدث هذا الخطأ إذا لم يتم إغلاق هذه المحفظة بشكل سليم وتم تحميلها مؤخرًا باستخدام إصدار أحدث من Berkeley DB. إذا كان الأمر كذلك ، فالرجاء استخدام البرنامج الذي تم تحميل هذه المحفظة آخر مرة @@ -3970,16 +5239,20 @@ خطأ في القراءة من قاعدة البيانات ، والتوقف. - Failed to listen on any port. Use -listen=0 if you want this. - فشل في الاستماع على أي منفذ. استخدام الاستماع = 0 إذا كنت تريد هذا. + Error: Missing checksum + خطأ: المجموع الاختباري مفقود + + + Error: Unable to parse version %u as a uint32_t + خطأ: غير قادر على تحليل الإصدار %u كـ uint32_t - -maxtxfee is set very high! Fees this large could be paid on a single transaction. - يتم تعيين maxtxfee عالية جدا! يمكن دفع هذه الرسوم في معاملة واحدة. + Error: Unable to write record to new wallet + خطأ: غير قادر على كتابة السجل إلى المحفظة الجديدة - Cannot provide specific connections and have addrman find outgoing connections at the same. - لا يمكن توفير اتصالات محددة ولديك addrman يجد الاتصالات الصادرة في نفس الوقت. + Failed to listen on any port. Use -listen=0 if you want this. + فشل في الاستماع على أي منفذ. استخدام الاستماع = 0 إذا كنت تريد هذا. Found unconfirmed denominated outputs, will wait till they confirm to continue. @@ -3990,13 +5263,17 @@ تم تحديد أحداث مأخذ توصيل غير صالحة ('%s'). يتم دعم هذه الأوضاع فقط: %s - Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions) - كمية غير صالحة لـ -maxtxfee = : '%s' <amount> (يجب أن تكون على الأقل رسوم minrelay %s لمنع المعاملات عالقة) + SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is supported + قاعدة بيانات SQLite: إصدار مخطط محفظة sqlite غير معروف %d. الإصدار %d فقط مدعوم Transaction index can't be disabled with governance validation enabled. Either start with -disablegovernance command line switch or enable transaction index. لا يمكن تعطيل فهرس المعاملات مع تمكين التحقق من صحة الحوكمة. إما أن تبدأ بمفتاح سطر الأوامر -disablegovernance أو تمكين فهرس المعاملات. + + Unsupported category-specific logging level -loglevel=%s. Expected -loglevel=<category>:<loglevel>. Valid categories: %s. Valid loglevels: %s. + مستوى تسجيل خاص بالفئة غير مدعوم -loglevel=%s. متوقع -loglevel=<category>:<loglevel>. الفئات الصالحة: %s. مستويات السجل الصالحة: %s. + Can't mix: no compatible inputs found! لا يمكن الجمع: لم يتم العثور على مدخلات متوافقة! @@ -4005,6 +5282,14 @@ Entry exceeds maximum size. يتجاوز الدخول الحد الأقصى للحجم. + + Error upgrading evo database for EHF + خطأ في ترقية قاعدة بيانات evo لـ EHF + + + Failed to commit Evo database + فشل في تنفيذ قاعدة بيانات Evo + Found enough users, signing ( waiting %s ) العثور على عدد كافٍ من المستخدمين ، والتوقيع (الانتظار %s) @@ -4029,18 +5314,14 @@ Insufficient funds. رصيد غير كاف. - - Invalid amount for -discardfee=<amount>: '%s' - مبلغ غير صالح لـ -discardfee =<amount>: '%s' - - - Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s) - مبلغ غير صالح لـ -paytxfee = : '%s' <amount> (يجب أن يكون على الأقل %s) - Invalid minimum number of spork signers specified with -minsporkkeys الحد الأدنى لعدد مميّزي مواقع السبط المحدد + + Listening for incoming connections failed (listen returned error %s) + فشل الاستماع للاتصالات الواردة (أرجع الاستماع خطأ %s) + Lock is already in place. قفل بالفعل في المكان. @@ -4097,6 +5378,10 @@ Synchronizing governance objects… مزامنة كائنات الحوكمة … + + Transaction change output index out of range + مؤشر مخرجات تغيير المعاملة خارج النطاق + Unable to start HTTP server. See debug log for details. غير قادر على بدء خادم ال HTTP. راجع سجل تصحيح الأخطاء للحصول على التفاصيل. @@ -4105,6 +5390,10 @@ Unknown response. استجابة غير معروفة. + + Unsupported global logging level -loglevel=%s. Valid values: %s. + مستوى تسجيل عام غير مدعوم -loglevel=%s. القيم الصالحة: %s. + User Agent comment (%s) contains unsafe characters. يحتوي تعليق وكيل المستخدم (%s) على أحرف غير آمنة. @@ -4145,6 +5434,10 @@ Make sure to encrypt your wallet and delete all non-encrypted backups after you have verified that the wallet works! تأكد من تشفير محفظتك وحذف جميع النسخ الاحتياطية غير المشفرة بعد التحقق من عمل المحفظة! + + More than one onion bind address is provided. Using %s for the automatically created Tor onion service. + تم توفير أكثر من عنوان ربط onion واحد. استخدام %s لخدمة Tor onion التي تم إنشاؤها تلقائياً. + Prune configured below the minimum of %d MiB. Please use a higher number. تم تكوين Prune أسفل الحد الأدنى من %d MiB. يرجى استخدام عدد أكبر. @@ -4173,10 +5466,6 @@ Wallet is locked, can't replenish keypool! Automatic backups and mixing are disabled, please unlock your wallet to replenish keypool. المحفظة مؤمّنة ، ولا يمكن تجديد مفتاح keypool! تم تعطيل النسخ الاحتياطي التلقائي والاختلاط ، يرجى فتح محفظتك لتجديد keypool - - You need to rebuild the database using -reindex to change -timestampindex - تحتاج إلى إعادة بناء قاعدة البيانات باستخدام -reindex لتغيير -timestampindex - You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain تحتاج إلى إعادة إنشاء قاعدة البيانات باستخدام -reindex للعودة إلى الوضعية الغير مجردة. هذا سوف يعيد تحميل سلسلة الكتل بأكملها @@ -4218,20 +5507,32 @@ خطأ في تحميل%s: لا يمكن تعطيل المفاتيح الخاصة إلا أثناء الإنشاء - Error upgrading evo database - خطأ في ترقية قاعدة بيانات evo + Error: Couldn't create cursor into database + خطأ: تعذر إنشاء مؤشر في قاعدة البيانات Error: Disk space is low for %s خطأ: مساحة القرص منخفضة لـ%s - Exceeded max tries. - تم تجاوز الحد الأقصى من المحاولات. + Error: Dumpfile checksum does not match. Computed %s, expected %s + خطأ: المجموع الاختباري لملف التفريغ لا يتطابق. محسوب %s، متوقع %s + + + Error: Got key that was not hex: %s + خطأ: تم الحصول على مفتاح ليس بصيغة ست عشرية: %s + + + Error: Got value that was not hex: %s + خطأ: تم الحصول على قيمة ليست بصيغة ست عشرية: %s + + + Error: Keypool ran out, please call keypoolrefill first + خطأ: نفد مجمع المفاتيح، يرجى استدعاء keypoolrefill أولاً - Failed to commit EvoDB - فشل الالتزام بـ EvoDB + Error: No addresses available. + خطأ: لا توجد عناوين متاحة. Failed to create backup %s! @@ -4249,17 +5550,29 @@ Failed to rescan the wallet during initialization فشل في إعادة فحص المحفظة أثناء التهيئة + + Failed to verify database + فشل في التحقق من قاعدة البيانات + + + Fee rate (%s) is lower than the minimum fee rate setting (%s) + معدل الرسوم (%s) أقل من إعداد الحد الأدنى لمعدل الرسوم (%s) + Found enough users, signing… العثور على عدد كافٍ من المستخدمين ، والتوقيع… - Invalid P2P permission: '%s' - إذن P2P غير صالح: '%s' + Ignoring duplicate -wallet %s. + تجاهل المحفظة المكررة -wallet %s. + + + Input not found or already spent + لم يتم العثور على المدخل أو تم إنفاقه بالفعل - Invalid amount for -fallbackfee=<amount>: '%s' - المبلغ غير صالح fallbackfee = <amount> :'%s- + Invalid P2P permission: '%s' + إذن P2P غير صالح: '%s' Invalid masternodeblsprivkey. Please see documentation. @@ -4281,6 +5594,10 @@ Mixing in progress… الدمج قيد التقدم … + + No addresses available + لا توجد عناوين متاحة + No errors detected. لم يتم اكتشاف أخطاء. @@ -4309,6 +5626,22 @@ Prune mode is incompatible with -txindex. وضع التجريد غير متوافق مع -txindex. + + SQLiteDatabase: Failed to execute statement to verify database: %s + قاعدة بيانات SQLite: فشل تنفيذ البيان للتحقق من قاعدة البيانات: %s + + + SQLiteDatabase: Failed to prepare statement to verify database: %s + قاعدة بيانات SQLite: فشل تحضير البيان للتحقق من قاعدة البيانات: %s + + + SQLiteDatabase: Failed to read database verification error: %s + قاعدة بيانات SQLite: فشل قراءة خطأ التحقق من قاعدة البيانات: %s + + + SQLiteDatabase: Unexpected application id. Expected %u, got %u + قاعدة بيانات SQLite: معرف تطبيق غير متوقع. متوقع %u، تم الحصول على %u + Section [%s] is not recognized. المقطع [%s] غير معروف. @@ -4341,6 +5674,10 @@ This is the transaction fee you will pay if you send a transaction. هذه هي رسوم المعاملة التي ستدفعها إذا أرسلت معاملة. + + Topping up keypool… + تعبئة مجمع المفاتيح… + Transaction amounts must not be negative يجب ألا تكون قيمة المعاملة سلبية @@ -4369,13 +5706,17 @@ Unable to generate initial keys تعذر إنشاء المفاتيح الأولية + + Unable to open %s for writing + غير قادر على فتح %s للكتابة + Unknown -blockfilterindex value %s. قيمة فهرس كتلة التصفية غير معروفة%s. - Upgrading UTXO database - ترقية قاعدة بيانات UTXO + Unknown new rules activated (versionbit %i) + تم تفعيل قواعد جديدة غير معروفة (بت الإصدار %i) Verifying blocks… @@ -4394,16 +5735,12 @@ لم يكن قادراً على إنشاء مجلد النسخ الاحتياطي المحفظة %s! - You can not start a masternode with wallet enabled. - لا يمكنك بدء Masternode مع محفظة ممكنة. - - - You need to rebuild the database using -reindex to change -addressindex - تحتاج إلى إعادة بناء قاعدة البيانات باستخدام -reindex لتغيير -addressindex + Wiping wallet transactions… + مسح معاملات المحفظة… - You need to rebuild the database using -reindex to change -spentindex - تحتاج إلى إعادة بناء قاعدة البيانات باستخدام -reindex لتغيير -spentindex + You can not start a masternode with wallet enabled. + لا يمكنك بدء Masternode مع محفظة ممكنة. no mixing available. @@ -4421,6 +5758,22 @@ %s uses exact denominated amounts to send funds, you might simply need to mix some more coins. يستخدم%s مبالغ محددة بدقة لإرسال الأموال ، قد تحتاج ببساطة إلى خلط بعض العملات المعدنية. + + -reindex-chainstate option is not compatible with -blockfilterindex. Please temporarily disable blockfilterindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes. + خيار -reindex-chainstate غير متوافق مع -blockfilterindex. يرجى تعطيل blockfilterindex مؤقتاً أثناء استخدام -reindex-chainstate، أو استبدال -reindex-chainstate بـ -reindex لإعادة بناء جميع الفهارس بالكامل. + + + -reindex-chainstate option is not compatible with -coinstatsindex. Please temporarily disable coinstatsindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes. + خيار -reindex-chainstate غير متوافق مع -coinstatsindex. يرجى تعطيل coinstatsindex مؤقتاً أثناء استخدام -reindex-chainstate، أو استبدال -reindex-chainstate بـ -reindex لإعادة بناء جميع الفهارس بالكامل. + + + -reindex-chainstate option is not compatible with -txindex. Please temporarily disable txindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes. + خيار -reindex-chainstate غير متوافق مع -txindex. يرجى تعطيل txindex مؤقتاً أثناء استخدام -reindex-chainstate، أو استبدال -reindex-chainstate بـ -reindex لإعادة بناء جميع الفهارس بالكامل. + + + Cannot downgrade wallet from version %i to version %i. Wallet version unchanged. + لا يمكن تخفيض إصدار المحفظة من الإصدار %i إلى الإصدار %i. إصدار المحفظة دون تغيير. + Cannot obtain a lock on data directory %s. %s is probably already running. لا يمكن الحصول على قفل على دليل البيانات %s. من المحتمل أن %s يعمل بالفعل. @@ -4433,14 +5786,82 @@ Error loading %s: You can't enable HD on an already existing non-HD wallet خطأ في تحميل %s: لا يمكنك تمكين HD في محفظة موجودة بالفعل بخلاف HD + + 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 + خطأ في تحميل المحفظة. تتطلب المحفظة تنزيل الكتل، ولا يدعم البرنامج حالياً تحميل المحافظ أثناء تنزيل الكتل خارج الترتيب عند استخدام لقطات assumeutxo. يجب أن تكون المحفظة قادرة على التحميل بنجاح بعد وصول مزامنة العقدة إلى الارتفاع %s + Error reading %s! All keys read correctly, but transaction data or address book entries might be missing or incorrect. خطأ في قراءة %s! قراءة كافة المفاتيح بشكل صحيح ، ولكن قد تكون بيانات المعاملة أو إدخالات دفتر العناوين مفقودة أو غير صحيحة. + + Error: Dumpfile format record is incorrect. Got "%s", expected "format". + خطأ: سجل تنسيق ملف التفريغ غير صحيح. تم الحصول على "%s"، متوقع "format". + + + Error: Dumpfile identifier record is incorrect. Got "%s", expected "%s". + خطأ: سجل معرف ملف التفريغ غير صحيح. تم الحصول على "%s"، متوقع "%s". + + + Error: Dumpfile version is not supported. This version of bitcoin-wallet only supports version 1 dumpfiles. Got dumpfile with version %s + خطأ: إصدار ملف التفريغ غير مدعوم. هذا الإصدار من bitcoin-wallet يدعم فقط ملفات التفريغ الإصدار 1. تم الحصول على ملف تفريغ بالإصدار %s + + + Failed to rename invalid peers.dat file. Please move or delete it and try again. + فشل في إعادة تسمية ملف peers.dat غير صالح. يرجى نقله أو حذفه والمحاولة مرة أخرى. + + + Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable %s. + فشل تقدير الرسوم. تم تعطيل رسوم الاحتياط. انتظر بضع كتل أو قم بتمكين %s. + + + File %s already exists. If you are sure this is what you want, move it out of the way first. + الملف %s موجود بالفعل. إذا كنت متأكداً من أن هذا ما تريده، انقله بعيداً أولاً. + + + Incompatible options: -dnsseed=1 was explicitly specified, but -onlynet forbids connections to IPv4/IPv6 + خيارات غير متوافقة: تم تحديد -dnsseed=1 صراحةً، لكن -onlynet يمنع الاتصالات بـ IPv4/IPv6 + Incorrect or no devnet genesis block found. Wrong datadir for devnet specified? تم العثور على كتلة تكوين devnet غير صحيحة أو لا. datadir خاطئة ل devnet المحدد؟ + + Invalid amount for %s=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions) + مبلغ غير صالح لـ %s=<amount>: '%s' (يجب أن يكون على الأقل رسوم الحد الأدنى للترحيل %s لمنع المعاملات العالقة) + + + 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. + ملف peers.dat (%s) غير صالح أو تالف. إذا كنت تعتقد أن هذا خطأ، يرجى الإبلاغ عنه إلى %s. كحل بديل، يمكنك نقل الملف (%s) بعيداً (إعادة تسمية أو نقل أو حذف) لإنشاء ملف جديد في البداية التالية. + + + No dump file provided. To use createfromdump, -dumpfile=<filename> must be provided. + لم يتم توفير ملف تفريغ. لاستخدام createfromdump، يجب توفير -dumpfile=<filename>. + + + No dump file provided. To use dump, -dumpfile=<filename> must be provided. + لم يتم توفير ملف تفريغ. لاستخدام dump، يجب توفير -dumpfile=<filename>. + + + No wallet file format provided. To use createfromdump, -format=<format> must be provided. + لم يتم توفير تنسيق ملف المحفظة. لاستخدام createfromdump، يجب توفير -format=<format>. + + + Outbound connections restricted to CJDNS (-onlynet=cjdns) but -cjdnsreachable is not provided + الاتصالات الصادرة مقيدة بـ CJDNS (-onlynet=cjdns) ولكن لم يتم توفير -cjdnsreachable + + + Outbound connections restricted to Tor (-onlynet=onion) but the proxy for reaching the Tor network is explicitly forbidden: -onion=0 + الاتصالات الصادرة مقيدة بـ Tor (-onlynet=onion) ولكن الوكيل للوصول إلى شبكة Tor محظور صراحةً: -onion=0 + + + 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 + الاتصالات الصادرة مقيدة بـ Tor (-onlynet=onion) ولكن لم يتم توفير الوكيل للوصول إلى شبكة Tor: لم يتم تقديم أي من -proxy أو -onion أو -listenonion + + + Outbound connections restricted to i2p (-onlynet=i2p) but -i2psam is not provided + الاتصالات الصادرة مقيدة بـ i2p (-onlynet=i2p) ولكن لم يتم توفير -i2psam + Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly. يرجى التحقق من صحة تاريخ ووقت جهازك! إذا كانت ساعتك خاطئة ، فلن يعمل %s بشكل صحيح. @@ -4449,6 +5870,14 @@ Please contribute if you find %s useful. Visit %s for further information about the software. يرجى المساهمة إذا وجدت %s مفيداً. تفضل بزيارة %s لمزيد من المعلومات حول البرنامج. + + Prune mode is incompatible with -reindex-chainstate. Use full -reindex instead. + وضع التقليم غير متوافق مع -reindex-chainstate. استخدم -reindex كاملاً بدلاً من ذلك. + + + This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection. + هذه هي الحد الأقصى لرسوم المعاملة التي تدفعها (بالإضافة إلى الرسوم العادية) لإعطاء الأولوية لتجنب الإنفاق الجزئي على اختيار العملات العادي. + This is the transaction fee you may discard if change is smaller than dust at this level هذه هي رسوم المعاملة التي يمكنك تجاهلها إذا كان التغيير أصغر من الغبار عند هذا المستوى @@ -4457,14 +5886,38 @@ This is the transaction fee you may pay when fee estimates are not available. هذه هي رسوم المعاملة التي قد تدفعها عندما لا تكون تقديرات الرسوم متاح. + + Transaction requires one destination of non-0 value, a non-0 feerate, or a pre-selected input + تتطلب المعاملة وجهة واحدة بقيمة غير صفرية، أو معدل رسوم غير صفري، أو مدخل محدد مسبقاً + Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate. غير قادر على إعادة الكتل. ستحتاج إلى إعادة بناء قاعدة البيانات باستخدام -reindex-chainstate. + + Unknown wallet file format "%s" provided. Please provide one of "bdb" or "sqlite". + تم توفير تنسيق ملف محفظة غير معروف "%s". يرجى توفير أحد "bdb" أو "sqlite". + + + Unsupported chainstate database format found. Please restart with -reindex-chainstate. This will rebuild the chainstate database. + تم العثور على تنسيق قاعدة بيانات chainstate غير مدعوم. يرجى إعادة التشغيل باستخدام -reindex-chainstate. سيؤدي هذا إلى إعادة بناء قاعدة بيانات chainstate. + + + Warning: Dumpfile wallet format "%s" does not match command line specified format "%s". + تحذير: تنسيق محفظة ملف التفريغ "%s" لا يتطابق مع التنسيق المحدد في سطر الأوامر "%s". + Warning: Private keys detected in wallet {%s} with disabled private keys تحذير: تم اكتشاف مفاتيح خاصة في المحفظة {%s} مع تعطيل المفاتيح الخاصة + + You need to rebuild the database using -reindex to enable -timestampindex + تحتاج إلى إعادة بناء قاعدة البيانات باستخدام -reindex لتمكين -timestampindex + + + %s -- Incorrect seed, it should be a hex string + %s -- البذرة غير صحيحة، يجب أن تكون سلسلة سداسية عشرية + %s is not a valid backup folder! %s ليس مجلد نسخ احتياطي صالح! @@ -4489,10 +5942,30 @@ -rpcport must be specified when -devnet and -server are specified يجب تحديد -ppcport عند تحديد -devnet و -server + + -statsbatchsize cannot be configured with a negative value. + لا يمكن تكوين -statsbatchsize بقيمة سالبة. + + + -statsduration cannot be configured with a negative value. + لا يمكن تكوين -statsduration بقيمة سالبة. + A fatal internal error occurred, see debug.log for details حدث خطأ داخلي فادح ، راجع debug.log للحصول على التفاصيل + + Cannot create socket (socket() returned error %s) + لا يمكن إنشاء مقبس (أرجع ()socket خطأ %s) + + + Cannot get socket address for %s + لا يمكن الحصول على عنوان المقبس لـ %s + + + Cannot init Statsd client + لا يمكن تهيئة عميل Statsd + Cannot resolve -%s address: '%s' لا يمكن حل - عنوان%s: '%s' @@ -4501,10 +5974,6 @@ Cannot write to data directory '%s'; check permissions. لا يمكن الكتابة إلى دليل البيانات '%s' ؛ تحقق من الأذونات. - - Change index out of range - فهرس الفكة خارج النطاق - Copyright (C) حقوق الطبع والنشر (C) @@ -4513,6 +5982,14 @@ Disk space is too low! مساحة القرص منخفضة جدًا! + + Dump file %s does not exist. + ملف التفريغ %s غير موجود. + + + Error creating %s + خطأ في إنشاء %s + Error loading %s خطأ في تحميل %s @@ -4530,8 +6007,8 @@ حدث خطأ أثناء تحميل %s: لا يمكنك تعطيل HD في محفظة HD موجودة بالفعل - Error upgrading chainstate database - خطأ في ترقية قاعدة بيانات chainstate + Error reading next record from wallet database + خطأ في قراءة السجل التالي من قاعدة بيانات المحفظة Loading P2P addresses… @@ -4601,6 +6078,14 @@ Inputs vs outputs size mismatch. عدم تطابق حجم المدخلات مقابل المخرجات. + + Invalid '%s'. Allowed values: 128, 160, 192, 224, 256. + '%s' غير صالح. القيم المسموح بها: 128، 160، 192، 224، 256. + + + Invalid -i2psam address or hostname: '%s' + عنوان أو اسم مضيف -i2psam غير صالح: '%s' + Invalid -onion address or hostname: '%s' عنوان أو اسم مضيف غير صالح: '%s' @@ -4645,14 +6130,78 @@ %s corrupt. Try using the wallet tool dash-wallet to salvage or restoring a backup. %s تالف. حاول استخدام dash-wallet لأداة المحفظة لإنقاذ أو استعادة نسخة احتياطية. + + %s is set very high! Fees this large could be paid on a single transaction. + تم تعيين %s مرتفعاً جداً! يمكن دفع رسوم بهذا الحجم على معاملة واحدة. + + + %s request to listen on port %u. This port is considered "bad" and thus it is unlikely that any Dash Core peers connect to it. See doc/p2p-bad-ports.md for details and a full list. + طلب %s للاستماع على المنفذ %u. يعتبر هذا المنفذ "سيئاً" وبالتالي من غير المحتمل أن يتصل به أي نظراء Dash Core. راجع doc/p2p-bad-ports.md للحصول على التفاصيل والقائمة الكاملة. + + + Cannot provide specific connections and have addrman find outgoing connections at the same time. + لا يمكن توفير اتصالات محددة وجعل addrman يجد اتصالات صادرة في نفس الوقت. + + + Failed to upgrade Evo database + فشل في ترقية قاعدة بيانات Evo + + + Fee needed > fee paid + الرسوم المطلوبة > الرسوم المدفوعة + + + Host %s on unsupported network + المضيف %s على شبكة غير مدعومة + + + Invalid amount for %s=<amount>: '%s' (must be at least %s) + مبلغ غير صالح لـ %s=<amount>: '%s' (يجب أن يكون على الأقل %s) + + + Invalid amount for %s=<amount>: '%s' + مبلغ غير صالح لـ %s=<amount>: '%s' + + + Invalid port specified in %s: '%s' + منفذ غير صالح محدد في %s: '%s' + Last successful action was too recent. آخر إجراء ناجح كان حديثًا جدًا. + + Missing solving data for estimating transaction size + بيانات الحل مفقودة لتقدير حجم المعاملة + + + No host specified + لم يتم تحديد مضيف + + + No host specified, malformed URL + لم يتم تحديد مضيف، عنوان URL مشوه + + + No text before the scheme delimiter, malformed URL + لا يوجد نص قبل محدد المخطط، عنوان URL مشوه + + + Port must be between %d and %d, supplied %d + يجب أن يكون المنفذ بين %d و %d، تم توفير %d + + + Socket not initialized, cannot send message + المقبس غير مهيأ، لا يمكن إرسال الرسالة + The source code is available from %s. شفرة المصدر متاح من %s. + + The specified config file %s does not exist + ملف التكوين المحدد %s غير موجود + The transaction amount is too small to pay the fee قيمة المعاملة صغيرة جدا لدفع الأجر @@ -4673,6 +6222,10 @@ Transaction fees are too high. رسوم المعاملات مرتفعة للغاية. + + Transaction needs a change address, but we can't generate it. + تحتاج المعاملة إلى عنوان تغيير، لكن لا يمكننا إنشاءه. + Transaction not valid. المعاملة غير صالحة. @@ -4693,6 +6246,18 @@ Unable to locate enough non-denominated funds for this transaction. غير قادر على تحديد موقع أموال كافية غير مقومة لهذه المعاملة. + + Unable to lookup host %s + غير قادر على البحث عن المضيف %s + + + Unable to parse -maxuploadtarget: '%s' + غير قادر على تحليل -maxuploadtarget: '%s' + + + Unable to send message to %s (::sendto() returned error %s) + غير قادر على إرسال رسالة إلى %s (أرجع ()::sendto خطأ %s) + Unable to sign spork message, wrong key? غير قادر على التوقيع على رسالة ورش ، مفتاح خاطئ؟ @@ -4706,12 +6271,12 @@ حالة غير معروفة: id = %u - Unsupported logging category %s=%s. - فئة التسجيل غير المعتمدة%s=%s. + Unsupported URL scheme, must begin with udp:// + مخطط URL غير مدعوم، يجب أن يبدأ بـ udp:// - Upgrading txindex database - تحديث قاعدة بيانات txindex + Unsupported logging category %s=%s. + فئة التسجيل غير المعتمدة%s=%s. Very low number of keys left: %d @@ -4741,9 +6306,25 @@ You can not disable governance validation on a masternode. لا يمكنك تعطيل التحقق من الحوكمة على Masternode. + + You need to rebuild the database using -reindex to enable -addressindex + تحتاج إلى إعادة بناء قاعدة البيانات باستخدام -reindex لتمكين -addressindex + + + You need to rebuild the database using -reindex to enable -spentindex + تحتاج إلى إعادة بناء قاعدة البيانات باستخدام -reindex لتمكين -spentindex + Your entries added successfully. تمت إضافة إدخالاتك بنجاح. + + Settings file could not be read + تعذر قراءة ملف الإعدادات + + + Settings file could not be written + تعذر كتابة ملف الإعدادات + \ No newline at end of file diff --git a/src/qt/locale/dash_bg.ts b/src/qt/locale/dash_bg.ts index b517fef2dc28..106e18adbe81 100644 --- a/src/qt/locale/dash_bg.ts +++ b/src/qt/locale/dash_bg.ts @@ -65,14 +65,6 @@ C&hoose Избери - - Sending addresses - Адреси за изпращане - - - Receiving addresses - Адреси за получаване - These are your Dash addresses for sending payments. Always check the amount and the receiving address before sending coins. Това са вашите Dash адреси за изпращане на плащания. Преди изпращане винаги проверявайте количеството и адреса за получаване на монетите. @@ -94,8 +86,8 @@ &Редактирай - &Show address QR code - &Покажи QR код на адреса + Show address &QR code + Покажи &QR код на адреса QR code @@ -105,6 +97,24 @@ Export Address List Експортиране на списъка с адреси + + Comma separated file + Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values. + Файл със стойности разделени със запетая + + + There was an error trying to save the address list to %1. Please try again. + An error message. %1 is a stand-in argument for the name of the file we attempted to save to. + Възникна грешка при опит за запазване на списъка с адреси в %1. Моля, опитайте отново. + + + Sending addresses - %1 + Адреси за изпращане - %1 + + + Receiving addresses - %1 + Адреси за получаване - %1 + Exporting Failed Грешка при експортирането @@ -274,10 +284,22 @@ The passphrase entered for the wallet decryption was incorrect. Паролата въведена за дешифриране на портфейла е грешна. + + 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 23.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. + Паролата въведена за дешифриране на портфейла е грешна. Тя съдържа нулев символ (т.е. - нулев байт). Ако паролата е зададена с версия на този софтуер преди 23.0, моля опитайте отново само със символите до — но без да включвате — първия нулев символ. Ако това е успешно, моля задайте нова парола, за да избегнете този проблем в бъдеще. + Wallet passphrase was successfully changed. Паролата на портфейла беше променена успешно. + + Passphrase change failed + Грешка при смяна на паролата + + + 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 23.0, please try again with only the characters up to — but not including — the first null character. + Старата парола въведена за дешифриране на портфейла е грешна. Тя съдържа нулев символ (т.е. - нулев байт). Ако паролата е зададена с версия на този софтуер преди 23.0, моля опитайте отново само със символите до — но без да включвате — първия нулев символ. + Warning: The Caps Lock key is on! Внимание: Caps Lock (главни букви) е включен. @@ -303,7 +325,23 @@ BitcoinApplication - + + Runaway exception + Неконтролирано изключение + + + A fatal error occurred. %1 can no longer continue safely and will quit. + Възникна фатална грешка. %1 не може повече да продължи безопасно и ще се затвори. + + + Internal error + Вътрешна грешка + + + An internal error occurred. %1 will attempt to continue safely. This is an unexpected bug which can be reported as described below. + Възникна вътрешна грешка. %1 ще се опита да продължи безопасно. Това е неочакван бъг, който може да бъде докладван, както е описано по-долу. + + BitcoinGUI @@ -330,6 +368,10 @@ Request payments (generates QR codes and dash: URIs) Заявка за плащане (генерира QR кодове и Dash: URI) + + Ctrl+Q + Ctrl+Q + &Options… &Опции… @@ -358,6 +400,10 @@ &Verify message… &Проверка на съобщение… + + &Load PSBT from file… + &Зареди PSBT от файл… + &Sending addresses &Адреси за изпращане @@ -390,10 +436,6 @@ &Window &Прозорец - - Minimize - Минимизирай - Zoom Увеличи @@ -446,14 +488,6 @@ Modify configuration options for %1 Промяна на опциите за конфигурация на %1 - - &Show / Hide - &Показване / Скриване - - - Show or hide the main Window - Показване и скриване на основния прозорец - Encrypt the private keys that belong to your wallet Криптирай частните ключове принадлежащи към твоя портфейл @@ -518,10 +552,6 @@ Show wallet repair options Покажи опции за възстановяване на портфейла - - Open Wallet &Configuration File - Отвори Портфейл &Конфигурационен файл - Open configuration file Отвори конфигурационния файл @@ -577,13 +607,17 @@ Показване на информация за %1  - Load Partially Signed Dash Transaction - Зареждане на частично подписана Dash трансакция + Load PSBT from &clipboard… + Зареди PSBT от &клипборда… Open debugging and diagnostic console Отвори конзолата за отстраняване на грешки и диагностика + + Open &wallet configuration file + Отвори &конфигурационен файл на портфейла + Open a dash: URI Отвори dash: URI @@ -592,6 +626,20 @@ Create a new wallet Създай нов портфейл + + Restore Wallet… + Name of the menu item that restores wallet from a backup file. + Възстанови портфейл… + + + Restore a wallet from a backup file + Status tip for Restore Wallet menu item + Възстановяване на портфейл от резервен файл + + + Close all wallets + Затвори всички портфейли + %1 &information %1 &информация @@ -600,10 +648,42 @@ Show the %1 basic information Покажи %1 основната информация + + &Discreet mode + &Дискретен режим + + + Mask the values in the Overview tab + Скрий стойностите в раздела Общ преглед + + + Wallet Data + Name of the wallet data file format. + Данни на портфейла + + + Load Wallet Backup + The title for Restore Wallet File Windows + Зареди резервно копие на портфейла + + + Restore Wallet + Title of pop-up window shown when the user is attempting to restore a wallet. + Възстанови портфейл + + + Wallet Name + Label of the input field where the name of the wallet is entered. + Име на портфейла + &Settings &Настройки + + &Minimize + &Минимизиране + &Help &Помощ @@ -620,8 +700,17 @@ View Governance Proposals Преглед на предложенията за управление  + + &Hide + &Скрий + + + S&how + П&окажи + %n active connection(s) to Dash network + A substring of the tooltip. %n активни връзки към Dash мрежата%n активни връзки към Dash мрежата @@ -640,10 +729,50 @@ Close Wallet… Затваряне на портфейла… + + Load Partially Signed Blockchain Transaction + Зареди частично подписана блокчейн транзакция + + + Load Partially Signed Blockchain Transaction from clipboard + Зареди частично подписана блокчейн транзакция от клипборда + Create Wallet… Създай портфейл… + + Close All Wallets… + Затвори всички портфейли… + + + Ctrl+Shift+D + Ctrl+Shift+D + + + Ctrl+M + Ctrl+M + + + Click for more actions. + A substring of the tooltip. "More actions" are available via the context menu. + Кликнете за повече действия. + + + Show Peers tab + A context menu item. The "Peers tab" is an element of the "Node window". + Покажи раздел Пиъри + + + Disable network activity + A context menu item. + Изключи мрежова активност + + + Enable network activity + A context menu item. The network activity was disabled previously. + Включи мрежова активност + Syncing Headers (%1%)… Синхронизиране на Headers (%1%)… @@ -660,10 +789,6 @@ Processing blocks on disk… Обработване блоковете на диска… - - Reindexing blocks on disk… - Преиндексиране на блокове на диска… - Connecting to peers… Свързване към пиъри… @@ -817,10 +942,6 @@ Coin Selection Избор на монети - - Dust: - Незначителен остатък: - After Fee: След таксата: @@ -878,28 +999,32 @@ Потвърдени - Copy address - Копирай адрес + Copy amount + Копирай сума - Copy label - Копирай наименование + &Copy address + &Копирай адрес - Copy amount - Копирай сума + Copy &label + Копирай &наименование + + + Copy &amount + Копирай &сума - Copy transaction ID - Копирай транзакция с ID + Copy transaction &ID and output index + Копирай &ID на транзакцията и изходен индекс - Lock unspent - Заключи неизхарченото + L&ock unspent + З&аключи непохарчени - Unlock unspent - Отключи неизхарченото + &Unlock unspent + &Отключи непохарчени Copy quantity @@ -917,10 +1042,6 @@ Copy bytes Копирай байтовете - - Copy dust - Копирай остатъка - Copy change Копирай рестото @@ -933,18 +1054,6 @@ (%1 locked) (%1 заключен) - - yes - да - - - no - не - - - This label turns red if any recipient receives an amount smaller than the current dust threshold. - Този етикет става червен, ако получателят получи сума, по-малка от прага за незначителен остатък. - Can vary +/- %1 duff(s) per input. Може да варира +/- %1 duff(s) за вход. @@ -988,8 +1097,14 @@ CreateWalletActivity + + Create Wallet + Title of window indicating the progress of creation of a new wallet. + Създай портфейл + Creating Wallet <b>%1</b>… + Descriptive text of the create wallet progress window which indicates to the user which wallet is currently being created. Създаване на портфейл <b>%1</b>… @@ -1015,7 +1130,51 @@ Wallet Портфейл - + + Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice. + Шифрирай портфейла. Портфейлът ще бъде шифриран с парола по ваш избор. + + + Encrypt Wallet + Шифриране на портфейла + + + Advanced Options + Допълнителни опции + + + 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. + Деактивирай частните ключове за този портфейл. Портфейлите с деактивирани частни ключове няма да имат частни ключове и не могат да имат HD seed или импортирани частни ключове. Това е идеално за портфейли само за наблюдение. + + + Disable Private Keys + Деактивирай частните ключове + + + 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. + Създай празен портфейл. Празните портфейли първоначално нямат частни ключове или скриптове. Частните ключове и адреси могат да бъдат импортирани или HD seed може да бъде зададен по-късно. + + + Make Blank Wallet + Създай празен портфейл + + + Use descriptors for scriptPubKey management. This feature is well-tested but still considered experimental and not recommended for use yet. + Използвай дескриптори за управление на scriptPubKey. Тази функция е добре тествана, но все още се счита за експериментална и не се препоръчва за употреба засега. + + + Descriptor Wallet (EXPERIMENTAL) + Дескрипторен портфейл (ЕКСПЕРИМЕНТАЛЕН) + + + Create + Създай + + + Compiled without sqlite support (required for descriptor wallets) + Компилиран без sqlite поддръжка (необходима за дескрипторни портфейли) + + EditAddressDialog @@ -1054,6 +1213,14 @@ The entered address "%1" is not a valid Dash address. Въведеният адрес "%1" не е валиден Dash адрес. + + Address "%1" already exists as a receiving address with label "%2" and so cannot be added as a sending address. + Адресът "%1" вече съществува като адрес за получаване с наименование "%2" и затова не може да бъде добавен като адрес за изпращане. + + + The entered address "%1" is already in the address book with label "%2". + Въведеният адрес "%1" вече е в адресната книга с наименование "%2". + Could not unlock wallet. Отключването на портфейла беше неуспешно. @@ -1088,7 +1255,115 @@ GovernanceList - + + Form + Формуляр + + + Filter List: + Филтрирай списъка: + + + Filter proposal list + Филтрирай списъка с предложения + + + Masternode Count: + Брой Masternodes: + + + Number of masternodes this wallet can vote with (masternodes for which this wallet holds the voting key) + Брой masternodes с които този портфейл може да гласува (masternodes за които този портфейл държи гласуващия ключ) + + + Proposal Count: + Брой предложения: + + + Create Proposal + Създай предложение + + + Filter by Title + Филтрирай по заглавие + + + Unavailable + Недостъпен + + + A synced node and an unlocked wallet are required. + Изисква се синхронизиран възел и отключен портфейл. + + + Vote Yes + Гласувай ДА + + + Vote No + Гласувай НЕ + + + Vote Abstain + Гласувай ВЪЗДЪРЖАЛ СЕ + + + Proposal Info: %1 + Информация за предложението: %1 + + + Voting Failed + Гласуването се провали + + + No wallet available. + Няма наличен портфейл. + + + No masternode voting keys found in wallet. + Не са намерени гласуващи ключове за masternode в портфейла. + + + Please select a proposal to vote on. + Моля изберете предложение за гласуване. + + + Unable to unlock wallet. + Невъзможно отключване на портфейла. + + + Unable to get masternode list. Please try again later. + Невъзможно е да се вземе списъкът с masternodes. Моля опитайте отново по-късно. + + + Masternode %1 not found + Masternode %1 не е намерен + + + Failed to sign vote for masternode %1 + Неуспешно подписване на глас за masternode %1 + + + Masternode %1: %2 + Masternode %1: %2 + + + Voted successfully %n time(s) + Гласувано успешно %n пътГласувано успешно %n пъти + + + Failed to vote %n time(s) + Неуспешно гласуване %n пътНеуспешно гласуване %n пъти + + + Errors: + Грешки: + + + Voting Results + Резултати от гласуването + + HelpMessageDialog @@ -1126,10 +1401,26 @@ As this is the first time the program is launched, you can choose where %1 will store its data. Тъй като това е първият път, когато програмата се стартира, можете да изберете къде %1 да съхранява данните си. + + Limit block chain storage to + Ограничи хранилището на блокчейна до + + + 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. + Връщането на тази настройка изисква повторно изтегляне на целия блокчейн. По-бързо е първо да изтеглите пълната верига и после да я подрежете. Деактивира някои разширени функции. + + + GB + GB + 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. Тази първоначална синхронизация изисква много ресурси и може да покаже хардуерните проблеми с компютъра, които преди това не сте забелязали. Всеки път, когато стартирате %1, той ще продължи да се изтегля там, където е спрял. + + 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. + Когато кликнете OK, %1 ще започне да изтегля и обработва пълния %4 блокчейн (%2 GB), започвайки с най-ранните транзакции в %3, когато %4 е стартиран първоначално. + 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. Ако сте избрали да ограничите пространството за съхранение на блок веригата(съкращаване), историческите данни ще трябва да се изтеглят и обработят, но след това ще бъдат изтрити, за да се запази използването на по-малко пространство на диска. @@ -1142,6 +1433,18 @@ Use a custom data directory: Определете папка по ваш избор: + + %n GB of space available + %n GB налично пространство%n GB налично пространство + + + (of %n GB needed) + (от %n GB необходими)(от %n GB необходими) + + + (%n GB needed for full chain) + (%n GB необходими за пълна верига)(%n GB необходими за пълна верига) + At least %1 GB of data will be stored in this directory, and it will grow over time. Най малко %1 GB данни ще бъдат запаметени в тази директория, и ще нарастват през времето. @@ -1150,6 +1453,11 @@ Approximately %1 GB of data will be stored in this directory. Около %1 GB данни ще бъдат запаметени в тази директория. + + (sufficient to restore backups %n day(s) old) + Explanatory text on the capability of the current prune target. + (достатъчно за възстановяване на резервни копия на %n ден)(достатъчно за възстановяване на резервни копия на %n дни) + %1 will download and store a copy of the Dash block chain. %1 ще изтегли и съхрани копие на Dash блок веригата. @@ -1167,6 +1475,13 @@ Грешка + + LoadWalletsActivity + + Loading wallets… + Зареждане на портфейли… + + MasternodeList @@ -1201,6 +1516,10 @@ Service Услуга + + Type + Тип + PoSe Score PoSe резултат @@ -1336,7 +1655,15 @@ Hide Скрий - + + %1 is currently syncing. It will download headers and blocks from peers and validate them until reaching the tip of the block chain. + %1 в момента се синхронизира. Ще изтегли хедъри и блокове от пиъри и ще ги валидира докато достигне върха на блокчейна. + + + Unknown. Syncing Headers (%1, %2%)… + Неизвестно. Синхронизиране на хедъри (%1, %2%)… + + OpenURIDialog @@ -1347,10 +1674,37 @@ URI: URI: + + Paste address from clipboard + Tooltip text for button that allows you to paste an address that is in your clipboard. + Постави адрес от клипборда + OpenWalletActivity - + + Open wallet failed + Неуспешно отваряне на портфейл + + + Open wallet warning + Предупреждение при отваряне на портфейл + + + default wallet + портфейл по подразбиране + + + Open Wallet + Title of window indicating the progress of opening of a wallet. + Отвори портфейл + + + Opening Wallet <b>%1</b>… + Descriptive text of the open wallet progress window which indicates to the user which wallet is currently being opened. + Отваряне на портфейл <b>%1</b>… + + OptionsDialog @@ -1382,36 +1736,116 @@ &Външен вид - Show additional tab listing all your masternodes in first sub-tab<br/>and all masternodes on the network in second sub-tab. - Показване на допълнителен раздел показваш всичките Ви masternodes в първият подраздел<br/>и всички masternodes в мрежата във вторият подраздел. + Show the icon in the system tray. + Покажи иконата в системния трей. - Show Masternodes Tab - Показване на раздел Masternodes + &Show tray icon + &Покажи икона в трея - If you disable the spending of unconfirmed change, the change from a transaction<br/>cannot be used until that transaction has at least one confirmation.<br/>This also affects how your balance is computed. - Ако деактивирате харченето на непотвърдено ресто, рестото от транзакция<br/> няма да може да се използва преди да бъде получено поне едно потвърждение. <br/>Това се отразява и на начина на изчисление на баланса ви. + Prune &block storage to + Подрежи &хранилището на блокове до - Show mixing interface on Overview screen and reveal an additional screen which allows to spend fully mixed coins only.<br/>A new tab with more settings will also appear in this dialog, please make sure to check them before mixing your coins. - Показване на интерфейса за смесване в основния прозорец и показване на допълнителен процорез, който позволява да се харчат само напълно смесени монети.<br/> В този диалогов прозорец ще се появи и нов раздел с повече настройки, моля не забравяйте да ги проверите, преди да смесите монетите си. + GB + GB - Show additional information and buttons on overview screen. - Показване на допълнителна информация и бутони на основния екран. + Reverting this setting requires re-downloading the entire blockchain. + Връщането на тази настройка изисква повторно изтегляне на целия блокчейн. - Enable advanced interface - Включване на интерфейс за напреднали + 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. + Tooltip text for Options window setting that sets the size of the database cache. Explains the corresponding effects of increasing/decreasing this value. + Максимален размер на кеша на базата данни. По-голям кеш може да допринесе за по-бърза синхронизация, след което ползата е по-малко изразена за повечето случаи на употреба. Намаляването на размера на кеша ще намали използването на паметта. Неизползваната mempool памет се споделя за този кеш. - Show system popups for mixing transactions<br/>just like for all other transaction types. - Показване на изскачащи прозорци за смесване на транзакции<br/>също както за всички други видове транзакции. + MiB + MiB - Show popups for mixing transactions - Показване на изскачащи прозорци за смесените транзакции + Set the number of script verification threads. Negative values correspond to the number of cores you want to leave free to the system. + 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. + Задайте броя нишки за проверка на скриптове. Отрицателните стойности съответстват на броя ядра, които искате да оставите свободни за системата. + + + This allows you or a third party tool to communicate with the node through command-line and JSON-RPC commands. + Tooltip text for Options window setting that enables the RPC server. + Това позволява на вас или на инструмент на трета страна да комуникирате с възела чрез командната линия и JSON-RPC команди. + + + Enable R&PC server + An Options window setting to enable the RPC server. + Активирай R&PC сървър + + + Whether to set subtract fee from amount as default or not. + Tooltip text for Options window setting that sets subtracting the fee from a sending amount as default. + Дали да се задава изваждане на таксата от сумата по подразбиране или не. + + + Subtract &fee from amount by default + An Options window setting to set subtracting the fee from a sending amount as default. + Извади &таксата от сумата по подразбиране + + + Enable &PSBT controls + An options window setting to enable PSBT controls. + Активирай &PSBT контроли + + + Whether to show PSBT controls. + Tooltip text for options window setting that enables PSBT controls. + Дали да се показват PSBT контроли. + + + Whether to keep the specified custom change address or not. + Дали да се запази посоченият персонализиран адрес за ресто или не. + + + Keep custom change &address + Запази персонализиран &адрес за ресто + + + Show additional tab listing all your masternodes in first sub-tab<br/>and all masternodes on the network in second sub-tab. + Показване на допълнителен раздел показваш всичките Ви masternodes в първият подраздел<br/>и всички masternodes в мрежата във вторият подраздел. + + + Show Masternodes Tab + Показване на раздел Masternodes + + + Show additional tab listing governance proposals. + Покажи допълнителен раздел със списък на предложенията за управление. + + + Show Governance Tab + Покажи раздел Управление + + + If you disable the spending of unconfirmed change, the change from a transaction<br/>cannot be used until that transaction has at least one confirmation.<br/>This also affects how your balance is computed. + Ако деактивирате харченето на непотвърдено ресто, рестото от транзакция<br/> няма да може да се използва преди да бъде получено поне едно потвърждение. <br/>Това се отразява и на начина на изчисление на баланса ви. + + + Show mixing interface on Overview screen and reveal an additional screen which allows to spend fully mixed coins only.<br/>A new tab with more settings will also appear in this dialog, please make sure to check them before mixing your coins. + Показване на интерфейса за смесване в основния прозорец и показване на допълнителен процорез, който позволява да се харчат само напълно смесени монети.<br/> В този диалогов прозорец ще се появи и нов раздел с повече настройки, моля не забравяйте да ги проверите, преди да смесите монетите си. + + + Show additional information and buttons on overview screen. + Показване на допълнителна информация и бутони на основния екран. + + + Enable advanced interface + Включване на интерфейс за напреднали + + + Show system popups for mixing transactions<br/>just like for all other transaction types. + Показване на изскачащи прозорци за смесване на транзакции<br/>също както за всички други видове транзакции. + + + Show popups for mixing transactions + Показване на изскачащи прозорци за смесените транзакции Show warning dialog when the wallet has very low number of keys left. @@ -1429,6 +1863,14 @@ Enable &multi-session Включи &мулти-сесия + + Use this many separate masternodes in parallel to mix funds.<br/>Note: You must use this feature carefully.<br/>Make sure you always have recent wallet (auto)backup in a safe place! + Използвай толкова отделни masternodes паралелно за смесване на средства.<br/>Забележка: Трябва да използвате тази функция внимателно.<br/>Уверете се, че винаги имате скорошно (авто)резервно копие на портфейла на безопасно място! + + + Parallel sessions + Паралелни сесии + Mixing rounds Цикли на смесване @@ -1441,10 +1883,38 @@ Target balance Желан баланс + + How many inputs of each denominated amount are created.<br/>Lower these numbers if you want fewer smaller denominations. + Колко входа от всяка деноминирана сума се създават.<br/>Намалете тези числа, ако искате по-малко по-малки деноминации. + + + Inputs per denomination + Входове на деноминация + + + Try to create at least this many inputs for each denominated amount.<br/>Lower this number if you want fewer smaller denominations. + Опитайте се да създадете поне толкова входа за всяка деноминирана сума.<br/>Намалете това число, ако искате по-малко по-малки деноминации. + + + Target + Цел + + + Create up to this many inputs for each denominated amount.<br/>Lower this number if you want fewer smaller denominations. + Създайте до толкова входа за всяка деноминирана сума.<br/>Намалете това число, ако искате по-малко по-малки деноминации. + + + Maximum + Максимум + Automatically open the Dash Core client port on the router. This only works when your router supports UPnP and it is enabled. Автоматично отваря порта за Dash Core клиента в маршрутизатора. Това работи само когато вашият маршрутизатор поддържа UPnP и той е разрешен. + + Map port using NA&T-PMP + Мапвай порт използвайки NA&T-PMP + Accept connections from outside. Приеми връзки отвън @@ -1466,16 +1936,26 @@ Показва ако зададеното по подразбиране SOCKS5 proxy се използва за намиране на пиъри чрез тази мрежа. - 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. - При затваряне на прозореца приложението остава минимизирано. Ако изберете тази опция, приложението може да се затвори само чрез Изход в менюто. + Language missing or translation incomplete? Help contributing translations here: +https://explore.transifex.com/dash/dash/ + Липсва език или преводът е непълен? Помогнете с принос за преводи тук: +https://explore.transifex.com/dash/dash/ - Third party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items.<br/>%s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |. - URL адреси на трети страни (например block Explorer), които се появяват в раздела с транзакции, като елементи от контекстното меню. %s в URL е заменен с хеша на транзакцията. Отделните URL адреси са разделени с вертикална линия |. + Third-party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items.<br/>%s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |. + URL адреси на трети страни (напр. block explorer), които се появяват в раздела транзакции като елементи от контекстното меню.<br/>%s в URL адреса се заменя с хеш на транзакцията. Множество URL адреси се разделят с вертикална черта |. - &Third party transaction URLs - &URL транзакции на трети страни + &Third-party transaction URLs + &URL адреси на транзакции на трети страни + + + Options set in this dialog are overridden by the command line or in the configuration file: + Опциите зададени в този диалог се заменят от командния ред или в конфигурационния файл: + + + 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. + При затваряне на прозореца приложението остава минимизирано. Ако изберете тази опция, приложението може да се затвори само чрез Изход в менюто. Whether to show coin control features or not. @@ -1505,13 +1985,21 @@ &Network &Мрежа + + 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. + Активирането на подрязването значително намалява дисковото пространство необходимо за съхранение на транзакции. Всички блокове все още са напълно валидирани. Връщането на тази настройка изисква повторно изтегляне на целия блокчейн. + Map port using &UPnP Отваряне на входящия порт чрез &UPnP + + Automatically open the Dash Core client port on the router. This only works when your router supports NAT-PMP and it is enabled. The external port could be random. + Автоматично отвори порта на Dash Core клиента на рутера. Това работи само когато рутерът ви поддържа NAT-PMP и е активиран. Външният порт може да бъде случаен. + Proxy &IP: - Прокси & IP: + Прокси &IP: IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1) @@ -1557,6 +2045,14 @@ &Display &Интерфейс + + Connect to the Dash network through a separate SOCKS5 proxy for Tor onion services. + Свържи се към Dash мрежата чрез отделен SOCKS5 прокси за Tor onion услуги. + + + Use separate SOCKS&5 proxy to reach peers via Tor onion services: + Използвай отделен SOCKS&5 прокси за достигане до пиъри чрез Tor onion услуги: + User Interface &language: Език на потребителски &изглед : @@ -1603,14 +2099,22 @@ Confirm options reset + Window title text of pop-up window shown when the user has chosen to reset options. Потвърди изчистване на настройките Client restart required to activate changes. + Text explaining that the settings changed will not come into effect until the client is restarted. За да влязат в сила промените е необходим рестарт на клиента. + + Current settings will be backed up at "%1". + 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. + Текущите настройки ще бъдат архивирани в "%1". + Client will be shut down. Do you want to proceed? + Text asking the user to confirm if they would like to proceed with a client shutdown. Клиентът ще бъде изключен, искате ли да продължите? @@ -1748,6 +2252,10 @@ %1 Balance %1 Баланс + + Discreet mode activated for the Overview tab. To unmask the values, uncheck Settings->Discreet mode. + Дискретен режим активиран за раздела Общ преглед. За да покажете стойностите, премахнете отметката от Настройки->Дискретен режим. + %n Rounds %n Цикли%n Цикли @@ -1847,7 +2355,140 @@ PSBTOperationsDialog - + + Dialog + Диалог + + + Sign Tx + Подпиши транзакция + + + Broadcast Tx + Разпрати транзакция + + + Copy to Clipboard + Копирай в клипборда + + + Save… + Запази… + + + Close + Затвори + + + Failed to load transaction: %1 + Неуспешно зареждане на транзакция: %1 + + + Failed to sign transaction: %1 + Неуспешно подписване на транзакция: %1 + + + Cannot sign inputs while wallet is locked. + Не могат да се подпишат входове докато портфейлът е заключен. + + + Could not sign any more inputs. + Не могат да се подпишат повече входове. + + + Signed %1 inputs, but more signatures are still required. + Подписани %1 входа, но все още са необходими повече подписи. + + + Signed transaction successfully. Transaction is ready to broadcast. + Транзакцията е подписана успешно. Транзакцията е готова за разпращане. + + + Unknown error processing transaction. + Неизвестна грешка при обработка на транзакцията. + + + Transaction broadcast successfully! Transaction ID: %1 + Транзакцията е разпратена успешно! ID на транзакцията: %1 + + + Transaction broadcast failed: %1 + Разпращането на транзакцията се провали: %1 + + + PSBT copied to clipboard. + PSBT е копиран в клипборда. + + + Save Transaction Data + Запази данни за транзакцията + + + Partially Signed Transaction (Binary) + Expanded name of the binary PSBT file format. See: BIP 174. + Частично подписана транзакция (двоична) + + + PSBT saved to disk. + PSBT запазен на диска. + + + * Sends %1 to %2 + * Изпраща %1 до %2 + + + own address + собствен адрес + + + Unable to calculate transaction fee or total transaction amount. + Невъзможно е да се изчисли таксата на транзакцията или общата сума на транзакцията. + + + Pays transaction fee: + Плаща такса за транзакция: + + + Total Amount + Обща сума + + + or + или + + + Transaction has %1 unsigned inputs. + Транзакцията има %1 неподписани входа. + + + Transaction is missing some information about inputs. + На транзакцията липсва информация за входовете. + + + Transaction still needs signature(s). + Транзакцията все още се нуждае от подпис(и). + + + (But no wallet is loaded.) + (Но не е зареден портфейл.) + + + (But this wallet cannot sign transactions.) + (Но този портфейл не може да подписва транзакции.) + + + (But this wallet does not have the right keys.) + (Но този портфейл няма правилните ключове.) + + + Transaction is fully signed and ready for broadcast. + Транзакцията е напълно подписана и готова за разпращане. + + + Transaction status is unknown. + Статусът на транзакцията е неизвестен. + + PaymentServer @@ -1866,6 +2507,12 @@ 'dash://' is not a valid URI. Use 'dash:' instead. 'dash://' не е валиден URI. Използвайте 'dash:' вместо това. + + Cannot process payment request as BIP70 is no longer supported. +Due to discontinued support, you should request the merchant to provide you with a BIP21 compatible URI or use a wallet that does continue to support BIP70. + Не може да се обработи заявка за плащане, тъй като BIP70 вече не се поддържа. +Поради прекратената поддръжка, трябва да поискате от търговеца да ви предостави BIP21 съвместимо URI или да използвате портфейл, който продължава да поддържа BIP70. + URI cannot be parsed! This can be caused by an invalid Dash address or malformed URI parameters. Грешка при анализ на URI! Това може да е следствие от неправилен Dash адрес или неправилно зададени URI параметри. @@ -1887,6 +2534,26 @@ Title of Peers Table column which indicates the current latency of the connection with the peer. Пинг + + Peer + Title of Peers Table column which contains a unique number used to identify a connection. + Клиентът ще бъде изключен. Искате ли да продължите? + + + Age + Title of Peers Table column which indicates the duration (length of time) since the peer connection started. + Възраст + + + Direction + Title of Peers Table column which indicates the direction the peer connection was initiated from. + Посока + + + Type + Title of Peers Table column which describes the type of peer connection. The "type" describes why the connection exists. + Тип + Sent Title of Peers Table column which indicates the total amount of network information we have sent to the peer. @@ -1897,15 +2564,264 @@ Title of Peers Table column which indicates the total amount of network information we have received from the peer. Получени - + + Address + Title of Peers Table column which contains the IP/Onion/I2P address of the connected peer. + Тип + + + Network + Title of Peers Table column which states the network the peer connected through. + Мрежа + + + Inbound + An Inbound Connection from a Peer. + Входящ + + + Outbound + An Outbound Connection to a Peer. + Изходящ + + Proposal - + + Passing +%1 + Преминаващ +%1 + + + Needs additional %1 votes + Нужда от допълнителни %1 гласа + + ProposalModel - + + Yes + Да + + + No + Не + + + Hash + Хеш + + + Title + Заглавие + + + Start + Начало + + + End + Край + + + Amount + Сума + + + Active + Активен + + + Status + Статус + + + + ProposalWizard + + Create Governance Proposal + Създай предложение за управление + + + Enter proposal details + Въведете детайли за предложението + + + A fee will be burned when you prepare the proposal. + Такса ще бъде изгорена когато подготвите предложението. + + + Proposal &name + Име на &предложението + + + &Description URL + URL за &описание + + + Payment &address + &Адрес за плащане + + + Payment &amount + &Сума за плащане + + + The amount to request in a single payment + Сумата за заявка в едно плащане + + + &First payment + &Първо плащане + + + Pa&yments + Пла&щания + + + To&tal amount + Об&ща сума + + + Proposal &fee + &Такса на предложението + + + Next + Напред + + + Review proposal JSON and validate. + Прегледайте JSON на предложението и валидирайте. + + + Hex-encoded JSON + Hex-кодиран JSON + + + Back + Назад + + + Validate + Валидирай + + + Prepare (burn fee) and wait for confirmations. + Подгответе (изгорете такса) и изчакайте потвърждения. + + + Copy + Копирай + + + At 1/6 confirmations: can be relayed and queued. At 6/6: accepted and processed. + При 1/6 потвърждения: може да се препрати и добави в опашката. При 6/6: приета и обработена. + + + Confirmations progress + Напредък на потвържденията + + + Shows progress toward the required number of confirmations for the proposal fee transaction. + Показва напредъка към необходимия брой потвърждения за транзакцията с таксата на предложението. + + + Estimated time remaining: - + Приблизително оставащо време: - + + + Prepare Proposal + Подгответе предложението + + + You can submit after 1 confirmation. At 6 confirmations it is accepted and processed. + Можете да подадете след 1 потвърждение. При 6 потвърждения се приема и обработва. + + + Proposal ID: + ID на предложението: + + + Submit Proposal + Подайте предложение + + + Close + Затвори + + + Valid + Валиден + + + Invalid: %1 + Невалиден: %1 + + + Burn %1 + Изгори %1 + + + Burn %1 to create the fee transaction? + Изгори %1 за създаване на транзакция за такса? + + + Prepare failed + Подготовката се провали + + + Confirmations: %1 / %2 required + Потвърждения: %1 / %2 необходими + + + Estimated time remaining: Ready + Оценено оставащо време: Готово + + + Estimated time remaining: %n minute(s) + Оценено оставащо време: %n минутаОценено оставащо време: %n минути + + + Your proposal was submitted successfully. + Вашето предложение е подадено успешно. + + + Already submitted + Вече подадено + + + This proposal has already been submitted. + Това предложение вече е подадено. + + + Submission failed + Подаването се провали + + + Proposal submitted + Предложението е подадено + + + A fee of %1 will be burned when you prepare the proposal. + Такса от %1 ще бъде изгорена, когато подготвите предложението. + + + Prepare (burn %1) and wait for %2 confirmations. + Подготви (изгори %1) и изчакай %2 потвърждения. + + QObject + + Do you want to reset settings to default values, or to abort without making changes? + Explanatory text shown on startup when the settings file cannot be read. Prompts user to make a choice between resetting or aborting. + Искате ли да възстановите настройките до стойностите по подразбиране или да прекратите без да правите промени? + + + A fatal error occurred. Check that settings file is writable, or try running with -nosettings. + 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. + Възраст + Choose data directory on startup (default: %u) Изберете папка за данни при стартиране (по подразбиране: %u) @@ -1942,6 +2858,46 @@ Show splash screen on startup (default: %u) Покажи начален екран при стартиране (по подразбиране: %u) + + Error: Specified data directory "%1" does not exist. + Грешка: Посочената директория за данни "%1" не съществува. + + + Error: Cannot parse configuration file: %1. + Грешка: Не може да се анализира конфигурационен файл: %1. + + + Error: %1 + Грешка: %1 + + + Error: Failed to load application fonts. + Грешка: Неуспешно зареждане на шрифтовете на приложението. + + + Error: Specified font-family invalid. Valid values: %1. + Грешка: Посоченото семейство шрифтове е невалидно. Валидни стойности: %1. + + + Error: Specified font-weight-normal invalid. Valid range %1 to %2. + Грешка: Посочената font-weight-normal е невалидна. Валиден обхват %1 до %2. + + + Error: Specified font-weight-bold invalid. Valid range %1 to %2. + Грешка: Посочената font-weight-bold е невалидна. Валиден обхват %1 до %2. + + + Error: Specified font-scale invalid. Valid range %1 to %2. + Грешка: Посочената font-scale е невалидна. Валиден обхват %1 до %2. + + + Error: Invalid -custom-css-dir path. + Грешка: Невалиден път за -custom-css-dir. + + + Error: %1 CSS file(s) missing in -custom-css-dir path. + Грешка: %1 CSS файл(ове) липсват в пътя -custom-css-dir. + %1 didn't yet exit safely… %1 все още не е излязъл безопастно… @@ -1966,6 +2922,53 @@ This can also be adjusted later in the "Appearance" tab of the preferences. Това може да бъде настроено по-късно от "Изглед" таб в настройките. + + Ctrl+W + Ctrl+W + + + Unroutable + Немаршрутизируем + + + Internal + Вътрешен + + + Inbound + An inbound connection from a peer. An inbound connection is a connection initiated by a peer. + Входящ + + + Outbound + An outbound connection to a peer. An outbound connection is a connection initiated by us. + Изходящ + + + Full Relay + Peer connection type that relays all network information. + Входящ + + + Block Relay + Peer connection type that relays network information about blocks and not transactions or addresses. + Входящ + + + Manual + Peer connection type established manually through one of several methods. + Ръчен + + + Feeler + Short-lived peer connection type that tests the aliveness of known addresses. + Пробващ + + + Address Fetch + Short-lived peer connection type that solicits known addresses from a peer. + Взимане на адреси + %1 d %1 дни @@ -2027,8 +3030,8 @@ %1 Б - %1 KB - %1 КБ + %1 kB + %1 kB %1 MB @@ -2068,11 +3071,28 @@ &Copy Image &Копирай изображението + + Resulting URI too long, try to reduce the text for label / message. + Получените URI е твърде дълъг, опитайте се да намалите текста за наименование / съобщение. + + + Error encoding URI into QR Code. + Грешка при кодиране на URI в QR код. + + + QR code support not available. + Поддръжката на QR код не е налична. + Save QR Code Запази QR Кода - + + PNG Image + Expanded name of the PNG file format. See: https://en.wikipedia.org/wiki/Portable_Network_Graphics. + Възраст + + RPCConsole @@ -2179,6 +3199,14 @@ Version Версия + + High bandwidth BIP152 compact block relay: %1 + Препращане на компактни блокове BIP152 с висока честотна лента: %1 + + + High Bandwidth + Висока честотна лента + Starting Block Начален блок @@ -2191,6 +3219,51 @@ Synced Blocks Синхронизирани блокове + + Elapsed time since a novel block passing initial validity checks was received from this peer. + Изминало време откакто нов блок преминал първоначални проверки за валидност беше получен от този пиър. + + + Last Block + Последен блок + + + Elapsed time since a novel transaction accepted into our mempool was received from this peer. + Tooltip text for the Last Transaction field in the peer details area. + Изминало време от получаването на нова транзакция приета в нашия mempool от този пиър. + + + Last Transaction + Последна транзакция + + + The mapped Autonomous System used for diversifying peer selection. + Мапнатата автономна система използвана за диверсификация на избора на пиъри. + + + Mapped AS + Мапнат AS + + + Whether we relay addresses to this peer. + Tooltip text for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No). + Дали препращаме адреси към този пиър. + + + Address Relay + Text title for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No). + Дали препращаме адреси към този пиър. + + + Addresses Processed + 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). + Обработени адреси + + + Addresses Rate-Limited + 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. + Адреси с ограничена честота + Rescan blockchain files 1 Повторно сканиране на блокчейн файловете 1 @@ -2199,6 +3272,10 @@ Rescan blockchain files 2 Повторно сканиране на блокчейн файловете 2 + + The buttons below will restart the wallet with command-line options to repair the wallet, fix issues with corrupt blockchain files or missing/obsolete transactions. + Бутоните по-долу ще рестартират портфейла с опции от командния ред за поправка на портфейла, коригиране на проблеми с повредени блокчейн файлове или липсващи/остарели транзакции. + -rescan=1: Rescan the block chain for missing wallet transactions starting from wallet creation time. -rescan=1: Повторно сканиране на блокчейна за липсващи транзакции в портфейла, започвайки от времето на създаване на портфейла. @@ -2215,10 +3292,50 @@ Datadir Datadir + + To specify a non-default location of the data directory use the '%1' option. + За да посочите нестандартна локация на директорията за данни използвайте опцията '%1'. + + + Blocksdir + Директория за блокове + + + To specify a non-default location of the blocks directory use the '%1' option. + За да посочите нестандартна локация на директорията за блокове използвайте опцията '%1'. + + + Local Addresses + Локални адреси + + + Network addresses that your Dash node is currently using to communicate with other nodes. + Мрежови адреси, които вашият Dash възел в момента използва за комуникация с други възли. + + + Number of regular Masternodes + Брой обикновени Masternodes + + + Number of EvoNodes + Брой EvoNodes + + + Current block height + Текуща височина на блока + Last block hash Хеш на последният блок + + Latest ChainLocked block hash + Хеш на последния ChainLocked блок + + + Latest ChainLocked block height + Височина на последния ChainLocked блок + Open the %1 debug log file from the current data directory. This can take a few seconds for large log files. Отваря %1 файла за откриване на грешки от текущата папка. Това може да отнеме няколко секунди при по-големи файлове. @@ -2251,10 +3368,50 @@ PoSe Score PoSe точки + + The transport layer version: %1 + Версия на транспортния слой: %1 + + + Transport + Транспорт + + + The BIP324 session ID string in hex. + BIP324 session ID стринг в hex. + + + Session ID + ID на сесията + + + The network protocol this peer is connected through: IPv4, IPv6, Onion, I2P, or CJDNS. + Мрежовият протокол през който този пиър е свързан: IPv4, IPv6, Onion, I2P или CJDNS. + + + Permissions + Разрешения + + + The direction and type of peer connection: %1 + Посоката и типа на връзката към пиъра: %1 + + + Direction/Type + Посока/Тип + Services Услуги + + Whether we relay transactions to this peer. + Дали препращаме транзакции към този пиър. + + + Transaction Relay + Препращане на транзакции + Connection Time Време на връзката @@ -2291,17 +3448,81 @@ &Wallet Repair &Поправяне на портфейла + + The total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting). + 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). + Възраст + + + The total number of addresses received from this peer that were dropped (not processed) due to rate-limiting. + 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. + Общият брой адреси получени от този пиър, които са изпуснати (не обработени) поради ограничаване на честотата. + Wallet repair options. Опции за възстановяване на портфейла. - Rebuild index - Възстановяване на индекса + Rebuild index + Възстановяване на индекса + + + -reindex: Rebuild block chain index from current blk000??.dat files. + -reindex: Възстановява блок индекс веригата от настоящия blk000??.dat файл. + + + Inbound: initiated by peer + Explanatory text for an inbound peer connection. + Входяща: инициирана от пиър + + + Outbound Full Relay: default + Explanatory text for an outbound peer connection that relays all network information. This is the default behavior for outbound connections. + Изходящ пълно препращане: по подразбиране + + + Outbound Block Relay: does not relay transactions or addresses + Explanatory text for an outbound peer connection that relays network information about blocks and not transactions or addresses. + Изходящ препращане на блокове: не препраща транзакции или адреси + + + Outbound Manual: added using RPC %1 or %2/%3 configuration options + 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. + Изходящ ръчен: добавен чрез RPC %1 или %2/%3 конфигурационни опции + + + Outbound Feeler: short-lived, for testing addresses + Explanatory text for a short-lived outbound peer connection that is used to test the aliveness of known addresses. + Изходящ пробващ: краткотраен, за тестване на адреси + + + Outbound Address Fetch: short-lived, for soliciting addresses + Explanatory text for a short-lived outbound peer connection that is used to request addresses from a peer. + Изходящ взимане на адреси: краткотраен, за искане на адреси + + + To + До + + + we selected the peer for high bandwidth relay + избрахме пиъра за препращане с висока честотна лента + + + From + От + + + the peer selected us for high bandwidth relay + пиърът ни избра за препращане с висока честотна лента + + + No + Не - -reindex: Rebuild block chain index from current blk000??.dat files. - -reindex: Възстановява блок индекс веригата от настоящия blk000??.dat файл. + no high bandwidth relay selected + не е избран препращач с висока честотна лента &Disconnect @@ -2315,10 +3536,6 @@ 1 &hour 1 &час - - 1 &day - 1 &ден - 1 &week 1 &седмица @@ -2331,26 +3548,6 @@ &Unban &Премахване на бан - - Welcome to the %1 RPC console. - Добре дошли в %1 RPC конзолата. - - - Use up and down arrows to navigate history, and %1 to clear screen. - Използвайте стрелките нагоре и надолу за разглеждане на историята, и %1 за изчистване на екрана. - - - Type %1 for an overview of available commands. - Въведи %1 за преглед на наличните команди. - - - For more information on using this console type %1. - За повече информация при използването на тази конзола въведете %1. - - - WARNING: Scammers have been active, telling users to type commands here, stealing their wallet contents. Do not use this console without fully understanding the ramifications of a command. - ВНИМАНИЕ: Измамниците са били активни, казвайки на потребителите да въвеждат команди тук, като крадат съдържанието на портфейла им. Не използвайте тази конзола, без да разберете напълно значението на командата. - In: Вход: @@ -2363,6 +3560,10 @@ Network activity disabled Мрежова активност изключена + + None + Няма + Total: %1 (Enabled: %2) Общо: %1 (Включено: %2) @@ -2371,10 +3572,105 @@ Executing command without any wallet Изпълнение на команди без портфейл + + Ctrl++ + Main shortcut to increase the RPC console font size. + Изходящ пълно препращане: по подразбиране + + + Ctrl+= + Secondary shortcut to increase the RPC console font size. + Ctrl+= + + + Ctrl+- + Main shortcut to decrease the RPC console font size. + Ctrl+- + + + Ctrl+_ + Secondary shortcut to decrease the RPC console font size. + Ctrl+_ + + + Ctrl+Shift+I + Ctrl+Shift+I + + + Ctrl+Shift+C + Ctrl+Shift+C + + + Ctrl+Shift+G + Ctrl+Shift+G + + + Ctrl+Shift+P + Ctrl+Shift+P + + + Ctrl+Shift+R + Ctrl+Shift+R + Executing command using "%1" wallet За изпълняване на команди използвайте "%1" портфейл + + detecting: peer could be v1 or v2 + Explanatory text for "detecting" transport type. + Ctrl+= + + + v1: unencrypted, plaintext transport protocol + Explanatory text for v1 transport type. + v1: нешифрован, plaintext транспортен протокол + + + v2: BIP324 encrypted transport protocol + Explanatory text for v2 transport type. + v2: BIP324 шифрован транспортен протокол + + + &Copy address + Context menu action to copy the address of a peer + &Копирай адрес + + + 1 d&ay + 1 д&ен + + + &Copy IP/Netmask + 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 + v1: нешифрован, plaintext транспортен протокол + + + 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 + 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. + Добре дошли в %1 RPC конзолата. +Използвайте стрелките нагоре и надолу за навигация в историята и %2 за изчистване на екрана. +Използвайте %3 и %4 за увеличаване или намаляване на размера на шрифта. +Въведете %5 за преглед на наличните команди. +За повече информация относно използването на тази конзола, въведете %6. + +%7ВНИМАНИЕ: Измамниците са активни, казвайки на потребителите да въвеждат команди тук, крадейки съдържанието на портфейлите им. Не използвайте тази конзола без да разбирате напълно последиците от командата.%8 + + + Executing… + A console message indicating an entered command is currently being executed. + Изпълняване… + + + (peer: %1) + (пиър: %1) + via %1 чрез %1 @@ -2391,11 +3687,19 @@ Verified Masternode Проверен Masternode + + Yes + Да + Unknown Неизвестни - + + Never + Никога + + ReceiveCoinsDialog @@ -2414,6 +3718,10 @@ An optional message to attach to the payment request, which will be displayed when the request is opened.<br>Note: The message will not be sent with the payment over the Dash network. Възможност да се прикрепи съобщение към заявката за плащане, което да бъде показано при отваряне на заявката. <br>Забележка: съобщението няма да бъде изпратено с плащането по мрежата на Dash. + + 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. + Незадължително наименование за асоцииране с новия адрес за получаване (използвано от вас за идентифициране на фактура). То също се прикача към заявката за плащане. + Use this form to request payments. All fields are <b>optional</b>. Използвате този формуляр за заявяване на плащания. Всички полета са <b>незадължителни</b>. @@ -2430,6 +3738,10 @@ &Amount: &Сума + + &Create new receiving address + &Създай нов адрес за получаване + Clear all fields of the form. Изчисти всички полета от формуляра. @@ -2467,24 +3779,60 @@ Въведете съобщение, което да прикачите към искането за плащане - Copy URI - Копирай URI + Copy &URI + Копирай &URI - Copy label - Копирай наименование + &Copy address + &Копирай адрес - Copy message - Копиране на съобщението + Copy &label + Копирай &наименование - Copy amount - Копирай сума + Copy &message + Копирай &съобщение + + + Copy &amount + Копирай &сума + + + Could not unlock wallet. + Не можа да се отключи портфейлът. - + + Could not generate new address + Не може да се генерира нов адрес + + ReceiveRequestDialog + + Request payment to … + Искане за плащане към … + + + Address: + Адрес: + + + Amount: + Сума: + + + Label: + Наименование: + + + Message: + Съобщение: + + + Wallet: + Портфейл: + Copy &URI Копирай &URI @@ -2537,6 +3885,34 @@ Заявени + + RestoreWalletActivity + + Restore Wallet + Title of progress window which is displayed when wallets are being restored. + Изпълняване… + + + Restoring Wallet <b>%1</b>… + Descriptive text of the restore wallets progress window which indicates to the user that wallets are currently being restored. + Възстановяване на портфейл <b>%1</b>… + + + Restore wallet failed + Title of message box which is displayed when the wallet could not be restored. + Възраст + + + Restore wallet warning + Title of message box which is displayed when the wallet is restored with some warning. + Предупреждение при възстановяване на портфейл + + + Restore wallet message + Title of message box which is displayed when the wallet is successfully restored. + Съобщение при възстановяване на портфейл + + SendCoinsDialog @@ -2571,10 +3947,6 @@ Fee: Такса: - - Dust: - Незначителен остатък: - Inputs… Входове… @@ -2599,6 +3971,14 @@ Transaction Fee: Такса транзакция: + + 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 dash transactions than the network can process. + Когато има по-малък обем транзакции от пространството в блоковете, майнърите както и препращащите възли могат да наложат минимална такса. Плащането само на тази минимална такса е напълно добре, но имайте предвид, че това може да доведе до никога непотвърдена транзакция, щом има повече търсене на dash транзакции, отколкото мрежата може да обработи. + + + A too low fee might result in a never confirming transaction (read the tooltip) + Твърде ниска такса може да доведе до никога непотвърдена транзакция (прочетете подсказката) + (Smart fee not initialized yet. This usually takes a few blocks…) (Смарт таксата не е разпозната все още.Това ще отнеме няколко блока… ) @@ -2627,6 +4007,10 @@ Note: Not enough data for fee estimation, using the fallback fee instead. Бележка: Няма достатъчно данни за оценка на таксата, вместо това използвайте резервната такса. + + Hide transaction fee settings + Скрий настройки за такса за транзакция + Hide Скрит @@ -2687,10 +4071,6 @@ Copy bytes Копирай байтовете - - Copy dust - Копирай остатъка - Copy change Копирай рестото @@ -2707,10 +4087,6 @@ %1 to %2 %1 до %2 - - Are you sure you want to send? - Наистина ли искате да изпратите? - <b>(%1 of %2 entries displayed)</b> <b>(%1 of %2 показани записи)</b> @@ -2723,6 +4099,18 @@ Confirm the %1 send action Потвърдете изпращането %1 + + Cr&eate Unsigned + Съ&здай неподписана + + + from wallet '%1' + от портфейл '%1' + + + %1 to '%2' + %1 до '%2' + %1 funds only %1 средства само @@ -2731,6 +4119,10 @@ any available funds всякакви налични средства + + Transaction fee + Такса за транзакция + (%1 transactions have higher fees usually due to no change output being allowed) (%1 транзакциите имат по-високи такси, обикновено поради това, че не се допуска промяна на изхода) @@ -2751,10 +4143,67 @@ Warning: Using %1 with %2 or more inputs can harm your privacy and is not recommended Внимание: Използването %1 с %2 или повече входове могат да навредят на поверителността ви и не се препоръчва + + Click to learn more + Кликнете за да научите повече + + + Total Amount + Обща сума + + + or + или + Confirm send coins Потвърди изпращането на монетите + + Save Transaction Data + Запази данни за транзакцията + + + PSBT saved + PSBT е запазен + + + Watch-only balance: + Баланс само за наблюдение: + + + Creates a Partially Signed Blockchain Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet. + Създава частично подписана блокчейн транзакция (PSBT) за използване например с офлайн %1 портфейл или с хардуерен портфейл съвместим с PSBT. + + + Do you want to create this transaction? + 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. + Искате ли да създадете тази транзакция? + + + Please, review your transaction proposal. This will produce a Partially Signed Blockchain Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet. + 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. + Моля, прегледайте вашето предложение за транзакция. Това ще създаде частично подписана блокчейн транзакция (PSBT), която можете да запазите или копирате и след това да подпишете с например офлайн %1 портфейл или с хардуерен портфейл съвместим с PSBT. + + + Please, review your transaction. You can create and send this transaction or create a Partially Signed Blockchain Transaction (PSBT), which you can save or copy and then sign with, e.g., an offline %1 wallet, or a PSBT-compatible hardware wallet. + 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. + Моля, прегледайте вашата транзакция. Можете да създадете и изпратите тази транзакция или да създадете частично подписана блокчейн транзакция (PSBT), която можете да запазите или копирате и след това да подпишете с например офлайн %1 портфейл или с хардуерен портфейл съвместим с PSBT. + + + Please, review your transaction. + Text to prompt a user to review the details of the transaction they are attempting to send. + Моля, прегледайте вашата транзакция. + + + To review recipient list click "Show Details…" + За да прегледате списъка с получатели кликнете "Покажи детайли…" + + + Partially Signed Transaction (Binary) + Expanded name of the binary PSBT file format. See: BIP 174. + Частично подписана транзакция (двоична) + The recipient address is not valid. Please recheck. Адресът на получателя е невалиден. Моля проверете отново. @@ -2850,6 +4299,10 @@ A&mount: С&ума: + + The amount to send in the selected unit + Сумата за изпращане в избраната единица + The fee will be deducted from the amount being sent. The recipient will receive a lower amount of Dash than you enter in the amount field. If multiple recipients are selected, the fee is split equally. Таксата ще бъде приспадната от количеството за изпращане. Получателят ще получи по-малко количество Dash от това, което сте въвели в полето. Ако са избрани няколко получателя, таксата ще бъде разделена по равно. @@ -2870,21 +4323,16 @@ A message that was attached to the dash: URI which will be stored with the transaction for your reference. Note: This message will not be sent over the Dash network. Съобщението което беше прикрепено към dash: URI ще бъде запазено с транзакцията за ваше сведение. Забележка: Това съобщение няма да бъде изпратено през Dash мрежата. + + + SendConfirmationDialog - This is an unauthenticated payment request. - Това е не удостоверено искане за плащане. - - - This is an authenticated payment request. - Това е удостоверено искане за плащане. - - - Pay To: - Плащане на: + Send + Изпрати - Memo: - Бележка: + Create Unsigned + Създай неподписана @@ -2972,6 +4420,14 @@ The Dash address the message was signed with Dash адресът ,с който е подписано съобщението + + The signed message to verify + Подписаното съобщение за проверка + + + The signature given when the message was signed + Подписът даден когато съобщението беше подписано + Verify the message to ensure it was signed with the specified Dash address Проверете съобщението, за да сте сигурни че е подписано с определен Dash адрес @@ -3016,6 +4472,10 @@ Wallet unlock was cancelled. Отключването на портфейла беше отменено. + + No error + Няма грешка + Private key for the entered address is not available. Не е наличен частен ключ за въведеният адрес. @@ -3049,11 +4509,22 @@ Съобщението е потвърдено. + + SplashScreen + + (press q to shutdown and continue later) + (натиснете q за изключване и продължаване по-късно) + + + press q to shutdown + натиснете q за изключване + + TrafficGraphWidget - KB/s - КБ/с + kB/s + kB/s Total @@ -3070,20 +4541,9 @@ TransactionDesc - - Open for %n more block(s) - Отворен за още %n блокаОтворен за още %n блока - - - Open until %1 - Подлежи на промяна до %1 - - - conflicted - конфликтно - 0/unconfirmed, %1 + 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. 0/непотвърдени, %1 @@ -3096,22 +4556,32 @@ abandoned + 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. изоставен + + conflicted with a transaction with %1 confirmations + 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. + конфликтираща с транзакция с %1 потвърждения + %1/unconfirmed + 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, and still not locked via ChainLocks. %1/непотвърдени %1 confirmations + 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 or locked via ChainLocks. включена в %1 блока locked via ChainLocks + 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 and has been locked by ChainLocks. заключена чрез ChainLocks verified via InstantSend + 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 has been locked by InstantSend. потвърдено чрез InstantSend @@ -3130,6 +4600,10 @@ Generated Издадени + + Platform Transfer + Трансфер на платформа + From От @@ -3260,14 +4734,6 @@ Address / Label Адрес / Етикет - - Open for %n more block(s) - Отворен за още %n блокаОтворен за още %n блока - - - Open until %1 - Подлежи на промяна до %1 - Unconfirmed Непотвърдено @@ -3328,6 +4794,10 @@ Mined Емитирани + + Platform Transfer + Трансфер на платформа + %1 Mixing %1 Смесване @@ -3455,6 +4925,10 @@ Mined Емитирани + + Platform Transfer + Трансфер на платформа + Other Други @@ -3468,45 +4942,63 @@ Минимална сума - Abandon transaction - Изоставена транзакция + &Copy address + &Копирай адрес + + + Copy &label + Копирай &наименование - Copy address - Копирай адрес + Copy &amount + Копирай &сума - Copy label - Копирай наименование + Copy transaction &ID + Копирай &ID на транзакцията - Copy amount - Копирай сума + Copy &raw transaction + Копирай &необработена транзакция - Copy transaction ID - Копирай транзакция с ID + Copy full transaction &details + Копирай пълни &детайли за транзакцията - Copy raw transaction - Копира необработена транзакция + &Show transaction details + &Покажи детайли за транзакцията - Copy full transaction details - Копирай всички детайли за транзакцията + A&bandon transaction + Изо&стави транзакция - Show transaction details - Подробности за транзакцията + Rese&nd transaction + Препра&ти транзакция - Show address QR code - Покажи QR код + &Edit address label + &Редактирай наименование на адрес + + + Show address &QR code + Покажи &QR код на адреса + + + Show in %1 + 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. + Покажи в %1 Export Transaction History Изнасяне историята на транзакциите + + Comma separated file + Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values. + Частично подписана транзакция (двоична) + Confirmed Потвърдени @@ -3548,42 +5040,102 @@ Изнасянето е успешно - The transaction history was successfully saved to %1. - Направените транзакции са запазени до %1. + The transaction history was successfully saved to %1. + Направените транзакции са запазени до %1. + + + QR code + QR код + + + Range: + От: + + + to + до + + + + UnitDisplayStatusBarControl + + Unit to show amounts in. Click to select another unit. + Единица за показване на количеството.Клик за избиране на друга единица. + + + + WalletController + + Close wallet + Затвори портфейл + + + Are you sure you wish to close the wallet <i>%1</i>? + Сигурни ли сте, че искате да затворите портфейла <i>%1</i>? + + + Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled. + Затварянето на портфейла за твърде дълго време може да доведе до необходимост от ресинхронизиране на цялата верига ако е активирано подрязването. + + + Close all wallets + Затвори всички портфейли + + + Are you sure you wish to close all wallets? + Сигурни ли сте, че искате да затворите всички портфейли? + + + + WalletFrame + + No wallet has been loaded. +Go to File > Open Wallet to load a wallet. +- OR - + Не е зареден портфейл. +Отидете на Файл > Отвори портфейл за да заредите портфейл. +- ИЛИ - + + + Create a new wallet + Създай нов портфейл + + + Error + Грешка + + + Unable to decode PSBT from clipboard (invalid base64) + Невъзможно декодиране на PSBT от клипборда (невалиден base64) - QR code - QR код + Load Transaction Data + Зареди данни за транзакцията - Range: - От: + Partially Signed Transaction (*.psbt) + Частично подписана транзакция (*.psbt) - to - до + PSBT file must be smaller than 100 MiB + PSBT файлът трябва да бъде по-малък от 100 MiB - - - UnitDisplayStatusBarControl - Unit to show amounts in. Click to select another unit. - Единица за показване на количеството.Клик за избиране на друга единица. + Unable to decode PSBT + Невъзможно декодиране на PSBT - - WalletController - - - WalletFrame - WalletModel Send Coins Изпращане - + + default wallet + портфейл по подразбиране + + WalletView @@ -3598,6 +5150,11 @@ Selected amount: Избрана сума: + + Wallet Data + Name of the wallet data file format. + Частично подписана транзакция (двоична) + Backup Wallet Запазване на портфейла @@ -3626,8 +5183,8 @@ dash-core - Error: Listening for incoming connections failed (listen returned error %s) - Грешка: Очакването на входящи връзки е неуспешно (върната грешка %s) + 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 + Тази грешка може да се появи, ако този портфейл не беше изключен правилно и беше последно зареден използвайки версия с по-нова версия на Berkeley DB. Ако е така, моля използвайте софтуера, който последно зареди този портфейл This is a pre-release test build - use at your own risk - do not use for mining or merchant applications @@ -3682,16 +5239,20 @@ Грешка при четене от базата данни, изключване. - Failed to listen on any port. Use -listen=0 if you want this. - Неуспешно "слушане" на всеки порт. Използвайте -listen=0 ако искате това. + Error: Missing checksum + Грешка: Липсва контролна сума + + + Error: Unable to parse version %u as a uint32_t + Грешка: Невъзможно анализиране на версия %u като uint32_t - -maxtxfee is set very high! Fees this large could be paid on a single transaction. - -maxtxfee е с много голяма зададена стойност! Това е транзакционната такса, която ще платите ако направите единична транзакция. + Error: Unable to write record to new wallet + Грешка: Невъзможно записване на запис в нов портфейл - Cannot provide specific connections and have addrman find outgoing connections at the same. - Не може да осигури конкретни връзки и да накара addrman да намира изходящи връзки едновременно. + Failed to listen on any port. Use -listen=0 if you want this. + Неуспешно "слушане" на всеки порт. Използвайте -listen=0 ако искате това. Found unconfirmed denominated outputs, will wait till they confirm to continue. @@ -3702,13 +5263,17 @@ Невалидни -socketevents ('%s') . Само тези режим се поддържат: %s - Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions) - Невалидна сума за -maxtxfee=<amount>: '%s' (трябва да бъде най-малко от %s за да се избегне забиване на транзакциите) + SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is supported + SQLiteDatabase: Неизвестна sqlite wallet schema версия %d. Само версия %d се поддържа Transaction index can't be disabled with governance validation enabled. Either start with -disablegovernance command line switch or enable transaction index. Индексът на транзакциите не може да бъде деактивиран в пълен режим. Или започнете с -disablegovernanc от командния ред или активирайте индексиране на транзакциите. + + Unsupported category-specific logging level -loglevel=%s. Expected -loglevel=<category>:<loglevel>. Valid categories: %s. Valid loglevels: %s. + Неподдържано ниво на логване специфично за категория -loglevel=%s. Очаквано -loglevel=<category>:<loglevel>. Валидни категории: %s. Валидни loglevels: %s. + Can't mix: no compatible inputs found! Не може да бъде миксирано: няма останали съвместими входящи средства. @@ -3717,6 +5282,14 @@ Entry exceeds maximum size. Входа надвишава максималният размер. + + Error upgrading evo database for EHF + Грешка при надграждане на evo базата данни за EHF + + + Failed to commit Evo database + Неуспешно commit на Evo базата данни + Found enough users, signing ( waiting %s ) Открити са достатъчно потребители, подписване ( изчаква %s ) @@ -3741,18 +5314,14 @@ Insufficient funds. Недостатъчно средства. - - Invalid amount for -discardfee=<amount>: '%s' - Невалидно количество -discardfee=<amount>: '%s' - - - Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s) - Невалидна сума за -paytxfee=<amount>: '%s' (трябва да бъде най-малко %s) - Invalid minimum number of spork signers specified with -minsporkkeys Невалиден минимален брой ауторизатори на spork определен с -minsporkkeys + + Listening for incoming connections failed (listen returned error %s) + Слушането за входящи връзки се провали (listen върна грешка %s) + Lock is already in place. Заключването е вече налично. @@ -3809,6 +5378,10 @@ Synchronizing governance objects… Синхронизиране на governance обектите… + + Transaction change output index out of range + Индексът на изхода за ресто на транзакцията е извън обхвата + Unable to start HTTP server. See debug log for details. Неуспешно стартиране на HTTP сървър. Виж debug log за подробности. @@ -3817,6 +5390,10 @@ Unknown response. Неизвестен отговор. + + Unsupported global logging level -loglevel=%s. Valid values: %s. + Неподдържано глобално ниво на логване -loglevel=%s. Валидни стойности: %s. + User Agent comment (%s) contains unsafe characters. User Agent comment (%s) съдържа опасни символи. @@ -3857,6 +5434,10 @@ Make sure to encrypt your wallet and delete all non-encrypted backups after you have verified that the wallet works! Уверете се, че криптирате портфейла си и изтривате всички незашифровани резервни копия, след като сте се уверили, че портфейлът Ви работи! + + More than one onion bind address is provided. Using %s for the automatically created Tor onion service. + Предоставени са повече от един onion bind адрес. Използва се %s за автоматично създадената Tor onion услуга. + Prune configured below the minimum of %d MiB. Please use a higher number. Изчистването е конфигурирано под минимума от %d MiB. Моля задайте по висока цифра. @@ -3885,14 +5466,14 @@ Wallet is locked, can't replenish keypool! Automatic backups and mixing are disabled, please unlock your wallet to replenish keypool. Портфейлът е заключен, невъзможно е попълването на keypool! Автоматичното архивиране са изключени, моля отключете вашият портфейл за попълване на keypool. - - You need to rebuild the database using -reindex to change -timestampindex - Трябва да възстановите базата данни, като използвате -reindex за да промените -timestampindex - You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain Необходимо е повторно изграждане на базата данни използвайки -reindex за да се върнете в неизчистен режим.Това ще изтегли отново съществуващата блок-верига + + %s failed + %s се провали + -maxmempool must be at least %d MB -maxmempoolтрябва да бъде поне %d MB @@ -3901,21 +5482,57 @@ Automatic backups disabled Автоматичното архивиране е изключено + + Cannot set -peerblockfilters without -blockfilterindex. + Не може да се зададе -peerblockfilters без -blockfilterindex. + + + Config setting for %s only applied on %s network when in [%s] section. + Настройката на конфигурацията за %s се прилага само в %s мрежа когато е в секция [%s]. + + + Could not find asmap file %s + Не може да се намери asmap файл %s + + + Could not parse asmap file %s + Не може да се анализира asmap файл %s + ERROR! Failed to create automatic backup ГРЕШКА! Неуспешно създаване на автоматичен архив - Error upgrading evo database - Грешка при надстройката на базата данни evo + Error loading %s: Private keys can only be disabled during creation + Грешка при зареждане на %s: Частните ключове могат да бъдат деактивирани само при създаване + + + Error: Couldn't create cursor into database + Грешка: Не можа да се създаде курсор в базата данни + + + Error: Disk space is low for %s + Грешка: Дисковото пространство е малко за %s - Exceeded max tries. - Надвишен брой опити. + Error: Dumpfile checksum does not match. Computed %s, expected %s + Грешка: Контролната сума на дъмп файла не съвпада. Изчислена %s, очаквана %s - Failed to commit EvoDB - Неуспешно фиксиране на EvoDB + Error: Got key that was not hex: %s + Грешка: Получен ключ, който не е hex: %s + + + Error: Got value that was not hex: %s + Грешка: Получена стойност, която не е hex: %s + + + Error: Keypool ran out, please call keypoolrefill first + Грешка: Keypool свърши, моля извикайте keypoolrefill първо + + + Error: No addresses available. + Грешка: Няма налични адреси. Failed to create backup %s! @@ -3933,13 +5550,29 @@ Failed to rescan the wallet during initialization Неуспешно сканиране на портфейла по време на инициализация + + Failed to verify database + Неуспешна проверка на базата данни + + + Fee rate (%s) is lower than the minimum fee rate setting (%s) + Процентът на таксата (%s) е по-нисък от настройката за минимален процент на таксата (%s) + Found enough users, signing… Открити са достатъчно потребители, подписва… - Invalid amount for -fallbackfee=<amount>: '%s' - Невалидно количество за -fallbackfee=<amount>: '%s' + Ignoring duplicate -wallet %s. + Игнориране на дублиран -wallet %s. + + + Input not found or already spent + Входът не е намерен или вече е похарчен + + + Invalid P2P permission: '%s' + Невалидно P2P разрешение: '%s' Invalid masternodeblsprivkey. Please see documentation. @@ -3961,6 +5594,10 @@ Mixing in progress… В процес на смесване… + + No addresses available + Няма налични адреси + No errors detected. Не са открити грешки. @@ -3989,6 +5626,26 @@ Prune mode is incompatible with -txindex. Изчистен режим е несъвместим с -txindex. + + SQLiteDatabase: Failed to execute statement to verify database: %s + SQLiteDatabase: Неуспешно изпълнение на израз за проверка на базата данни: %s + + + SQLiteDatabase: Failed to prepare statement to verify database: %s + SQLiteDatabase: Неуспешна подготовка на израз за проверка на базата данни: %s + + + SQLiteDatabase: Failed to read database verification error: %s + SQLiteDatabase: Неуспешно четене на грешка при проверка на базата данни: %s + + + SQLiteDatabase: Unexpected application id. Expected %u, got %u + SQLiteDatabase: Неочаквано application id. Очаквано %u, получено %u + + + Section [%s] is not recognized. + Секция [%s] не е разпозната. + Specified -walletdir "%s" does not exist Посоченият -walletdir "%s" не съществува @@ -4017,6 +5674,10 @@ This is the transaction fee you will pay if you send a transaction. Това е таксата за транзакцията, която ще платите ако изпратите транзакция. + + Topping up keypool… + Попълване на keypool… + Transaction amounts must not be negative Сумите на транзакциите не трябва да бъдат отрицателни @@ -4037,13 +5698,25 @@ Unable to bind to %s on this computer. %s is probably already running. Невъзможно да се свърже към %s на този компютър. %s вероятно вече работи. + + Unable to create the PID file '%s': %s + Невъзможно създаване на PID файл '%s': %s + Unable to generate initial keys Не може да се генерират първоначални ключове - Upgrading UTXO database - Обновяване на UTXO база данни + Unable to open %s for writing + Невъзможно отваряне на %s за писане + + + Unknown -blockfilterindex value %s. + Неизвестна стойност на -blockfilterindex %s. + + + Unknown new rules activated (versionbit %i) + Активирани неизвестни нови правила (versionbit %i) Verifying blocks… @@ -4062,16 +5735,12 @@ Не е в състояние да създаде архивираща папка за портфейла %s! - You can not start a masternode with wallet enabled. - Не може да стартирате masternode с включен портфейл. - - - You need to rebuild the database using -reindex to change -addressindex - Необходимо е повторно изграждане на базата данни използвайки -reindex, за да промените -addressindex + Wiping wallet transactions… + Изтриване на транзакциите на портфейла… - You need to rebuild the database using -reindex to change -spentindex - Необходимо е повторно изграждане на базата данни използвайки -reindex, за да промените -spentindex + You can not start a masternode with wallet enabled. + Не може да стартирате masternode с включен портфейл. no mixing available. @@ -4089,6 +5758,22 @@ %s uses exact denominated amounts to send funds, you might simply need to mix some more coins. %s използва точно деноминирани суми за изпращане на средства, може просто да се наложи да смесите още няколко монети. + + -reindex-chainstate option is not compatible with -blockfilterindex. Please temporarily disable blockfilterindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes. + Опцията -reindex-chainstate не е съвместима с -blockfilterindex. Моля, временно деактивирайте blockfilterindex докато използвате -reindex-chainstate, или заменете -reindex-chainstate с -reindex за да възстановите напълно всички индекси. + + + -reindex-chainstate option is not compatible with -coinstatsindex. Please temporarily disable coinstatsindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes. + Опцията -reindex-chainstate не е съвместима с -coinstatsindex. Моля, временно деактивирайте coinstatsindex докато използвате -reindex-chainstate, или заменете -reindex-chainstate с -reindex за да възстановите напълно всички индекси. + + + -reindex-chainstate option is not compatible with -txindex. Please temporarily disable txindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes. + Опцията -reindex-chainstate не е съвместима с -txindex. Моля, временно деактивирайте txindex докато използвате -reindex-chainstate, или заменете -reindex-chainstate с -reindex за да възстановите напълно всички индекси. + + + Cannot downgrade wallet from version %i to version %i. Wallet version unchanged. + Не може да се занижи версията на портфейла от версия %i до версия %i. Версията на портфейла е непроменена. + Cannot obtain a lock on data directory %s. %s is probably already running. Не може да се заключи дата директорията %s.%s вероятно вече работи. @@ -4101,14 +5786,82 @@ Error loading %s: You can't enable HD on an already existing non-HD wallet Грешка при зареждане %s: Не можете да активирате HD във вече съществуващ не-HD портфейл + + 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 + Грешка при зареждане на портфейл. Портфейлът изисква блоковете да бъдат изтеглени, а софтуерът в момента не поддържа зареждане на портфейли докато блоковете се изтеглят в неправилен ред при използване на assumeutxo snapshots. Портфейлът трябва да може да се зареди успешно след като синхронизацията на възела достигне височина %s + Error reading %s! All keys read correctly, but transaction data or address book entries might be missing or incorrect. Грешка при четене на %s! Всички ключове са прочетени коректно, но данните за транзакциите или записите в адресната книга може да липсват или са некоректни. + + Error: Dumpfile format record is incorrect. Got "%s", expected "format". + Грешка: Записът на формата на дъмп файла е неправилен. Получен "%s", очакван "format". + + + Error: Dumpfile identifier record is incorrect. Got "%s", expected "%s". + Грешка: Записът на идентификатора на дъмп файла е неправилен. Получен "%s", очакван "%s". + + + Error: Dumpfile version is not supported. This version of bitcoin-wallet only supports version 1 dumpfiles. Got dumpfile with version %s + Грешка: Версията на дъмп файла не се поддържа. Тази версия на bitcoin-wallet поддържа само версия 1 дъмп файлове. Получен дъмп файл с версия %s + + + Failed to rename invalid peers.dat file. Please move or delete it and try again. + Неуспешно преименуване на невалиден peers.dat файл. Моля, преместете или изтрийте го и опитайте отново. + + + Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable %s. + Оценката на таксата се провали. Fallbackfee е деактивирана. Изчакайте няколко блока или активирайте %s. + + + File %s already exists. If you are sure this is what you want, move it out of the way first. + Файлът %s вече съществува. Ако сте сигурни, че това искате, първо го преместете встрани. + + + Incompatible options: -dnsseed=1 was explicitly specified, but -onlynet forbids connections to IPv4/IPv6 + Несъвместими опции: -dnsseed=1 е изрично посочена, но -onlynet забранява връзки към IPv4/IPv6 + Incorrect or no devnet genesis block found. Wrong datadir for devnet specified? Намерен е неправилен или не devnet блок. Грешно зададена data директория за devnet мрежата? + + Invalid amount for %s=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions) + Невалидна сума за %s=<amount>: '%s' (трябва да бъде поне минималната minrelay такса от %s за да се предотвратят блокирани транзакции) + + + 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. + Невалиден или повреден peers.dat (%s). Ако смятате, че това е бъг, моля докладвайте го на %s. Като временно решение, можете да преместите файла (%s) встрани (преименувайте, преместете или изтрийте) за да се създаде нов при следващото стартиране. + + + No dump file provided. To use createfromdump, -dumpfile=<filename> must be provided. + Не е предоставен дъмп файл. За да използвате createfromdump, -dumpfile=<filename> трябва да бъде предоставен. + + + No dump file provided. To use dump, -dumpfile=<filename> must be provided. + Не е предоставен дъмп файл. За да използвате dump, -dumpfile=<filename> трябва да бъде предоставен. + + + No wallet file format provided. To use createfromdump, -format=<format> must be provided. + Не е предоставен формат на файл на портфейл. За да използвате createfromdump, -format=<format> трябва да бъде предоставен. + + + Outbound connections restricted to CJDNS (-onlynet=cjdns) but -cjdnsreachable is not provided + Изходящите връзки са ограничени до CJDNS (-onlynet=cjdns), но -cjdnsreachable не е предоставен + + + Outbound connections restricted to Tor (-onlynet=onion) but the proxy for reaching the Tor network is explicitly forbidden: -onion=0 + Изходящите връзки са ограничени до Tor (-onlynet=onion), но проксито за достигане до Tor мрежата е изрично забранено: -onion=0 + + + 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 + Изходящите връзки са ограничени до Tor (-onlynet=onion), но проксито за достигане до Tor мрежата не е предоставено: нито -proxy, нито -onion, нито -listenonion са дадени + + + Outbound connections restricted to i2p (-onlynet=i2p) but -i2psam is not provided + Изходящите връзки са ограничени до i2p (-onlynet=i2p), но -i2psam не е предоставен + Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly. Моля проверете дали датата и часът на вашият компютър са верни! Ако часовникът ви не е сверен, %s няма да работи правилно. @@ -4117,6 +5870,14 @@ Please contribute if you find %s useful. Visit %s for further information about the software. Моля помогнете ако намерите %s полезен. Посетете %s за допълнителна информация за софтуера. + + Prune mode is incompatible with -reindex-chainstate. Use full -reindex instead. + Режимът на подрязване е несъвместим с -reindex-chainstate. Използвайте пълен -reindex вместо това. + + + This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection. + Това е максималната такса за транзакция, която плащате (в допълнение към нормалната такса) за приоритизиране на избягване на частично харчене спрямо редовния подбор на монети. + This is the transaction fee you may discard if change is smaller than dust at this level Това е таксата за транзакцията, която можете да отхвърлите, ако промяната е по-малка от незначителната стойност на това ниво @@ -4125,10 +5886,38 @@ This is the transaction fee you may pay when fee estimates are not available. Това е таксата за транзакция, която можете да платите, когато не са налице оценки на таксите. + + Transaction requires one destination of non-0 value, a non-0 feerate, or a pre-selected input + Транзакцията изисква една дестинация с ненулева стойност, ненулев feerate или предварително избран вход + Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate. Блокове не могат да се възпроизведат. Ще трябва да възстановите базата данни с помощта на -reindex-chainstate. + + Unknown wallet file format "%s" provided. Please provide one of "bdb" or "sqlite". + Предоставен неизвестен формат на файл на портфейл "%s". Моля, предоставете един от "bdb" или "sqlite". + + + Unsupported chainstate database format found. Please restart with -reindex-chainstate. This will rebuild the chainstate database. + Намерен неподдържан формат на chainstate база данни. Моля, рестартирайте с -reindex-chainstate. Това ще възстанови chainstate базата данни. + + + Warning: Dumpfile wallet format "%s" does not match command line specified format "%s". + Предупреждение: Форматът на дъмп файла на портфейла "%s" не съвпада със зададения формат в командния ред "%s". + + + Warning: Private keys detected in wallet {%s} with disabled private keys + Предупреждение: Открити са частни ключове в портфейл {%s} с деактивирани частни ключове + + + You need to rebuild the database using -reindex to enable -timestampindex + Трябва да възстановите базата данни използвайки -reindex за да активирате -timestampindex + + + %s -- Incorrect seed, it should be a hex string + %s -- Неправилен seed, трябва да бъде hex стринг + %s is not a valid backup folder! %s не е валидна папка за архиви! @@ -4137,6 +5926,10 @@ %s is set very high! %s е зададен твърде високо! + + %s request incomplete: + %s заявката непълна: + -devnet can only be specified once -devnet може да се зададе само веднъж @@ -4149,6 +5942,30 @@ -rpcport must be specified when -devnet and -server are specified -rpcport трябва да се зададе когато -devnet и -server са зададени + + -statsbatchsize cannot be configured with a negative value. + -statsbatchsize не може да се конфигурира с отрицателна стойност. + + + -statsduration cannot be configured with a negative value. + -statsduration не може да се конфигурира с отрицателна стойност. + + + A fatal internal error occurred, see debug.log for details + Възникна фатална вътрешна грешка, вижте debug.log за детайли + + + Cannot create socket (socket() returned error %s) + Не може да се създаде socket (socket() върна грешка %s) + + + Cannot get socket address for %s + Не може да се вземе socket адрес за %s + + + Cannot init Statsd client + Не може да се инициализира Statsd клиент + Cannot resolve -%s address: '%s' Не може да установи -%s адрес: '%s' @@ -4157,14 +5974,22 @@ Cannot write to data directory '%s'; check permissions. Не може да се записва в data папката '%s'; проверете правата. - - Change index out of range - Изместете индекса извън обхвата - Copyright (C) Авторски права (C) + + Disk space is too low! + Дисковото пространство е твърде малко! + + + Dump file %s does not exist. + Дъмп файлът %s не съществува. + + + Error creating %s + Грешка при създаване на %s + Error loading %s Грешка при зареждане на %s @@ -4182,8 +6007,8 @@ Грешка при зареждане %s: Не можете да деактивирате HD във вече съществуващ HD портфейл - Error upgrading chainstate database - Грешка при надграждане на верижната база данни + Error reading next record from wallet database + Грешка при четене на следващ запис от базата данни на портфейла Loading P2P addresses… @@ -4201,10 +6026,38 @@ Loading wallet… Зареждане на портфейла… + + Failed to clear fulfilled requests cache at %s + Неуспешно изчистване на кеша на изпълнени заявки в %s + + + Failed to clear governance cache at %s + Неуспешно изчистване на кеша на управлението в %s + + + Failed to clear masternode cache at %s + Неуспешно изчистване на кеша на masternode в %s + Failed to find mixing queue to join Неуспех при намиране на опашка за миксиране + + Failed to load fulfilled requests cache from %s + Неуспешно зареждане на кеша на изпълнени заявки от %s + + + Failed to load governance cache from %s + Неуспешно зареждане на кеша на управлението от %s + + + Failed to load masternode cache from %s + Неуспешно зареждане на кеша на masternode от %s + + + Failed to load sporks cache from %s + Неуспешно зареждане на кеша на sporks от %s + Failed to start a new mixing queue Неуспешно стартиране на нова опашка за миксиране @@ -4225,6 +6078,14 @@ Inputs vs outputs size mismatch. Несъответствие на размера на входовете и изходите. + + Invalid '%s'. Allowed values: 128, 160, 192, 224, 256. + Невалиден '%s'. Разрешени стойности: 128, 160, 192, 224, 256. + + + Invalid -i2psam address or hostname: '%s' + Невалиден -i2psam адрес или име на хост: '%s' + Invalid -onion address or hostname: '%s' Невалиден -onion адрес или хост: '%s' @@ -4265,14 +6126,82 @@ Last queue was created too recently. Последната опашка беше твърде скоро. + + %s corrupt. Try using the wallet tool dash-wallet to salvage or restoring a backup. + %s повреден. Опитайте използвайки инструмента за портфейл dash-wallet за спасяване или възстановяване на резервно копие. + + + %s is set very high! Fees this large could be paid on a single transaction. + %s е зададен много високо! Такси толкова големи могат да бъдат платени в една транзакция. + + + %s request to listen on port %u. This port is considered "bad" and thus it is unlikely that any Dash Core peers connect to it. See doc/p2p-bad-ports.md for details and a full list. + %s искане за слушане на порт %u. Този порт се счита за "лош" и следователно е малко вероятно Dash Core пиъри да се свържат към него. Вижте doc/p2p-bad-ports.md за детайли и пълен списък. + + + Cannot provide specific connections and have addrman find outgoing connections at the same time. + Не могат да се предоставят специфични връзки и addrman да търси изходящи връзки едновременно. + + + Failed to upgrade Evo database + Неуспешно надграждане на Evo базата данни + + + Fee needed > fee paid + Необходима такса > платена такса + + + Host %s on unsupported network + Хост %s на неподдържана мрежа + + + Invalid amount for %s=<amount>: '%s' (must be at least %s) + Невалидна сума за %s=<amount>: '%s' (трябва да е поне %s) + + + Invalid amount for %s=<amount>: '%s' + Невалидна сума за %s=<amount>: '%s' + + + Invalid port specified in %s: '%s' + Невалиден порт посочен в %s: '%s' + Last successful action was too recent. Последното успешно действие беше твърде скоро. + + Missing solving data for estimating transaction size + Липсват данни за разрешаване за оценка на размера на транзакцията + + + No host specified + Не е посочен хост + + + No host specified, malformed URL + Не е посочен хост, невалиден URL + + + No text before the scheme delimiter, malformed URL + Няма текст преди разделителя на схемата, невалиден URL + + + Port must be between %d and %d, supplied %d + Портът трябва да бъде между %d и %d, предоставен е %d + + + Socket not initialized, cannot send message + Сокетът не е инициализиран, не може да се изпрати съобщение + The source code is available from %s. Изходният код е достъпен от %s. + + The specified config file %s does not exist + Посоченият конфигурационен файл %s не съществува + The transaction amount is too small to pay the fee Сумата на транзакцията е твърде малка за плащане на таксата @@ -4293,6 +6222,10 @@ Transaction fees are too high. Таксите за транзакция са твърде високи. + + Transaction needs a change address, but we can't generate it. + Транзакцията се нуждае от адрес за ресто, но не можем да го генерираме. + Transaction not valid. Транзакцията е невалидна. @@ -4313,6 +6246,18 @@ Unable to locate enough non-denominated funds for this transaction. Не са намерени достатъчно неденоминирани средства за тази транзакция. + + Unable to lookup host %s + Невъзможно намиране на хост %s + + + Unable to parse -maxuploadtarget: '%s' + Невъзможно анализиране на -maxuploadtarget: '%s' + + + Unable to send message to %s (::sendto() returned error %s) + Невъзможно изпращане на съобщение до %s (::sendto() върна грешка %s) + Unable to sign spork message, wrong key? Неуспешно подписване на spork-съобщение. Грешен ключ? @@ -4325,6 +6270,10 @@ Unknown state: id = %u Неизвестно състояние: id = %u + + Unsupported URL scheme, must begin with udp:// + Неподдържана URL схема, трябва да започва с udp:// + Unsupported logging category %s=%s. Неподдържана категория на журналиране %s=%s. @@ -4357,9 +6306,25 @@ You can not disable governance validation on a masternode. Не можете да деактивирате валидирането на управлението на masternode. + + You need to rebuild the database using -reindex to enable -addressindex + Трябва да възстановите базата данни използвайки -reindex за да активирате -addressindex + + + You need to rebuild the database using -reindex to enable -spentindex + Трябва да възстановите базата данни използвайки -reindex за да активирате -spentindex + Your entries added successfully. Вашите записи са добавени успешно. + + Settings file could not be read + Файлът с настройки не може да бъде прочетен + + + Settings file could not be written + Файлът с настройки не може да бъде записан + \ No newline at end of file diff --git a/src/qt/locale/dash_de.ts b/src/qt/locale/dash_de.ts index 6a4ba46464e1..e1fb5e70d8e0 100644 --- a/src/qt/locale/dash_de.ts +++ b/src/qt/locale/dash_de.ts @@ -65,14 +65,6 @@ C&hoose &Auswählen - - Sending addresses - Zahlungsadressen - - - Receiving addresses - Empfangsadressen - These are your Dash addresses for sending payments. Always check the amount and the receiving address before sending coins. Dies sind ihre Dash-Adressen zum Tätigen von Überweisungen. Bitte prüfen Sie den Betrag und die Empfangsadresse, bevor Sie Dash überweisen. @@ -115,6 +107,14 @@ An error message. %1 is a stand-in argument for the name of the file we attempted to save to. Beim Speichern der Adressliste nach %1 ist ein Fehler aufgetreten. Bitte noch einmal versuchen. + + Sending addresses - %1 + Sendeadressen - %1 + + + Receiving addresses - %1 + Empfangsadressen - %1 + Exporting Failed Exportieren fehlgeschlagen @@ -178,23 +178,23 @@ AskPassphraseDialog Passphrase Dialog - Passphrasendialog + Passwort-Dialog Enter passphrase - Passphrase eingeben + Passwort eingeben New passphrase - Neue Passphrase + Neues Passwort eingeben Repeat new passphrase - Neue Passphrase wiederholen + Neues Passwort wiederholen Show passphrase - Passphrase anzeigen + Passwort anzeigen Encrypt wallet @@ -202,7 +202,7 @@ This operation needs your wallet passphrase to unlock the wallet. - Dieser Vorgang benötigt ihre Passphrase, um die Wallet zu entsperren. + Dieser Vorgang benötigt ihr Passwort, um die Wallet zu entsperren. Unlock wallet for mixing only @@ -214,7 +214,7 @@ Change passphrase - Passphrase ändern + Passwort ändern Confirm wallet encryption @@ -222,7 +222,7 @@ Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR DASH</b>! - Warnung: Wenn Sie ihre Wallet verschlüsseln und ihre Passphrase verlieren werden Sie <b>alle ihre Dash verlieren</b>! + Warnung: Wenn Sie ihre Wallet verschlüsseln und ihre Passwort verlieren werden Sie <b>alle ihre Dash verlieren</b>! Are you sure you wish to encrypt your wallet? @@ -234,11 +234,11 @@ 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>. - Gib die neue Passphrase für die Wallet ein.<br/>Bitte nutze eine Passphrase mit <b>zehn oder mehr zufälligen Zeichen</b>, oder <b>acht oder mehr Wörtern</b>. + Gib die neue Passphrase für die Wallet ein.<br/>Bitte nutze ein Passwort mit <b>zehn oder mehr zufälligen Zeichen</b>, oder eine Passphrase mit <b>acht oder mehr Wörtern</b>. Enter the old passphrase and new passphrase for the wallet. - Gib nun sowhl die bisherige Passphrase als auch die neue Passphrase für die Wallet ein. + Gib nun sowohl das bisherige Passwort als auch die neue Passwort für die Wallet ein. Remember that encrypting your wallet cannot fully protect your funds from being stolen by malware infecting your computer. @@ -282,11 +282,23 @@ The passphrase entered for the wallet decryption was incorrect. - Die eingegebene Passphrase zur Wallet-Entschlüsselung war nicht korrekt. + Das eingegebene Passwort zur Wallet-Entschlüsselung war nicht korrekt. + + + 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 23.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. + Das eingegebene Passwort zur Wallet-Entschlüsselung ist fehlerhaft. Es enthält ein Null-Zeichen (d.h. ein Null-Byte). Wenn das Passwort mit einer Version dieser Software vor 23.0 gesetzt wurde, versuchen Sie es bitte erneut mit nur den Zeichen bis zum — aber nicht einschließlich — dem ersten Null-Zeichen. Wenn dies erfolgreich ist, setzen Sie bitte ein neues Passwort, um dieses Problem in Zukunft zu vermeiden. Wallet passphrase was successfully changed. - Die Wallet-Passphrase wurde erfolgreich geändert. + Das Wallet-Passwort wurde erfolgreich geändert. + + + Passphrase change failed + Passwortänderung fehlgeschlagen + + + 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 23.0, please try again with only the characters up to — but not including — the first null character. + Das alte Passwort zur Wallet-Entschlüsselung ist fehlerhaft. Es enthält ein Null-Zeichen (d.h. ein Null-Byte). Wenn das Passwort mit einer Version dieser Software vor 23.0 gesetzt wurde, versuchen Sie es bitte erneut mit nur den Zeichen bis zum — aber nicht einschließlich — dem ersten Null-Zeichen. Warning: The Caps Lock key is on! @@ -374,7 +386,7 @@ &Change Passphrase… - Passphrase &ändern… + Passwort &ändern… &Unlock Wallet… @@ -392,10 +404,6 @@ &Load PSBT from file… &lade PSBT aus Datei... - - Load PSBT from clipboard… - Lade PSBT aus der Zwischenablage... - &Sending addresses &Absendeadressen @@ -428,10 +436,6 @@ &Window &Fenster - - Minimize - Minimieren - Zoom Zoom @@ -484,14 +488,6 @@ Modify configuration options for %1 Konfiguration von %1 bearbeiten - - &Show / Hide - &Anzeigen / Verstecken - - - Show or hide the main Window - Das Hauptfenster anzeigen oder verstecken - Encrypt the private keys that belong to your wallet Verschlüsselt die zu ihrer Wallet gehörenden privaten Schlüssel @@ -502,7 +498,7 @@ Change the passphrase used for wallet encryption - Ändert die Passphrase, die für die Wallet-Verschlüsselung benutzt wird + Ändert das Passwort, die für die Wallet-Verschlüsselung benutzt wird Unlock wallet @@ -556,10 +552,6 @@ Show wallet repair options Optionen zur Wallet-Reparatur anzeigen - - Open Wallet &Configuration File - &Konfigurationsdatei öffnen - Open configuration file Konfigurationsdatei öffnen @@ -614,10 +606,18 @@ Show information about %1 Zeige Informationen über %1 + + Load PSBT from &clipboard… + PSBT aus &Zwischenablage laden… + Open debugging and diagnostic console Debugging- und Diagnose-Konsole öffnen + + Open &wallet configuration file + &Wallet-Konfigurationsdatei öffnen + Open a dash: URI Ein Dash öffnen: URI @@ -626,6 +626,16 @@ Create a new wallet Eine neue Wallet erstellen + + Restore Wallet… + Name of the menu item that restores wallet from a backup file. + Wallet wiederherstellen… + + + Restore a wallet from a backup file + Status tip for Restore Wallet menu item + Eine Wallet aus einer Sicherungsdatei wiederherstellen + Close all wallets Alle Wallets schließen @@ -646,10 +656,34 @@ Mask the values in the Overview tab Werte im Tab "Übersicht" verbergen + + Wallet Data + Name of the wallet data file format. + Wallet-Daten + + + Load Wallet Backup + The title for Restore Wallet File Windows + Wallet-Sicherung laden + + + Restore Wallet + Title of pop-up window shown when the user is attempting to restore a wallet. + Wallet wiederherstellen + + + Wallet Name + Label of the input field where the name of the wallet is entered. + Wallet-Name + &Settings &Einstellungen + + &Minimize + &Minimieren + &Help &Hilfe @@ -666,6 +700,14 @@ View Governance Proposals Zeige Governance Proposals + + &Hide + &Verbergen + + + S&how + &Anzeigen + %n active connection(s) to Dash network A substring of the tooltip. @@ -687,6 +729,14 @@ Close Wallet… Wallet schließen… + + Load Partially Signed Blockchain Transaction + Lade Partially Signed Blockchain Transaction + + + Load Partially Signed Blockchain Transaction from clipboard + Lade Partially Signed Blockchain Transaction aus der Zwischenablage + Create Wallet… Wallet erstellen… @@ -739,10 +789,6 @@ Processing blocks on disk… Verarbeite Blöcke auf Datenträger… - - Reindexing blocks on disk… - Reindiziere Blöcke auf Datenträger… - Connecting to peers… Verbinde mit Peers… @@ -896,10 +942,6 @@ Coin Selection "Coin Control"-Auswahl - - Dust: - "Dust" - After Fee: Abzüglich Gebühr: @@ -1000,10 +1042,6 @@ Copy bytes Byte kopieren - - Copy dust - "Dust" Betrag kopieren - Copy change Wechselgeld kopieren @@ -1016,18 +1054,6 @@ (%1 locked) (%1 gesperrt) - - yes - ja - - - no - nein - - - This label turns red if any recipient receives an amount smaller than the current dust threshold. - Diese Bezeichnung wird rot, wenn ein Empfänger einen Betrag kleiner als die gegenwärtige Schwelle für Dust erhält. - Can vary +/- %1 duff(s) per input. Kann um +/- %1 duff(s) pro Eingabe variieren. @@ -1106,7 +1132,7 @@ Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice. - Verschlüssele die Wallet. Die Wallet wird mit einer Passphrase deiner Wahl verschlüsselt. + Verschlüssele die Wallet. Die Wallet wird mit einem Passwort deiner Wahl verschlüsselt. Encrypt Wallet @@ -1241,18 +1267,102 @@ Filter proposal list Proposal-List filtern + + Masternode Count: + Masternode-Anzahl: + + + Number of masternodes this wallet can vote with (masternodes for which this wallet holds the voting key) + Anzahl der Masternodes, mit denen diese Wallet abstimmen kann (Masternodes, für die diese Wallet den Abstimmungsschlüssel hält) + Proposal Count: Proposal Zahl: + + Create Proposal + Proposal erstellen + Filter by Title Filter nach Titel + + Unavailable + Nicht verfügbar + + + A synced node and an unlocked wallet are required. + Ein synchronisierter Knoten und eine entsperrte Wallet sind erforderlich. + + + Vote Yes + Ja stimmen + + + Vote No + Nein stimmen + + + Vote Abstain + Enthaltung + Proposal Info: %1 Proposal Info: %1 + + Voting Failed + Abstimmung fehlgeschlagen + + + No wallet available. + Keine Wallet verfügbar. + + + No masternode voting keys found in wallet. + Keine Masternode-Abstimmungsschlüssel in der Wallet gefunden. + + + Please select a proposal to vote on. + Bitte wählen Sie einen Proposal aus, über den abgestimmt werden soll. + + + Unable to unlock wallet. + Wallet kann nicht entsperrt werden. + + + Unable to get masternode list. Please try again later. + Masternode-Liste kann nicht abgerufen werden. Bitte versuchen Sie es später erneut. + + + Masternode %1 not found + Masternode %1 nicht gefunden + + + Failed to sign vote for masternode %1 + Signierung der Abstimmung für Masternode %1 fehlgeschlagen + + + Masternode %1: %2 + Masternode %1: %2 + + + Voted successfully %n time(s) + %n Mal erfolgreich abgestimmt%n Mal erfolgreich abgestimmt + + + Failed to vote %n time(s) + %n Mal fehlgeschlagen abzustimmen%n Mal fehlgeschlagen abzustimmen + + + Errors: + Fehler: + + + Voting Results + Abstimmungsergebnisse + HelpMessageDialog @@ -1323,13 +1433,17 @@ Use a custom data directory: Ein benutzerdefiniertes Datenverzeichnis verwenden: - - (of %1 GB needed) - (von benötigten %1 GB) + + %n GB of space available + %n GB Speicherplatz verfügbar%n GB Speicherplatz verfügbar - - (%1 GB needed for full chain) - (%1 GB für die gesamte Blockchain benötigt) + + (of %n GB needed) + (von %n GB benötigt)(von %n GB benötigt) + + + (%n GB needed for full chain) + (%n GB für die vollständige Blockchain benötigt)(%n GB für die vollständige Blockchain benötigt) At least %1 GB of data will be stored in this directory, and it will grow over time. @@ -1361,6 +1475,13 @@ Fehler + + LoadWalletsActivity + + Loading wallets… + Wallets werden geladen… + + MasternodeList @@ -1553,6 +1674,11 @@ URI: URI: + + Paste address from clipboard + Tooltip text for button that allows you to paste an address that is in your clipboard. + Adresse aus Zwischenablage einfügen + OpenWalletActivity @@ -1663,6 +1789,16 @@ An Options window setting to set subtracting the fee from a sending amount as default. &Gebühr vom Gesamtbetrag standardmäßig abziehen + + Enable &PSBT controls + An options window setting to enable PSBT controls. + &PSBT-Steuerelemente aktivieren + + + Whether to show PSBT controls. + Tooltip text for options window setting that enables PSBT controls. + Ob PSBT-Steuerelemente angezeigt werden sollen. + Whether to keep the specified custom change address or not. Ob die benutzerdefinierte Wechselgeld-Adresse beibehalten wird oder nicht. @@ -1806,20 +1942,20 @@ https://explore.transifex.com/dash/dash/ https://explore.transifex.com/dash/dash/ - Options set in this dialog are overridden by the command line or in the configuration file: - In diesem Dialog eingestellte Optionen werden in der Kommandozeile oder in der Konfigurationsdatei überschrieben: + Third-party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items.<br/>%s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |. + Drittanbieter-URLs (z.B. ein Block-Explorer), die im Transaktions-Tab als Kontextmenü-Einträge erscheinen.<br/>%s in der URL wird durch den Transaktions-Hash ersetzt. Mehrere URLs werden durch senkrechten Strich | getrennt. - 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. - Minimiert die Anwendung anstatt sie zu beenden wenn das Fenster geschlossen wird. Wenn dies aktiviert ist, müssen Sie das Programm über "Beenden" im Menü schließen. + &Third-party transaction URLs + &Drittanbieter-Transaktions-URLs - Third party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items.<br/>%s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |. - Externe URLs (z.B. ein Block-Explorer), die im Kontextmenü des Transaktionsverlaufs eingefügt werden. In der URL wird %s durch den Transaktionshash ersetzt. Bei Angabe mehrerer URLs müssen diese durch "|" voneinander getrennt werden. + Options set in this dialog are overridden by the command line or in the configuration file: + In diesem Dialog eingestellte Optionen werden in der Kommandozeile oder in der Konfigurationsdatei überschrieben: - &Third party transaction URLs - &Externe Transaktions-URLs + 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. + Minimiert die Anwendung anstatt sie zu beenden wenn das Fenster geschlossen wird. Wenn dies aktiviert ist, müssen Sie das Programm über "Beenden" im Menü schließen. Whether to show coin control features or not. @@ -1963,14 +2099,22 @@ https://explore.transifex.com/dash/dash/ Confirm options reset + Window title text of pop-up window shown when the user has chosen to reset options. Zurücksetzen der Konfiguration bestätigen Client restart required to activate changes. + Text explaining that the settings changed will not come into effect until the client is restarted. Clientneustart nötig, um die Änderungen zu aktivieren. + + Current settings will be backed up at "%1". + 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. + Die aktuellen Einstellungen werden unter "%1" gesichert. + Client will be shut down. Do you want to proceed? + Text asking the user to confirm if they would like to proceed with a client shutdown. Client wird beendet, wollen Sie fortfahren? @@ -2243,6 +2387,10 @@ https://explore.transifex.com/dash/dash/ Failed to sign transaction: %1 Fehler beim Signieren der Transaktion: %1 + + Cannot sign inputs while wallet is locked. + Inputs können nicht signiert werden, weil die Wallet gesperrt ist. + Could not sign any more inputs. Es konnten keine weiteren Inputs mehr signiert werden. @@ -2487,6 +2635,181 @@ Da die Unterstützung eingestellt wurde, sollten Sie den Händler bitten, Ihnen Status + + ProposalWizard + + Create Governance Proposal + Governance-Proposal erstellen + + + Enter proposal details + Proposal-Details eingeben + + + A fee will be burned when you prepare the proposal. + Eine Gebühr wird verbrannt, wenn Sie den Proposal vorbereiten. + + + Proposal &name + Proposal-&Name + + + &Description URL + &Beschreibungs-URL + + + Payment &address + Zahlungs&adresse + + + Payment &amount + Zahlungs&betrag + + + The amount to request in a single payment + Der Betrag, der in einer einzelnen Zahlung angefordert werden soll + + + &First payment + &Erste Zahlung + + + Pa&yments + &Zahlungen + + + To&tal amount + &Gesamtbetrag + + + Proposal &fee + Proposal-&Gebühr + + + Next + Weiter + + + Review proposal JSON and validate. + Proposal-JSON überprüfen und validieren. + + + Hex-encoded JSON + Hex-kodiertes JSON + + + Back + Zurück + + + Validate + Validieren + + + Prepare (burn fee) and wait for confirmations. + Vorbereiten (Gebühr verbrennen) und auf Bestätigungen warten. + + + Copy + Kopieren + + + At 1/6 confirmations: can be relayed and queued. At 6/6: accepted and processed. + Bei 1/6 Bestätigungen: kann weitergeleitet und in die Warteschlange gestellt werden. Bei 6/6: akzeptiert und verarbeitet. + + + Confirmations progress + Bestätigungsfortschritt + + + Shows progress toward the required number of confirmations for the proposal fee transaction. + Zeigt den Fortschritt zur erforderlichen Anzahl von Bestätigungen für die Proposal-Gebührentransaktion an. + + + Estimated time remaining: - + Geschätzte verbleibende Zeit: - + + + Prepare Proposal + Proposal vorbereiten + + + You can submit after 1 confirmation. At 6 confirmations it is accepted and processed. + Sie können nach 1 Bestätigung einreichen. Bei 6 Bestätigungen wird es akzeptiert und verarbeitet. + + + Proposal ID: + Proposal-ID: + + + Submit Proposal + Proposal einreichen + + + Close + Schließen + + + Valid + Gültig + + + Invalid: %1 + Ungültig: %1 + + + Burn %1 + %1 verbrennen + + + Burn %1 to create the fee transaction? + %1 verbrennen, um die Gebührentransaktion zu erstellen? + + + Prepare failed + Vorbereitung fehlgeschlagen + + + Confirmations: %1 / %2 required + Bestätigungen: %1 / %2 erforderlich + + + Estimated time remaining: Ready + Geschätzte verbleibende Zeit: Bereit + + + Estimated time remaining: %n minute(s) + Geschätzte verbleibende Zeit: %n MinuteGeschätzte verbleibende Zeit: %n Minuten + + + Your proposal was submitted successfully. + Ihr Proposal wurde erfolgreich eingereicht. + + + Already submitted + Bereits eingereicht + + + This proposal has already been submitted. + Dieser Proposal wurde bereits eingereicht. + + + Submission failed + Einreichung fehlgeschlagen + + + Proposal submitted + Proposal eingereicht + + + A fee of %1 will be burned when you prepare the proposal. + Eine Gebühr von %1 wird verbrannt, wenn Sie den Proposal vorbereiten. + + + Prepare (burn %1) and wait for %2 confirmations. + Vorbereiten (%1 verbrennen) und auf %2 Bestätigungen warten. + + QObject @@ -2876,14 +3199,6 @@ Da die Unterstützung eingestellt wurde, sollten Sie den Händler bitten, Ihnen Version Version - - Whether the peer requested us to relay transactions. - Ob der Peer uns gebeten hat, Transaktionen weiterzuleiten. - - - Wants Tx Relay - Möchte Transaktionsweiterleitung - High bandwidth BIP152 compact block relay: %1 Kompaktes Blockrelais BIP152 mit hoher Bandbreite: %1 @@ -2989,6 +3304,14 @@ Da die Unterstützung eingestellt wurde, sollten Sie den Händler bitten, Ihnen To specify a non-default location of the blocks directory use the '%1' option. Wenn du einen anderen Ort als das Standardverzeichnis für die Blöcke angeben möchtest, verwende die Option "%1". + + Local Addresses + Lokale Adressen + + + Network addresses that your Dash node is currently using to communicate with other nodes. + Netzwerkadressen, die Ihr Dash-Knoten derzeit zur Kommunikation mit anderen Knoten verwendet. + Number of regular Masternodes Anzahl regulärer Masternodes @@ -3081,6 +3404,14 @@ Da die Unterstützung eingestellt wurde, sollten Sie den Händler bitten, Ihnen Services Dienste + + Whether we relay transactions to this peer. + Ob wir Transaktionen an diesen Peer weiterleiten. + + + Transaction Relay + Transaktionsweiterleitung + Connection Time Verbindungszeit @@ -3229,6 +3560,10 @@ Da die Unterstützung eingestellt wurde, sollten Sie den Händler bitten, Ihnen Network activity disabled Netzwerk-Aktivität deaktiviert + + None + Keine + Total: %1 (Enabled: %2) Insgesamt: %1 (Aktiv: %2) @@ -3550,6 +3885,34 @@ Für mehr Information, wie diese Konsole zu nutzen ist, %6 tippen. Angefordert + + RestoreWalletActivity + + Restore Wallet + Title of progress window which is displayed when wallets are being restored. + Wallet wiederherstellen + + + Restoring Wallet <b>%1</b>… + Descriptive text of the restore wallets progress window which indicates to the user that wallets are currently being restored. + Wallet <b>%1</b> wird wiederhergestellt… + + + Restore wallet failed + Title of message box which is displayed when the wallet could not be restored. + Wallet-Wiederherstellung fehlgeschlagen + + + Restore wallet warning + Title of message box which is displayed when the wallet is restored with some warning. + Wallet-Wiederherstellungswarnung + + + Restore wallet message + Title of message box which is displayed when the wallet is successfully restored. + Wallet-Wiederherstellungsmeldung + + SendCoinsDialog @@ -3584,10 +3947,6 @@ Für mehr Information, wie diese Konsole zu nutzen ist, %6 tippen. Fee: Gebühr: - - Dust: - "Dust" - Inputs… Inputs… @@ -3712,10 +4071,6 @@ Für mehr Information, wie diese Konsole zu nutzen ist, %6 tippen. Copy bytes Byte kopieren - - Copy dust - "Dust" Betrag kopieren - Copy change Wechselgeld kopieren @@ -3724,10 +4079,6 @@ Für mehr Information, wie diese Konsole zu nutzen ist, %6 tippen. %1 (%2 blocks) %1 (%2 blocks) - - This will produce a Partially Signed Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet. - Dies wird eine Partially Signed Transaction (PSBT) erstellen, die Sie sichern oder kopieren und mit einer z.B. Offline-%1Wallet oder PSBT kompatiblen Hardware-Wallet signieren können. - using mittels @@ -3736,10 +4087,6 @@ Für mehr Information, wie diese Konsole zu nutzen ist, %6 tippen. %1 to %2 %1 an %2 - - Are you sure you want to send? - Wollen Sie die Überweisung ausführen? - <b>(%1 of %2 entries displayed)</b> <b>(%1 von %2 Einträgen angezeigt)</b> @@ -3764,10 +4111,6 @@ Für mehr Information, wie diese Konsole zu nutzen ist, %6 tippen. %1 to '%2' %1 zu '%2' - - Do you want to draft this transaction? - Möchtest du diese Transaktion erstellen? - %1 funds only Nur %1-Guthaben @@ -3816,14 +4159,6 @@ Für mehr Information, wie diese Konsole zu nutzen ist, %6 tippen. Confirm send coins Überweisung bestätigen - - Confirm transaction proposal - Transaktionsvorschlag erstellen - - - Create Unsigned - Ohne Signatur erstellen - Save Transaction Data Transaktionsdaten speichern @@ -3837,8 +4172,28 @@ Für mehr Information, wie diese Konsole zu nutzen ist, %6 tippen. Watch-Only Guthaben: - Send - Senden + Creates a Partially Signed Blockchain Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet. + Erstellt eine Partially Signed Blockchain Transaction (PSBT) um z.B. mit einer Offline-%1Wallet oder einer PSBT kompatiblen Hardware-Wallet genutzt werden zu können. + + + Do you want to create this transaction? + 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. + Möchten Sie diese Transaktion erstellen? + + + Please, review your transaction proposal. This will produce a Partially Signed Blockchain Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet. + 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. + Bitte überprüfen Sie Ihren Transaktionsvorschlag. Dies erzeugt eine Partially Signed Blockchain Transaction (PSBT), die Sie speichern oder kopieren und dann z.B. mit einer Offline-%1-Wallet oder einer PSBT-kompatiblen Hardware-Wallet signieren können. + + + Please, review your transaction. You can create and send this transaction or create a Partially Signed Blockchain Transaction (PSBT), which you can save or copy and then sign with, e.g., an offline %1 wallet, or a PSBT-compatible hardware wallet. + 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. + Bitte überprüfen Sie Ihre Transaktion. Sie können diese Transaktion erstellen und senden oder eine Partially Signed Blockchain 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. + + + Please, review your transaction. + Text to prompt a user to review the details of the transaction they are attempting to send. + Bitte überprüfen Sie Ihre Transaktion. To review recipient list click "Show Details…" @@ -3968,21 +4323,16 @@ Für mehr Information, wie diese Konsole zu nutzen ist, %6 tippen. A message that was attached to the dash: URI which will be stored with the transaction for your reference. Note: This message will not be sent over the Dash network. Eine an die "dash:"-URI angefügte Nachricht, die zusammen mit der Transaktion gespeichert wird. Hinweis: Diese Nachricht wird nicht über das Dash-Netzwerk gesendet. + + + SendConfirmationDialog - This is an unauthenticated payment request. - Dies ist eine unverifizierte Zahlungsanforderung. - - - This is an authenticated payment request. - Dies ist eine verifizierte Zahlungsanforderung. - - - Pay To: - Empfänger: + Send + Senden - Memo: - Memo: + Create Unsigned + Unsigniert erstellen @@ -4191,20 +4541,9 @@ Für mehr Information, wie diese Konsole zu nutzen ist, %6 tippen. TransactionDesc - - Open for %n more block(s) - Geöffnet für %n weiteren BlockGeöffnet für %n weitere Blöcke - - - Open until %1 - Offen bis %1 - - - conflicted - in Konflikt stehend - 0/unconfirmed, %1 + 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. 0/unbestätigt, %1 @@ -4217,22 +4556,32 @@ Für mehr Information, wie diese Konsole zu nutzen ist, %6 tippen. abandoned + 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. aufgegeben + + conflicted with a transaction with %1 confirmations + 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. + steht im Konflikt mit einer Transaktion mit %1 Bestätigungen + %1/unconfirmed + 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, and still not locked via ChainLocks. %1/unbestätigt %1 confirmations + 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 or locked via ChainLocks. %1 Bestätigungen locked via ChainLocks + 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 and has been locked by ChainLocks. Via ChainLocks gesperrt verified via InstantSend + 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 has been locked by InstantSend. Verifiziert via InstantSend @@ -4385,14 +4734,6 @@ Für mehr Information, wie diese Konsole zu nutzen ist, %6 tippen. Address / Label Adresse / Label - - Open for %n more block(s) - Geöffnet für %n weiteren BlockGeöffnet für %n weitere Blöcke - - - Open until %1 - Offen bis %1 - Unconfirmed Unbestätigt @@ -4644,6 +4985,11 @@ Für mehr Information, wie diese Konsole zu nutzen ist, %6 tippen. Show address &QR code Adresse und &QR-Code anzeigen + + Show in %1 + 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. + In %1 anzeigen + Export Transaction History Transaktionsverlauf exportieren @@ -4836,10 +5182,6 @@ Gehen Sie zu "Datei" > "Wallet öffnen" um Wallet zu laden dash-core - - Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee. - Gebührenberechnung fehlgeschlagen. Fallbackfee ist deaktiviert. Warte ein paar Blöcke oder aktiviere -fallbackfee. - 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 Die Fehlermeldung kann auftreten, wenn diese Wallet nicht sauber heruntergefahren wurde und zuletzt mit einem Build mit einer neueren Version von Berkeley DB geladen wurde. In diesem Fall verwende bitte die Software, mit der diese Wallet zuletzt geladen wurde @@ -4912,10 +5254,6 @@ Gehen Sie zu "Datei" > "Wallet öffnen" um Wallet zu laden Failed to listen on any port. Use -listen=0 if you want this. Fehler, es konnte kein Port abgehört werden. Wenn dies so gewünscht wird -listen=0 verwenden. - - -maxtxfee is set very high! Fees this large could be paid on a single transaction. - Warnung: -maxtxfee ist auf einen sehr hohen Wert gesetzt! Diese Gebühr könnte schon beim Senden einer einzelnen Transaktion fällig werden. - Found unconfirmed denominated outputs, will wait till they confirm to continue. Unbestätigte für PrivateSend vorbereitete Ausgabebeträge gefunden, warte bis sie bestätigt sind bevor weitergemacht wird. @@ -4924,10 +5262,6 @@ Gehen Sie zu "Datei" > "Wallet öffnen" um Wallet zu laden Invalid -socketevents ('%s') specified. Only these modes are supported: %s Ungültige -socketevents ('%s') spezifiziert. Nur diese Modi werden unterstützt: %s - - Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions) - Ungültiger Betrag für -maxtxfee=<amount>: '%s' (Betrag muss mindestens minrelay von %s Gebühren sein um "hängende" Transaktionen zu vermeiden) - SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is supported SQLite-Datenbank: Unbekannte Version des Sqlite-Wallet-Schemas %d. Nur Version %d wird unterstützt @@ -4936,6 +5270,10 @@ Gehen Sie zu "Datei" > "Wallet öffnen" um Wallet zu laden Transaction index can't be disabled with governance validation enabled. Either start with -disablegovernance command line switch or enable transaction index. Der Transaktionsindex nicht deaktiviert werden, solange die Governance-Validierung aktiviert ist. Der Transaktionsindex muss entweder aktiviert sein oder der Knoten muss mit dem Befehl -disablegovernance gestartet werden. + + Unsupported category-specific logging level -loglevel=%s. Expected -loglevel=<category>:<loglevel>. Valid categories: %s. Valid loglevels: %s. + Nicht unterstütze Kategorie: -specific logging level -loglevel=%s. Erwartet -loglevel=<category>:<loglevel>. Gültige Kategorien: %s. Gültige Log-Levels : %s. + Can't mix: no compatible inputs found! Mixen nicht möglich: Keine kompatiblen Inputs gefunden! @@ -4944,6 +5282,14 @@ Gehen Sie zu "Datei" > "Wallet öffnen" um Wallet zu laden Entry exceeds maximum size. Eingabe überschreitet maximale Größe. + + Error upgrading evo database for EHF + Fehler bei der Aktualisierung der Datenbank für EHF + + + Failed to commit Evo database + Evo-Datenbank konnte nicht übertragen werden + Found enough users, signing ( waiting %s ) Genug Partner gefunden, signiere ( warte %s ) @@ -4968,18 +5314,14 @@ Gehen Sie zu "Datei" > "Wallet öffnen" um Wallet zu laden Insufficient funds. Unzureichender Kontostand. - - Invalid amount for -discardfee=<amount>: '%s' - Ungültiger Betrag für -discardfee=<amount>: '%s' - - - Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s) - Ungültiger Betrag für -paytxfee=<amount>: '%s' (Betrag muss mindestens %s sein) - Invalid minimum number of spork signers specified with -minsporkkeys Ungültige minimale Anzahl an Spork-Unterzeichnern durch -minsporkkeys spezifiziert + + Listening for incoming connections failed (listen returned error %s) + Fehler: Listening nach eingehenden Verbindungen fehlgeschlagen (Listening produziert Fehler %s) + Lock is already in place. Schon gesperrt. @@ -5036,6 +5378,10 @@ Gehen Sie zu "Datei" > "Wallet öffnen" um Wallet zu laden Synchronizing governance objects… Synchronisiere Governance Objekte… + + Transaction change output index out of range + Output-Index der Transaktionsänderung außerhalb des Bereichs + Unable to start HTTP server. See debug log for details. Interner HTTP-Server konnte nicht gestartet werden. Details finden Sie in debug.log @@ -5044,6 +5390,10 @@ Gehen Sie zu "Datei" > "Wallet öffnen" um Wallet zu laden Unknown response. Unbekannte Rückantwort. + + Unsupported global logging level -loglevel=%s. Valid values: %s. + Nicht unterstütztes globales Logging-Level -loglevel=%s. Gültige Werte: %s. + User Agent comment (%s) contains unsafe characters. Der "User Agent"-Text (%s) enthält unsichere Zeichen. @@ -5108,10 +5458,6 @@ Gehen Sie zu "Datei" > "Wallet öffnen" um Wallet zu laden Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments. Die Gesamtlänge des Versions-Namens (%i) überschreitet die erlaubte Maximallänge (%i). Bitte verringern Sie Anzahl oder Größe der Eingaben für die Kommandozeilenoption -uacomments. - - Transaction needs a change address, but we can't generate it. Please call keypoolrefill first. - Transaktion benötigt eine Wechselgeld-Adresse. Diese kann aber nicht erstellt werden. Bitte vorher keypoolrefill aufrufen. - WARNING! Failed to replenish keypool, please unlock your wallet to do so. WARNUNG! Erzeugen neuer Schlüssel ist fehlgeschlagen, bitte entsperren Sie Ihre Wallet um dies zu ermöglichen. @@ -5188,10 +5534,6 @@ Gehen Sie zu "Datei" > "Wallet öffnen" um Wallet zu laden Error: No addresses available. Fehler: Keine Adresse verfügbar. - - Exceeded max tries. - Maximale Zahl an Versuchen überschritten. - Failed to create backup %s! Datensicherung %s ist fehlgeschlagen! @@ -5232,10 +5574,6 @@ Gehen Sie zu "Datei" > "Wallet öffnen" um Wallet zu laden Invalid P2P permission: '%s' Ungültige P2P-Erlaubnis: '%s' - - Invalid amount for -fallbackfee=<amount>: '%s' - Ungültiger Betrag für -fallbackfee=<amount>: '%s' - Invalid masternodeblsprivkey. Please see documentation. Ungültiger masternodeblsprivkey. Weitere Informationen befinden sich in der Dokumentation. @@ -5372,10 +5710,6 @@ Gehen Sie zu "Datei" > "Wallet öffnen" um Wallet zu laden Unable to open %s for writing Es ist nicht möglich %s zum Beschreiben zu öffnen - - Unable to parse -maxuploadtarget: '%s' (possible integer overflow?) - Nicht möglich zu parsen -maxuploadtarget: '%s' (möglicher Integer-Overflow?) - Unknown -blockfilterindex value %s. Nicht bekannter -blockfilterindex Wert %s. @@ -5384,10 +5718,6 @@ Gehen Sie zu "Datei" > "Wallet öffnen" um Wallet zu laden Unknown new rules activated (versionbit %i) Unbekannte neue Regeln aktiviert (versionbit %i) - - Upgrading UTXO database - Aktualisierung der UTXO Datenbank - Verifying blocks… Verifiziere Blöcke… @@ -5448,10 +5778,6 @@ Gehen Sie zu "Datei" > "Wallet öffnen" um Wallet zu laden Cannot obtain a lock on data directory %s. %s is probably already running. Datenverzeichnis %s kann nicht gesperrt werden. Evtl. wurde %s bereits gestartet. - - Cannot upgrade a non HD wallet from version %i to version %i which is non-HD wallet. Use upgradetohd RPC - Non-HD-Wallet kann nicht von Version %i zu Version %i geupgradet werden, die eine Nicht-HD-Wallet ist. upgradetohd RPC benutzten. - Distributed under the MIT software license, see the accompanying file %s or %s Veröffentlicht unter der MIT-Softwarelizenz, siehe beiligende Datei %s oder %s. @@ -5484,6 +5810,10 @@ Gehen Sie zu "Datei" > "Wallet öffnen" um Wallet zu laden Failed to rename invalid peers.dat file. Please move or delete it and try again. Ungültige Datei peers.dat konnte nicht umbenannt werden. Bitte verschieben oder löschen Sie sie und versuchen Sie es erneut. + + Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable %s. + Gebührenschätzung fehlgeschlagen. Fallback-Gebühr ist deaktiviert. Warten Sie einige Blöcke oder aktivieren Sie %s. + File %s already exists. If you are sure this is what you want, move it out of the way first. Datei %s existiert bereits. Wenn Sie sicher sind, müssen Sie diese Datei vorher beseitigen. @@ -5496,6 +5826,10 @@ Gehen Sie zu "Datei" > "Wallet öffnen" um Wallet zu laden Incorrect or no devnet genesis block found. Wrong datadir for devnet specified? Fehlerhafter oder kein Genesis-Block gefunden. Falsches Datenverzeichnis für devnet ausgewählt? + + Invalid amount for %s=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions) + Ungültiger Betrag für %s=<amount>: '%s' (muss mindestens die Mindestrelay-Gebühr von %s betragen, um festsitzende Transaktionen zu vermeiden) + 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. Ungültige oder beschädigte peers.dat (%s). Wenn Sie glauben, dass dies ein Bug ist, melden Sie ihn bitte an %s. Als Abhilfe können Sie die Datei (%s) beseitigen (umbenennen, verschieben oder löschen), damit beim nächsten Start eine neue Datei erstellt wird. @@ -5512,6 +5846,10 @@ Gehen Sie zu "Datei" > "Wallet öffnen" um Wallet zu laden No wallet file format provided. To use createfromdump, -format=<format> must be provided. Kein Wallet-Format bereits gestellt. Um createfromdump zu nutzen, muss -format=<format> must geliefert werden. + + Outbound connections restricted to CJDNS (-onlynet=cjdns) but -cjdnsreachable is not provided + Ausgehende Verbindungen sind auf CJDNS beschränkt (-onlynet=cjdns), aber -cjdnsreachable wurde nicht angegeben + Outbound connections restricted to Tor (-onlynet=onion) but the proxy for reaching the Tor network is explicitly forbidden: -onion=0 Ausgehende Verbindungen sind auf Tor beschränkt (-onlynet=onion), aber der Proxy zum Erreichen des Tor-Netzwerks ist explizit verboten: -onion=0 @@ -5520,6 +5858,10 @@ Gehen Sie zu "Datei" > "Wallet öffnen" um Wallet zu laden 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 Ausgehende Verbindungen sind auf Tor beschränkt (-onlynet=onion), aber der Proxy zum Erreichen des Tor-Netzwerks wurde nicht bereit gestellt: keine der -proxy, -onion oder -listenonion wurde angegeben. + + Outbound connections restricted to i2p (-onlynet=i2p) but -i2psam is not provided + Ausgehende Verbindungen sind auf i2p beschränkt (-onlynet=i2p), aber -i2psam wurde nicht angegeben + Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly. Bitte korrigieren Sie die Datums- und Uhrzeiteinstellungen Ihres Computers, da %s ansonsten nicht ordnungsgemäß funktionieren wird. @@ -5532,10 +5874,6 @@ Gehen Sie zu "Datei" > "Wallet öffnen" um Wallet zu laden Prune mode is incompatible with -reindex-chainstate. Use full -reindex instead. Prune Mode ist mit -reindex-chainstate nicht kompatibel. Stattdessen -reindex nutzen. - - The block index db contains a legacy 'txindex'. To clear the occupied disk space, run a full -reindex, otherwise ignore this error. This error message will not be displayed again. - Der Blockindex db enthält einen veralteten 'txindex'. Um den belegten Speicherplatz zu löschen, führen Sie einen vollständigen -reindex aus, andernfalls ignorieren Sie diesen Fehler. Diese Fehlermeldung wird nicht mehr angezeigt. - This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection. Dies ist die maximale Transaktionsgebühr (zusätzliche zur normalen Gebühr) die du zahlst, um dein die Vermeidung von Partial Spend gegenüber der normalen Coin-Auswahl zu priorisieren. @@ -5548,6 +5886,10 @@ Gehen Sie zu "Datei" > "Wallet öffnen" um Wallet zu laden This is the transaction fee you may pay when fee estimates are not available. Das ist die Transaktionsgebühr, welche du zahlen müsstest, wenn die Gebührenschätzungen nicht verfügbar sind. + + Transaction requires one destination of non-0 value, a non-0 feerate, or a pre-selected input + Transaktion erfordert ein Ziel mit Nicht-Null-Wert, einen Nicht-Null-Gebührensatz oder eine vorausgewählte Eingabe + Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate. Blöcke können nicht wiederholt werden. Sie müssen die Datenbank mit Hilfe von -reindex-chainstate neu aufbauen. @@ -5556,6 +5898,10 @@ Gehen Sie zu "Datei" > "Wallet öffnen" um Wallet zu laden Unknown wallet file format "%s" provided. Please provide one of "bdb" or "sqlite". Unbekanntes Wallet-Dateiformat "%s" angegeben. Bitte entweder "bdb" oder "sqlite" nutzen + + Unsupported chainstate database format found. Please restart with -reindex-chainstate. This will rebuild the chainstate database. + Nicht unterstütztes Chainstate-Datenbankformat gefunden. Bitte starten Sie mit -reindex-chainstate neu. Dies wird die Chainstate-Datenbank neu aufbauen. + Warning: Dumpfile wallet format "%s" does not match command line specified format "%s". Warnung: Dumpfile-Wallet-Format "%s" stimmt nicht mit dem in der Befehlszeile angegebenen Format "%s" überein. @@ -5596,10 +5942,30 @@ Gehen Sie zu "Datei" > "Wallet öffnen" um Wallet zu laden -rpcport must be specified when -devnet and -server are specified -rpcport muss angegeben werden, wenn -devnet und -server angeben wurden + + -statsbatchsize cannot be configured with a negative value. + -statsbatchsize kann nicht mit einem negativen Wert konfiguriert werden. + + + -statsduration cannot be configured with a negative value. + -statsduration kann nicht mit einem negativen Wert konfiguriert werden. + A fatal internal error occurred, see debug.log for details Schwerwiegender interner Fehler aufgetreten, siehe debug.log für Details + + Cannot create socket (socket() returned error %s) + Socket kann nicht erstellt werden (socket() gab Fehler %s zurück) + + + Cannot get socket address for %s + Socket-Adresse für %s kann nicht ermittelt werden + + + Cannot init Statsd client + Statsd-Client kann nicht initialisiert werden + Cannot resolve -%s address: '%s' Kann Adresse in -%s nicht auflösen: '%s' @@ -5644,10 +6010,6 @@ Gehen Sie zu "Datei" > "Wallet öffnen" um Wallet zu laden Error reading next record from wallet database Fehler beim Auslesen des nächsten Datensatzes aus der Wallet-Datenbank - - Error upgrading chainstate database - Fehler bei der Aktualisierung einer Kettenstatus-Datenbank - Loading P2P addresses… Lade P2P-Adressen… @@ -5768,10 +6130,70 @@ Gehen Sie zu "Datei" > "Wallet öffnen" um Wallet zu laden %s corrupt. Try using the wallet tool dash-wallet to salvage or restoring a backup. %s korrumpiert. Verwende das Wallet-Tool dash-wallet, um es zu retten, oder stelle ein Backup wieder her. + + %s is set very high! Fees this large could be paid on a single transaction. + %s ist sehr hoch eingestellt! Gebühren dieser Höhe könnten bei einer einzelnen Transaktion bezahlt werden. + + + %s request to listen on port %u. This port is considered "bad" and thus it is unlikely that any Dash Core peers connect to it. See doc/p2p-bad-ports.md for details and a full list. + %s Anfrage zum Abhören von Port %u. Dieser Port wird als "schlecht" angesehen. Es ist unwahrscheinlich, dass andere Dash-Core-Peers sich mit diesem verbinden. Siehe See doc/p2p-bad-ports.md für Details und die gesamte Liste. + + + Cannot provide specific connections and have addrman find outgoing connections at the same time. + Es ist nicht möglich, bestimmte Verbindungen anzubieten und addrman gleichzeitig ausgehende Verbindungen finden zu lassen. + + + Failed to upgrade Evo database + Upgrade der Evo-Datenbank fehlgeschlagen + + + Fee needed > fee paid + Benötigte Gebühr > bezahlte Gebühr + + + Host %s on unsupported network + Host %s im nicht unterstützten Netzwerk + + + Invalid amount for %s=<amount>: '%s' (must be at least %s) + Ungültiger Betrag für %s=<amount>: '%s' (muss mindestens %s sein) + + + Invalid amount for %s=<amount>: '%s' + Ungültiger Betrag für %s=<amount>: '%s' + + + Invalid port specified in %s: '%s' + Ungültiger Port in %s angegeben: '%s' + Last successful action was too recent. Letzte erfolgreiche Transaktion ist noch zu neu. + + Missing solving data for estimating transaction size + Fehlende Lösungsdaten zur Schätzung der Transaktionsgröße + + + No host specified + Kein Host angegeben + + + No host specified, malformed URL + Kein Host angegeben, fehlerhafte URL + + + No text before the scheme delimiter, malformed URL + Kein Text vor dem Schema-Trennzeichen, fehlerhafte URL + + + Port must be between %d and %d, supplied %d + Port muss zwischen %d und %d liegen, angegeben wurde %d + + + Socket not initialized, cannot send message + Socket nicht initialisiert, kann Nachricht nicht senden + The source code is available from %s. Der Quellcode ist von %s verfügbar. @@ -5800,6 +6222,10 @@ Gehen Sie zu "Datei" > "Wallet öffnen" um Wallet zu laden Transaction fees are too high. Transaktionsgebühren sind zu hoch. + + Transaction needs a change address, but we can't generate it. + Transaktion benötigt eine Wechselgeld-Adresse, aber wir können sie nicht generieren. + Transaction not valid. Transaktion ungültig. @@ -5820,6 +6246,18 @@ Gehen Sie zu "Datei" > "Wallet öffnen" um Wallet zu laden Unable to locate enough non-denominated funds for this transaction. Für diese Transaktion konnten nicht genug nicht mit gestückelte Beträge gefunden werden. + + Unable to lookup host %s + Host %s kann nicht aufgelöst werden + + + Unable to parse -maxuploadtarget: '%s' + -maxuploadtarget kann nicht geparst werden: '%s' + + + Unable to send message to %s (::sendto() returned error %s) + Nachricht kann nicht an %s gesendet werden (::sendto() gab Fehler %s zurück) + Unable to sign spork message, wrong key? Die Spork-Nachricht konnte nicht signiert werden. Wurde der Key falsch gesetzt? @@ -5832,6 +6270,10 @@ Gehen Sie zu "Datei" > "Wallet öffnen" um Wallet zu laden Unknown state: id = %u Unbekannter Status: id = %u + + Unsupported URL scheme, must begin with udp:// + Nicht unterstütztes URL-Schema, muss mit udp:// beginnen + Unsupported logging category %s=%s. Nicht unterstützte Protokollkategorie %s=%s. diff --git a/src/qt/locale/dash_en.ts b/src/qt/locale/dash_en.ts index 4d01405250eb..30ef1b6b193a 100644 --- a/src/qt/locale/dash_en.ts +++ b/src/qt/locale/dash_en.ts @@ -50,7 +50,7 @@ - + &Delete &Delete @@ -70,7 +70,7 @@ C&lose - + Choose the address to send coins to Choose the address to send coins to @@ -86,16 +86,6 @@ - Sending addresses - Sending addresses - - - - Receiving addresses - Receiving addresses - - - These are your Dash addresses for sending payments. Always check the amount and the receiving address before sending coins. These are your Dash addresses for sending payments. Always check the amount and the receiving address before sending coins. @@ -125,7 +115,7 @@ Show address &QR code - + QR code QR code @@ -147,7 +137,17 @@ There was an error trying to save the address list to %1. Please try again. - + + Sending addresses - %1 + Sending addresses - %1 + + + + Receiving addresses - %1 + Receiving addresses - %1 + + + Exporting Failed Exporting Failed @@ -274,7 +274,7 @@ Change passphrase - + Confirm wallet encryption Confirm wallet encryption @@ -291,12 +291,12 @@ - + Wallet encrypted Wallet encrypted - + 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>. 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>. @@ -306,7 +306,7 @@ Enter the old passphrase and new passphrase for the wallet. - + Remember that encrypting your wallet cannot fully protect your funds from being stolen by malware infecting your computer. Remember that encrypting your wallet cannot fully protect your funds from being stolen by malware infecting your computer. @@ -339,41 +339,57 @@ - - + Wallet encryption failed Wallet encryption failed - + Wallet encryption failed due to an internal error. Your wallet was not encrypted. Wallet encryption failed due to an internal error. Your wallet was not encrypted. - + The supplied passphrases do not match. The supplied passphrases do not match. - - + + + Wallet unlock failed Wallet unlock failed - - + + The passphrase entered for the wallet decryption was incorrect. The passphrase entered for the wallet decryption was incorrect. - + + 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 23.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. + 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 23.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. + + + Wallet passphrase was successfully changed. Wallet passphrase was successfully changed. - + + + Passphrase change failed + Passphrase change failed + + + + 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 23.0, please try again with only the characters up to — but not including — the first null character. + 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 23.0, please try again with only the characters up to — but not including — the first null character. + + + Warning: The Caps Lock key is on! Warning: The Caps Lock key is on! @@ -395,7 +411,7 @@ BitcoinAmountField - + Amount in %1 Amount in %1 @@ -403,7 +419,7 @@ BitcoinApplication - + Runaway exception Runaway exception @@ -426,7 +442,7 @@ BitcoinGUI - + &Overview &Overview @@ -436,7 +452,7 @@ Show general overview of wallet - + &Send &Send @@ -446,7 +462,7 @@ Send coins to a Dash address - + &Receive &Receive @@ -466,7 +482,7 @@ &Options… - + &Encrypt Wallet… &Encrypt Wallet… @@ -501,12 +517,7 @@ &Load PSBT from file… - - Load PSBT from clipboard… - Load PSBT from clipboard… - - - + &Sending addresses &Sending addresses @@ -536,22 +547,17 @@ Close wallet - + No wallets available No wallets available - + &Window &Window - - Minimize - Minimize - - - + Zoom Zoom @@ -581,7 +587,7 @@ Browse masternodes - + E&xit E&xit @@ -616,17 +622,7 @@ Modify configuration options for %1 - - &Show / Hide - &Show / Hide - - - - Show or hide the main Window - Show or hide the main Window - - - + Encrypt the private keys that belong to your wallet Encrypt the private keys that belong to your wallet @@ -706,12 +702,7 @@ Show wallet repair options - - Open Wallet &Configuration File - Open Wallet &Configuration File - - - + Open configuration file Open configuration file @@ -736,7 +727,7 @@ Show the list of used receiving addresses and labels - + &Command-line options &Command-line options @@ -746,44 +737,54 @@ Show the %1 help message to get a list with possible Dash command-line options - + default wallet default wallet - + %1 client %1 client - + Wallet: %1 Wallet: %1 - + Wallet is <b>unencrypted</b> Wallet is <b>unencrypted</b> - + &File &File - + Show information about %1 Show information about %1 - + + Load PSBT from &clipboard… + Load PSBT from &clipboard… + + + Open debugging and diagnostic console Open debugging and diagnostic console - + + Open &wallet configuration file + Open &wallet configuration file + + + Open a dash: URI Open a dash: URI @@ -792,6 +793,18 @@ Create a new wallet Create a new wallet + + + Restore Wallet… + Name of the menu item that restores wallet from a backup file. + Restore Wallet… + + + + Restore a wallet from a backup file + Status tip for Restore Wallet menu item + Restore a wallet from a backup file + Close all wallets @@ -818,12 +831,41 @@ - + + Wallet Data + Name of the wallet data file format. + Wallet Data + + + + Load Wallet Backup + The title for Restore Wallet File Windows + Load Wallet Backup + + + + Restore Wallet + Title of pop-up window shown when the user is attempting to restore a wallet. + Restore Wallet + + + + Wallet Name + Label of the input field where the name of the wallet is entered. + Wallet Name + + + &Settings &Settings - + + &Minimize + &Minimize + + + &Help &Help @@ -842,8 +884,18 @@ View Governance Proposals View Governance Proposals + + + &Hide + &Hide + + + + S&how + S&how + - + %n active connection(s) to Dash network A substring of the tooltip. @@ -857,7 +909,7 @@ Network activity disabled - + Processed %n block(s) of transaction history. Processed %n block of transaction history. @@ -870,7 +922,7 @@ %1 behind - + Close Wallet… Close Wallet… @@ -890,7 +942,7 @@ Create Wallet… - + Close All Wallets… Close All Wallets… @@ -900,12 +952,12 @@ Ctrl+Shift+D - + Ctrl+M Ctrl+M - + Click for more actions. A substring of the tooltip. "More actions" are available via the context menu. Click for more actions. @@ -934,7 +986,7 @@ Syncing Headers (%1%)… - + Synchronizing with network… Synchronizing with network… @@ -949,12 +1001,7 @@ Processing blocks on disk… - - Reindexing blocks on disk… - Reindexing blocks on disk… - - - + Connecting to peers… Connecting to peers… @@ -1088,7 +1135,7 @@ HD key generation is <b>enabled</b> - + Wallet is <b>encrypted</b> and currently <b>unlocked</b> Wallet is <b>encrypted</b> and currently <b>unlocked</b> @@ -1116,7 +1163,7 @@ CoinControlDialog - + Quantity: Quantity: @@ -1131,22 +1178,17 @@ Amount: - + Fee: Fee: - + Coin Selection Coin Selection - - Dust: - Dust: - - - + After Fee: After Fee: @@ -1216,7 +1258,7 @@ Confirmed - + Copy amount Copy amount @@ -1270,48 +1312,28 @@ Copy bytes Copy bytes - - - Copy dust - Copy dust - Copy change Copy change - + Please switch to "List mode" to use this function. Please switch to "List mode" to use this function. - + (%1 locked) (%1 locked) - - yes - yes - - - - no - no - - - - This label turns red if any recipient receives an amount smaller than the current dust threshold. - This label turns red if any recipient receives an amount smaller than the current dust threshold. - - - + Can vary +/- %1 duff(s) per input. Can vary +/- %1 duff(s) per input. - + Some coins were unselected because they were spent. Some coins were unselected because they were spent. @@ -1360,7 +1382,7 @@ CreateWalletActivity - + Create Wallet Title of window indicating the progress of creation of a new wallet. Create Wallet @@ -1372,7 +1394,7 @@ Creating Wallet <b>%1</b>… - + Create wallet failed Create wallet failed @@ -1569,25 +1591,140 @@ Filter proposal list - + + Masternode Count: + Masternode Count: + + + + Number of masternodes this wallet can vote with (masternodes for which this wallet holds the voting key) + Number of masternodes this wallet can vote with (masternodes for which this wallet holds the voting key) + + + Proposal Count: Proposal Count: - + + Create Proposal + Create Proposal + + + Filter by Title Filter by Title + Unavailable + Unavailable + + + + A synced node and an unlocked wallet are required. + A synced node and an unlocked wallet are required. + + + + Vote Yes + Vote Yes + + + + Vote No + Vote No + + + + Vote Abstain + Vote Abstain + + + Proposal Info: %1 Proposal Info: %1 + + + + + + + Voting Failed + Voting Failed + + + + No wallet available. + No wallet available. + + + + No masternode voting keys found in wallet. + No masternode voting keys found in wallet. + + + + Please select a proposal to vote on. + Please select a proposal to vote on. + + + + Unable to unlock wallet. + Unable to unlock wallet. + + + + Unable to get masternode list. Please try again later. + Unable to get masternode list. Please try again later. + + + + Masternode %1 not found + Masternode %1 not found + + + + Failed to sign vote for masternode %1 + Failed to sign vote for masternode %1 + + + + Masternode %1: %2 + Masternode %1: %2 + + + + Voted successfully %n time(s) + + Voted successfully %n time + Voted successfully %n times + + + + + Failed to vote %n time(s) + + Failed to vote %n time + Failed to vote %n times + + + + + Errors: + Errors: + + + + Voting Results + Voting Results + HelpMessageDialog - + version version @@ -1597,12 +1734,12 @@ About %1 - + Command-line options Command-line options - + %1 information %1 information @@ -1669,20 +1806,29 @@ Use a custom data directory: Use a custom data directory: - - - %1 GB of space available - %1 GB of space available + + + %n GB of space available + + %n GB of space available + %n GB of space available + - + - (of %1 GB needed) - (of %1 GB needed) + (of %n GB needed) + + (of %n GB needed) + (of %n GB needed) + - + - (%1 GB needed for full chain) - (%1 GB needed for full chain) + (%n GB needed for full chain) + + (%n GB needed for full chain) + (%n GB needed for full chain) + @@ -1724,6 +1870,14 @@ Error + + LoadWalletsActivity + + + Loading wallets… + Loading wallets… + + MasternodeList @@ -1817,7 +1971,7 @@ Voting Address - + Copy ProTx Hash Copy ProTx Hash @@ -1909,7 +2063,7 @@ - + Unknown… Unknown… @@ -1967,11 +2121,17 @@ URI: URI: - - + + + Paste address from clipboard + Tooltip text for button that allows you to paste an address that is in your clipboard. + Paste address from clipboard + + + OpenWalletActivity - + Open wallet failed Open wallet failed @@ -2103,6 +2263,18 @@ + Enable &PSBT controls + An options window setting to enable PSBT controls. + Enable &PSBT controls + + + + Whether to show PSBT controls. + Tooltip text for options window setting that enables PSBT controls. + Whether to show PSBT controls. + + + Whether to keep the specified custom change address or not. Whether to keep the specified custom change address or not. @@ -2281,28 +2453,28 @@ https://explore.transifex.com/dash/dash/ https://explore.transifex.com/dash/dash/ - - Options set in this dialog are overridden by the command line or in the configuration file: - Options set in this dialog are overridden by the command line or in the configuration file: + + + Third-party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items.<br/>%s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |. + Third-party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items.<br/>%s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |. - - 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. - 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. + + &Third-party transaction URLs + &Third-party transaction URLs - - - Third party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items.<br/>%s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |. - Third party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items.<br/>%s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |. + + Options set in this dialog are overridden by the command line or in the configuration file: + Options set in this dialog are overridden by the command line or in the configuration file: - - &Third party transaction URLs - &Third party transaction URLs + + 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. + 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. - + Whether to show coin control features or not. Whether to show coin control features or not. @@ -2322,7 +2494,7 @@ https://explore.transifex.com/dash/dash/ Enable coin &control features - + &Spend unconfirmed change &Spend unconfirmed change @@ -2332,7 +2504,7 @@ https://explore.transifex.com/dash/dash/ This setting determines the amount of individual masternodes that an input will be mixed through.<br/>More rounds of mixing gives a higher degree of privacy, but also costs more in fees. - + &Network &Network @@ -2342,7 +2514,7 @@ https://explore.transifex.com/dash/dash/ 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. - + Map port using &UPnP Map port using &UPnP @@ -2396,7 +2568,7 @@ https://explore.transifex.com/dash/dash/ Tor - + Show only a tray icon after minimizing the window. Show only a tray icon after minimizing the window. @@ -2416,7 +2588,7 @@ https://explore.transifex.com/dash/dash/ &Display - + Connect to the Dash network through a separate SOCKS5 proxy for Tor onion services. Connect to the Dash network through a separate SOCKS5 proxy for Tor onion services. @@ -2471,7 +2643,7 @@ https://explore.transifex.com/dash/dash/ &Cancel - + Enable %1 features Enable %1 features @@ -2481,23 +2653,32 @@ https://explore.transifex.com/dash/dash/ default - + Confirm options reset + Window title text of pop-up window shown when the user has chosen to reset options. Confirm options reset - - + + Client restart required to activate changes. + Text explaining that the settings changed will not come into effect until the client is restarted. Client restart required to activate changes. - + + Current settings will be backed up at "%1". + 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. + Current settings will be backed up at "%1". + + + Client will be shut down. Do you want to proceed? + Text asking the user to confirm if they would like to proceed with a client shutdown. Client will be shut down. Do you want to proceed? - + This change would require a client restart. This change would require a client restart. @@ -2654,29 +2835,30 @@ https://explore.transifex.com/dash/dash/ out of sync - + Automatic backups are disabled, no mixing available! Automatic backups are disabled, no mixing available! - + No inputs detected No inputs detected - + %1 Balance %1 Balance - + Discreet mode activated for the Overview tab. To unmask the values, uncheck Settings->Discreet mode. Discreet mode activated for the Overview tab. To unmask the values, uncheck Settings->Discreet mode. - - + + + %n Rounds @@ -2695,7 +2877,7 @@ https://explore.transifex.com/dash/dash/ Not enough compatible inputs to mix <span style='%1'>%2</span>,<br>will mix <span style='%1'>%3</span> instead - + Overall progress Overall progress @@ -2842,7 +3024,7 @@ https://explore.transifex.com/dash/dash/ Close - + Failed to load transaction: %1 Failed to load transaction: %1 @@ -2981,7 +3163,7 @@ https://explore.transifex.com/dash/dash/ PaymentServer - + Payment request error Payment request error @@ -2991,7 +3173,7 @@ https://explore.transifex.com/dash/dash/ Cannot start dash: click-to-pay handler - + @@ -3085,7 +3267,7 @@ Due to discontinued support, you should request the merchant to provide you with Network - + Inbound An Inbound Connection from a Peer. Inbound @@ -3100,7 +3282,7 @@ Due to discontinued support, you should request the merchant to provide you with Proposal - + Passing +%1 Passing +%1 @@ -3158,10 +3340,242 @@ Due to discontinued support, you should request the merchant to provide you with Status + + ProposalWizard + + + Create Governance Proposal + Create Governance Proposal + + + + Enter proposal details + Enter proposal details + + + + A fee will be burned when you prepare the proposal. + A fee will be burned when you prepare the proposal. + + + + Proposal &name + Proposal &name + + + + &Description URL + &Description URL + + + + Payment &address + Payment &address + + + + Payment &amount + Payment &amount + + + + The amount to request in a single payment + The amount to request in a single payment + + + + &First payment + &First payment + + + + Pa&yments + Pa&yments + + + + To&tal amount + To&tal amount + + + + Proposal &fee + Proposal &fee + + + + + + Next + Next + + + + Review proposal JSON and validate. + Review proposal JSON and validate. + + + + Hex-encoded JSON + Hex-encoded JSON + + + + + Back + Back + + + + Validate + Validate + + + + Prepare (burn fee) and wait for confirmations. + Prepare (burn fee) and wait for confirmations. + + + + + Copy + Copy + + + + At 1/6 confirmations: can be relayed and queued. At 6/6: accepted and processed. + At 1/6 confirmations: can be relayed and queued. At 6/6: accepted and processed. + + + + + Confirmations progress + Confirmations progress + + + + + Shows progress toward the required number of confirmations for the proposal fee transaction. + Shows progress toward the required number of confirmations for the proposal fee transaction. + + + + + Estimated time remaining: - + Estimated time remaining: - + + + + Prepare Proposal + Prepare Proposal + + + + You can submit after 1 confirmation. At 6 confirmations it is accepted and processed. + You can submit after 1 confirmation. At 6 confirmations it is accepted and processed. + + + + Proposal ID: + Proposal ID: + + + + Submit Proposal + Submit Proposal + + + + Close + Close + + + + Valid + Valid + + + + Invalid: %1 + Invalid: %1 + + + + Burn %1 + Burn %1 + + + + Burn %1 to create the fee transaction? + Burn %1 to create the fee transaction? + + + + + Prepare failed + Prepare failed + + + + + Confirmations: %1 / %2 required + Confirmations: %1 / %2 required + + + + + Estimated time remaining: Ready + Estimated time remaining: Ready + + + + + Estimated time remaining: %n minute(s) + + Estimated time remaining: %n minute + Estimated time remaining: %n minutes + + + + + Your proposal was submitted successfully. + Your proposal was submitted successfully. + + + + Already submitted + Already submitted + + + + This proposal has already been submitted. + This proposal has already been submitted. + + + + Submission failed + Submission failed + + + + Proposal submitted + Proposal submitted + + + + A fee of %1 will be burned when you prepare the proposal. + A fee of %1 will be burned when you prepare the proposal. + + + + Prepare (burn %1) and wait for %2 confirmations. + Prepare (burn %1) and wait for %2 confirmations. + + QObject - + Do you want to reset settings to default values, or to abort without making changes? Explanatory text shown on startup when the settings file cannot be read. Prompts user to make a choice between resetting or aborting. Do you want to reset settings to default values, or to abort without making changes? @@ -3173,7 +3587,7 @@ Due to discontinued support, you should request the merchant to provide you with A fatal error occurred. Check that settings file is writable, or try running with -nosettings. - + Choose data directory on startup (default: %u) Choose data directory on startup (default: %u) @@ -3218,17 +3632,17 @@ Due to discontinued support, you should request the merchant to provide you with Show splash screen on startup (default: %u) - + Error: Specified data directory "%1" does not exist. Error: Specified data directory "%1" does not exist. - + Error: Cannot parse configuration file: %1. Error: Cannot parse configuration file: %1. - + Error: %1 Error: %1 @@ -3273,12 +3687,12 @@ Due to discontinued support, you should request the merchant to provide you with %1 didn't yet exit safely… - + Amount Amount - + Enter a Dash address (e.g. %1) Enter a Dash address (e.g. %1) @@ -3298,7 +3712,7 @@ Due to discontinued support, you should request the merchant to provide you with This can also be adjusted later in the "Appearance" tab of the preferences. - + Ctrl+W Ctrl+W @@ -3355,7 +3769,7 @@ Due to discontinued support, you should request the merchant to provide you with Address Fetch - + %1 d %1 d @@ -3455,11 +3869,14 @@ Due to discontinued support, you should request the merchant to provide you with + %1 kB %1 kB + + %1 MB %1 MB @@ -3495,7 +3912,7 @@ Due to discontinued support, you should request the merchant to provide you with QRImageWidget - + &Save Image… &Save Image… @@ -3561,7 +3978,7 @@ Due to discontinued support, you should request the merchant to provide you with - + @@ -3601,28 +4018,28 @@ Due to discontinued support, you should request the merchant to provide you with - + N/A N/A - + Number of connections Number of connections - + &Open &Open - + Startup time Startup time - + Network Network @@ -3637,12 +4054,12 @@ Due to discontinued support, you should request the merchant to provide you with Debug log file - + Client version Client version - + Block chain Block chain @@ -3662,22 +4079,22 @@ Due to discontinued support, you should request the merchant to provide you with Memory usage - + &Console &Console - + Clear console Clear console - + &Network Traffic &Network Traffic - + Received Received @@ -3687,12 +4104,12 @@ Due to discontinued support, you should request the merchant to provide you with Sent - + &Peers &Peers - + Wallet: Wallet: @@ -3703,7 +4120,7 @@ Due to discontinued support, you should request the merchant to provide you with - + Select a peer to view detailed information. Select a peer to view detailed information. @@ -3713,17 +4130,7 @@ Due to discontinued support, you should request the merchant to provide you with Version - - Whether the peer requested us to relay transactions. - Whether the peer requested us to relay transactions. - - - - Wants Tx Relay - Wants Tx Relay - - - + High bandwidth BIP152 compact block relay: %1 High bandwidth BIP152 compact block relay: %1 @@ -3828,13 +4235,13 @@ Due to discontinued support, you should request the merchant to provide you with -rescan=2: Rescan the block chain for missing wallet transactions starting from genesis block. - - + + User Agent User Agent - + Datadir Datadir @@ -3855,6 +4262,16 @@ Due to discontinued support, you should request the merchant to provide you with + Local Addresses + Local Addresses + + + + Network addresses that your Dash node is currently using to communicate with other nodes. + Network addresses that your Dash node is currently using to communicate with other nodes. + + + Number of regular Masternodes Number of regular Masternodes @@ -3969,7 +4386,17 @@ Due to discontinued support, you should request the merchant to provide you with Services - + + Whether we relay transactions to this peer. + Whether we relay transactions to this peer. + + + + Transaction Relay + Transaction Relay + + + Connection Time Connection Time @@ -4009,12 +4436,12 @@ Due to discontinued support, you should request the merchant to provide you with Time Offset - + &Wallet Repair &Wallet Repair - + The total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting). 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). The total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting). @@ -4041,7 +4468,7 @@ Due to discontinued support, you should request the merchant to provide you with -reindex: Rebuild block chain index from current blk000??.dat files. - + Inbound: initiated by peer Explanatory text for an inbound peer connection. Inbound: initiated by peer @@ -4137,7 +4564,7 @@ Due to discontinued support, you should request the merchant to provide you with &Unban - + In: In: @@ -4152,18 +4579,23 @@ Due to discontinued support, you should request the merchant to provide you with Network activity disabled - + + None + None + + + Total: %1 (Enabled: %2) Total: %1 (Enabled: %2) - + Executing command without any wallet Executing command without any wallet - + Ctrl++ Main shortcut to increase the RPC console font size. Ctrl++ @@ -4187,7 +4619,7 @@ Due to discontinued support, you should request the merchant to provide you with Ctrl+_ - + Ctrl+Shift+I Ctrl+Shift+I @@ -4217,7 +4649,7 @@ Due to discontinued support, you should request the merchant to provide you with Executing command using "%1" wallet - + detecting: peer could be v1 or v2 Explanatory text for "detecting" transport type. detecting: peer could be v1 or v2 @@ -4252,7 +4684,7 @@ Due to discontinued support, you should request the merchant to provide you with &Copy IP/Netmask - + 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. @@ -4270,7 +4702,7 @@ 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 - + Executing… A console message indicating an entered command is currently being executed. Executing… @@ -4286,7 +4718,7 @@ For more information on using this console, type %6. via %1 - + Regular Regular @@ -4311,7 +4743,7 @@ For more information on using this console, type %6. Unknown - + Never Never @@ -4415,7 +4847,7 @@ For more information on using this console, type %6. Enter a message to attach to the payment request - + Copy &URI Copy &URI @@ -4526,7 +4958,7 @@ For more information on using this console, type %6. Message - + (no label) (no label) @@ -4546,11 +4978,44 @@ For more information on using this console, type %6. Requested + + RestoreWalletActivity + + + Restore Wallet + Title of progress window which is displayed when wallets are being restored. + Restore Wallet + + + + Restoring Wallet <b>%1</b>… + Descriptive text of the restore wallets progress window which indicates to the user that wallets are currently being restored. + Restoring Wallet <b>%1</b>… + + + + Restore wallet failed + Title of message box which is displayed when the wallet could not be restored. + Restore wallet failed + + + + Restore wallet warning + Title of message box which is displayed when the wallet is restored with some warning. + Restore wallet warning + + + + Restore wallet message + Title of message box which is displayed when the wallet is successfully restored. + Restore wallet message + + SendCoinsDialog - + Send Coins Send Coins @@ -4570,7 +5035,7 @@ For more information on using this console, type %6. Insufficient funds! - + Quantity: Quantity: @@ -4585,22 +5050,17 @@ For more information on using this console, type %6. Amount: - + Fee: Fee: - - Dust: - Dust: - - - + Inputs… Inputs… - + After Fee: After Fee: @@ -4691,7 +5151,7 @@ For more information on using this console, type %6. - + Confirm the send action Confirm the send action @@ -4727,7 +5187,7 @@ For more information on using this console, type %6. Balance: - + Copy quantity Copy quantity @@ -4751,49 +5211,34 @@ For more information on using this console, type %6. Copy bytes Copy bytes - - - Copy dust - Copy dust - Copy change Copy change - + %1 (%2 blocks) %1 (%2 blocks) - - This will produce a Partially Signed Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet. - This will produce a Partially Signed Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet. - - - + using using - + %1 to %2 %1 to %2 - - Are you sure you want to send? - Are you sure you want to send? - - - + <b>(%1 of %2 entries displayed)</b> <b>(%1 of %2 entries displayed)</b> - + S&end mixed funds S&end mixed funds @@ -4818,12 +5263,7 @@ For more information on using this console, type %6. %1 to '%2' - - Do you want to draft this transaction? - Do you want to draft this transaction? - - - + %1 funds only %1 funds only @@ -4871,7 +5311,7 @@ For more information on using this console, type %6. Click to learn more - + Total Amount Total Amount @@ -4881,22 +5321,12 @@ For more information on using this console, type %6. or - + Confirm send coins Confirm send coins - - Confirm transaction proposal - Confirm transaction proposal - - - - Create Unsigned - Create Unsigned - - - + Save Transaction Data Save Transaction Data @@ -4906,22 +5336,41 @@ For more information on using this console, type %6. PSBT saved - + Watch-only balance: Watch-only balance: - - Send - Send - - - + Creates a Partially Signed Blockchain Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet. Creates a Partially Signed Blockchain Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet. - + + Do you want to create this transaction? + 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. + Do you want to create this transaction? + + + + Please, review your transaction proposal. This will produce a Partially Signed Blockchain Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet. + 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. + Please, review your transaction proposal. This will produce a Partially Signed Blockchain Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet. + + + + Please, review your transaction. You can create and send this transaction or create a Partially Signed Blockchain Transaction (PSBT), which you can save or copy and then sign with, e.g., an offline %1 wallet, or a PSBT-compatible hardware wallet. + 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. + Please, review your transaction. You can create and send this transaction or create a Partially Signed Blockchain Transaction (PSBT), which you can save or copy and then sign with, e.g., an offline %1 wallet, or a PSBT-compatible hardware wallet. + + + + Please, review your transaction. + Text to prompt a user to review the details of the transaction they are attempting to send. + Please, review your transaction. + + + To review recipient list click "Show Details…" To review recipient list click "Show Details…" @@ -4932,7 +5381,7 @@ For more information on using this console, type %6. Partially Signed Transaction (Binary) - + The recipient address is not valid. Please recheck. The recipient address is not valid. Please recheck. @@ -4975,7 +5424,7 @@ For more information on using this console, type %6. - + Warning: Invalid Dash address Warning: Invalid Dash address @@ -5003,7 +5452,7 @@ For more information on using this console, type %6. SendCoinsEntry - + Pay &To: Pay &To: @@ -5034,13 +5483,11 @@ For more information on using this console, type %6. - - Remove this entry Remove this entry - + &Label: &Label: @@ -5052,13 +5499,11 @@ For more information on using this console, type %6. - - A&mount: A&mount: - + The amount to send in the selected unit The amount to send in the selected unit @@ -5087,27 +5532,18 @@ For more information on using this console, type %6. A message that was attached to the dash: URI which will be stored with the transaction for your reference. Note: This message will not be sent over the Dash network. A message that was attached to the dash: URI which will be stored with the transaction for your reference. Note: This message will not be sent over the Dash network. + + + SendConfirmationDialog - - This is an unauthenticated payment request. - This is an unauthenticated payment request. - - - - This is an authenticated payment request. - This is an authenticated payment request. - - - - - Pay To: - Pay To: + + Send + Send - - - Memo: - Memo: + + Create Unsigned + Create Unsigned @@ -5338,7 +5774,7 @@ For more information on using this console, type %6. SplashScreen - + (press q to shutdown and continue later) (press q to shutdown and continue later) @@ -5373,27 +5809,10 @@ For more information on using this console, type %6. TransactionDesc - - - Open for %n more block(s) - - Open for %n more block - Open for %n more blocks - - - - - Open until %1 - Open until %1 - - - - conflicted - conflicted - - + 0/unconfirmed, %1 + 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. 0/unconfirmed, %1 @@ -5407,32 +5826,43 @@ For more information on using this console, type %6. not in memory pool - + abandoned + 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. abandoned - + + conflicted with a transaction with %1 confirmations + 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. + conflicted with a transaction with %1 confirmations + + + %1/unconfirmed + 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, and still not locked via ChainLocks. %1/unconfirmed - + %1 confirmations + 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 or locked via ChainLocks. %1 confirmations - + locked via ChainLocks + 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 and has been locked by ChainLocks. locked via ChainLocks - + verified via InstantSend + 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 has been locked by InstantSend. verified via InstantSend - + Status Status @@ -5613,7 +6043,7 @@ For more information on using this console, type %6. This pane shows a detailed description of the transaction - + Details for %1 Details for %1 @@ -5621,7 +6051,7 @@ For more information on using this console, type %6. TransactionTableModel - + Date Date @@ -5635,21 +6065,8 @@ For more information on using this console, type %6. Address / Label Address / Label - - - Open for %n more block(s) - - Open for %n more block - Open for %n more blocks - - - - Open until %1 - Open until %1 - - - + Unconfirmed Unconfirmed @@ -5764,7 +6181,7 @@ For more information on using this console, type %6. (n/a) - + (no label) (no label) @@ -5802,7 +6219,7 @@ For more information on using this console, type %6. TransactionView - + All All @@ -5963,7 +6380,13 @@ For more information on using this console, type %6. Show address &QR code - + + Show in %1 + 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. + Show in %1 + + + Export Transaction History Export Transaction History @@ -6055,7 +6478,7 @@ For more information on using this console, type %6. WalletController - + Close wallet Close wallet @@ -6097,14 +6520,14 @@ Go to File > Open Wallet to load a wallet. Create a new wallet - - + + Error Error - + Unable to decode PSBT from clipboard (invalid base64) Unable to decode PSBT from clipboard (invalid base64) @@ -6124,7 +6547,7 @@ Go to File > Open Wallet to load a wallet. PSBT file must be smaller than 100 MiB - + Unable to decode PSBT Unable to decode PSBT @@ -6132,12 +6555,12 @@ Go to File > Open Wallet to load a wallet. WalletModel - + Send Coins Send Coins - + default wallet default wallet @@ -6145,7 +6568,7 @@ Go to File > Open Wallet to load a wallet. WalletView - + &Export &Export @@ -6160,7 +6583,7 @@ Go to File > Open Wallet to load a wallet. Selected amount: - + Wallet Data Name of the wallet data file format. Wallet Data @@ -6191,7 +6614,7 @@ Go to File > Open Wallet to load a wallet. The wallet data was successfully saved to %1. - + Cancel Cancel @@ -6199,12 +6622,7 @@ Go to File > Open Wallet to load a wallet. dash-core - - Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee. - Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee. - - - + 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 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 @@ -6214,17 +6632,17 @@ Go to File > Open Wallet to load a wallet. This is a pre-release test build - use at your own risk - do not use for mining or merchant applications - + Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade. Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade. - + Already have that input. Already have that input. - + Collateral not valid. Collateral not valid. @@ -6274,7 +6692,7 @@ Go to File > Open Wallet to load a wallet. Error reading from database, shutting down. - + Error: Missing checksum Error: Missing checksum @@ -6289,17 +6707,12 @@ Go to File > Open Wallet to load a wallet. Error: Unable to write record to new wallet - + Failed to listen on any port. Use -listen=0 if you want this. Failed to listen on any port. Use -listen=0 if you want this. - - -maxtxfee is set very high! Fees this large could be paid on a single transaction. - -maxtxfee is set very high! Fees this large could be paid on a single transaction. - - - + Found unconfirmed denominated outputs, will wait till they confirm to continue. Found unconfirmed denominated outputs, will wait till they confirm to continue. @@ -6309,22 +6722,12 @@ Go to File > Open Wallet to load a wallet. Invalid -socketevents ('%s') specified. Only these modes are supported: %s - - Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions) - Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions) - - - + SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is supported SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is supported - - The -txindex upgrade started by a previous version cannot be completed. Restart with the previous version or run a full -reindex. - The -txindex upgrade started by a previous version cannot be completed. Restart with the previous version or run a full -reindex. - - - + Transaction index can't be disabled with governance validation enabled. Either start with -disablegovernance command line switch or enable transaction index. Transaction index can't be disabled with governance validation enabled. Either start with -disablegovernance command line switch or enable transaction index. @@ -6334,37 +6737,32 @@ Go to File > Open Wallet to load a wallet. Unsupported category-specific logging level -loglevel=%s. Expected -loglevel=<category>:<loglevel>. Valid categories: %s. Valid loglevels: %s. - + Can't mix: no compatible inputs found! Can't mix: no compatible inputs found! - + Entry exceeds maximum size. Entry exceeds maximum size. - Error upgrading Evo database - Error upgrading Evo database - - - Error upgrading evo database for EHF Error upgrading evo database for EHF - + Failed to commit Evo database Failed to commit Evo database - + Found enough users, signing ( waiting %s ) Found enough users, signing ( waiting %s ) - + Incompatible mode. Incompatible mode. @@ -6389,22 +6787,12 @@ Go to File > Open Wallet to load a wallet. Insufficient funds. - - Invalid amount for -discardfee=<amount>: '%s' - Invalid amount for -discardfee=<amount>: '%s' - - - - Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s) - Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s) - - - + Invalid minimum number of spork signers specified with -minsporkkeys Invalid minimum number of spork signers specified with -minsporkkeys - + Listening for incoming connections failed (listen returned error %s) Listening for incoming connections failed (listen returned error %s) @@ -6414,7 +6802,7 @@ Go to File > Open Wallet to load a wallet. Lock is already in place. - + Need to specify a port with -whitebind: '%s' Need to specify a port with -whitebind: '%s' @@ -6429,7 +6817,7 @@ Go to File > Open Wallet to load a wallet. No compatible Masternode found. - + Not enough funds to mix. Not enough funds to mix. @@ -6439,7 +6827,7 @@ Go to File > Open Wallet to load a wallet. Not in the Masternode list. - + Pruning blockstore… Pruning blockstore… @@ -6454,7 +6842,7 @@ Go to File > Open Wallet to load a wallet. Rescanning… - + Starting network threads… Starting network threads… @@ -6484,7 +6872,7 @@ Go to File > Open Wallet to load a wallet. Transaction change output index out of range - + Unable to start HTTP server. See debug log for details. Unable to start HTTP server. See debug log for details. @@ -6494,22 +6882,22 @@ Go to File > Open Wallet to load a wallet. Unknown response. - + Unsupported global logging level -loglevel=%s. Valid values: %s. Unsupported global logging level -loglevel=%s. Valid values: %s. - + User Agent comment (%s) contains unsafe characters. User Agent comment (%s) contains unsafe characters. - + Can't find random Masternode. Can't find random Masternode. - + %s can't be lower than %s %s can't be lower than %s @@ -6519,27 +6907,27 @@ Go to File > Open Wallet to load a wallet. %s is idle. - + Can't mix while sync in progress. Can't mix while sync in progress. - + Invalid netmask specified in -whitelist: '%s' Invalid netmask specified in -whitelist: '%s' - + Invalid script detected. Invalid script detected. - + %s file contains all private keys from this wallet. Do not share it with anyone! %s file contains all private keys from this wallet. Do not share it with anyone! - + Failed to create backup, file already exists! This could happen if you restarted wallet in less than 60 seconds. You can continue if you are ok with this. Failed to create backup, file already exists! This could happen if you restarted wallet in less than 60 seconds. You can continue if you are ok with this. @@ -6554,7 +6942,7 @@ Go to File > Open Wallet to load a wallet. More than one onion bind address is provided. Using %s for the automatically created Tor onion service. - + Prune configured below the minimum of %d MiB. Please use a higher number. Prune configured below the minimum of %d MiB. Please use a higher number. @@ -6564,12 +6952,12 @@ Go to File > Open Wallet to load a wallet. Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node) - + 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 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 - + The transaction amount is too small to send after the fee has been deducted The transaction amount is too small to send after the fee has been deducted @@ -6579,12 +6967,7 @@ Go to File > Open Wallet to load a wallet. Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments. - - Transaction needs a change address, but we can't generate it. Please call keypoolrefill first. - Transaction needs a change address, but we can't generate it. Please call keypoolrefill first. - - - + WARNING! Failed to replenish keypool, please unlock your wallet to do so. WARNING! Failed to replenish keypool, please unlock your wallet to do so. @@ -6609,12 +6992,12 @@ Go to File > Open Wallet to load a wallet. -maxmempool must be at least %d MB - + Automatic backups disabled Automatic backups disabled - + Cannot set -peerblockfilters without -blockfilterindex. Cannot set -peerblockfilters without -blockfilterindex. @@ -6644,7 +7027,7 @@ Go to File > Open Wallet to load a wallet. Error loading %s: Private keys can only be disabled during creation - + Error: Couldn't create cursor into database Error: Couldn't create cursor into database @@ -6679,12 +7062,7 @@ Go to File > Open Wallet to load a wallet. Error: No addresses available. - - Exceeded max tries. - Exceeded max tries. - - - + Failed to create backup %s! Failed to create backup %s! @@ -6704,12 +7082,12 @@ Go to File > Open Wallet to load a wallet. Failed to rescan the wallet during initialization - + Failed to verify database Failed to verify database - + Fee rate (%s) is lower than the minimum fee rate setting (%s) Fee rate (%s) is lower than the minimum fee rate setting (%s) @@ -6719,7 +7097,7 @@ Go to File > Open Wallet to load a wallet. Found enough users, signing… - + Ignoring duplicate -wallet %s. Ignoring duplicate -wallet %s. @@ -6734,17 +7112,12 @@ Go to File > Open Wallet to load a wallet. Invalid P2P permission: '%s' - - Invalid amount for -fallbackfee=<amount>: '%s' - Invalid amount for -fallbackfee=<amount>: '%s' - - - + Invalid masternodeblsprivkey. Please see documentation. Invalid masternodeblsprivkey. Please see documentation. - + Masternode queue is full. Masternode queue is full. @@ -6759,7 +7132,7 @@ Go to File > Open Wallet to load a wallet. Missing input transaction information. - + Mixing in progress… Mixing in progress… @@ -6774,12 +7147,12 @@ Go to File > Open Wallet to load a wallet. No errors detected. - + No matching denominations found for mixing. No matching denominations found for mixing. - + Not compatible with existing transactions. Not compatible with existing transactions. @@ -6789,7 +7162,7 @@ Go to File > Open Wallet to load a wallet. Not enough file descriptors available. - + Prune cannot be configured with a negative value. Prune cannot be configured with a negative value. @@ -6829,7 +7202,7 @@ Go to File > Open Wallet to load a wallet. Section [%s] is not recognized. - + Specified -walletdir "%s" does not exist Specified -walletdir "%s" does not exist @@ -6884,7 +7257,7 @@ Go to File > Open Wallet to load a wallet. Transaction must have at least one recipient - + Transaction too large Transaction too large @@ -6904,17 +7277,12 @@ Go to File > Open Wallet to load a wallet. Unable to generate initial keys - + Unable to open %s for writing Unable to open %s for writing - - Unable to parse -maxuploadtarget: '%s' (possible integer overflow?) - Unable to parse -maxuploadtarget: '%s' (possible integer overflow?) - - - + Unknown -blockfilterindex value %s. Unknown -blockfilterindex value %s. @@ -6924,12 +7292,7 @@ Go to File > Open Wallet to load a wallet. Unknown new rules activated (versionbit %i) - - Upgrading UTXO database - Upgrading UTXO database - - - + Verifying blocks… Verifying blocks… @@ -6969,17 +7332,17 @@ Go to File > Open Wallet to load a wallet. see debug.log for details. - + The %s developers The %s developers - + %s uses exact denominated amounts to send funds, you might simply need to mix some more coins. %s uses exact denominated amounts to send funds, you might simply need to mix some more coins. - + -reindex-chainstate option is not compatible with -blockfilterindex. Please temporarily disable blockfilterindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes. -reindex-chainstate option is not compatible with -blockfilterindex. Please temporarily disable blockfilterindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes. @@ -7005,11 +7368,6 @@ Go to File > Open Wallet to load a wallet. - Cannot upgrade a non HD wallet from version %i to version %i which is non-HD wallet. Use upgradetohd RPC - Cannot upgrade a non HD wallet from version %i to version %i which is non-HD wallet. Use upgradetohd RPC - - - Distributed under the MIT software license, see the accompanying file %s or %s Distributed under the MIT software license, see the accompanying file %s or %s @@ -7049,7 +7407,12 @@ Go to File > Open Wallet to load a wallet. Failed to rename invalid peers.dat file. Please move or delete it and try again. - + + Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable %s. + Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable %s. + + + File %s already exists. If you are sure this is what you want, move it out of the way first. File %s already exists. If you are sure this is what you want, move it out of the way first. @@ -7064,7 +7427,12 @@ Go to File > Open Wallet to load a wallet. Incorrect or no devnet genesis block found. Wrong datadir for devnet specified? - + + Invalid amount for %s=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions) + Invalid amount for %s=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions) + + + 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. 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. @@ -7083,6 +7451,11 @@ Go to File > Open Wallet to load a wallet. No wallet file format provided. To use createfromdump, -format=<format> must be provided. No wallet file format provided. To use createfromdump, -format=<format> must be provided. + + + Outbound connections restricted to CJDNS (-onlynet=cjdns) but -cjdnsreachable is not provided + Outbound connections restricted to CJDNS (-onlynet=cjdns) but -cjdnsreachable is not provided + Outbound connections restricted to Tor (-onlynet=onion) but the proxy for reaching the Tor network is explicitly forbidden: -onion=0 @@ -7095,6 +7468,11 @@ Go to File > Open Wallet to load a wallet. + Outbound connections restricted to i2p (-onlynet=i2p) but -i2psam is not provided + Outbound connections restricted to i2p (-onlynet=i2p) but -i2psam is not provided + + + Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly. Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly. @@ -7109,12 +7487,7 @@ Go to File > Open Wallet to load a wallet. Prune mode is incompatible with -reindex-chainstate. Use full -reindex instead. - - The block index db contains a legacy 'txindex'. To clear the occupied disk space, run a full -reindex, otherwise ignore this error. This error message will not be displayed again. - The block index db contains a legacy 'txindex'. To clear the occupied disk space, run a full -reindex, otherwise ignore this error. This error message will not be displayed again. - - - + This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection. This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection. @@ -7129,7 +7502,12 @@ Go to File > Open Wallet to load a wallet. This is the transaction fee you may pay when fee estimates are not available. - + + Transaction requires one destination of non-0 value, a non-0 feerate, or a pre-selected input + Transaction requires one destination of non-0 value, a non-0 feerate, or a pre-selected input + + + Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate. Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate. @@ -7139,7 +7517,12 @@ Go to File > Open Wallet to load a wallet. Unknown wallet file format "%s" provided. Please provide one of "bdb" or "sqlite". - + + Unsupported chainstate database format found. Please restart with -reindex-chainstate. This will rebuild the chainstate database. + Unsupported chainstate database format found. Please restart with -reindex-chainstate. This will rebuild the chainstate database. + + + Warning: Dumpfile wallet format "%s" does not match command line specified format "%s". Warning: Dumpfile wallet format "%s" does not match command line specified format "%s". @@ -7188,6 +7571,16 @@ Go to File > Open Wallet to load a wallet. -rpcport must be specified when -devnet and -server are specified -rpcport must be specified when -devnet and -server are specified + + + -statsbatchsize cannot be configured with a negative value. + -statsbatchsize cannot be configured with a negative value. + + + + -statsduration cannot be configured with a negative value. + -statsduration cannot be configured with a negative value. + A fatal internal error occurred, see debug.log for details @@ -7195,6 +7588,21 @@ Go to File > Open Wallet to load a wallet. + Cannot create socket (socket() returned error %s) + Cannot create socket (socket() returned error %s) + + + + Cannot get socket address for %s + Cannot get socket address for %s + + + + Cannot init Statsd client + Cannot init Statsd client + + + Cannot resolve -%s address: '%s' Cannot resolve -%s address: '%s' @@ -7249,12 +7657,7 @@ Go to File > Open Wallet to load a wallet. Error reading next record from wallet database - - Error upgrading chainstate database - Error upgrading chainstate database - - - + Loading P2P addresses… Loading P2P addresses… @@ -7274,7 +7677,7 @@ Go to File > Open Wallet to load a wallet. Loading wallet… - + Failed to clear fulfilled requests cache at %s Failed to clear fulfilled requests cache at %s @@ -7319,7 +7722,7 @@ Go to File > Open Wallet to load a wallet. Failed to start a new mixing queue - + Importing… Importing… @@ -7359,17 +7762,17 @@ Go to File > Open Wallet to load a wallet. Invalid -proxy address or hostname: '%s' - + Invalid amount for -%s=<amount>: '%s' Invalid amount for -%s=<amount>: '%s' - + Invalid spork address specified with -sporkaddr Invalid spork address specified with -sporkaddr - + Reducing -maxconnections from %d to %d, because of system limitations. Reducing -maxconnections from %d to %d, because of system limitations. @@ -7389,37 +7792,102 @@ Go to File > Open Wallet to load a wallet. Signing transaction failed - + Specified blocks directory "%s" does not exist. Specified blocks directory "%s" does not exist. - + Last queue was created too recently. Last queue was created too recently. - + %s corrupt. Try using the wallet tool dash-wallet to salvage or restoring a backup. %s corrupt. Try using the wallet tool dash-wallet to salvage or restoring a backup. + %s is set very high! Fees this large could be paid on a single transaction. + %s is set very high! Fees this large could be paid on a single transaction. + + + %s request to listen on port %u. This port is considered "bad" and thus it is unlikely that any Dash Core peers connect to it. See doc/p2p-bad-ports.md for details and a full list. %s request to listen on port %u. This port is considered "bad" and thus it is unlikely that any Dash Core peers connect to it. See doc/p2p-bad-ports.md for details and a full list. - + Cannot provide specific connections and have addrman find outgoing connections at the same time. Cannot provide specific connections and have addrman find outgoing connections at the same time. - + + Failed to upgrade Evo database + Failed to upgrade Evo database + + + + Fee needed > fee paid + Fee needed > fee paid + + + + Host %s on unsupported network + Host %s on unsupported network + + + + Invalid amount for %s=<amount>: '%s' (must be at least %s) + Invalid amount for %s=<amount>: '%s' (must be at least %s) + + + + Invalid amount for %s=<amount>: '%s' + Invalid amount for %s=<amount>: '%s' + + + + Invalid port specified in %s: '%s' + Invalid port specified in %s: '%s' + + + Last successful action was too recent. Last successful action was too recent. - + + Missing solving data for estimating transaction size + Missing solving data for estimating transaction size + + + + No host specified + No host specified + + + + No host specified, malformed URL + No host specified, malformed URL + + + + No text before the scheme delimiter, malformed URL + No text before the scheme delimiter, malformed URL + + + + Port must be between %d and %d, supplied %d + Port must be between %d and %d, supplied %d + + + + Socket not initialized, cannot send message + Socket not initialized, cannot send message + + + The source code is available from %s. The source code is available from %s. @@ -7455,6 +7923,11 @@ Go to File > Open Wallet to load a wallet. + Transaction needs a change address, but we can't generate it. + Transaction needs a change address, but we can't generate it. + + + Transaction not valid. Transaction not valid. @@ -7479,7 +7952,22 @@ Go to File > Open Wallet to load a wallet. Unable to locate enough non-denominated funds for this transaction. - + + Unable to lookup host %s + Unable to lookup host %s + + + + Unable to parse -maxuploadtarget: '%s' + Unable to parse -maxuploadtarget: '%s' + + + + Unable to send message to %s (::sendto() returned error %s) + Unable to send message to %s (::sendto() returned error %s) + + + Unable to sign spork message, wrong key? Unable to sign spork message, wrong key? @@ -7493,13 +7981,18 @@ Go to File > Open Wallet to load a wallet. Unknown state: id = %u Unknown state: id = %u + + + Unsupported URL scheme, must begin with udp:// + Unsupported URL scheme, must begin with udp:// + Unsupported logging category %s=%s. Unsupported logging category %s=%s. - + Very low number of keys left: %d Very low number of keys left: %d @@ -7549,7 +8042,7 @@ Go to File > Open Wallet to load a wallet. Your entries added successfully. - + Settings file could not be read Settings file could not be read diff --git a/src/qt/locale/dash_en.xlf b/src/qt/locale/dash_en.xlf index c4a01dee73ff..4276d5c132e0 100644 --- a/src/qt/locale/dash_en.xlf +++ b/src/qt/locale/dash_en.xlf @@ -1,3733 +1,3426 @@ - + - + Enter address or label to search - Enter address or label to search 27 - + Right-click to edit address or label - Right-click to edit address or label 37 - + Create a new address - Create a new address 64 - + &New - &New 67 - + Copy the currently selected address to the system clipboard - Copy the currently selected address to the system clipboard 77 - + &Copy - &Copy 80 - + Show QR code for the currently selected address - Show QR code for the currently selected address 90 - + &Show QR code - &Show QR code 93 - + Delete the currently selected address from the list - Delete the currently selected address from the list 103 - + &Delete - &Delete 106 - ../addressbookpage.cpp121 + ../addressbookpage.cpp117 - + Export the data in the current tab to a file - Export the data in the current tab to a file 129 - + &Export - &Export 132 - + C&lose - C&lose 148 - + - + Choose the address to send coins to - Choose the address to send coins to - 79 + 83 - + Choose the address to receive coins with - Choose the address to receive coins with - 80 + 84 - + C&hoose - C&hoose - 85 - - - Sending addresses - Sending addresses - 91 - - - Receiving addresses - Receiving addresses - 92 + 89 - + These are your Dash addresses for sending payments. Always check the amount and the receiving address before sending coins. - These are your Dash addresses for sending payments. Always check the amount and the receiving address before sending coins. - 99 + 95 - + These are your Dash addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses. - These are your Dash addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses. - 104 + 100 - + &Copy Address - &Copy Address - 112 + 108 - + Copy &Label - Copy &Label - 113 + 109 - + &Edit - &Edit - 114 + 110 - + Show address &QR code - Show address &QR code - 115 + 111 - + QR code - QR code - 239 + 236 - + Export Address List - Export Address List - 307 + 304 - + Comma separated file - Comma separated file - 310 + 307 Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values. - + There was an error trying to save the address list to %1. Please try again. - There was an error trying to save the address list to %1. Please try again. - 326 + 323 An error message. %1 is a stand-in argument for the name of the file we attempted to save to. - + + Sending addresses - %1 + 355 + + + Receiving addresses - %1 + 356 + + Exporting Failed - Exporting Failed - 323 + 320 - + - + Label - Label 165 - + Address - Address 165 - + (no label) - (no label) 203 - + - + Lighter - Lighter 60 350 - + Bolder - Bolder 116 406 - + Font Weight Normal: - Font Weight Normal: 134 - + Smaller - Smaller 158 - + Bigger - Bigger 223 - + Font Scale: - Font Scale: 241 - + Font Family: - Font Family: 277 - + Theme: - Theme: 313 - + Font Weight Bold: - Font Weight Bold: 326 - + - + Passphrase Dialog - Passphrase Dialog 26 - + Enter passphrase - Enter passphrase 56 - + New passphrase - New passphrase 70 - + Repeat new passphrase - Repeat new passphrase 84 - + Show passphrase - Show passphrase 98 - + - + Encrypt wallet - Encrypt wallet 58 - + This operation needs your wallet passphrase to unlock the wallet. - This operation needs your wallet passphrase to unlock the wallet. 61 69 - + Unlock wallet for mixing only - Unlock wallet for mixing only 66 - + Unlock wallet - Unlock wallet 74 - + Change passphrase - Change passphrase 77 - + Confirm wallet encryption - Confirm wallet encryption - 125 + 124 - + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR DASH</b>! - Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR DASH</b>! - 126 + 125 - + Are you sure you wish to encrypt your wallet? - Are you sure you wish to encrypt your wallet? - 126 + 125 - + Wallet encrypted - Wallet encrypted - 145 - 155 - 204 + 144 + 154 + 214 - + 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>. - 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>. 55 - + Enter the old passphrase and new passphrase for the wallet. - Enter the old passphrase and new passphrase for the wallet. 78 - + Remember that encrypting your wallet cannot fully protect your funds from being stolen by malware infecting your computer. - Remember that encrypting your wallet cannot fully protect your funds from being stolen by malware infecting your computer. - 133 + 132 - + Wallet to be encrypted - Wallet to be encrypted - 137 + 136 - + Your wallet is about to be encrypted. - Your wallet is about to be encrypted. - 139 + 138 - + Your wallet is now encrypted. - Your wallet is now encrypted. - 147 - 157 + 146 + 156 - + IMPORTANT: Any previous backups you have made of your wallet file should be replaced with the newly generated, encrypted wallet file. Previous backups of the unencrypted wallet file contain the same HD seed and still have full access to all your funds just like the new, encrypted wallet. - IMPORTANT: Any previous backups you have made of your wallet file should be replaced with the newly generated, encrypted wallet file. Previous backups of the unencrypted wallet file contain the same HD seed and still have full access to all your funds just like the new, encrypted wallet. - 149 + 148 - + 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. - 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. - 159 + 158 - + Wallet encryption failed - Wallet encryption failed - 166 - 174 - 210 - 216 + 165 + 173 + 236 - + Wallet encryption failed due to an internal error. Your wallet was not encrypted. - Wallet encryption failed due to an internal error. Your wallet was not encrypted. - 167 + 166 - + The supplied passphrases do not match. - The supplied passphrases do not match. - 175 - 217 + 174 + 237 - + Wallet unlock failed - Wallet unlock failed - 188 - 196 + 189 + 192 + 206 - + The passphrase entered for the wallet decryption was incorrect. - The passphrase entered for the wallet decryption was incorrect. - 189 - 211 + 190 + 223 + + + 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 23.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. + 193 - + Wallet passphrase was successfully changed. - Wallet passphrase was successfully changed. - 205 + 215 + + + Passphrase change failed + 222 + 225 + + + 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 23.0, please try again with only the characters up to — but not including — the first null character. + 226 - + Warning: The Caps Lock key is on! - Warning: The Caps Lock key is on! - 252 - 285 + 272 + 305 - + - + IP/Netmask - IP/Netmask 85 - + Banned Until - Banned Until 85 - + - + Amount in %1 - Amount in %1 - 292 + 293 - + - + Runaway exception - Runaway exception - 419 + 452 - + A fatal error occurred. %1 can no longer continue safely and will quit. - A fatal error occurred. %1 can no longer continue safely and will quit. - 420 + 453 - + Internal error - Internal error - 429 + 462 - + An internal error occurred. %1 will attempt to continue safely. This is an unexpected bug which can be reported as described below. - An internal error occurred. %1 will attempt to continue safely. This is an unexpected bug which can be reported as described below. - 430 + 463 - + Do you want to reset settings to default values, or to abort without making changes? - Do you want to reset settings to default values, or to abort without making changes? - 166 + 187 Explanatory text shown on startup when the settings file cannot be read. Prompts user to make a choice between resetting or aborting. - + A fatal error occurred. Check that settings file is writable, or try running with -nosettings. - A fatal error occurred. Check that settings file is writable, or try running with -nosettings. - 190 + 211 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. - + Choose data directory on startup (default: %u) - Choose data directory on startup (default: %u) - 455 + 488 - + Set the font family. Possible values: %1. (default: %2) - Set the font family. Possible values: %1. (default: %2) - 457 + 490 - + Set a scale factor which gets applied to the base font size. Possible range %1 (smallest fonts) to %2 (largest fonts). (default: %3) - Set a scale factor which gets applied to the base font size. Possible range %1 (smallest fonts) to %2 (largest fonts). (default: %3) - 458 + 491 - + Set the font weight for bold texts. Possible range %1 to %2 (default: %3) - Set the font weight for bold texts. Possible range %1 to %2 (default: %3) - 459 + 492 - + Set the font weight for normal texts. Possible range %1 to %2 (default: %3) - Set the font weight for normal texts. Possible range %1 to %2 (default: %3) - 460 + 493 - + Set language, for example "de_DE" (default: system locale) - Set language, for example "de_DE" (default: system locale) - 461 + 494 - + Start minimized - Start minimized - 462 + 495 - + Reset all settings changed in the GUI - Reset all settings changed in the GUI - 463 + 496 - + Show splash screen on startup (default: %u) - Show splash screen on startup (default: %u) - 464 + 497 - + Error: Specified data directory "%1" does not exist. - Error: Specified data directory "%1" does not exist. - 560 + 595 - + Error: Cannot parse configuration file: %1. - Error: Cannot parse configuration file: %1. - 566 + 604 - + Error: %1 - Error: %1 - 581 + 618 - + Error: Failed to load application fonts. - Error: Failed to load application fonts. - 632 + 669 - + Error: Specified font-family invalid. Valid values: %1. - Error: Specified font-family invalid. Valid values: %1. - 645 + 682 - + Error: Specified font-weight-normal invalid. Valid range %1 to %2. - Error: Specified font-weight-normal invalid. Valid range %1 to %2. - 655 + 692 - + Error: Specified font-weight-bold invalid. Valid range %1 to %2. - Error: Specified font-weight-bold invalid. Valid range %1 to %2. - 665 + 702 - + Error: Specified font-scale invalid. Valid range %1 to %2. - Error: Specified font-scale invalid. Valid range %1 to %2. - 676 + 713 - + Error: Invalid -custom-css-dir path. - Error: Invalid -custom-css-dir path. - 690 + 727 - + Error: %1 CSS file(s) missing in -custom-css-dir path. - Error: %1 CSS file(s) missing in -custom-css-dir path. - 710 + 747 - + %1 didn't yet exit safely… - %1 didn't yet exit safely… - 742 + 779 - + Settings file could not be read - Settings file could not be read - 159 + 180 - + Settings file could not be written - Settings file could not be written - 182 + 203 - + - + &Overview - &Overview - 683 + 703 - + Show general overview of wallet - Show general overview of wallet - 684 + 704 - + &Send - &Send - 356 + 353 - + Send coins to a Dash address - Send coins to a Dash address - 357 + 354 - + &Receive - &Receive - 365 + 360 - + Request payments (generates QR codes and dash: URIs) - Request payments (generates QR codes and dash: URIs) - 366 + 361 - + Ctrl+Q - Ctrl+Q - 382 + 377 - + &Options… - &Options… - 391 + 386 - + &Encrypt Wallet… - &Encrypt Wallet… - 398 + 391 - + &Backup Wallet… - &Backup Wallet… - 400 + 393 - + &Change Passphrase… - &Change Passphrase… - 402 + 395 - + &Unlock Wallet… - &Unlock Wallet… - 404 + 397 - + Sign &message… - Sign &message… - 407 + 400 - + &Verify message… - &Verify message… - 409 + 402 - + &Load PSBT from file… - &Load PSBT from file… - 411 - - - Load PSBT from clipboard… - Load PSBT from clipboard… - 413 + 404 - + &Sending addresses - &Sending addresses - 440 + 433 - + &Receiving addresses - &Receiving addresses - 442 + 435 - + Open &URI… - Open &URI… - 445 + 438 - + Open Wallet - Open Wallet - 448 + 441 - + Open a wallet - Open a wallet - 450 + 443 - + Close wallet - Close wallet - 454 + 447 - + No wallets available - No wallets available - 542 + 540 - + &Window - &Window - 611 - - - Minimize - Minimize - 613 + 631 - + Zoom - Zoom - 623 + 643 - + Main Window - Main Window - 641 + 661 - + &Transactions - &Transactions - 698 + 718 - + Browse transaction history - Browse transaction history - 699 + 719 - + &Masternodes - &Masternodes - 710 + 730 - + Browse masternodes - Browse masternodes - 711 + 731 - + E&xit - E&xit - 380 + 375 - + Quit application - Quit application - 381 + 376 - + About &Qt - About &Qt - 388 + 383 - + Show information about Qt - Show information about Qt - 389 + 384 - + &About %1 - &About %1 - 384 + 379 - + Send %1 funds to a Dash address - Send %1 funds to a Dash address - 362 + 357 - + Modify configuration options for %1 - Modify configuration options for %1 - 392 - - - &Show / Hide - &Show / Hide - 395 - - - Show or hide the main Window - Show or hide the main Window - 396 + 387 - + Encrypt the private keys that belong to your wallet - Encrypt the private keys that belong to your wallet - 399 + 392 - + Backup wallet to another location - Backup wallet to another location - 401 + 394 - + Change the passphrase used for wallet encryption - Change the passphrase used for wallet encryption - 403 + 396 - + Unlock wallet - Unlock wallet - 405 + 398 - + &Lock Wallet - &Lock Wallet - 406 + 399 - + Sign messages with your Dash addresses to prove you own them - Sign messages with your Dash addresses to prove you own them - 408 + 401 - + Verify messages to ensure they were signed with specified Dash addresses - Verify messages to ensure they were signed with specified Dash addresses - 410 + 403 - + &Information - &Information - 416 + 409 - + Show diagnostic information - Show diagnostic information - 417 + 410 - + &Debug console - &Debug console - 418 + 411 - + &Network Monitor - &Network Monitor - 420 + 413 - + Show network monitor - Show network monitor - 421 + 414 - + &Peers list - &Peers list - 422 + 415 - + Show peers info - Show peers info - 423 + 416 - + Wallet &Repair - Wallet &Repair - 424 + 417 - + Show wallet repair options - Show wallet repair options - 425 - - - Open Wallet &Configuration File - Open Wallet &Configuration File - 426 + 418 - + Open configuration file - Open configuration file - 427 + 420 - + Show Automatic &Backups - Show Automatic &Backups - 430 + 423 - + Show automatically created wallet backups - Show automatically created wallet backups - 431 + 424 - + Show the list of used sending addresses and labels - Show the list of used sending addresses and labels - 441 + 434 - + Show the list of used receiving addresses and labels - Show the list of used receiving addresses and labels - 443 + 436 - + &Command-line options - &Command-line options - 463 + 462 - + Show the %1 help message to get a list with possible Dash command-line options - Show the %1 help message to get a list with possible Dash command-line options - 465 + 464 - + default wallet - default wallet - 522 + 520 - + %1 client - %1 client - 1030 + 1060 - + Wallet: %1 - Wallet: %1 - - 1805 + 1862 - + Wallet is <b>unencrypted</b> - Wallet is <b>unencrypted</b> - 1880 + 1943 - + &File - &File - 575 + 593 - + Show information about %1 - Show information about %1 - 385 + 380 + + + Load PSBT from &clipboard… + 406 - + Open debugging and diagnostic console - Open debugging and diagnostic console + 412 + + + Open &wallet configuration file 419 - + Open a dash: URI - Open a dash: URI - 446 + 439 - + Create a new wallet - Create a new wallet - 458 + 451 - - Close all wallets - Close all wallets - 461 + + Restore Wallet… + 454 + Name of the menu item that restores wallet from a backup file. - + + Restore a wallet from a backup file + 457 + Status tip for Restore Wallet menu item + + + Close all wallets + 460 + + %1 &information - %1 &information - 467 + 466 - + Show the %1 basic information - Show the %1 basic information - 469 + 468 - + &Discreet mode - &Discreet mode - 471 + 470 - + Mask the values in the Overview tab - - 473 + 472 + + + Wallet Data + 546 + Name of the wallet data file format. + + + Load Wallet Backup + 549 + The title for Restore Wallet File Windows + + + Restore Wallet + 557 + Title of pop-up window shown when the user is attempting to restore a wallet. + + + Wallet Name + 559 + Label of the input field where the name of the wallet is entered. - + &Settings - &Settings - 598 + 618 - + + &Minimize + 633 + + &Help - &Help - 661 + 681 - + Tabs toolbar - Tabs toolbar - 674 + 694 - + &Governance - &Governance - 719 + 739 - + View Governance Proposals - View Governance Proposals - 720 + 740 + + + &Hide + 1121 + + + S&how + 1122 - 1293 + 1351 A substring of the tooltip. - + %n active connection(s) to Dash network - %n active connection to Dash network - + %n active connection(s) to Dash network - %n active connections to Dash network - + Network activity disabled - Network activity disabled - 1295 + 1353 - 1495 - + 1552 + Processed %n block(s) of transaction history. - Processed %n block of transaction history. - + Processed %n block(s) of transaction history. - Processed %n blocks of transaction history. - + %1 behind - %1 behind - 1514 + 1571 - + Close Wallet… - Close Wallet… - 453 + 446 - + Load Partially Signed Blockchain Transaction - - 412 + 405 - + Load Partially Signed Blockchain Transaction from clipboard - - 414 + 407 - + Create Wallet… - Create Wallet… - 456 + 449 - + Close All Wallets… - Close All Wallets… - 460 + 459 - + Ctrl+Shift+D - Ctrl+Shift+D - 472 + 471 - + Ctrl+M - Ctrl+M - 614 + 634 - + Click for more actions. - Click for more actions. - 1303 + 1361 A substring of the tooltip. "More actions" are available via the context menu. - + Show Peers tab - Show Peers tab - 1326 + 1384 A context menu item. The "Peers tab" is an element of the "Node window". - + Disable network activity - Disable network activity - 1334 + 1392 A context menu item. - + Enable network activity - Enable network activity - 1336 + 1394 A context menu item. The network activity was disabled previously. - + Syncing Headers (%1%)… - Syncing Headers (%1%)… - 1346 + 1404 - + Synchronizing with network… - Synchronizing with network… - 1469 + 1529 - + Indexing blocks on disk… - Indexing blocks on disk… - 1474 + 1534 - + Processing blocks on disk… - Processing blocks on disk… - 1476 - - - Reindexing blocks on disk… - Reindexing blocks on disk… - 1480 + 1536 - + Connecting to peers… - Connecting to peers… - 1486 + 1543 - + Catching up… - Catching up… - 1518 + 1575 - + Last received block was generated %1 ago. - Last received block was generated %1 ago. - 1528 + 1585 - + Transactions after this will not yet be visible. - Transactions after this will not yet be visible. - 1530 + 1587 - + Up to date - Up to date - 1569 + 1626 - + Synchronizing additional data: %p% - Synchronizing additional data: %p% - 1582 + 1639 - + Error - Error - 1613 + 1670 - + Error: %1 - Error: %1 - 1614 + 1671 - + Warning - Warning - 1617 + 1674 - + Warning: %1 - Warning: %1 - 1618 + 1675 - + Information - Information - 1621 + 1678 - + Received and sent multiple transactions - Received and sent multiple transactions - 1778 + 1835 - + Sent multiple transactions - Sent multiple transactions - 1780 + 1837 - + Received multiple transactions - Received multiple transactions - 1782 + 1839 - + Sent Amount: %1 - Sent Amount: %1 - - 1792 + 1849 - + Received Amount: %1 - Received Amount: %1 - - 1795 + 1852 - + Date: %1 - Date: %1 - - 1802 + 1859 - + Amount: %1 - Amount: %1 - - 1803 + 1860 - + Type: %1 - Type: %1 - - 1807 + 1864 - + Label: %1 - Label: %1 - - 1809 + 1866 - + Address: %1 - Address: %1 - - 1811 + 1868 - + Sent transaction - Sent transaction - 1812 + 1869 - + Incoming transaction - Incoming transaction - 1812 + 1869 - + HD key generation is <b>enabled</b> - HD key generation is <b>enabled</b> - 1867 + 1924 - + Wallet is <b>encrypted</b> and currently <b>unlocked</b> - Wallet is <b>encrypted</b> and currently <b>unlocked</b> - 1889 + 1952 - + Wallet is <b>encrypted</b> and currently <b>unlocked</b> for mixing only - Wallet is <b>encrypted</b> and currently <b>unlocked</b> for mixing only - 1898 + 1961 - + Wallet is <b>encrypted</b> and currently <b>locked</b> - Wallet is <b>encrypted</b> and currently <b>locked</b> - 1907 + 1970 - + Proxy is <b>enabled</b>: %1 - Proxy is <b>enabled</b>: %1 - 1939 + 2002 - + Original message: - Original message: - 2031 + 2094 - + Unit to show amounts in. Click to select another unit. - Unit to show amounts in. Click to select another unit. - 2078 + 2141 - + - + Quantity: - Quantity: - 42 + 45 - + Bytes: - Bytes: - 65 + 68 - + Amount: - Amount: - 104 + 107 - + Fee: - Fee: - 172 + 146 - + Coin Selection - Coin Selection 14 - - Dust: - Dust: - 130 - - + After Fee: - After Fee: - 211 + 188 - + Change: - Change: - 237 + 214 - + (un)select all - (un)select all - 293 + 270 - + toggle lock state - toggle lock state - 309 + 286 - + Tree mode - Tree mode - 341 + 318 - + List mode - List mode - 354 + 331 - + (1 locked) - (1 locked) - 364 + 341 - + Amount - Amount - 410 + 387 - + Received with label - Received with label - 415 + 392 - + Received with address - Received with address - 420 + 397 - + Mixing Rounds - Mixing Rounds - 425 + 402 - + Date - Date - 430 + 407 - + Confirmations - Confirmations - 435 + 412 - + Confirmed - Confirmed - 438 + 415 - + - + Copy amount - Copy amount - 78 + 79 - + &Copy address - &Copy address - 67 + 68 - + Copy &label - Copy &label - 68 + 69 - + Copy &amount - Copy &amount - 69 + 70 - + Copy transaction &ID and output index - Copy transaction &ID and output index - 70 + 71 - + L&ock unspent - L&ock unspent - 72 + 73 - + &Unlock unspent - &Unlock unspent - 73 + 74 - + Copy quantity - Copy quantity - 77 + 78 - + Copy fee - Copy fee - 79 - - - Copy after fee - Copy after fee 80 - - Copy bytes - Copy bytes + + Copy after fee 81 - - Copy dust - Copy dust + + Copy bytes 82 - + Copy change - Copy change 83 - + Please switch to "List mode" to use this function. - Please switch to "List mode" to use this function. - 222 + 220 - + (%1 locked) - (%1 locked) - 432 - - - yes - yes - 589 - - - no - no - 589 - - - This label turns red if any recipient receives an amount smaller than the current dust threshold. - This label turns red if any recipient receives an amount smaller than the current dust threshold. - 603 + 424 - + Can vary +/- %1 duff(s) per input. - Can vary +/- %1 duff(s) per input. - 608 + 580 - + Some coins were unselected because they were spent. - Some coins were unselected because they were spent. - 628 + 598 - + Show all coins - Show all coins - 652 + 622 - + Hide %1 coins - Hide %1 coins - 654 + 624 - + Show all %1 coins - Show all %1 coins - 658 + 628 - + Show spendable coins only - Show spendable coins only - 660 + 630 - + (no label) - (no label) - 680 - 755 + 650 + 725 - + change from %1 (%2) - change from %1 (%2) - 750 + 720 - + (change) - (change) - 751 + 721 - + n/a - n/a - 775 + 745 - + - + Create Wallet - Create Wallet - 258 + 244 Title of window indicating the progress of creation of a new wallet. - + Creating Wallet <b>%1</b>… - Creating Wallet <b>%1</b>… - 261 + 247 Descriptive text of the create wallet progress window which indicates to the user which wallet is currently being created. - + Create wallet failed - Create wallet failed - 289 + 277 - + Create wallet warning - Create wallet warning - 291 + 279 + + + + + Loading wallets… + 357 - + Open wallet failed - Open wallet failed - 330 + 316 - + Open wallet warning - Open wallet warning - 332 + 318 - + default wallet - default wallet - 342 + 328 - + Open Wallet - Open Wallet - 346 + 332 Title of window indicating the progress of opening of a wallet. - + Opening Wallet <b>%1</b>… - Opening Wallet <b>%1</b>… - 349 + 335 Descriptive text of the open wallet progress window which indicates to the user which wallet is currently being opened. + + + Restore Wallet + 379 + Title of progress window which is displayed when wallets are being restored. + + + Restoring Wallet <b>%1</b>… + 382 + Descriptive text of the restore wallets progress window which indicates to the user that wallets are currently being restored. + + + Restore wallet failed + 401 + Title of message box which is displayed when the wallet could not be restored. + + + Restore wallet warning + 404 + Title of message box which is displayed when the wallet is restored with some warning. + + + Restore wallet message + 407 + Title of message box which is displayed when the wallet is successfully restored. + + - + Close wallet - Close wallet - 88 + 84 - + Are you sure you wish to close the wallet <i>%1</i>? - Are you sure you wish to close the wallet <i>%1</i>? - 89 + 85 - + Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled. - Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled. - 90 + 86 - + Close all wallets - Close all wallets - 103 + 99 - + Are you sure you wish to close all wallets? - Are you sure you wish to close all wallets? - 104 + 100 - + - + Create Wallet - Create Wallet 14 - + Wallet Name - Wallet Name 25 - + Wallet - Wallet 38 - + Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice. - Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice. 47 - + Encrypt Wallet - Encrypt Wallet 50 - + Advanced Options - Advanced Options 76 - + 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. - 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. 85 - + Disable Private Keys - Disable Private Keys 88 - + 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. - 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. 95 - + Make Blank Wallet - Make Blank Wallet 98 - + Use descriptors for scriptPubKey management. This feature is well-tested but still considered experimental and not recommended for use yet. - Use descriptors for scriptPubKey management. This feature is well-tested but still considered experimental and not recommended for use yet. 105 - + Descriptor Wallet (EXPERIMENTAL) - Descriptor Wallet (EXPERIMENTAL) 108 - + - + Create - Create 21 - + Compiled without sqlite support (required for descriptor wallets) - Compiled without sqlite support (required for descriptor wallets) 62 - + - + Edit Address - Edit Address 14 - + &Label - &Label 25 - + The label associated with this address list entry - The label associated with this address list entry 35 - + &Address - &Address 42 - + The address associated with this address list entry. This can only be modified for sending addresses. - The address associated with this address list entry. This can only be modified for sending addresses. 52 - + - + New sending address - New sending address 31 - + Edit receiving address - Edit receiving address 34 - + Edit sending address - Edit sending address 38 - + The entered address "%1" is not a valid Dash address. - The entered address "%1" is not a valid Dash address. 114 - + Address "%1" already exists as a receiving address with label "%2" and so cannot be added as a sending address. - Address "%1" already exists as a receiving address with label "%2" and so cannot be added as a sending address. 147 - + The entered address "%1" is already in the address book with label "%2". - The entered address "%1" is already in the address book with label "%2". 152 - + Could not unlock wallet. - Could not unlock wallet. 124 - + New key generation failed. - New key generation failed. 129 - + - + A new data directory will be created. - A new data directory will be created. 74 - + name - name 96 - + Directory already exists. Add %1 if you intend to create a new directory here. - Directory already exists. Add %1 if you intend to create a new directory here. 98 - + Path already exists, and is not a directory. - Path already exists, and is not a directory. 101 - + Cannot create data directory here. - Cannot create data directory here. 108 - - %1 GB of space available - - 307 - - - (of %1 GB needed) - (of %1 GB needed) + 309 - - - (%1 GB needed for full chain) - (%1 GB needed for full chain) - 312 - - + + %n GB of space available + + + %n GB of space available + + + + 311 + + (of %n GB needed) + + + (of %n GB needed) + + + + 314 + + (%n GB needed for full chain) + + + (%n GB needed for full chain) + + + At least %1 GB of data will be stored in this directory, and it will grow over time. - At least %1 GB of data will be stored in this directory, and it will grow over time. - 384 + 386 - + Approximately %1 GB of data will be stored in this directory. - Approximately %1 GB of data will be stored in this directory. - 387 + 389 - 396 + 398 Explanatory text on the capability of the current prune target. - + (sufficient to restore backups %n day(s) old) - (sufficient to restore backups %n day old) - + (sufficient to restore backups %n day(s) old) - (sufficient to restore backups %n days old) - + %1 will download and store a copy of the Dash block chain. - %1 will download and store a copy of the Dash block chain. - 398 + 400 - + The wallet will also be stored in this directory. - The wallet will also be stored in this directory. - 400 + 402 - + Error: Specified data directory "%1" cannot be created. - Error: Specified data directory "%1" cannot be created. - 255 + 257 - + Error - Error - 286 + 288 - + - + Form - Form 14 - + Filter List: - Filter List: 57 - + Filter proposal list - Filter proposal list 64 - + + Masternode Count: + 90 + + + Number of masternodes this wallet can vote with (masternodes for which this wallet holds the voting key) + 93 + + Proposal Count: - Proposal Count: - 87 + 123 + + + Create Proposal + 153 - + Filter by Title - Filter by Title 67 - + - - Proposal Info: %1 - Proposal Info: %1 + + Unavailable 426 - - - - Passing +%1 - Passing +%1 - 86 + + A synced node and an unlocked wallet are required. + 426 - - Needs additional %1 votes - Needs additional %1 votes - 88 + + Vote Yes + 462 - - - - Yes - Yes - 144 + + Vote No + 463 - - No - No - 144 + + Vote Abstain + 464 - - Hash - Hash - 184 + + Proposal Info: %1 + 481 - - Title - Title - 186 + + Voting Failed + 523 + 528 + 535 + 549 + 560 - - Start - Start - 188 + + No wallet available. + 523 - - End - End - 190 + + No masternode voting keys found in wallet. + 528 - - Amount - Amount - 192 + + Please select a proposal to vote on. + 535 - - Active - Active - 194 + + Unable to unlock wallet. + 549 - - Status - Status - 196 + + Unable to get masternode list. Please try again later. + 560 + + + Masternode %1 not found + 570 + + + Failed to sign vote for masternode %1 + 581 + + + Masternode %1: %2 + 592 + + + 599 + + Voted successfully %n time(s) + + + Voted successfully %n time(s) + + + + 605 + + Failed to vote %n time(s) + + + Failed to vote %n time(s) + + + + Errors: + 608 + + + Voting Results + 611 + + + + + Passing +%1 + 95 + + + Needs additional %1 votes + 97 + + + + + Yes + 153 + + + No + 153 + + + Hash + 193 + + + Title + 195 + + + Start + 197 + + + End + 199 + + + Amount + 201 + + + Active + 203 + + + Status + 205 - + - + version - version - 40 + 41 - + About %1 - About %1 - 44 + 45 - + Command-line options - Command-line options 64 - + %1 information - %1 information - 111 + 112 - + <h3>%1 Basics</h3> %1 gives you true financial privacy by obscuring the origins of your funds. All the Dash in your wallet is comprised of different "inputs" which you can think of as separate, discrete coins.<br> %1 uses an innovative process to mix your inputs with the inputs of two or more other people, without having your coins ever leave your wallet. You retain control of your money at all times.<hr> <b>The %1 process works like this:</b><ol type="1"> <li>%1 begins by breaking your transaction inputs down into standard denominations. These denominations are 0.001 DASH, 0.01 DASH, 0.1 DASH, 1 DASH and 10 DASH -- sort of like the paper money you use every day.</li> <li>Your wallet then sends requests to specially configured software nodes on the network, called "masternodes." These masternodes are informed then that you are interested in mixing a certain denomination. No identifiable information is sent to the masternodes, so they never know "who" you are.</li> <li>When two or more other people send similar messages, indicating that they wish to mix the same denomination, a mixing session begins. The masternode mixes up the inputs and instructs all three users' wallets to pay the now-transformed input back to themselves. Your wallet pays that denomination directly to itself, but in a different address (called a change address).</li> <li>In order to fully obscure your funds, your wallet must repeat this process a number of times with each denomination. Each time the process is completed, it's called a "round." Each round of %1 makes it exponentially more difficult to determine where your funds originated.</li> <li>This mixing process happens in the background without any intervention on your part. When you wish to make a transaction, your funds will already be mixed. No additional waiting is required.</li> </ol> <hr><b>IMPORTANT:</b> Your wallet only contains 1000 of these "change addresses." Every time a mixing event happens, up to 9 of your addresses are used up. This means those 1000 addresses last for about 100 mixing events. When 900 of them are used, your wallet must create more addresses. It can only do this, however, if you have automatic backups enabled.<br> Consequently, users who have backups disabled will also have %1 disabled. <hr>For more information, see the <a style="%2" href="%3">%1 documentation</a>. - <h3>%1 Basics</h3> %1 gives you true financial privacy by obscuring the origins of your funds. All the Dash in your wallet is comprised of different "inputs" which you can think of as separate, discrete coins.<br> %1 uses an innovative process to mix your inputs with the inputs of two or more other people, without having your coins ever leave your wallet. You retain control of your money at all times.<hr> <b>The %1 process works like this:</b><ol type="1"> <li>%1 begins by breaking your transaction inputs down into standard denominations. These denominations are 0.001 DASH, 0.01 DASH, 0.1 DASH, 1 DASH and 10 DASH -- sort of like the paper money you use every day.</li> <li>Your wallet then sends requests to specially configured software nodes on the network, called "masternodes." These masternodes are informed then that you are interested in mixing a certain denomination. No identifiable information is sent to the masternodes, so they never know "who" you are.</li> <li>When two or more other people send similar messages, indicating that they wish to mix the same denomination, a mixing session begins. The masternode mixes up the inputs and instructs all three users' wallets to pay the now-transformed input back to themselves. Your wallet pays that denomination directly to itself, but in a different address (called a change address).</li> <li>In order to fully obscure your funds, your wallet must repeat this process a number of times with each denomination. Each time the process is completed, it's called a "round." Each round of %1 makes it exponentially more difficult to determine where your funds originated.</li> <li>This mixing process happens in the background without any intervention on your part. When you wish to make a transaction, your funds will already be mixed. No additional waiting is required.</li> </ol> <hr><b>IMPORTANT:</b> Your wallet only contains 1000 of these "change addresses." Every time a mixing event happens, up to 9 of your addresses are used up. This means those 1000 addresses last for about 100 mixing events. When 900 of them are used, your wallet must create more addresses. It can only do this, however, if you have automatic backups enabled.<br> Consequently, users who have backups disabled will also have %1 disabled. <hr>For more information, see the <a style="%2" href="%3">%1 documentation</a>. - 115 + 116 - + %1 is shutting down… - %1 is shutting down… - 189 + 190 - + Do not shut down the computer until this window disappears. - Do not shut down the computer until this window disappears. - 190 + 191 - + - + Welcome - Welcome 14 - + Welcome to %1. - Welcome to %1. 23 - + As this is the first time the program is launched, you can choose where %1 will store its data. - As this is the first time the program is launched, you can choose where %1 will store its data. 49 - + Limit block chain storage to - Limit block chain storage to 238 - + 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. - 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. 241 - + GB - GB 248 - + 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. - 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. 216 - + 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. - 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. 206 - + 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. - 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. 226 - + Use the default data directory - Use the default data directory 66 - + Use a custom data directory: - Use a custom data directory: 73 - + - + Form - Form 14 - + Status - Status 142 - + Filter List: - Filter List: 57 - + Filter masternode list - Filter masternode list 64 - + Node Count: - Node Count: 97 - + Show only masternodes this wallet has keys for. - Show only masternodes this wallet has keys for. 74 - + My masternodes only - My masternodes only 77 - + Service - Service 132 - + Type - Type 137 - + PoSe Score - PoSe Score 147 - + Registered - Registered 152 - + Last Paid - Last Paid 157 - + Next Payment - Next Payment 162 - + Payout Address - Payout Address 167 - + Operator Reward - Operator Reward 172 - + Collateral Address - Collateral Address 177 - + Owner Address - Owner Address 182 - + Voting Address - Voting Address 187 - + Filter by any property (e.g. address or protx hash) - Filter by any property (e.g. address or protx hash) 67 - + - + Copy ProTx Hash - Copy ProTx Hash - 85 + 83 - + Copy Collateral Outpoint - Copy Collateral Outpoint - 86 + 84 - + Please wait… - Please wait… - 143 - 323 + 141 + 321 - + Updating… - Updating… - 193 + 191 - + ENABLED - ENABLED - 229 + 227 - + POSE_BANNED - POSE_BANNED - 229 + 227 - + UNKNOWN - UNKNOWN - 243 - 266 + 241 + 264 - + to %1 - to %1 - 256 + 254 - + to UNKNOWN - to UNKNOWN - 258 + 256 - + but not claimed - but not claimed - 261 + 259 - + NONE - NONE - 249 + 247 - + Additional information for DIP3 Masternode %1 - Additional information for DIP3 Masternode %1 - 370 + 368 - + - + Form - Form 14 - + 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 Dash network, as detailed below. - 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 Dash network, as detailed below. 114 - + Attempting to spend Dash that are affected by not-yet-displayed transactions will not be accepted by the network. - Attempting to spend Dash that are affected by not-yet-displayed transactions will not be accepted by the network. 127 - + Number of blocks left - Number of blocks left 187 - + Unknown… - Unknown… 194 214 - ../modaloverlay.cpp172 + ../modaloverlay.cpp171 - + calculating… - calculating… 246 260 - + Last block time - Last block time 201 - + Progress - Progress 221 - + Progress increase per hour - Progress increase per hour 239 - + Estimated time left until synced - Estimated time left until synced 253 - + Hide - Hide 290 - + - + %1 is currently syncing. It will download headers and blocks from peers and validate them until reaching the tip of the block chain. - %1 is currently syncing. It will download headers and blocks from peers and validate them until reaching the tip of the block chain. - 49 + 48 - + Unknown. Syncing Headers (%1, %2%)… - Unknown. Syncing Headers (%1, %2%)… - 178 + 177 - + unknown - unknown - 143 + 142 - + - + Open URI - Open URI 14 - + URI: - URI: 22 + + Paste address from clipboard + 36 + Tooltip text for button that allows you to paste an address that is in your clipboard. + - + - + Options - Options 20 - + &Main - &Main 37 - + Size of &database cache - Size of &database cache 223 - + Number of script &verification threads - Number of script &verification threads 269 - + (0 = auto, <0 = leave that many cores free) - (0 = auto, <0 = leave that many cores free) 282 - + W&allet - W&allet 47 - + &Appearance - &Appearance 87 - + Show the icon in the system tray. - Show the icon in the system tray. 135 - + &Show tray icon - &Show tray icon 138 - + Prune &block storage to - Prune &block storage to 173 - + GB - GB 183 - + Reverting this setting requires re-downloading the entire blockchain. - Reverting this setting requires re-downloading the entire blockchain. 208 - + 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. - 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. 220 Tooltip text for Options window setting that sets the size of the database cache. Explains the corresponding effects of increasing/decreasing this value. - + MiB - MiB 239 - + Set the number of script verification threads. Negative values correspond to the number of cores you want to leave free to the system. - Set the number of script verification threads. Negative values correspond to the number of cores you want to leave free to the system. 266 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. - + This allows you or a third party tool to communicate with the node through command-line and JSON-RPC commands. - This allows you or a third party tool to communicate with the node through command-line and JSON-RPC commands. 304 Tooltip text for Options window setting that enables the RPC server. - + Enable R&PC server - Enable R&PC server 307 An Options window setting to enable the RPC server. - + Whether to set subtract fee from amount as default or not. - Whether to set subtract fee from amount as default or not. 331 Tooltip text for Options window setting that sets subtracting the fee from a sending amount as default. - + Subtract &fee from amount by default - Subtract &fee from amount by default 334 An Options window setting to set subtracting the fee from a sending amount as default. - - Whether to keep the specified custom change address or not. - Whether to keep the specified custom change address or not. + + Enable &PSBT controls 353 + An options window setting to enable PSBT controls. - - Keep custom change &address - Keep custom change &address + + Whether to show PSBT controls. 356 + Tooltip text for options window setting that enables PSBT controls. - - Show additional tab listing all your masternodes in first sub-tab<br/>and all masternodes on the network in second sub-tab. - Show additional tab listing all your masternodes in first sub-tab<br/>and all masternodes on the network in second sub-tab. + + Whether to keep the specified custom change address or not. 363 - - Show Masternodes Tab - Show Masternodes Tab + + Keep custom change &address 366 - - Show additional tab listing governance proposals. - Show additional tab listing governance proposals. + + Show additional tab listing all your masternodes in first sub-tab<br/>and all masternodes on the network in second sub-tab. 373 - - Show Governance Tab - Show Governance Tab + + Show Masternodes Tab 376 - - If you disable the spending of unconfirmed change, the change from a transaction<br/>cannot be used until that transaction has at least one confirmation.<br/>This also affects how your balance is computed. - If you disable the spending of unconfirmed change, the change from a transaction<br/>cannot be used until that transaction has at least one confirmation.<br/>This also affects how your balance is computed. + + Show additional tab listing governance proposals. 383 - - Show mixing interface on Overview screen and reveal an additional screen which allows to spend fully mixed coins only.<br/>A new tab with more settings will also appear in this dialog, please make sure to check them before mixing your coins. - Show mixing interface on Overview screen and reveal an additional screen which allows to spend fully mixed coins only.<br/>A new tab with more settings will also appear in this dialog, please make sure to check them before mixing your coins. + + Show Governance Tab + 386 + + + If you disable the spending of unconfirmed change, the change from a transaction<br/>cannot be used until that transaction has at least one confirmation.<br/>This also affects how your balance is computed. 393 - + + Show mixing interface on Overview screen and reveal an additional screen which allows to spend fully mixed coins only.<br/>A new tab with more settings will also appear in this dialog, please make sure to check them before mixing your coins. + 403 + + Show additional information and buttons on overview screen. - Show additional information and buttons on overview screen. - 422 + 432 - + Enable advanced interface - Enable advanced interface - 425 + 435 - + Show system popups for mixing transactions<br/>just like for all other transaction types. - Show system popups for mixing transactions<br/>just like for all other transaction types. - 432 + 442 - + Show popups for mixing transactions - Show popups for mixing transactions - 435 + 445 - + Show warning dialog when the wallet has very low number of keys left. - Show warning dialog when the wallet has very low number of keys left. - 442 + 452 - + Warn if the wallet is running out of keys - Warn if the wallet is running out of keys - 445 + 455 - + Whether to use experimental mode with multiple mixing sessions per block.<br/>Note: You must use this feature carefully.<br/>Make sure you always have recent wallet (auto)backup in a safe place! - Whether to use experimental mode with multiple mixing sessions per block.<br/>Note: You must use this feature carefully.<br/>Make sure you always have recent wallet (auto)backup in a safe place! - 452 + 462 - + Enable &multi-session - Enable &multi-session - 455 + 465 - + Use this many separate masternodes in parallel to mix funds.<br/>Note: You must use this feature carefully.<br/>Make sure you always have recent wallet (auto)backup in a safe place! - Use this many separate masternodes in parallel to mix funds.<br/>Note: You must use this feature carefully.<br/>Make sure you always have recent wallet (auto)backup in a safe place! - 464 + 474 - + Parallel sessions - Parallel sessions - 467 + 477 - + Mixing rounds - Mixing rounds - 490 + 500 - + This amount acts as a threshold to turn off mixing once it's reached. - This amount acts as a threshold to turn off mixing once it's reached. - 510 + 520 - + Target balance - Target balance - 525 + 535 - + How many inputs of each denominated amount are created.<br/>Lower these numbers if you want fewer smaller denominations. - How many inputs of each denominated amount are created.<br/>Lower these numbers if you want fewer smaller denominations. - 548 + 558 - + Inputs per denomination - Inputs per denomination - 551 + 561 - + Try to create at least this many inputs for each denominated amount.<br/>Lower this number if you want fewer smaller denominations. - Try to create at least this many inputs for each denominated amount.<br/>Lower this number if you want fewer smaller denominations. - 562 + 572 - + Target - Target - 565 + 575 - + Create up to this many inputs for each denominated amount.<br/>Lower this number if you want fewer smaller denominations. - Create up to this many inputs for each denominated amount.<br/>Lower this number if you want fewer smaller denominations. - 592 + 602 - + Maximum - Maximum - 595 + 605 - + Automatically open the Dash Core client port on the router. This only works when your router supports UPnP and it is enabled. - Automatically open the Dash Core client port on the router. This only works when your router supports UPnP and it is enabled. - 641 + 651 - + Map port using NA&T-PMP - Map port using NA&T-PMP - 654 + 664 - + Accept connections from outside. - Accept connections from outside. - 661 + 671 - + Allow incomin&g connections - Allow incomin&g connections - 664 + 674 - + Connect to the Dash network through a SOCKS5 proxy. - Connect to the Dash network through a SOCKS5 proxy. - 671 + 681 - + &Connect through SOCKS5 proxy (default proxy): - &Connect through SOCKS5 proxy (default proxy): - 674 + 684 - + Shows if the supplied default SOCKS5 proxy is used to reach peers via this network type. - Shows if the supplied default SOCKS5 proxy is used to reach peers via this network type. - 777 - 790 - 803 + 787 + 800 + 813 - + Language missing or translation incomplete? Help contributing translations here: https://explore.transifex.com/dash/dash/ - Language missing or translation incomplete? Help contributing translations here: -https://explore.transifex.com/dash/dash/ - 972 + 982 - + + Third-party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items.<br/>%s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |. + 1046 + 1059 + + + &Third-party transaction URLs + 1049 + + Options set in this dialog are overridden by the command line or in the configuration file: - Options set in this dialog are overridden by the command line or in the configuration file: - 1103 + 1113 - + 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. - 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. 158 - - Third party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items.<br/>%s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |. - Third party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items.<br/>%s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |. - 1036 - 1049 - - - &Third party transaction URLs - &Third party transaction URLs - 1039 - - + Whether to show coin control features or not. - Whether to show coin control features or not. 343 - + Automatically start %1 after logging in to the system. - Automatically start %1 after logging in to the system. 112 - + &Start %1 on system login - &Start %1 on system login 115 - + Enable coin &control features - Enable coin &control features 346 - + &Spend unconfirmed change - &Spend unconfirmed change - 386 + 396 - + This setting determines the amount of individual masternodes that an input will be mixed through.<br/>More rounds of mixing gives a higher degree of privacy, but also costs more in fees. - This setting determines the amount of individual masternodes that an input will be mixed through.<br/>More rounds of mixing gives a higher degree of privacy, but also costs more in fees. - 487 + 497 - + &Network - &Network 67 - + 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. - 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. 170 - + Map port using &UPnP - Map port using &UPnP - 644 + 654 - + Automatically open the Dash Core client port on the router. This only works when your router supports NAT-PMP and it is enabled. The external port could be random. - Automatically open the Dash Core client port on the router. This only works when your router supports NAT-PMP and it is enabled. The external port could be random. - 651 + 661 - + Proxy &IP: - Proxy &IP: - 683 - 840 + 693 + 850 - + IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1) - IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1) - 708 - 865 + 718 + 875 - + &Port: - &Port: - 715 - 872 + 725 + 882 - + Port of the proxy (e.g. 9050) - Port of the proxy (e.g. 9050) - 740 - 897 + 750 + 907 - + Used for reaching peers via: - Used for reaching peers via: - 764 + 774 - + IPv4 - IPv4 - 780 + 790 - + IPv6 - IPv6 - 793 + 803 - + Tor - Tor - 806 + 816 - + Show only a tray icon after minimizing the window. - Show only a tray icon after minimizing the window. 148 - + &Minimize to the tray instead of the taskbar - &Minimize to the tray instead of the taskbar 151 - + M&inimize on close - M&inimize on close 161 - + &Display - &Display 77 - + Connect to the Dash network through a separate SOCKS5 proxy for Tor onion services. - Connect to the Dash network through a separate SOCKS5 proxy for Tor onion services. - 828 + 838 - + Use separate SOCKS&5 proxy to reach peers via Tor onion services: - Use separate SOCKS&5 proxy to reach peers via Tor onion services: - 831 + 841 - + User Interface &language: - User Interface &language: - 938 + 948 - + The user interface language can be set here. This setting will take effect after restarting %1. - The user interface language can be set here. This setting will take effect after restarting %1. - 951 + 961 - + &Unit to show amounts in: - &Unit to show amounts in: - 998 + 1008 - + Choose the default subdivision unit to show in the interface and when sending coins. - Choose the default subdivision unit to show in the interface and when sending coins. - 1011 + 1021 - + Decimal digits - Decimal digits - 1022 + 1032 - + Reset all client options to default. - Reset all client options to default. - 1149 + 1159 - + &Reset Options - &Reset Options - 1152 + 1162 - + &OK - &OK - 1207 + 1217 - + &Cancel - &Cancel - 1220 + 1230 - + - + Enable %1 features - Enable %1 features - 74 + 77 - + default - default - 155 + 158 - + Confirm options reset - Confirm options reset - 399 + 418 + Window title text of pop-up window shown when the user has chosen to reset options. - + Client restart required to activate changes. - Client restart required to activate changes. - 400 - 455 + 409 + 474 + Text explaining that the settings changed will not come into effect until the client is restarted. - + + Current settings will be backed up at "%1". + 413 + 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. + + Client will be shut down. Do you want to proceed? - Client will be shut down. Do you want to proceed? - 400 + 416 + Text asking the user to confirm if they would like to proceed with a client shutdown. - + This change would require a client restart. - This change would require a client restart. - 459 + 478 - + The supplied proxy address is invalid. - The supplied proxy address is invalid. - 487 + 506 - + - + Form - Form 20 - + The displayed information may be out of date. Your wallet automatically synchronizes with the Dash network after a connection is established, but this process has not completed yet. - The displayed information may be out of date. Your wallet automatically synchronizes with the Dash network after a connection is established, but this process has not completed yet. 80 378 615 - + Available: - Available: 290 - + Your current spendable balance - Your current spendable balance 300 - + Pending: - Pending: 335 - + Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance - Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance 135 - + Immature: - Immature: 235 - + Mined balance that has not yet matured - Mined balance that has not yet matured 206 - + Balances - Balances 73 - + Unconfirmed transactions to watch-only addresses - Unconfirmed transactions to watch-only addresses 116 - + Mined balance in watch-only addresses that has not yet matured - Mined balance in watch-only addresses that has not yet matured 154 - + Total: - Total: 196 - + Your current total balance - Your current total balance 245 - + Current total balance in watch-only addresses - Current total balance in watch-only addresses 264 - + Watch-only: - Watch-only: 280 - + Your current balance in watch-only addresses - Your current balance in watch-only addresses 319 - + Spendable: - Spendable: 342 - + Status: - Status: 417 - + Enabled/Disabled - Enabled/Disabled 424 - + Completion: - Completion: 431 - + Amount and Rounds: - Amount and Rounds: 465 - + 0 DASH / 0 Rounds - 0 DASH / 0 Rounds 472 - + Submitted Denom: - Submitted Denom: 479 - + n/a - n/a 489 - + Recent transactions - Recent transactions 608 - + Start/Stop Mixing - Start/Stop Mixing 527 - + The denominations you submitted to the Masternode.<br>To mix, other users must submit the exact same denominations. - The denominations you submitted to the Masternode.<br>To mix, other users must submit the exact same denominations. 486 - + - + out of sync - out of sync 181 182 183 - + Automatic backups are disabled, no mixing available! - Automatic backups are disabled, no mixing available! - 499 + 504 - + No inputs detected - No inputs detected - 385 - 391 + 388 + 394 - + %1 Balance - %1 Balance 187 - + Discreet mode activated for the Overview tab. To unmask the values, uncheck Settings->Discreet mode. - Discreet mode activated for the Overview tab. To unmask the values, uncheck Settings->Discreet mode. - 215 + 219 - 389 + 392 409 - 420 - + 415 + 426 + %n Rounds - %n Round - + %n Rounds - %n Rounds - + Found enough compatible inputs to mix %1 - Found enough compatible inputs to mix %1 - 406 + 412 - + Not enough compatible inputs to mix <span style='%1'>%2</span>,<br>will mix <span style='%1'>%3</span> instead - Not enough compatible inputs to mix <span style='%1'>%2</span>,<br>will mix <span style='%1'>%3</span> instead - 412 + 418 - + Overall progress - Overall progress - 471 + 476 - + Denominated - Denominated - 472 + 477 - + Partially mixed - Partially mixed - 473 + 478 - + Mixed - Mixed - 474 + 479 - 475 - + 480 + Denominated inputs have %5 of %n rounds on average - Denominated inputs have %5 of %n round on average - + Denominated inputs have %5 of %n rounds on average - Denominated inputs have %5 of %n rounds on average - + keys left: %1 - keys left: %1 - 557 + 562 - + Start %1 - Start %1 - 575 - 710 + 580 + 715 - + If you don't want to see internal %1 fees/transactions select "Most Common" as Type on the "Transactions" tab. - If you don't want to see internal %1 fees/transactions select "Most Common" as Type on the "Transactions" tab. - 673 + 678 - + %1 requires at least %2 to use. - %1 requires at least %2 to use. - 684 + 689 - + Wallet is locked and user declined to unlock. Disabling %1. - Wallet is locked and user declined to unlock. Disabling %1. - 698 + 703 - + Stop %1 - Stop %1 - 714 + 719 - + Disabled - Disabled - 577 - 631 - 750 - 753 + 582 + 636 + 755 + 758 - + Very low number of keys left since last automatic backup! - Very low number of keys left since last automatic backup! - 596 + 601 - + We are about to create a new automatic backup for you, however <span style='%1'> you should always make sure you have backups saved in some safe place</span>! - We are about to create a new automatic backup for you, however <span style='%1'> you should always make sure you have backups saved in some safe place</span>! - 597 + 602 - + Note: You can turn this message off in options. - Note: You can turn this message off in options. - 600 + 605 - + WARNING! Something went wrong on automatic backup - WARNING! Something went wrong on automatic backup - 616 + 621 - + ERROR! Failed to create automatic backup - ERROR! Failed to create automatic backup - 624 - 641 + 629 + 646 - + Mixing is disabled, please close your wallet and fix the issue! - Mixing is disabled, please close your wallet and fix the issue! - 625 - 643 + 630 + 648 - + Enabled - Enabled - 631 + 636 - + see debug.log for details. - see debug.log for details. - 642 + 647 - + WARNING! Failed to replenish keypool, please unlock your wallet to do so. - WARNING! Failed to replenish keypool, please unlock your wallet to do so. - 649 + 654 - + - + Dialog - Dialog 14 - + Sign Tx - Sign Tx 86 - + Broadcast Tx - Broadcast Tx 102 - + Copy to Clipboard - Copy to Clipboard 122 - + Save… - Save… 129 - + Close - Close 136 - + - + Failed to load transaction: %1 - Failed to load transaction: %1 - 58 + 61 - + Failed to sign transaction: %1 - Failed to sign transaction: %1 - 83 + 86 - + Cannot sign inputs while wallet is locked. - - 91 + 94 - + Could not sign any more inputs. - Could not sign any more inputs. - 93 + 96 - + Signed %1 inputs, but more signatures are still required. - Signed %1 inputs, but more signatures are still required. - 95 + 98 - + Signed transaction successfully. Transaction is ready to broadcast. - Signed transaction successfully. Transaction is ready to broadcast. - 98 + 101 - + Unknown error processing transaction. - Unknown error processing transaction. - 110 + 113 - + Transaction broadcast successfully! Transaction ID: %1 - Transaction broadcast successfully! Transaction ID: %1 - 120 + 123 - + Transaction broadcast failed: %1 - Transaction broadcast failed: %1 - 123 + 126 - + PSBT copied to clipboard. - PSBT copied to clipboard. - 132 + 135 - + Save Transaction Data - Save Transaction Data - 155 + 158 - + Partially Signed Transaction (Binary) - Partially Signed Transaction (Binary) - 157 + 160 Expanded name of the binary PSBT file format. See: BIP 174. - + PSBT saved to disk. - PSBT saved to disk. - 164 + 167 - + * Sends %1 to %2 - * Sends %1 to %2 - 180 + 183 - + own address - own address - 184 + 187 - + Unable to calculate transaction fee or total transaction amount. - Unable to calculate transaction fee or total transaction amount. - 192 + 195 - + Pays transaction fee: - Pays transaction fee: - 194 + 197 - + Total Amount - Total Amount - 206 + 209 - + or - or - 209 + 212 - + Transaction has %1 unsigned inputs. - Transaction has %1 unsigned inputs. - 215 + 218 - + Transaction is missing some information about inputs. - Transaction is missing some information about inputs. - 261 + 264 - + Transaction still needs signature(s). - Transaction still needs signature(s). - 265 + 268 - + (But no wallet is loaded.) - (But no wallet is loaded.) - 268 + 271 - + (But this wallet cannot sign transactions.) - (But this wallet cannot sign transactions.) - 271 + 274 - + (But this wallet does not have the right keys.) - (But this wallet does not have the right keys.) - 274 + 277 - + Transaction is fully signed and ready for broadcast. - Transaction is fully signed and ready for broadcast. - 282 + 285 - + Transaction status is unknown. - Transaction status is unknown. - 286 + 289 - + - + Payment request error - Payment request error - 153 + 151 - + Cannot start dash: click-to-pay handler - Cannot start dash: click-to-pay handler - 154 + 152 - + URI handling - URI handling - 204 - 220 - 225 - 233 + 200 + 216 + 221 + 229 - + 'dash://' is not a valid URI. Use 'dash:' instead. - 'dash://' is not a valid URI. Use 'dash:' instead. - 204 + 200 - + Cannot process payment request as BIP70 is no longer supported. Due to discontinued support, you should request the merchant to provide you with a BIP21 compatible URI or use a wallet that does continue to support BIP70. - Cannot process payment request as BIP70 is no longer supported. -Due to discontinued support, you should request the merchant to provide you with a BIP21 compatible URI or use a wallet that does continue to support BIP70. - 221 - 244 + 217 + 240 - + URI cannot be parsed! This can be caused by an invalid Dash address or malformed URI parameters. - URI cannot be parsed! This can be caused by an invalid Dash address or malformed URI parameters. - 234 + 230 - + Payment request file handling - Payment request file handling - 243 + 239 - + - + User Agent - User Agent 112 Title of Peers Table column which contains the peer's User Agent string. - + Ping - Ping 103 Title of Peers Table column which indicates the current latency of the connection with the peer. - + Peer - Peer 85 Title of Peers Table column which contains a unique number used to identify a connection. - + Age - Age 88 Title of Peers Table column which indicates the duration (length of time) since the peer connection started. - + Direction - Direction 94 Title of Peers Table column which indicates the direction the peer connection was initiated from. - + Type - Type 97 Title of Peers Table column which describes the type of peer connection. The "type" describes why the connection exists. - + Sent - Sent 106 Title of Peers Table column which indicates the total amount of network information we have sent to the peer. - + Received - Received 109 Title of Peers Table column which indicates the total amount of network information we have received from the peer. - + Address - Address 91 Title of Peers Table column which contains the IP/Onion/I2P address of the connected peer. - + Network - Network 100 Title of Peers Table column which states the network the peer connected through. - + - + Inbound - Inbound - 81 + 77 An Inbound Connection from a Peer. - + Outbound - Outbound - 83 + 79 An Outbound Connection to a Peer. - + + + + Create Governance Proposal + 14 + + + Enter proposal details + 54 + + + A fee will be burned when you prepare the proposal. + 70 + + + Proposal &name + 97 + + + &Description URL + 123 + + + Payment &address + 149 + + + Payment &amount + 172 + + + The amount to request in a single payment + 188 + + + &First payment + 195 + + + Pa&yments + 223 + + + To&tal amount + 248 + + + Proposal &fee + 265 + + + Next + 305 + 396 + 562 + + + Review proposal JSON and validate. + 324 + + + Hex-encoded JSON + 338 + + + Back + 370 + 536 + + + Validate + 383 + + + Prepare (burn fee) and wait for confirmations. + 418 + + + Copy + 450 + 674 + + + At 1/6 confirmations: can be relayed and queued. At 6/6: accepted and processed. + 474 + + + Confirmations progress + 499 + 630 + + + Shows progress toward the required number of confirmations for the proposal fee transaction. + 502 + 633 + + + Estimated time remaining: - + 509 + 640 + + + Prepare Proposal + 549 + + + You can submit after 1 confirmation. At 6 confirmations it is accepted and processed. + 584 + + + Proposal ID: + 654 + + + Submit Proposal + 707 + + + Close + 723 + + + + + + + Valid + 211 + + + Invalid: %1 + 214 + + + Burn %1 + 230 + + + Burn %1 to create the fee transaction? + 231 + + + Prepare failed + 247 + 252 + + + Confirmations: %1 / %2 required + 279 + 283 + + + Estimated time remaining: Ready + 288 + 289 + + + 293 + 294 + + Estimated time remaining: %n minute(s) + + + Estimated time remaining: %n minute(s) + + + + Your proposal was submitted successfully. + 324 + + + Already submitted + 311 + + + This proposal has already been submitted. + 311 + + + Submission failed + 318 + + + Proposal submitted + 323 + + + A fee of %1 will be burned when you prepare the proposal. + 359 + + + Prepare (burn %1) and wait for %2 confirmations. + 363 + + + + - + Amount - Amount - 258 + 213 - + - + Enter a Dash address (e.g. %1) - Enter a Dash address (e.g. %1) - 298 + 294 - + Appearance Setup - Appearance Setup - 310 + 306 - + Please choose your preferred settings for the appearance of %1 - Please choose your preferred settings for the appearance of %1 - 313 + 309 - + This can also be adjusted later in the "Appearance" tab of the preferences. - This can also be adjusted later in the "Appearance" tab of the preferences. - 316 + 312 - + Ctrl+W - Ctrl+W - 640 + 641 - + Unroutable - Unroutable - 1674 + 1675 - + Internal - Internal - 1680 + 1681 - + Inbound - Inbound - 1693 + 1694 An inbound connection from a peer. An inbound connection is a connection initiated by a peer. - + Outbound - Outbound - 1696 + 1697 An outbound connection to a peer. An outbound connection is a connection initiated by us. - + Full Relay - Full Relay - 1701 + 1702 Peer connection type that relays all network information. - + Block Relay - Block Relay - 1704 + 1705 Peer connection type that relays network information about blocks and not transactions or addresses. - + Manual - Manual - 1706 + 1707 Peer connection type established manually through one of several methods. - + Feeler - Feeler - 1708 + 1709 Short-lived peer connection type that tests the aliveness of known addresses. - + Address Fetch - Address Fetch - 1710 + 1711 Short-lived peer connection type that solicits known addresses from a peer. - + %1 d - %1 d 1723 1735 - + %1 h - %1 h 1724 1736 - + %1 m - %1 m 1725 1737 - + %1 s - %1 s 1727 1738 1764 - + None - None 1752 - + N/A - N/A 1758 - + %1 ms - %1 ms 1759 1777 - + %n second(s) - %n second - + %n second(s) - %n seconds 1781 - + %n minute(s) - %n minute - + %n minute(s) - %n minutes 1785 - + %n hour(s) - %n hour - + %n hour(s) - %n hours 1789 - + %n day(s) - %n day - + %n day(s) - %n days 1793 1799 - + %n week(s) - %n week - + %n week(s) - %n weeks 1799 - + %n year(s) - %n year - + %n year(s) - %n years - + %1 and %2 - %1 and %2 1799 - + %1 B - %1 B 1807 - + %1 kB - %1 kB 1809 + ../rpcconsole.cpp1114 - + %1 MB - %1 MB 1811 + ../rpcconsole.cpp1115 + ../rpcconsole.cpp1116 - + %1 GB - %1 GB 1813 - + - + QR-Code Title - QR-Code Title 17 - + QR Code - QR Code 39 - + &Save Image… - &Save Image… 85 - + - + &Save Image… - &Save Image… - 30 + 29 - + &Copy Image - &Copy Image - 31 + 30 - + Resulting URI too long, try to reduce the text for label / message. - Resulting URI too long, try to reduce the text for label / message. - 42 + 41 - + Error encoding URI into QR Code. - Error encoding URI into QR Code. - 49 + 48 - + QR code support not available. - QR code support not available. - 104 + 103 - + Save QR Code - Save QR Code - 134 + 133 - + PNG Image - PNG Image - 137 + 136 Expanded name of the PNG file format. See: https://en.wikipedia.org/wiki/Portable_Network_Graphics. - + - + Tools window - Tools window 14 - + &Information - &Information 44 - + General - General 112 - + Name - Name 256 - + N/A - N/A 129 155 181 @@ -3735,679 +3428,571 @@ Due to discontinued support, you should request the merchant to provide you with 236 266 289 - 312 - 332 - 359 - 382 - 405 - 428 - 451 - 481 - 504 - 567 - 946 - 969 - 995 - 1021 - 1047 - 1070 - 1096 - 1119 - 1142 - 1168 - 1194 - 1220 - 1243 - 1266 - 1289 - 1312 - 1338 - 1364 - 1387 - 1410 - 1433 - 1456 - 1479 - 1505 - 1528 - 1551 - 1577 - 1603 - 1629 - 1655 - ../rpcconsole.h156 - - + 347 + 367 + 394 + 417 + 440 + 463 + 486 + 516 + 539 + 602 + 981 + 1004 + 1030 + 1056 + 1082 + 1105 + 1131 + 1154 + 1177 + 1203 + 1229 + 1255 + 1278 + 1301 + 1324 + 1347 + 1373 + 1399 + 1422 + 1445 + 1468 + 1491 + 1514 + 1540 + 1563 + 1586 + 1612 + 1638 + 1664 + 1690 + ../rpcconsole.h166 + + Number of connections - Number of connections 279 - + &Open - &Open - 545 + 580 - + Startup time - Startup time 226 - + Network - Network 249 - 1037 + 1072 - + Last block time - Last block time - 372 + 407 - + Debug log file - Debug log file - 535 + 570 - + Client version - Client version 119 - + Block chain - Block chain - 342 + 377 - + Memory Pool - Memory Pool - 464 + 499 - + Current number of transactions - Current number of transactions - 471 + 506 - + Memory usage - Memory usage - 494 + 529 - + &Console - &Console 54 - + Clear console - Clear console - 654 + 689 - + &Network Traffic - &Network Traffic 64 - + Received - Received - 1446 + 1481 - + Sent - Sent - 1423 + 1458 - + &Peers - &Peers 74 - + Wallet: - Wallet: - 608 + 643 - + Banned peers - Banned peers - 842 + 877 - + Select a peer to view detailed information. - Select a peer to view detailed information. - 905 - ../rpcconsole.cpp1275 + 940 + ../rpcconsole.cpp1297 - + Version - Version - 1109 - - - Whether the peer requested us to relay transactions. - Whether the peer requested us to relay transactions. - 1181 - - - Wants Tx Relay - Wants Tx Relay - 1184 + 1144 - + High bandwidth BIP152 compact block relay: %1 - High bandwidth BIP152 compact block relay: %1 - 1207 + 1242 - + High Bandwidth - High Bandwidth - 1210 + 1245 - + Starting Block - Starting Block - 1233 + 1268 - + Synced Headers - Synced Headers - 1256 + 1291 - + Synced Blocks - Synced Blocks - 1279 + 1314 - + Elapsed time since a novel block passing initial validity checks was received from this peer. - Elapsed time since a novel block passing initial validity checks was received from this peer. - 1325 + 1360 - + Last Block - Last Block - 1328 + 1363 - + Elapsed time since a novel transaction accepted into our mempool was received from this peer. - Elapsed time since a novel transaction accepted into our mempool was received from this peer. - 1351 + 1386 Tooltip text for the Last Transaction field in the peer details area. - + Last Transaction - Last Transaction - 1354 + 1389 - + The mapped Autonomous System used for diversifying peer selection. - The mapped Autonomous System used for diversifying peer selection. - 1564 + 1599 - + Mapped AS - Mapped AS - 1567 + 1602 - + Whether we relay addresses to this peer. - Whether we relay addresses to this peer. - 1590 + 1625 Tooltip text for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No). - + Address Relay - Address Relay - 1593 + 1628 Text title for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No). - + Addresses Processed - Addresses Processed - 1619 + 1654 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). - + Addresses Rate-Limited - Addresses Rate-Limited - 1645 + 1680 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. - + Rescan blockchain files 1 - Rescan blockchain files 1 - 1726 + 1761 - + Rescan blockchain files 2 - Rescan blockchain files 2 - 1749 + 1784 - + The buttons below will restart the wallet with command-line options to repair the wallet, fix issues with corrupt blockchain files or missing/obsolete transactions. - The buttons below will restart the wallet with command-line options to repair the wallet, fix issues with corrupt blockchain files or missing/obsolete transactions. - 1706 + 1741 - + -rescan=1: Rescan the block chain for missing wallet transactions starting from wallet creation time. - -rescan=1: Rescan the block chain for missing wallet transactions starting from wallet creation time. - 1733 + 1768 - + -rescan=2: Rescan the block chain for missing wallet transactions starting from genesis block. - -rescan=2: Rescan the block chain for missing wallet transactions starting from genesis block. - 1756 + 1791 - + User Agent - User Agent 142 - 1132 + 1167 - + Datadir - Datadir 168 - + To specify a non-default location of the data directory use the '%1' option. - To specify a non-default location of the data directory use the '%1' option. 178 - + Blocksdir - Blocksdir 197 - + To specify a non-default location of the blocks directory use the '%1' option. - To specify a non-default location of the blocks directory use the '%1' option. 207 - - Number of regular Masternodes - Number of regular Masternodes + + Local Addresses 302 - + + Network addresses that your Dash node is currently using to communicate with other nodes. + 330 + + + Number of regular Masternodes + 337 + + Number of EvoNodes - Number of EvoNodes - 322 + 357 - + Current block height - Current block height - 349 + 384 - + Last block hash - Last block hash - 395 + 430 - + Latest ChainLocked block hash - Latest ChainLocked block hash - 418 + 453 - + Latest ChainLocked block height - Latest ChainLocked block height - 441 + 476 - + Open the %1 debug log file from the current data directory. This can take a few seconds for large log files. - Open the %1 debug log file from the current data directory. This can take a few seconds for large log files. - 542 + 577 - + InstantSend locks - InstantSend locks - 557 + 592 - + (none) - (none) - 619 + 654 - + Decrease font size - Decrease font size - 640 + 675 - + Increase font size - Increase font size - 647 + 682 - + &Reset - &Reset - 759 + 794 - + Node Type - Node Type - 936 + 971 - + PoSe Score - PoSe Score - 959 + 994 - + The transport layer version: %1 - The transport layer version: %1 - 982 + 1017 - + Transport - Transport - 985 + 1020 - + The BIP324 session ID string in hex. - The BIP324 session ID string in hex. - 1008 + 1043 - + Session ID - Session ID - 1011 + 1046 - + The network protocol this peer is connected through: IPv4, IPv6, Onion, I2P, or CJDNS. - The network protocol this peer is connected through: IPv4, IPv6, Onion, I2P, or CJDNS. - 1034 + 1069 - + Permissions - Permissions - 1060 + 1095 - + The direction and type of peer connection: %1 - The direction and type of peer connection: %1 - 1083 + 1118 - + Direction/Type - Direction/Type - 1086 + 1121 - + Services - Services - 1158 + 1193 + + + Whether we relay transactions to this peer. + 1216 + + + Transaction Relay + 1219 - + Connection Time - Connection Time - 1302 + 1337 - + Last Send - Last Send - 1377 + 1412 - + Last Receive - Last Receive - 1400 + 1435 - + Ping Time - Ping Time - 1469 + 1504 - + The duration of a currently outstanding ping. - The duration of a currently outstanding ping. - 1492 + 1527 - + Ping Wait - Ping Wait - 1495 + 1530 - + Min Ping - Min Ping - 1518 + 1553 - + Time Offset - Time Offset - 1541 + 1576 - + &Wallet Repair - &Wallet Repair 84 - + The total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting). - The total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting). - 1616 + 1651 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). - + The total number of addresses received from this peer that were dropped (not processed) due to rate-limiting. - The total number of addresses received from this peer that were dropped (not processed) due to rate-limiting. - 1642 + 1677 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. - + Wallet repair options. - Wallet repair options. - 1696 + 1731 - + Rebuild index - Rebuild index - 1766 + 1801 - + -reindex: Rebuild block chain index from current blk000??.dat files. - -reindex: Rebuild block chain index from current blk000??.dat files. - 1773 + 1808 - + - + Inbound: initiated by peer - Inbound: initiated by peer - 516 + 519 Explanatory text for an inbound peer connection. - + Outbound Full Relay: default - Outbound Full Relay: default - 520 + 523 Explanatory text for an outbound peer connection that relays all network information. This is the default behavior for outbound connections. - + Outbound Block Relay: does not relay transactions or addresses - Outbound Block Relay: does not relay transactions or addresses - 523 + 526 Explanatory text for an outbound peer connection that relays network information about blocks and not transactions or addresses. - + Outbound Manual: added using RPC %1 or %2/%3 configuration options - Outbound Manual: added using RPC %1 or %2/%3 configuration options - 528 + 531 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. - + Outbound Feeler: short-lived, for testing addresses - Outbound Feeler: short-lived, for testing addresses - 534 + 537 Explanatory text for a short-lived outbound peer connection that is used to test the aliveness of known addresses. - + Outbound Address Fetch: short-lived, for soliciting addresses - Outbound Address Fetch: short-lived, for soliciting addresses - 537 + 540 Explanatory text for a short-lived outbound peer connection that is used to request addresses from a peer. - + we selected the peer for high bandwidth relay - we selected the peer for high bandwidth relay - 550 + 553 - + the peer selected us for high bandwidth relay - the peer selected us for high bandwidth relay - 551 + 554 - + no high bandwidth relay selected - no high bandwidth relay selected - 552 + 555 - + &Disconnect - &Disconnect - 738 + 741 - + 1 &hour - 1 &hour - 739 + 742 - + 1 &week - 1 &week - 741 + 744 - + 1 &year - 1 &year - 742 + 745 - + &Unban - &Unban - 772 + 775 - + In: - In: - 1032 + 1039 - + Out: - Out: - 1033 + 1040 - + Network activity disabled - Network activity disabled - 1036 + 1043 + + + None + 1056 - + Total: %1 (Enabled: %2) - Total: %1 (Enabled: %2) - 1080 - 1084 + 1099 + 1103 - + Executing command without any wallet - Executing command without any wallet - 1163 + 1185 - + Ctrl++ - Ctrl++ - 1371 + 1397 Main shortcut to increase the RPC console font size. - + Ctrl+= - Ctrl+= - 1373 + 1399 Secondary shortcut to increase the RPC console font size. - + Ctrl+- - Ctrl+- - 1377 + 1403 Main shortcut to decrease the RPC console font size. - + Ctrl+_ - Ctrl+_ - 1379 + 1405 Secondary shortcut to decrease the RPC console font size. - + Ctrl+Shift+I - Ctrl+Shift+I - 1529 + 1551 - + Ctrl+Shift+C - Ctrl+Shift+C - 1530 + 1552 - + Ctrl+Shift+G - Ctrl+Shift+G - 1531 + 1553 - + Ctrl+Shift+P - Ctrl+Shift+P - 1532 + 1554 - + Ctrl+Shift+R - Ctrl+Shift+R - 1533 + 1555 - + Executing command using "%1" wallet - Executing command using "%1" wallet - 1161 + 1183 - + detecting: peer could be v1 or v2 - detecting: peer could be v1 or v2 - 542 + 545 Explanatory text for "detecting" transport type. - + v1: unencrypted, plaintext transport protocol - v1: unencrypted, plaintext transport protocol - 544 + 547 Explanatory text for v1 transport type. - + v2: BIP324 encrypted transport protocol - v2: BIP324 encrypted transport protocol - 546 + 549 Explanatory text for v2 transport type. - + &Copy address - &Copy address - 734 + 737 Context menu action to copy the address of a peer - + 1 d&ay - 1 d&ay - 740 + 743 - + &Copy IP/Netmask - &Copy IP/Netmask - 768 + 771 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 - + 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. @@ -4415,3320 +4000,2698 @@ 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 - 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 - 985 + 992 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. - + Executing… - Executing… - 1171 + 1193 A console message indicating an entered command is currently being executed. - + (peer: %1) - (peer: %1) - 1281 + 1303 - + via %1 - via %1 - 1283 + 1305 - + Regular - Regular - 1326 + 1352 - + Masternode - Masternode - 1330 + 1356 - + Verified Masternode - Verified Masternode - 1332 + 1358 - + - + To - To - 155 + 165 - + From - From - 155 + 165 - + No - No - 155 + 165 - + Ban for - Ban for - 156 + 166 - + Yes - Yes - 155 + 165 - + Unknown - Unknown - 156 + 166 - + Never - Never - 203 + 214 - + - + 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 Dash network. - 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 Dash network. 34 - + &Message: - &Message: 37 - + An optional label to associate with the new receiving address. - An optional label to associate with the new receiving address. 77 - + An optional message to attach to the payment request, which will be displayed when the request is opened.<br>Note: The message will not be sent with the payment over the Dash network. - An optional message to attach to the payment request, which will be displayed when the request is opened.<br>Note: The message will not be sent with the payment over the Dash network. 60 - + 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. - 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. 50 - + Use this form to request payments. All fields are <b>optional</b>. - Use this form to request payments. All fields are <b>optional</b>. 70 - + &Label: - &Label: 80 - + An optional amount to request. Leave this empty or zero to not request a specific amount. - An optional amount to request. Leave this empty or zero to not request a specific amount. 93 179 - + &Amount: - &Amount: 96 - + &Create new receiving address - &Create new receiving address 117 - + Clear all fields of the form. - Clear all fields of the form. 136 - + Clear - Clear 139 - + Requested payments history - Requested payments history 234 - + Show the selected request (does the same as double clicking an entry) - Show the selected request (does the same as double clicking an entry) 259 - + Show - Show 262 - + Remove the selected entries from the list - Remove the selected entries from the list 275 - + Remove - Remove 278 - + Enter a label to associate with the new receiving address - Enter a label to associate with the new receiving address 53 - + Enter a message to attach to the payment request - Enter a message to attach to the payment request 63 - + - + Copy &URI - Copy &URI - 36 + 33 - + &Copy address - &Copy address - 37 + 34 - + Copy &label - Copy &label - 38 + 35 - + Copy &message - Copy &message - 39 + 36 - + Copy &amount - Copy &amount - 40 + 37 - + Could not unlock wallet. - Could not unlock wallet. - 145 + 142 - + Could not generate new address - Could not generate new address - 150 + 147 - + - + Request payment to … - Request payment to … 14 - + Address: - Address: 90 - + Amount: - Amount: 119 - + Label: - Label: 148 - + Message: - Message: 180 - + Wallet: - Wallet: 212 - + Copy &URI - Copy &URI 240 - + Copy &Address - Copy &Address 250 - + &Save Image… - &Save Image… 260 - + Payment information - Payment information 39 - + - + Request payment to %1 - Request payment to %1 52 - + - + Date - Date 32 - + Label - Label 32 - + Message - Message 32 - + (no label) - (no label) - 73 + 70 - + (no message) - (no message) - 82 + 79 - + (no amount requested) - (no amount requested) - 90 + 87 - + Requested - Requested - 133 + 130 - + - + Send Coins - Send Coins 14 - ../sendcoinsdialog.cpp766 + ../sendcoinsdialog.cpp777 - + Coin Control Features - Coin Control Features 81 - + automatically selected - automatically selected 111 - + Insufficient funds! - Insufficient funds! 121 - + Quantity: - Quantity: - 204 + 207 - + Bytes: - Bytes: - 233 + 236 - + Amount: - Amount: - 275 + 278 - + Fee: - Fee: - 343 - - - Dust: - Dust: - 301 + 323 - + Inputs… - Inputs… 101 - + After Fee: - After Fee: - 388 + 371 - + Change: - Change: - 414 + 397 - + If this is activated, but the change address is empty or invalid, change will be sent to a newly generated address. - If this is activated, but the change address is empty or invalid, change will be sent to a newly generated address. - 458 + 441 - + Custom change address - Custom change address - 461 + 444 - + Transaction Fee: - Transaction Fee: - 658 + 641 - + 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 dash transactions than the network can process. - 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 dash transactions than the network can process. - 822 + 805 - + A too low fee might result in a never confirming transaction (read the tooltip) - A too low fee might result in a never confirming transaction (read the tooltip) - 825 + 808 - + (Smart fee not initialized yet. This usually takes a few blocks…) - (Smart fee not initialized yet. This usually takes a few blocks…) - 942 + 925 - + Confirmation time target: - Confirmation time target: - 968 + 951 - + If the custom fee is set to 1000 duffs and the transaction is only 250 bytes, then "per kilobyte" only pays 250 duffs in fee,<br />while "at least" pays 1000 duffs. For transactions bigger than a kilobyte both pay by kilobyte. - If the custom fee is set to 1000 duffs and the transaction is only 250 bytes, then "per kilobyte" only pays 250 duffs in fee,<br />while "at least" pays 1000 duffs. For transactions bigger than a kilobyte both pay by kilobyte. - 789 + 772 - + per kilobyte - per kilobyte - 792 + 775 - + 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. - 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. - 694 + 677 - + Choose… - Choose… - 672 + 655 - + Note: Not enough data for fee estimation, using the fallback fee instead. - Note: Not enough data for fee estimation, using the fallback fee instead. - 697 + 680 - + Hide transaction fee settings - Hide transaction fee settings - 735 + 718 - + Hide - Hide - 738 + 721 - + Recommended: - Recommended: - 857 + 840 - + Custom: - Custom: - 890 + 873 - + Confirm the send action - Confirm the send action - 1055 - ../sendcoinsdialog.cpp156 + 1038 + ../sendcoinsdialog.cpp151 - + S&end - S&end - 1058 - ../sendcoinsdialog.cpp155 + 1041 + ../sendcoinsdialog.cpp150 - + Clear all fields of the form. - Clear all fields of the form. - 1077 + 1060 - + Clear &All - Clear &All - 1080 + 1063 - + Send to multiple recipients at once - Send to multiple recipients at once - 1090 + 1073 - + Add &Recipient - Add &Recipient - 1093 + 1076 - + Balance: - Balance: - 1121 + 1104 - + - + Copy quantity - Copy quantity - 110 + 108 - + Copy amount - Copy amount - 111 + 109 - + Copy fee - Copy fee - 112 + 110 - + Copy after fee - Copy after fee - 113 + 111 - + Copy bytes - Copy bytes - 114 - - - Copy dust - Copy dust - 115 + 112 - + Copy change - Copy change - 116 + 113 - + %1 (%2 blocks) - %1 (%2 blocks) - 212 - - - This will produce a Partially Signed Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet. - This will produce a Partially Signed Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet. - 377 + 207 - + using - using - 387 - 389 + 397 + 399 - + %1 to %2 - %1 to %2 - 358 - - - Are you sure you want to send? - Are you sure you want to send? - 373 + 353 - + <b>(%1 of %2 entries displayed)</b> - <b>(%1 of %2 entries displayed)</b> - 398 + 408 - + S&end mixed funds - S&end mixed funds - 152 + 147 - + Confirm the %1 send action - Confirm the %1 send action - 153 + 148 - + Cr&eate Unsigned - Cr&eate Unsigned - 235 + 230 - + from wallet '%1' - from wallet '%1' - 342 + 337 - + %1 to '%2' - %1 to '%2' - 353 - - - Do you want to draft this transaction? - Do you want to draft this transaction? - 371 + 348 - + %1 funds only - %1 funds only - 387 + 397 - + any available funds - any available funds - 389 + 399 - + Transaction fee - Transaction fee - 408 + 418 - + (%1 transactions have higher fees usually due to no change output being allowed) - (%1 transactions have higher fees usually due to no change output being allowed) - 414 + 424 - + Transaction size: %1 - Transaction size: %1 - 421 + 431 - + Fee rate: %1 - Fee rate: %1 - 424 + 434 - 430 - + 440 + This transaction will consume %n input(s) - This transaction will consume %n input - + This transaction will consume %n input(s) - This transaction will consume %n inputs - + Warning: Using %1 with %2 or more inputs can harm your privacy and is not recommended - Warning: Using %1 with %2 or more inputs can harm your privacy and is not recommended - 436 + 446 - + Click to learn more - Click to learn more - 438 + 448 - + Total Amount - Total Amount - 455 + 464 - + or - or - 458 + 467 - + Confirm send coins - Confirm send coins - 477 - - - Confirm transaction proposal - Confirm transaction proposal - 477 - - - Create Unsigned - Create Unsigned - 478 + 489 - + Save Transaction Data - Save Transaction Data - 522 + 534 - + PSBT saved - PSBT saved - 531 + 543 - + Watch-only balance: - Watch-only balance: - 709 - - - Send - Send - 478 + 720 - + Creates a Partially Signed Blockchain Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet. - - 236 + 231 + + + Do you want to create this transaction? + 370 + 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. + + + Please, review your transaction proposal. This will produce a Partially Signed Blockchain Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet. + 379 + 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. + + + Please, review your transaction. You can create and send this transaction or create a Partially Signed Blockchain Transaction (PSBT), which you can save or copy and then sign with, e.g., an offline %1 wallet, or a PSBT-compatible hardware wallet. + 384 + 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. + + + Please, review your transaction. + 387 + Text to prompt a user to review the details of the transaction they are attempting to send. - + To review recipient list click "Show Details…" - To review recipient list click "Show Details…" - 461 + 473 - + Partially Signed Transaction (Binary) - Partially Signed Transaction (Binary) - 524 + 536 Expanded name of the binary PSBT file format. See: BIP 174. - + The recipient address is not valid. Please recheck. - The recipient address is not valid. Please recheck. - 739 + 750 - + The amount to pay must be larger than 0. - The amount to pay must be larger than 0. - 742 + 753 - + The amount exceeds your balance. - The amount exceeds your balance. - 745 + 756 - + The total exceeds your balance when the %1 transaction fee is included. - The total exceeds your balance when the %1 transaction fee is included. - 748 + 759 - + Duplicate address found: addresses should only be used once each. - Duplicate address found: addresses should only be used once each. - 751 + 762 - + Transaction creation failed! - Transaction creation failed! - 754 + 765 - + A fee higher than %1 is considered an absurdly high fee. - A fee higher than %1 is considered an absurdly high fee. - 758 + 769 - 876 - + 887 + Estimated to begin confirmation within %n block(s). - Estimated to begin confirmation within %n block. - + Estimated to begin confirmation within %n block(s). - Estimated to begin confirmation within %n blocks. - + Warning: Invalid Dash address - Warning: Invalid Dash address - 977 + 982 - + Warning: Unknown change address - Warning: Unknown change address - 982 + 987 - + Confirm custom change address - Confirm custom change address - 985 + 990 - + 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? - 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? - 985 + 990 - + (no label) - (no label) - 1006 + 1011 - + - + Pay &To: - Pay &To: - 39 + 35 - + The Dash address to send the payment to - The Dash address to send the payment to - 57 + 53 - + Choose previously used address - Choose previously used address - 64 + 60 - + Alt+A - Alt+A - 76 + 72 - + Paste address from clipboard - Paste address from clipboard - 83 + 79 - + Alt+P - Alt+P - 95 + 91 - + Remove this entry - Remove this entry - 102 - 660 - 1189 + 98 - + &Label: - &Label: - 120 + 116 - + Enter a label for this address to add it to the list of used addresses - Enter a label for this address to add it to the list of used addresses - 133 - 136 + 129 + 132 - + A&mount: - A&mount: - 143 - 689 - 1218 + 139 - + The amount to send in the selected unit - The amount to send in the selected unit - 158 + 154 - + The fee will be deducted from the amount being sent. The recipient will receive a lower amount of Dash than you enter in the amount field. If multiple recipients are selected, the fee is split equally. - The fee will be deducted from the amount being sent. The recipient will receive a lower amount of Dash than you enter in the amount field. If multiple recipients are selected, the fee is split equally. - 165 + 161 - + S&ubtract fee from amount - S&ubtract fee from amount - 168 + 164 - + Use available balance - Use available balance - 175 + 171 - + Message: - Message: - 184 + 180 - + A message that was attached to the dash: URI which will be stored with the transaction for your reference. Note: This message will not be sent over the Dash network. - A message that was attached to the dash: URI which will be stored with the transaction for your reference. Note: This message will not be sent over the Dash network. - 194 - - - This is an unauthenticated payment request. - This is an unauthenticated payment request. - 627 - - - This is an authenticated payment request. - This is an authenticated payment request. - 1152 + 190 - - Pay To: - Pay To: - 642 - 1167 + + + + + + Send + 133 - - Memo: - Memo: - 672 - 1201 + + Create Unsigned + 135 - + - + Signatures - Sign / Verify a Message - Signatures - Sign / Verify a Message 14 - + &Sign Message - &Sign Message 31 - + You can sign messages/agreements with your addresses to prove you can receive Dash 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. - You can sign messages/agreements with your addresses to prove you can receive Dash 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. 66 - + The Dash address to sign the message with - The Dash address to sign the message with 84 - + Choose previously used address - Choose previously used address 91 264 - + Alt+A - Alt+A 97 270 - + Paste address from clipboard - Paste address from clipboard 104 - + Alt+P - Alt+P 110 - + Enter the message you want to sign here - Enter the message you want to sign here 119 - + Signature - Signature 129 - + Copy the current signature to the system clipboard - Copy the current signature to the system clipboard 154 - + Sign the message to prove you own this Dash address - Sign the message to prove you own this Dash address 168 - + Sign &Message - Sign &Message 171 - + Reset all sign message fields - Reset all sign message fields 181 - + Clear &All - Clear &All 184 317 - + &Verify Message - &Verify Message 41 - + 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! - 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! 236 - + The Dash address the message was signed with - The Dash address the message was signed with 257 - + The signed message to verify - The signed message to verify 279 - + The signature given when the message was signed - The signature given when the message was signed 289 - + Verify the message to ensure it was signed with the specified Dash address - Verify the message to ensure it was signed with the specified Dash address 301 - + Verify &Message - Verify &Message 304 - + Reset all verify message fields - Reset all verify message fields 314 - + Enter a message to be signed - Enter a message to be signed 122 - + Click "Sign Message" to generate signature - Click "Sign Message" to generate signature 144 - + Enter a message to be verified - Enter a message to be verified 282 - + Enter a signature for the message to be verified - Enter a signature for the message to be verified 292 - + - + The entered address is invalid. - The entered address is invalid. 151 250 - + Please check the address and try again. - Please check the address and try again. 151 158 251 258 - + The entered address does not refer to a key. - The entered address does not refer to a key. 158 257 - + Wallet unlock was cancelled. - Wallet unlock was cancelled. 166 - + No error - No error 177 - + Private key for the entered address is not available. - Private key for the entered address is not available. 180 - + Message signing failed. - Message signing failed. 183 - + Message signed. - Message signed. 195 - + The signature could not be decoded. - The signature could not be decoded. 264 - + Please check the signature and try again. - Please check the signature and try again. 265 272 - + The signature did not match the message digest. - The signature did not match the message digest. 271 - + Message verification failed. - Message verification failed. 277 - + Message verified. - Message verified. 245 - + - + (press q to shutdown and continue later) - (press q to shutdown and continue later) - 192 + 181 - + press q to shutdown - press q to shutdown - 193 + 182 - + - + kB/s - kB/s 101 - + Total - Total 166 - + Received - Received 167 - + Sent - Sent 168 - + - - 36 - - Open for %n more block(s) - Open for %n more block - - - Open for %n more block(s) - Open for %n more blocks - - - - Open until %1 - Open until %1 - 38 - - - conflicted - conflicted - 43 - - + 0/unconfirmed, %1 - 0/unconfirmed, %1 - 50 + 57 + 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. - + in memory pool - in memory pool - 50 + 57 - + not in memory pool - not in memory pool - 50 + 57 - + abandoned - abandoned - 49 + 53 + 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. + + + conflicted with a transaction with %1 confirmations + 43 + 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. - + %1/unconfirmed - %1/unconfirmed - 52 + 63 + 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, and still not locked via ChainLocks. - + %1 confirmations - %1 confirmations - 54 + 69 + 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 or locked via ChainLocks. - + locked via ChainLocks - locked via ChainLocks - 56 + 74 + 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 and has been locked by ChainLocks. - + verified via InstantSend - verified via InstantSend - 62 + 83 + 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 has been locked by InstantSend. - + Status - Status - 87 + 107 - + Date - Date - 90 + 110 - + Source - Source - 97 - 101 + 117 + 121 - + Generated - Generated - 97 + 117 - + Platform Transfer - Platform Transfer - 101 + 121 - + From - From - 106 - 120 - 192 + 126 + 140 + 212 - + unknown - unknown - 120 + 140 - + To - To - 121 141 - 211 + 161 + 231 - + own address - own address - 123 + 143 - + watch-only - watch-only - 123 - 192 + 143 + 212 - + label - label - 125 + 145 - + Credit - Credit - 161 - 173 - 227 - 257 - 300 + 181 + 193 + 247 + 277 + 320 - 163 - + 183 + matures in %n more block(s) - matures in %n more block - + matures in %n more block(s) - matures in %n more blocks - + not accepted - not accepted - 165 + 185 - + Debit - Debit - 225 - 251 - 297 + 245 + 271 + 317 - + Total debit - Total debit - 235 + 255 - + Total credit - Total credit - 236 + 256 - + Transaction fee - Transaction fee - 241 + 261 - + Net amount - Net amount - 263 + 283 - + Message - Message - 269 - 280 + 289 + 300 - + Comment - Comment - 271 + 291 - + Transaction ID - Transaction ID - 273 + 293 - + Output index - Output index - 274 + 294 - + Transaction total size - Transaction total size - 275 + 295 - + 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. - 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. - 286 + 306 - + Debug information - Debug information - 294 + 314 - + Transaction - Transaction - 302 + 322 - + Inputs - Inputs - 305 + 325 - + Amount - Amount - 326 + 346 - + true - true - 327 - 328 + 347 + 348 - + false - false - 327 - 328 + 347 + 348 - + - + This pane shows a detailed description of the transaction - This pane shows a detailed description of the transaction 20 - + - + Details for %1 - Details for %1 - 21 + 20 - + - + Date - Date - 276 + 277 - + Type - Type - 276 + 277 - + Address / Label - Address / Label - 276 - - - 354 - - Open for %n more block(s) - Open for %n more block - - - Open for %n more block(s) - Open for %n more blocks - - - - Open until %1 - Open until %1 - 357 + 277 - + Unconfirmed - Unconfirmed - 360 + 355 - + Abandoned - Abandoned - 363 + 358 - + Confirming (%1 of %2 recommended confirmations) - Confirming (%1 of %2 recommended confirmations) - 366 + 361 - + Confirmed (%1 confirmations) - Confirmed (%1 confirmations) - 369 + 364 - + Conflicted - Conflicted - 372 + 367 - + Immature (%1 confirmations, will be available after %2) - Immature (%1 confirmations, will be available after %2) - 375 + 370 - + Generated but not accepted - Generated but not accepted - 378 + 373 - + verified via InstantSend - verified via InstantSend - 383 + 378 - + locked via ChainLocks - locked via ChainLocks - 386 + 381 - + Received with - Received with - 423 + 418 - + Received from - Received from - 425 + 420 - + Received via %1 - Received via %1 - 427 + 422 - + Sent to - Sent to - 430 + 425 - + Payment to yourself - Payment to yourself - 432 + 427 - + Mined - Mined - 434 + 429 - + Platform Transfer - Platform Transfer - 436 + 431 - + %1 Mixing - %1 Mixing - 439 + 434 - + %1 Collateral Payment - %1 Collateral Payment - 441 + 436 - + %1 Make Collateral Inputs - %1 Make Collateral Inputs - 443 + 438 - + %1 Create Denominations - %1 Create Denominations - 445 + 440 - + %1 Send - %1 Send - 447 + 442 - + watch-only - watch-only - 468 + 463 - + (n/a) - (n/a) - 493 + 488 - + (no label) - (no label) - 729 + 721 - + Transaction status. Hover over this field to show number of confirmations. - Transaction status. Hover over this field to show number of confirmations. - 768 + 760 - + Date and time that the transaction was received. - Date and time that the transaction was received. - 770 + 762 - + Type of transaction. - Type of transaction. - 772 + 764 - + Whether or not a watch-only address is involved in this transaction. - Whether or not a watch-only address is involved in this transaction. - 774 + 766 - + User-defined intent/purpose of the transaction. - User-defined intent/purpose of the transaction. - 776 + 768 - + Amount removed from or added to balance. - Amount removed from or added to balance. - 778 + 770 - + - + All - All - 70 - 83 + 71 + 84 - + Today - Today - 71 + 72 - + This week - This week - 72 + 73 - + This month - This month - 73 + 74 - + Last month - Last month - 74 + 75 - + This year - This year - 75 + 76 - + Range… - Range… - 76 + 77 - + Most Common - Most Common - 84 + 85 - + Received with - Received with - 85 + 86 - + Sent to - Sent to - 87 + 88 - + %1 Send - %1 Send - 89 + 90 - + %1 Make Collateral Inputs - %1 Make Collateral Inputs - 90 + 91 - + %1 Create Denominations - %1 Create Denominations - 91 + 92 - + %1 Mixing - %1 Mixing - 92 + 93 - + %1 Collateral Payment - %1 Collateral Payment - 93 + 94 - + To yourself - To yourself - 94 + 95 - + Mined - Mined - 95 + 96 - + Platform Transfer - Platform Transfer - 96 + 97 - + Other - Other - 97 + 98 - + Enter address, transaction id, or label to search - Enter address, transaction id, or label to search - 103 + 104 - + Min amount - Min amount - 108 + 109 - + &Copy address - &Copy address - 154 + 155 - + Copy &label - Copy &label - 155 + 156 - + Copy &amount - Copy &amount - 156 + 157 - + Copy transaction &ID - Copy transaction &ID - 157 + 158 - + Copy &raw transaction - Copy &raw transaction - 158 + 159 - + Copy full transaction &details - Copy full transaction &details - 159 + 160 - + &Show transaction details - &Show transaction details - 160 + 161 - + A&bandon transaction - A&bandon transaction - 162 + 163 - + Rese&nd transaction - Rese&nd transaction - 163 + 164 - + &Edit address label - &Edit address label - 164 + 165 - + Show address &QR code - Show address &QR code - 165 + 166 + + + Show in %1 + 244 + 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. - + Export Transaction History - Export Transaction History - 368 + 373 - + Comma separated file - Comma separated file - 371 + 376 Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values. - + Confirmed - Confirmed - 380 + 385 - + Watch-only - Watch-only - 382 + 387 - + Date - Date - 383 + 388 - + Type - Type - 384 + 389 - + Label - Label - 385 + 390 - + Address - Address - 386 + 391 - + ID - ID - 388 + 393 - + Exporting Failed - Exporting Failed - 391 + 396 - + There was an error trying to save the transaction history to %1. - There was an error trying to save the transaction history to %1. - 391 + 396 - + Exporting Successful - Exporting Successful - 395 + 400 - + The transaction history was successfully saved to %1. - The transaction history was successfully saved to %1. - 395 + 400 - + QR code - QR code - 553 + 558 - + Range: - Range: - 596 + 601 - + to - to - 605 + 610 - + - + No wallet has been loaded. Go to File > Open Wallet to load a wallet. - OR - - No wallet has been loaded. -Go to File > Open Wallet to load a wallet. -- OR - 46 - + Create a new wallet - Create a new wallet 51 - + Error - Error - 258 - 268 - 278 + 255 + 265 + 283 - + Unable to decode PSBT from clipboard (invalid base64) - Unable to decode PSBT from clipboard (invalid base64) - 258 + 255 - + Load Transaction Data - Load Transaction Data - 264 + 261 - + Partially Signed Transaction (*.psbt) - Partially Signed Transaction (*.psbt) - 265 + 262 - + PSBT file must be smaller than 100 MiB - PSBT file must be smaller than 100 MiB - 268 + 265 - + Unable to decode PSBT - Unable to decode PSBT - 278 + 283 - + - + Send Coins - Send Coins - 265 + 269 - + default wallet - default wallet - 587 + 594 - + - + &Export - &Export - 51 + 53 - + Export the data in the current tab to a file - Export the data in the current tab to a file - 52 + 54 - + Selected amount: - Selected amount: - 58 + 60 - + Wallet Data - Wallet Data - 319 + 306 Name of the wallet data file format. - + Backup Wallet - Backup Wallet - 317 + 304 - + Backup Failed - Backup Failed - 325 + 312 - + There was an error trying to save the wallet data to %1. - There was an error trying to save the wallet data to %1. - 325 + 312 - + Backup Successful - Backup Successful - 329 + 316 - + The wallet data was successfully saved to %1. - The wallet data was successfully saved to %1. - 329 + 316 - + Cancel - Cancel - 382 + 358 - + - - Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee. - Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee. - 79 - - + 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 - 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 - 155 + 150 - + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications - This is a pre-release test build - use at your own risk - do not use for mining or merchant applications - 159 + 154 - + Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade. - Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade. - 199 + 197 - + Already have that input. - Already have that input. 219 - + Collateral not valid. - Collateral not valid. - 227 + 230 - + Corrupted block database detected - Corrupted block database detected - 230 + 233 - + Do you want to rebuild the block database now? - Do you want to rebuild the block database now? - 234 + 237 - + Done loading - Done loading - 235 + 238 - + Entries are full. - Entries are full. - 238 + 241 - + Error initializing block database - Error initializing block database - 241 + 244 - + Error initializing wallet database environment %s! - Error initializing wallet database environment %s! - 242 + 245 - + Error loading block database - Error loading block database - 248 + 251 - + Error opening block database - Error opening block database - 249 + 252 - + Error reading from database, shutting down. - Error reading from database, shutting down. - 250 + 253 - + Error: Missing checksum - Error: Missing checksum - 261 + 262 - + Error: Unable to parse version %u as a uint32_t - Error: Unable to parse version %u as a uint32_t - 263 + 264 - + Error: Unable to write record to new wallet - Error: Unable to write record to new wallet - 264 + 265 - + Failed to listen on any port. Use -listen=0 if you want this. - Failed to listen on any port. Use -listen=0 if you want this. 274 - - -maxtxfee is set very high! Fees this large could be paid on a single transaction. - -maxtxfee is set very high! Fees this large could be paid on a single transaction. - 26 - - + Found unconfirmed denominated outputs, will wait till they confirm to continue. - Found unconfirmed denominated outputs, will wait till they confirm to continue. - 85 + 81 - + Invalid -socketevents ('%s') specified. Only these modes are supported: %s - Invalid -socketevents ('%s') specified. Only these modes are supported: %s - 94 - - - Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions) - Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions) - 96 + 90 - + SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is supported - SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is supported - 138 - - - The -txindex upgrade started by a previous version cannot be completed. Restart with the previous version or run a full -reindex. - - 141 + 140 - + Transaction index can't be disabled with governance validation enabled. Either start with -disablegovernance command line switch or enable transaction index. - Transaction index can't be disabled with governance validation enabled. Either start with -disablegovernance command line switch or enable transaction index. - 173 + 168 - + Unsupported category-specific logging level -loglevel=%s. Expected -loglevel=<category>:<loglevel>. Valid categories: %s. Valid loglevels: %s. - - 186 + 181 - + Can't mix: no compatible inputs found! - Can't mix: no compatible inputs found! 223 - + Entry exceeds maximum size. - Entry exceeds maximum size. - 239 - - - Error upgrading Evo database - - 252 + 242 - + Error upgrading evo database for EHF - - 254 + 255 - + Failed to commit Evo database - 269 - + Found enough users, signing ( waiting %s ) - Found enough users, signing ( waiting %s ) - 283 + 285 - + Incompatible mode. - Incompatible mode. - 287 + 290 - + Incompatible version. - Incompatible version. - 288 + 291 - + Incorrect or no genesis block found. Wrong datadir for network? - Incorrect or no genesis block found. Wrong datadir for network? - 290 + 293 - + Input is not valid. - Input is not valid. - 292 - - - Insufficient funds. - Insufficient funds. 295 - - Invalid amount for -discardfee=<amount>: '%s' - Invalid amount for -discardfee=<amount>: '%s' - 302 - - - Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s) - Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s) - 304 + + Insufficient funds. + 298 - + Invalid minimum number of spork signers specified with -minsporkkeys - Invalid minimum number of spork signers specified with -minsporkkeys - 306 + 308 - + Listening for incoming connections failed (listen returned error %s) - - 312 + 315 - + Lock is already in place. - Lock is already in place. - 317 + 320 - + Need to specify a port with -whitebind: '%s' - Need to specify a port with -whitebind: '%s' - 322 + 326 - + No Masternodes detected. - No Masternodes detected. - 323 + 327 - + No compatible Masternode found. - No compatible Masternode found. - 325 + 329 - + Not enough funds to mix. - Not enough funds to mix. - 330 + 337 - + Not in the Masternode list. - Not in the Masternode list. - 331 + 338 - + Pruning blockstore… - Pruning blockstore… - 335 + 343 - + Replaying blocks… - Replaying blocks… - 337 + 345 - + Rescanning… - Rescanning… - 338 + 346 - + Starting network threads… - Starting network threads… - 351 + 360 - + Submitted to masternode, waiting in queue %s - Submitted to masternode, waiting in queue %s - 352 + 361 - + Synchronization finished - Synchronization finished - 353 + 362 - + Synchronizing blockchain… - Synchronizing blockchain… - 354 + 363 - + Synchronizing governance objects… - Synchronizing governance objects… - 355 + 364 - + Transaction change output index out of range - - 367 + 376 - + Unable to start HTTP server. See debug log for details. - Unable to start HTTP server. See debug log for details. - 384 + 396 - + Unknown response. - Unknown response. - 388 + 400 - + Unsupported global logging level -loglevel=%s. Valid values: %s. - - 390 + 403 - + User Agent comment (%s) contains unsafe characters. - User Agent comment (%s) contains unsafe characters. - 393 + 405 - + Can't find random Masternode. - Can't find random Masternode. 221 - + %s can't be lower than %s - %s can't be lower than %s - 208 + 206 - + %s is idle. - %s is idle. - 210 + 208 - + Can't mix while sync in progress. - Can't mix while sync in progress. 222 - + Invalid netmask specified in -whitelist: '%s' - Invalid netmask specified in -whitelist: '%s' - 307 + 309 - + Invalid script detected. - Invalid script detected. - 308 + 311 - + %s file contains all private keys from this wallet. Do not share it with anyone! - %s file contains all private keys from this wallet. Do not share it with anyone! 16 - + Failed to create backup, file already exists! This could happen if you restarted wallet in less than 60 seconds. You can continue if you are ok with this. - Failed to create backup, file already exists! This could happen if you restarted wallet in less than 60 seconds. You can continue if you are ok with this. - 72 + 68 - + Make sure to encrypt your wallet and delete all non-encrypted backups after you have verified that the wallet works! - Make sure to encrypt your wallet and delete all non-encrypted backups after you have verified that the wallet works! - 103 + 99 - + More than one onion bind address is provided. Using %s for the automatically created Tor onion service. - More than one onion bind address is provided. Using %s for the automatically created Tor onion service. - 106 + 102 - + Prune configured below the minimum of %d MiB. Please use a higher number. - Prune configured below the minimum of %d MiB. Please use a higher number. - 130 + 132 - + Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node) - Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node) - 135 + 137 - + 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 - 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 - 144 + 143 - + The transaction amount is too small to send after the fee has been deducted - The transaction amount is too small to send after the fee has been deducted - 153 + 148 - + Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments. - Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments. - 170 - - - Transaction needs a change address, but we can't generate it. Please call keypoolrefill first. - Transaction needs a change address, but we can't generate it. Please call keypoolrefill first. - 177 + 165 - + WARNING! Failed to replenish keypool, please unlock your wallet to do so. - WARNING! Failed to replenish keypool, please unlock your wallet to do so. - 189 + 187 - + Wallet is locked, can't replenish keypool! Automatic backups and mixing are disabled, please unlock your wallet to replenish keypool. - Wallet is locked, can't replenish keypool! Automatic backups and mixing are disabled, please unlock your wallet to replenish keypool. - 191 + 189 - + You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain - You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain - 204 + 202 - + %s failed - %s failed - 209 + 207 - + -maxmempool must be at least %d MB - -maxmempool must be at least %d MB - 215 + 213 - + Automatic backups disabled - Automatic backups disabled 220 - + Cannot set -peerblockfilters without -blockfilterindex. - Cannot set -peerblockfilters without -blockfilterindex. - 225 + 228 - + Config setting for %s only applied on %s network when in [%s] section. - Config setting for %s only applied on %s network when in [%s] section. - 228 + 231 - + Could not find asmap file %s - Could not find asmap file %s - 231 + 234 - + Could not parse asmap file %s - Could not parse asmap file %s - 232 + 235 - + ERROR! Failed to create automatic backup - ERROR! Failed to create automatic backup - 237 + 240 - + Error loading %s: Private keys can only be disabled during creation - Error loading %s: Private keys can only be disabled during creation - 244 + 247 - + Error: Couldn't create cursor into database - Error: Couldn't create cursor into database - 255 + 256 - + Error: Disk space is low for %s - Error: Disk space is low for %s - 256 + 257 - + Error: Dumpfile checksum does not match. Computed %s, expected %s - Error: Dumpfile checksum does not match. Computed %s, expected %s - 257 + 258 - + Error: Got key that was not hex: %s - Error: Got key that was not hex: %s - 258 + 259 - + Error: Got value that was not hex: %s - Error: Got value that was not hex: %s - 259 + 260 - + Error: Keypool ran out, please call keypoolrefill first - Error: Keypool ran out, please call keypoolrefill first - 260 + 261 - + Error: No addresses available. - Error: No addresses available. - 262 - - - Exceeded max tries. - Exceeded max tries. - 265 + 263 - + Failed to create backup %s! - Failed to create backup %s! 270 - + Failed to create backup, error: %s - Failed to create backup, error: %s 271 - + Failed to delete backup, error: %s - Failed to delete backup, error: %s 272 - + Failed to rescan the wallet during initialization - Failed to rescan the wallet during initialization 279 - + Failed to verify database - Failed to verify database - 281 + 282 - + Fee rate (%s) is lower than the minimum fee rate setting (%s) - Fee rate (%s) is lower than the minimum fee rate setting (%s) - 282 + 284 - + Found enough users, signing… - Found enough users, signing… - 284 + 286 - + Ignoring duplicate -wallet %s. - Ignoring duplicate -wallet %s. - 285 + 288 - + Input not found or already spent - Input not found or already spent - 293 + 296 - + Invalid P2P permission: '%s' - Invalid P2P permission: '%s' - 300 - - - Invalid amount for -fallbackfee=<amount>: '%s' - Invalid amount for -fallbackfee=<amount>: '%s' 303 - + Invalid masternodeblsprivkey. Please see documentation. - Invalid masternodeblsprivkey. Please see documentation. - 305 + 307 - + Masternode queue is full. - Masternode queue is full. - 318 + 321 - + Masternode: - Masternode: - 319 + 322 - + Missing input transaction information. - Missing input transaction information. - 320 + 323 - + Mixing in progress… - Mixing in progress… - 321 + 325 - + No addresses available - No addresses available - 324 + 328 - + No errors detected. - No errors detected. - 326 + 330 - + No matching denominations found for mixing. - No matching denominations found for mixing. - 327 + 333 - + Not compatible with existing transactions. - Not compatible with existing transactions. - 328 + 335 - + Not enough file descriptors available. - Not enough file descriptors available. - 329 + 336 - + Prune cannot be configured with a negative value. - Prune cannot be configured with a negative value. - 332 + 340 - + Prune mode is incompatible with -disablegovernance=false. - Prune mode is incompatible with -disablegovernance=false. - 333 + 341 - + Prune mode is incompatible with -txindex. - Prune mode is incompatible with -txindex. - 334 + 342 - + SQLiteDatabase: Failed to execute statement to verify database: %s - SQLiteDatabase: Failed to execute statement to verify database: %s - 339 + 347 - + SQLiteDatabase: Failed to prepare statement to verify database: %s - SQLiteDatabase: Failed to prepare statement to verify database: %s - 340 + 348 - + SQLiteDatabase: Failed to read database verification error: %s - SQLiteDatabase: Failed to read database verification error: %s - 341 + 349 - + SQLiteDatabase: Unexpected application id. Expected %u, got %u - SQLiteDatabase: Unexpected application id. Expected %u, got %u - 342 + 350 - + Section [%s] is not recognized. - Section [%s] is not recognized. - 343 + 351 - + Specified -walletdir "%s" does not exist - Specified -walletdir "%s" does not exist - 347 + 356 - + Specified -walletdir "%s" is a relative path - Specified -walletdir "%s" is a relative path - 348 + 357 - + Specified -walletdir "%s" is not a directory - Specified -walletdir "%s" is not a directory - 349 + 358 - + The wallet will avoid paying less than the minimum relay fee. - The wallet will avoid paying less than the minimum relay fee. - 359 + 368 - + This is expected because you are running a pruned node. - This is expected because you are running a pruned node. - 360 + 369 - + This is the minimum transaction fee you pay on every transaction. - This is the minimum transaction fee you pay on every transaction. - 362 + 371 - + This is the transaction fee you will pay if you send a transaction. - This is the transaction fee you will pay if you send a transaction. - 363 + 372 - + Topping up keypool… - Topping up keypool… - 364 + 373 - + Transaction amounts must not be negative - Transaction amounts must not be negative - 366 + 375 - + Transaction has too long of a mempool chain - Transaction has too long of a mempool chain - 370 + 379 - + Transaction must have at least one recipient - Transaction must have at least one recipient - 371 + 380 - + Transaction too large - Transaction too large - 373 + 383 - + Unable to bind to %s on this computer. %s is probably already running. - Unable to bind to %s on this computer. %s is probably already running. - 376 + 386 - + Unable to create the PID file '%s': %s - Unable to create the PID file '%s': %s - 377 + 387 - + Unable to generate initial keys - Unable to generate initial keys - 378 + 388 - + Unable to open %s for writing - Unable to open %s for writing - 381 - - - Unable to parse -maxuploadtarget: '%s' (possible integer overflow?) - Unable to parse -maxuploadtarget: '%s' (possible integer overflow?) - 382 + 392 - + Unknown -blockfilterindex value %s. - Unknown -blockfilterindex value %s. - 385 + 397 - + Unknown new rules activated (versionbit %i) - Unknown new rules activated (versionbit %i) - 387 - - - Upgrading UTXO database - Upgrading UTXO database - 392 + 399 - + Verifying blocks… - Verifying blocks… - 394 + 406 - + Verifying wallet(s)… - Verifying wallet(s)… - 395 + 407 - + Wallet needed to be rewritten: restart %s to complete - Wallet needed to be rewritten: restart %s to complete - 398 + 410 - + Wasn't able to create wallet backup folder %s! - Wasn't able to create wallet backup folder %s! - 401 + 413 - + Wiping wallet transactions… - Wiping wallet transactions… - 403 + 415 - + You can not start a masternode with wallet enabled. - You can not start a masternode with wallet enabled. - 406 + 418 - + no mixing available. - no mixing available. - 410 + 422 - + see debug.log for details. - see debug.log for details. - 411 + 423 - + The %s developers - The %s developers 12 - + %s uses exact denominated amounts to send funds, you might simply need to mix some more coins. - %s uses exact denominated amounts to send funds, you might simply need to mix some more coins. - 23 + 25 - + -reindex-chainstate option is not compatible with -blockfilterindex. Please temporarily disable blockfilterindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes. - -reindex-chainstate option is not compatible with -blockfilterindex. Please temporarily disable blockfilterindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes. - 29 + 28 - + -reindex-chainstate option is not compatible with -coinstatsindex. Please temporarily disable coinstatsindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes. - -reindex-chainstate option is not compatible with -coinstatsindex. Please temporarily disable coinstatsindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes. - 33 + 32 - + -reindex-chainstate option is not compatible with -txindex. Please temporarily disable txindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes. - -reindex-chainstate option is not compatible with -txindex. Please temporarily disable txindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes. - 37 + 36 - + Cannot downgrade wallet from version %i to version %i. Wallet version unchanged. - Cannot downgrade wallet from version %i to version %i. Wallet version unchanged. - 41 + 40 - + Cannot obtain a lock on data directory %s. %s is probably already running. - Cannot obtain a lock on data directory %s. %s is probably already running. - 44 - - - Cannot upgrade a non HD wallet from version %i to version %i which is non-HD wallet. Use upgradetohd RPC - Cannot upgrade a non HD wallet from version %i to version %i which is non-HD wallet. Use upgradetohd RPC - 49 + 43 - + Distributed under the MIT software license, see the accompanying file %s or %s - Distributed under the MIT software license, see the accompanying file %s or %s - 52 + 48 - + Error loading %s: You can't enable HD on an already existing non-HD wallet - Error loading %s: You can't enable HD on an already existing non-HD wallet - 55 + 51 - + 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 - 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 - 57 + 53 - + Error reading %s! All keys read correctly, but transaction data or address book entries might be missing or incorrect. - Error reading %s! All keys read correctly, but transaction data or address book entries might be missing or incorrect. - 62 + 58 - + Error: Dumpfile format record is incorrect. Got "%s", expected "format". - Error: Dumpfile format record is incorrect. Got "%s", expected "format". - 65 + 61 - + Error: Dumpfile identifier record is incorrect. Got "%s", expected "%s". - Error: Dumpfile identifier record is incorrect. Got "%s", expected "%s". - 67 + 63 - + Error: Dumpfile version is not supported. This version of bitcoin-wallet only supports version 1 dumpfiles. Got dumpfile with version %s - Error: Dumpfile version is not supported. This version of bitcoin-wallet only supports version 1 dumpfiles. Got dumpfile with version %s - 69 + 65 - + Failed to rename invalid peers.dat file. Please move or delete it and try again. - Failed to rename invalid peers.dat file. Please move or delete it and try again. - 76 + 72 + + + Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable %s. + 75 - + File %s already exists. If you are sure this is what you want, move it out of the way first. - File %s already exists. If you are sure this is what you want, move it out of the way first. - 82 + 78 - + Incompatible options: -dnsseed=1 was explicitly specified, but -onlynet forbids connections to IPv4/IPv6 - Incompatible options: -dnsseed=1 was explicitly specified, but -onlynet forbids connections to IPv4/IPv6 - 88 + 84 - + Incorrect or no devnet genesis block found. Wrong datadir for devnet specified? - Incorrect or no devnet genesis block found. Wrong datadir for devnet specified? - 91 + 87 + + + Invalid amount for %s=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions) + 92 - + 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. - 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. - 99 + 95 - + No dump file provided. To use createfromdump, -dumpfile=<filename> must be provided. - No dump file provided. To use createfromdump, -dumpfile=<filename> must be provided. - 109 + 105 - + No dump file provided. To use dump, -dumpfile=<filename> must be provided. - No dump file provided. To use dump, -dumpfile=<filename> must be provided. - 112 + 108 - + No wallet file format provided. To use createfromdump, -format=<format> must be provided. - No wallet file format provided. To use createfromdump, -format=<format> must be provided. - 114 + 110 - + + Outbound connections restricted to CJDNS (-onlynet=cjdns) but -cjdnsreachable is not provided + 113 + + Outbound connections restricted to Tor (-onlynet=onion) but the proxy for reaching the Tor network is explicitly forbidden: -onion=0 - Outbound connections restricted to Tor (-onlynet=onion) but the proxy for reaching the Tor network is explicitly forbidden: -onion=0 - 117 + 116 - + 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 - 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 - 120 + 119 - + + Outbound connections restricted to i2p (-onlynet=i2p) but -i2psam is not provided + 123 + + Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly. - Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly. - 124 + 126 - + Please contribute if you find %s useful. Visit %s for further information about the software. - Please contribute if you find %s useful. Visit %s for further information about the software. - 127 + 129 - + Prune mode is incompatible with -reindex-chainstate. Use full -reindex instead. - Prune mode is incompatible with -reindex-chainstate. Use full -reindex instead. - 132 - - - The block index db contains a legacy 'txindex'. To clear the occupied disk space, run a full -reindex, otherwise ignore this error. This error message will not be displayed again. - The block index db contains a legacy 'txindex'. To clear the occupied disk space, run a full -reindex, otherwise ignore this error. This error message will not be displayed again. - 149 + 134 - + This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection. - This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection. - 162 + 157 - + This is the transaction fee you may discard if change is smaller than dust at this level - This is the transaction fee you may discard if change is smaller than dust at this level - 165 + 160 - + This is the transaction fee you may pay when fee estimates are not available. - This is the transaction fee you may pay when fee estimates are not available. - 168 + 163 + + + Transaction requires one destination of non-0 value, a non-0 feerate, or a pre-selected input + 172 - + Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate. - Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate. - 180 + 175 - + Unknown wallet file format "%s" provided. Please provide one of "bdb" or "sqlite". - Unknown wallet file format "%s" provided. Please provide one of "bdb" or "sqlite". - 183 + 178 + + + Unsupported chainstate database format found. Please restart with -reindex-chainstate. This will rebuild the chainstate database. + 184 - + Warning: Dumpfile wallet format "%s" does not match command line specified format "%s". - Warning: Dumpfile wallet format "%s" does not match command line specified format "%s". - 194 + 192 - + Warning: Private keys detected in wallet {%s} with disabled private keys - Warning: Private keys detected in wallet {%s} with disabled private keys - 197 + 195 - + You need to rebuild the database using -reindex to enable -timestampindex - You need to rebuild the database using -reindex to enable -timestampindex - 202 + 200 - + %s -- Incorrect seed, it should be a hex string - %s -- Incorrect seed, it should be a hex string - 207 + 205 - + %s is not a valid backup folder! - %s is not a valid backup folder! - 211 + 209 - + %s is set very high! - %s is set very high! - 212 + 210 - + %s request incomplete: - %s request incomplete: - 213 + 211 - + -devnet can only be specified once - -devnet can only be specified once - 214 + 212 - + -port must be specified when -devnet and -listen are specified - -port must be specified when -devnet and -listen are specified - 216 + 214 - + -rpcport must be specified when -devnet and -server are specified - -rpcport must be specified when -devnet and -server are specified + 215 + + + -statsbatchsize cannot be configured with a negative value. + 216 + + + -statsduration cannot be configured with a negative value. 217 - + A fatal internal error occurred, see debug.log for details - A fatal internal error occurred, see debug.log for details 218 - - Cannot resolve -%s address: '%s' - Cannot resolve -%s address: '%s' + + Cannot create socket (socket() returned error %s) 224 - - Cannot write to data directory '%s'; check permissions. - Cannot write to data directory '%s'; check permissions. + + Cannot get socket address for %s + 225 + + + Cannot init Statsd client 226 - - Copyright (C) - Copyright (C) + + Cannot resolve -%s address: '%s' + 227 + + + Cannot write to data directory '%s'; check permissions. 229 - + + Copyright (C) + 232 + + Disk space is too low! - Disk space is too low! - 233 + 236 - + Dump file %s does not exist. - Dump file %s does not exist. - 236 + 239 - + Error creating %s - Error creating %s - 240 + 243 - + Error loading %s - Error loading %s - 243 + 246 - + Error loading %s: Wallet corrupted - Error loading %s: Wallet corrupted - 245 + 248 - + Error loading %s: Wallet requires newer version of %s - Error loading %s: Wallet requires newer version of %s - 246 + 249 - + Error loading %s: You can't disable HD on an already existing HD wallet - Error loading %s: You can't disable HD on an already existing HD wallet - 247 + 250 - + Error reading next record from wallet database - Error reading next record from wallet database - 251 - - - Error upgrading chainstate database - Error upgrading chainstate database - 253 + 254 - + Loading P2P addresses… - Loading P2P addresses… - 313 + 316 - + Loading banlist… - Loading banlist… - 314 + 317 - + Loading block index… - Loading block index… - 315 + 318 - + Loading wallet… - Loading wallet… - 316 + 319 - + Failed to clear fulfilled requests cache at %s - Failed to clear fulfilled requests cache at %s 266 - + Failed to clear governance cache at %s - Failed to clear governance cache at %s 267 - + Failed to clear masternode cache at %s - Failed to clear masternode cache at %s 268 - + Failed to find mixing queue to join - Failed to find mixing queue to join 273 - + Failed to load fulfilled requests cache from %s - Failed to load fulfilled requests cache from %s 275 - + Failed to load governance cache from %s - Failed to load governance cache from %s 276 - + Failed to load masternode cache from %s - Failed to load masternode cache from %s 277 - + Failed to load sporks cache from %s - Failed to load sporks cache from %s 278 - + Failed to start a new mixing queue - Failed to start a new mixing queue 280 - + Importing… - Importing… - 286 + 289 - + Incorrect -rescan mode, falling back to default value - Incorrect -rescan mode, falling back to default value - 289 + 292 - + Initialization sanity check failed. %s is shutting down. - Initialization sanity check failed. %s is shutting down. - 291 + 294 - + Inputs vs outputs size mismatch. - Inputs vs outputs size mismatch. - 294 + 297 - + Invalid '%s'. Allowed values: 128, 160, 192, 224, 256. - Invalid '%s'. Allowed values: 128, 160, 192, 224, 256. - 296 + 299 - + Invalid -i2psam address or hostname: '%s' - Invalid -i2psam address or hostname: '%s' - 297 + 300 - + Invalid -onion address or hostname: '%s' - Invalid -onion address or hostname: '%s' - 298 + 301 - + Invalid -proxy address or hostname: '%s' - Invalid -proxy address or hostname: '%s' - 299 + 302 - + Invalid amount for -%s=<amount>: '%s' - Invalid amount for -%s=<amount>: '%s' - 301 + 306 - + Invalid spork address specified with -sporkaddr - Invalid spork address specified with -sporkaddr - 309 + 312 - + Reducing -maxconnections from %d to %d, because of system limitations. - Reducing -maxconnections from %d to %d, because of system limitations. - 336 + 344 - + Session not complete! - Session not complete! - 344 + 352 - + Session timed out. - Session timed out. - 345 + 353 - + Signing transaction failed - Signing transaction failed - 346 + 354 - + Specified blocks directory "%s" does not exist. - Specified blocks directory "%s" does not exist. - 350 + 359 - + Last queue was created too recently. - Last queue was created too recently. - 310 + 313 - + %s corrupt. Try using the wallet tool dash-wallet to salvage or restoring a backup. - %s corrupt. Try using the wallet tool dash-wallet to salvage or restoring a backup. 13 - - %s request to listen on port %u. This port is considered "bad" and thus it is unlikely that any Dash Core peers connect to it. See doc/p2p-bad-ports.md for details and a full list. - + + %s is set very high! Fees this large could be paid on a single transaction. 19 - + + %s request to listen on port %u. This port is considered "bad" and thus it is unlikely that any Dash Core peers connect to it. See doc/p2p-bad-ports.md for details and a full list. + 21 + + Cannot provide specific connections and have addrman find outgoing connections at the same time. - - 46 + 45 - + + Failed to upgrade Evo database + 281 + + + Fee needed > fee paid + 283 + + + Host %s on unsupported network + 287 + + + Invalid amount for %s=<amount>: '%s' (must be at least %s) + 304 + + + Invalid amount for %s=<amount>: '%s' + 305 + + + Invalid port specified in %s: '%s' + 310 + + Last successful action was too recent. - Last successful action was too recent. - 311 + 314 + + + Missing solving data for estimating transaction size + 324 + + + No host specified + 331 + + + No host specified, malformed URL + 332 + + + No text before the scheme delimiter, malformed URL + 334 - + + Port must be between %d and %d, supplied %d + 339 + + + Socket not initialized, cannot send message + 355 + + The source code is available from %s. - The source code is available from %s. - 356 + 365 - + The specified config file %s does not exist - The specified config file %s does not exist - 357 + 366 - + The transaction amount is too small to pay the fee - The transaction amount is too small to pay the fee - 358 + 367 - + This is experimental software. - This is experimental software. - 361 + 370 - + Transaction amount too small - Transaction amount too small - 365 + 374 - + Transaction created successfully. - Transaction created successfully. - 368 + 377 - + Transaction fees are too high. - Transaction fees are too high. - 369 + 378 + + + Transaction needs a change address, but we can't generate it. + 381 - + Transaction not valid. - Transaction not valid. - 372 + 382 - + Trying to connect… - Trying to connect… - 374 + 384 - + Unable to bind to %s on this computer (bind returned error %s) - Unable to bind to %s on this computer (bind returned error %s) - 375 + 385 - + Unable to locate enough mixed funds for this transaction. - Unable to locate enough mixed funds for this transaction. - 379 + 389 - + Unable to locate enough non-denominated funds for this transaction. - Unable to locate enough non-denominated funds for this transaction. - 380 + 390 + + + Unable to lookup host %s + 391 + + + Unable to parse -maxuploadtarget: '%s' + 393 + + + Unable to send message to %s (::sendto() returned error %s) + 394 - + Unable to sign spork message, wrong key? - Unable to sign spork message, wrong key? - 383 + 395 - + Unknown network specified in -onlynet: '%s' - Unknown network specified in -onlynet: '%s' - 386 + 398 - + Unknown state: id = %u - Unknown state: id = %u - 389 + 401 + + + Unsupported URL scheme, must begin with udp:// + 402 - + Unsupported logging category %s=%s. - Unsupported logging category %s=%s. - 391 + 404 - + Very low number of keys left: %d - Very low number of keys left: %d - 396 + 408 - + Wallet is locked. - Wallet is locked. - 397 + 409 - + Warning: can't use %s and %s together, will prefer %s - Warning: can't use %s and %s together, will prefer %s - 399 + 411 - + Warning: incorrect parameter %s, path must exist! Using default path. - Warning: incorrect parameter %s, path must exist! Using default path. - 400 + 412 - + Will retry… - Will retry… - 402 + 414 - + You are starting with governance validation disabled. - You are starting with governance validation disabled. - 404 + 416 - + You can not disable governance validation on a masternode. - You can not disable governance validation on a masternode. - 405 + 417 - + You need to rebuild the database using -reindex to enable -addressindex - You need to rebuild the database using -reindex to enable -addressindex - 407 + 419 - + You need to rebuild the database using -reindex to enable -spentindex - You need to rebuild the database using -reindex to enable -spentindex - 408 + 420 - + Your entries added successfully. - Your entries added successfully. - 409 + 421 diff --git a/src/qt/locale/dash_es.ts b/src/qt/locale/dash_es.ts index b973388b87ac..db2a59fafc5d 100644 --- a/src/qt/locale/dash_es.ts +++ b/src/qt/locale/dash_es.ts @@ -65,14 +65,6 @@ C&hoose E&scoger - - Sending addresses - Direcciones de envío - - - Receiving addresses - Direcciones de recepción - These are your Dash addresses for sending payments. Always check the amount and the receiving address before sending coins. Estas son sus direcciones Dash para enviar pagos. Compruebe siempre la cantidad y la dirección receptora antes de enviar monedas. @@ -94,8 +86,8 @@ &Editar - &Show address QR code - &Mostrar dirección en QR + Show address &QR code + Mostrar dirección y código QR QR code @@ -105,6 +97,24 @@ Export Address List Exportar la Lista de Direcciones + + Comma separated file + Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values. + Comma separated file + + + There was an error trying to save the address list to %1. Please try again. + An error message. %1 is a stand-in argument for the name of the file we attempted to save to. + Se produjo un error al intentar guardar la lista de direcciones en %1. Inténtalo de nuevo. + + + Sending addresses - %1 + Direcciones de envío - %1 + + + Receiving addresses - %1 + Direcciones de recepción - %1 + Exporting Failed Error al exportar @@ -141,7 +151,7 @@ Smaller - Mas pequeño + Más pequeño Bigger @@ -274,10 +284,22 @@ The passphrase entered for the wallet decryption was incorrect. La contraseña introducida para descifrar la billetera es incorrecta. + + 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 23.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. + La contraseña introducida para el descifrado de la billetera es incorrecta. Contiene un carácter nulo (es decir, un byte cero). Si la contraseña se estableció con una versión de este software anterior a la 23.0, inténtalo de nuevo solo con los caracteres hasta —pero sin incluir— el primer carácter nulo. Si esto funciona, establece una nueva contraseña para evitar este problema en el futuro. + Wallet passphrase was successfully changed. Se ha cambiado correctamente la contraseña de la billetera + + Passphrase change failed + Error al cambiar la contraseña + + + 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 23.0, please try again with only the characters up to — but not including — the first null character. + La contraseña antigua introducida para el descifrado de la billetera es incorrecta. Contiene un carácter nulo (es decir, un byte cero). Si la contraseña se estableció con una versión de este software anterior a la 23.0, inténtalo de nuevo solo con los caracteres hasta —pero sin incluir— el primer carácter nulo. + Warning: The Caps Lock key is on! Advertencia: ¡La tecla de bloqueo de mayúsculas está activada! @@ -303,7 +325,23 @@ BitcoinApplication - + + Runaway exception + Excepción fuera de control + + + A fatal error occurred. %1 can no longer continue safely and will quit. + Se ha producido un error fatal. %1 ya no puede continuar de forma segura y abandonará. + + + Internal error + Error interno + + + An internal error occurred. %1 will attempt to continue safely. This is an unexpected bug which can be reported as described below. + Se ha producido un error interno. %1 intentará continuar de forma segura. Se trata de un error inesperado que puede notificarse como se describe a continuación. + + BitcoinGUI @@ -330,6 +368,10 @@ Request payments (generates QR codes and dash: URIs) Solicitar pagos (genera códigos QR y URIs de Dash) + + Ctrl+Q + Ctrl+Q + &Options… &Opciones… @@ -358,6 +400,10 @@ &Verify message… &Verificar mensaje… + + &Load PSBT from file… + &Cargar PSBT desde archivo... + &Sending addresses &Direcciones de envío @@ -390,10 +436,6 @@ &Window &Ventana - - Minimize - Minimizar - Zoom Zoom @@ -446,14 +488,6 @@ Modify configuration options for %1 Modificar las opciones de configuración para %1 - - &Show / Hide - &Mostrar / ocultar - - - Show or hide the main Window - Mostrar u ocultar la ventana principal - Encrypt the private keys that belong to your wallet Cifrar las llaves privadas que pertenezcan a su billetera @@ -518,10 +552,6 @@ Show wallet repair options Mostrar opciones para reparar billetera - - Open Wallet &Configuration File - Abrir Archivo de &Configuración de la billetera - Open configuration file Abrir archivo de configuración @@ -576,10 +606,40 @@ Show information about %1 Mostrar información sobre %1 + + Load PSBT from &clipboard… + Cargar PSBT desde el &portapapeles… + + + Open debugging and diagnostic console + Abrir la consola de depuración y diagnóstico + + + Open &wallet configuration file + Abrir archivo de configuración de la &billetera + + + Open a dash: URI + Abrir un guión: URI + Create a new wallet Crear una nueva billetera + + Restore Wallet… + Name of the menu item that restores wallet from a backup file. + Restaurar billetera… + + + Restore a wallet from a backup file + Status tip for Restore Wallet menu item + Restaurar una billetera desde un archivo de respaldo + + + Close all wallets + Cerrar todas las billeteras + %1 &information %1 &Información @@ -588,10 +648,42 @@ Show the %1 basic information Mostrar la información básica de %1 + + &Discreet mode + &Modo discreto + + + Mask the values in the Overview tab + Ocultar los valores en la pestaña Descripción general + + + Wallet Data + Name of the wallet data file format. + Datos de billetera + + + Load Wallet Backup + The title for Restore Wallet File Windows + Cargar respaldo de billetera + + + Restore Wallet + Title of pop-up window shown when the user is attempting to restore a wallet. + Restaurar billetera + + + Wallet Name + Label of the input field where the name of the wallet is entered. + Nombre de la billetera + &Settings &Configuración + + &Minimize + &Minimizar + &Help &Ayuda @@ -608,8 +700,17 @@ View Governance Proposals Ver propuestas de gobernanza + + &Hide + &Ocultar + + + S&how + &Mostrar + %n active connection(s) to Dash network + A substring of the tooltip. %n conexion(es) activa a la red Dash%n conexion(es) activas a la red Dash%n conexion(es) activas a la red Dash @@ -628,10 +729,50 @@ Close Wallet… Cerrar billetera… + + Load Partially Signed Blockchain Transaction + Cargar transacción de blockchain parcialmente firmada + + + Load Partially Signed Blockchain Transaction from clipboard + Cargar transacción de blockchain parcialmente firmada desde el portapapeles + Create Wallet… Crear billetera… + + Close All Wallets… + Cerrar todas las billeteras… + + + Ctrl+Shift+D + Ctrl+Shift+D + + + Ctrl+M + Ctrl+M + + + Click for more actions. + A substring of the tooltip. "More actions" are available via the context menu. + Haz clic para más acciones. + + + Show Peers tab + A context menu item. The "Peers tab" is an element of the "Node window". + Mostrar pestaña de pares + + + Disable network activity + A context menu item. + Deshabilitar la actividad de red + + + Enable network activity + A context menu item. The network activity was disabled previously. + Habilitar la actividad de red + Syncing Headers (%1%)… Sincronizando encabezados (%1)… @@ -648,10 +789,6 @@ Processing blocks on disk… Procesando los bloques en el disco… - - Reindexing blocks on disk… - Reindexando bloques en disco… - Connecting to peers… Conectando con los pares… @@ -805,10 +942,6 @@ Coin Selection Selección de monedas - - Dust: - Polvo: - After Fee: Después de comisiones: @@ -866,28 +999,32 @@ Confirmado - Copy address - Copiar dirección + Copy amount + Copiar cantidad + + + &Copy address + &Copiar dirección - Copy label - Copiar etiqueta + Copy &label + Copiar &etiquetar - Copy amount - Copiar cantidad + Copy &amount + Copiar &cantidad - Copy transaction ID - Copiar ID de transacción + Copy transaction &ID and output index + Copiar transacción &ID y generar índice - Lock unspent - Bloquear lo no gastado + L&ock unspent + L&ock sin gastar - Unlock unspent - Desbloquear lo no gastado + &Unlock unspent + &Desbloquea lo no gastado Copy quantity @@ -905,10 +1042,6 @@ Copy bytes Copiar bytes - - Copy dust - Copiar polvo - Copy change Copiar cambio @@ -921,18 +1054,6 @@ (%1 locked) (%1 bloqueadas) - - yes - si - - - no - no - - - This label turns red if any recipient receives an amount smaller than the current dust threshold. - Esta etiqueta se vuelve roja si cualquier receptor recibe una cantidad mas pequeña que el límite, mínimo actual de polvo. - Can vary +/- %1 duff(s) per input. Puede variar +/- %1 duff(s) por entrada. @@ -976,8 +1097,14 @@ CreateWalletActivity + + Create Wallet + Title of window indicating the progress of creation of a new wallet. + Crear billetera + Creating Wallet <b>%1</b>… + Descriptive text of the create wallet progress window which indicates to the user which wallet is currently being created. Creando billetera <b>%1</b>… @@ -999,6 +1126,10 @@ Wallet Name Nombre de la billetera + + Wallet + Billetera + Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice. Encriptar la billetera. La billetera se encriptará con una frase de contraseña de tu elección. @@ -1007,6 +1138,10 @@ Encrypt Wallet Encriptar billetera + + Advanced Options + Opciones avanzadas + 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. Deshabilita las llaves privadas para esta billetera. Las billeteras con llaves privadas deshabilitadas no tendrán llaves privadas y no pueden tener una semilla HD o llaves privadas importadas. Esto es ideal para carteras de vigilancia @@ -1023,11 +1158,23 @@ Make Blank Wallet Hacer una billetera en blanco + + Use descriptors for scriptPubKey management. This feature is well-tested but still considered experimental and not recommended for use yet. + Utiliza descriptores para la gestión de scriptPubKey. Esta función está bien probada, pero aún se considera experimental y no se recomienda su uso todavía. + + + Descriptor Wallet (EXPERIMENTAL) + Billetera descriptora (EXPERIMENTAL) + Create Crear - + + Compiled without sqlite support (required for descriptor wallets) + Compilado sin soporte para sqlite (requerido para billeteras de descriptores) + + EditAddressDialog @@ -1116,18 +1263,106 @@ Filter List: Lista de filtros: + + Filter proposal list + Filtrar lista de propuestas + + + Masternode Count: + Cantidad de masternodos: + + + Number of masternodes this wallet can vote with (masternodes for which this wallet holds the voting key) + Número de masternodos con los que esta billetera puede votar (masternodos para los que esta billetera tiene la clave de votación) + Proposal Count: Número de propuestas: + + Create Proposal + Crear propuesta + Filter by Title Filtrar por título + + Unavailable + No disponible + + + A synced node and an unlocked wallet are required. + Se requiere un nodo sincronizado y una billetera desbloqueada. + + + Vote Yes + Votar Sí + + + Vote No + Votar No + + + Vote Abstain + Votar Abstención + Proposal Info: %1 Información de la propuesta: %1 + + Voting Failed + Votación fallida + + + No wallet available. + No hay billetera disponible. + + + No masternode voting keys found in wallet. + No se encontraron claves de votación de masternodos en la billetera. + + + Please select a proposal to vote on. + Por favor selecciona una propuesta para votar. + + + Unable to unlock wallet. + No se puede desbloquear la billetera. + + + Unable to get masternode list. Please try again later. + No se puede obtener la lista de masternodos. Por favor inténtalo de nuevo más tarde. + + + Masternode %1 not found + Masternodo %1 no encontrado + + + Failed to sign vote for masternode %1 + Error al firmar voto para el masternodo %1 + + + Masternode %1: %2 + Masternodo %1: %2 + + + Voted successfully %n time(s) + Votado exitosamente %n vezVotado exitosamente %n vecesVotado exitosamente %n veces + + + Failed to vote %n time(s) + Error al votar %n vezError al votar %n vecesError al votar %n veces + + + Errors: + Errores: + + + Voting Results + Resultados de votación + HelpMessageDialog @@ -1149,7 +1384,7 @@ <h3>%1 Basics</h3> %1 gives you true financial privacy by obscuring the origins of your funds. All the Dash in your wallet is comprised of different "inputs" which you can think of as separate, discrete coins.<br> %1 uses an innovative process to mix your inputs with the inputs of two or more other people, without having your coins ever leave your wallet. You retain control of your money at all times.<hr> <b>The %1 process works like this:</b><ol type="1"> <li>%1 begins by breaking your transaction inputs down into standard denominations. These denominations are 0.001 DASH, 0.01 DASH, 0.1 DASH, 1 DASH and 10 DASH -- sort of like the paper money you use every day.</li> <li>Your wallet then sends requests to specially configured software nodes on the network, called "masternodes." These masternodes are informed then that you are interested in mixing a certain denomination. No identifiable information is sent to the masternodes, so they never know "who" you are.</li> <li>When two or more other people send similar messages, indicating that they wish to mix the same denomination, a mixing session begins. The masternode mixes up the inputs and instructs all three users' wallets to pay the now-transformed input back to themselves. Your wallet pays that denomination directly to itself, but in a different address (called a change address).</li> <li>In order to fully obscure your funds, your wallet must repeat this process a number of times with each denomination. Each time the process is completed, it's called a "round." Each round of %1 makes it exponentially more difficult to determine where your funds originated.</li> <li>This mixing process happens in the background without any intervention on your part. When you wish to make a transaction, your funds will already be mixed. No additional waiting is required.</li> </ol> <hr><b>IMPORTANT:</b> Your wallet only contains 1000 of these "change addresses." Every time a mixing event happens, up to 9 of your addresses are used up. This means those 1000 addresses last for about 100 mixing events. When 900 of them are used, your wallet must create more addresses. It can only do this, however, if you have automatic backups enabled.<br> Consequently, users who have backups disabled will also have %1 disabled. <hr>For more information, see the <a style="%2" href="%3">%1 documentation</a>. - <h3>Conceptos básico de %1</h3>%1 te da verdadera privacidad financiera al ocultar los orígenes de tus fondos. Todos los Dash en tu billetera están compuestos por diferentes "entradas" en las que puedes pensar como monedas separadas discretas.<br>%1 utiliza un proceso innovador que mezcla tus entradas con las entradas de otras dos personas, sin que tus monedas salgan de la billetera. Tu retienes el control de tu dinero en todo momento.<hr><b>El proceso de %1 funciona así:</b><ol type="1"><li>%1 comienza dividiendo las entradas de tus transacciones en denominaciones estándares. Éstas denominaciones son 0.001 DASH, 0.01 DASH, 0.1 DASH, 1 DASH y 10 DASH - algo así como el papel moneda que usas todos los días.</li><li>Entonces, tu billetera envía solicitudes a nodos de software especialmente configurados en la red, llamados "masternodes". Estos masternodes son informados que estás interesado en mezclar una cierta denominación. Información no identificable es enviada a los masternodes, por lo que nunca saben "quién" eres tu.</li><li>Cuando otras dos personas envían mensajes similares, indicando que desean mezclar la misma denominación, comienza una sesión de mezclado. El masternode mezcla loas entradas e instruye a las billeteras de los tres usuarios para que paguen la entrada ahora transformada a si mismos. Tu billetera paga esa denominación directamente a sí misma, pero en una dirección diferente (llamada dirección de cambio).</li> <li>En orden de ocultar totalmente tus fondos, st billetera debe repetir este proceso varias veces con cada denominación. Cada vez que se completa el proceso, se denomina una "ronda". Cada ronda de %1 hace que sea exponencialmente más difícil determinar de dónde provienen los fondos.</li><li>Este proceso de mezclado ocurre en segundo plano sin ninguna intervención de tu parte. Cuando desees realizar una transacción, tus fondos ya serán anónimos. No se requiere tiempo de espera adicional.</li></ol><hr><b>IMPORTATE:</b>Tu billetera solo contiene 1000 de estas "direcciones de cambio". Cada vez que ocurre un evento de mezclado, hasta 9 de tus direcciones son usadas. Esto significa que esas 1000 direcciones duran alrededor de 100 eventos de mezclado. Cuando 900 de ellas sean usadas, tu billetera debe crear más direcciones. Sin embargo, solo podrá hacer esto si tiene las copias de seguridad automáticas habilitadas.<br>En consecuencia, los usuarios que tengan las copias de seguridad deshabilitadas también tendrán %1 deshabilitado.<hr>Para mas información, consulta la <a style="%2" href="%3">documentación de %1</a>. + <h3>Conceptos básico de %1</h3>%1 te da verdadera privacidad financiera al ocultar los orígenes de tus fondos. Todos los Dash en tu billetera están compuestos por diferentes "entradas" en las que puedes pensar como monedas separadas discretas.<br>%1 utiliza un proceso innovador que mezcla tus entradas con las entradas de otras dos personas, sin que tus monedas salgan de la billetera. Tu retienes el control de tu dinero en todo momento.<hr><b>El proceso de %1 funciona así:</b><ol type="1"><li>%1 comienza dividiendo las entradas de tus transacciones en denominaciones estándares. Éstas denominaciones son 0.001 DASH, 0.01 DASH, 0.1 DASH, 1 DASH y 10 DASH - algo así como el papel moneda que usas todos los días.</li><li>Entonces, tu billetera envía solicitudes a nodos de software especialmente configurados en la red, llamados "masternodes". Estos masternodes son informados que estás interesado en mezclar una cierta denominación. Información no identificable es enviada a los masternodes, por lo que nunca saben "quién" eres tu.</li><li>Cuando otras dos personas envían mensajes similares, indicando que desean mezclar la misma denominación, comienza una sesión de mezclado. El masternode mezcla loas entradas e instruye a las billeteras de los tres usuarios para que paguen la entrada ahora transformada a si mismos. Tu billetera paga esa denominación directamente a sí misma, pero en una dirección diferente (llamada dirección de cambio).</li> <li>En orden de ocultar totalmente tus fondos, st billetera debe repetir este proceso varias veces con cada denominación. Cada vez que se completa el proceso, se denomina una "ronda". Cada ronda de %1 hace que sea exponencialmente más difícil determinar de dónde provienen los fondos.</li><li>Este proceso de mezclado ocurre en segundo plano sin ninguna intervención de tu parte. Cuando desees realizar una transacción, tus fondos ya serán anónimos. No se requiere tiempo de espera adicional.</li></ol><hr><b>IMPORTATE:</b>Tu billetera solo contiene 1000 de estas "direcciones de cambio". Cada vez que ocurre un evento de mezclado, hasta 9 de tus direcciones son usadas. Esto significa que esas 1000 direcciones duran alrededor de 100 eventos de mezclado. Cuando 900 de ellas sean usadas, tu billetera debe crear más direcciones. Sin embargo, solo podrá hacer esto si tiene las copias de seguridad automáticas habilitadas.<br>En consecuencia, los usuarios que tengan las copias de seguridad deshabilitadas también tendrán %1 deshabilitado.<hr>Para más información, consulta la <a style="%2" href="%3">documentación de %1</a>. @@ -1166,10 +1401,26 @@ As this is the first time the program is launched, you can choose where %1 will store its data. Al ser la primera vez que se ejecuta el programa, puede elegir donde %1 almacenará sus datos. + + Limit block chain storage to + Limitar el almacenamiento de la cadena de bloques a + + + 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. + Para revertir esta configuración es necesario volver a descargar toda la cadena de bloques. Es más rápido descargar primero la cadena completa y podarla después. Desactiva algunas funciones avanzadas. + + + GB + GB + 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. La sincronización inicial demanda muchos recursos y podría revelar problemas de hardware que no se han notado previamente. Cada vez que ejecuta %1, continuará descargando a partir del punto anterior. + + 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. + Al hacer clic en OK, %1 comenzará a descargar y procesar la cadena de bloques %4 completa (%2 GB) comenzando con las primeras transacciones en %3 cuando %4 se lanzó inicialmente. + 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. Si ha elegido limitar el almacenamiento de la cadena de bloques ("prunning"), se descargarán y procesarán los datos históricos igualmente, sin embargo, estos se eliminarán después para mantener un bajo uso del disco. @@ -1182,6 +1433,18 @@ Use a custom data directory: Utilizar un directorio de datos personalizado: + + %n GB of space available + %n GB de espacio disponible%n GB de espacio disponible%n GB de espacio disponible + + + (of %n GB needed) + (de %n GB necesario)(de %n GB necesarios)(de %n GB necesarios) + + + (%n GB needed for full chain) + (%n GB necesario para la cadena completa)(%n GB necesarios para la cadena completa)(%n GB necesarios para la cadena completa) + At least %1 GB of data will be stored in this directory, and it will grow over time. Se almacenará cuanto menos %1 GB de datos en este directorio, y crecerá con el transcurso del tiempo. @@ -1190,6 +1453,11 @@ Approximately %1 GB of data will be stored in this directory. Se almacenará aproximadamente %1 GB de datos en este directorio. + + (sufficient to restore backups %n day(s) old) + Explanatory text on the capability of the current prune target. + (suficiente para restaurar copias de seguridad de %n día de antigüedad)(suficiente para restaurar copias de seguridad de %n días de antigüedad)(suficiente para restaurar copias de seguridad de %n días de antigüedad) + %1 will download and store a copy of the Dash block chain. %1 descargará y almacenará una copia de la cadena de bloques de Dash. @@ -1207,6 +1475,13 @@ Error + + LoadWalletsActivity + + Loading wallets… + Cargando billeteras… + + MasternodeList @@ -1241,6 +1516,10 @@ Service Servicio + + Type + Tipo + PoSe Score PoSe Marcador @@ -1376,6 +1655,10 @@ Hide Ocultar + + %1 is currently syncing. It will download headers and blocks from peers and validate them until reaching the tip of the block chain. + %1 se está sincronizando actualmente. Descargará encabezados y bloques de los pares y los validará hasta llegar a la punta de la cadena de bloques. + Unknown. Syncing Headers (%1, %2%)… Desconocido. Sincronización de encabezados (%1, %2%)… @@ -1391,6 +1674,11 @@ URI: URI: + + Paste address from clipboard + Tooltip text for button that allows you to paste an address that is in your clipboard. + Pegar dirección desde el portapapeles + OpenWalletActivity @@ -1406,8 +1694,14 @@ default wallet billetera predeterminada + + Open Wallet + Title of window indicating the progress of opening of a wallet. + Billetera abierta + Opening Wallet <b>%1</b>… + Descriptive text of the open wallet progress window which indicates to the user which wallet is currently being opened. Abriendo billetera <b>%1</b>… @@ -1441,6 +1735,14 @@ &Appearance &Apariencia + + Show the icon in the system tray. + Mostrar el icono en la bandeja del sistema. + + + &Show tray icon + &Mostrar icono de la bandeja + Prune &block storage to Despeja y bloquea el almacenamiento para @@ -1453,10 +1755,58 @@ Reverting this setting requires re-downloading the entire blockchain. Revertir esta configuración requiere volver a descargar toda la cadena de bloques. + + 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. + Tooltip text for Options window setting that sets the size of the database cache. Explains the corresponding effects of increasing/decreasing this value. + Tamaño máximo de 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. Reducir el tamaño de la caché reducirá el uso de memoria. La memoria de mempool no utilizada se comparte para esta caché. + MiB MiB + + Set the number of script verification threads. Negative values correspond to the number of cores you want to leave free to the system. + 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. + Establece la cantidad de subprocesos de verificación de scripts. Los valores negativos corresponden a la cantidad de núcleos que deseas dejar libres en el sistema. + + + This allows you or a third party tool to communicate with the node through command-line and JSON-RPC commands. + Tooltip text for Options window setting that enables the RPC server. + Esto te permite a ti o a una herramienta de terceros comunicarse con el nodo a través de la línea de comandos y comandos JSON-RPC. + + + Enable R&PC server + An Options window setting to enable the RPC server. + Habilitar servidor R&PC + + + Whether to set subtract fee from amount as default or not. + Tooltip text for Options window setting that sets subtracting the fee from a sending amount as default. + Si establecer o no la deducción de la comisión del monto como predeterminada. + + + Subtract &fee from amount by default + An Options window setting to set subtracting the fee from a sending amount as default. + Deducir &comisión del monto de manera predeterminada + + + Enable &PSBT controls + An options window setting to enable PSBT controls. + Activar controles de &PSBT + + + Whether to show PSBT controls. + Tooltip text for options window setting that enables PSBT controls. + Si se deben mostrar los controles de PSBT. + + + Whether to keep the specified custom change address or not. + Si se debe mantener o no la dirección de cambio personalizada especificada. + + + Keep custom change &address + Mantener la &dirección de cambio personalizada + Show additional tab listing all your masternodes in first sub-tab<br/>and all masternodes on the network in second sub-tab. Mostrar una pestaña adicional listando todos sus masternodes en la primera sub-pestaña<br/> y todos los masternodos en la red en la segunda sub-pestaña. @@ -1513,6 +1863,14 @@ Enable &multi-session Habilitar &multisesión + + Use this many separate masternodes in parallel to mix funds.<br/>Note: You must use this feature carefully.<br/>Make sure you always have recent wallet (auto)backup in a safe place! + Utiliza estos muchos masternodes separados en paralelo para mezclar fondos.<br/>Nota: Debes utilizar esta función con cuidado.<br/>¡Asegúrate de tener siempre una copia de seguridad (automática) reciente de tu billetera en un lugar seguro! + + + Parallel sessions + Sesiones paralelas + Mixing rounds Rondas de mezcla @@ -1525,6 +1883,30 @@ Target balance Saldo objetivo + + How many inputs of each denominated amount are created.<br/>Lower these numbers if you want fewer smaller denominations. + ¿Cuántas entradas de cada monto denominado se crean?.<br/>Disminuye estos números si deseas menos denominaciones más pequeñas. + + + Inputs per denomination + Entradas por denominación + + + Try to create at least this many inputs for each denominated amount.<br/>Lower this number if you want fewer smaller denominations. + Intenta crear al menos esta cantidad de entradas para cada monto denominado.<br/>Disminuye este número si deseas menos denominaciones más pequeñas. + + + Target + Objetivo + + + Create up to this many inputs for each denominated amount.<br/>Lower this number if you want fewer smaller denominations. + Crea hasta esta cantidad de entradas para cada monto denominado.<br/>Disminuye este número si deseas menos denominaciones más pequeñas. + + + Maximum + Máximo + Automatically open the Dash Core client port on the router. This only works when your router supports UPnP and it is enabled. Abrir automáticamente el puerto del cliente Dash Core en el enrutador. Esto solo funciona cuando su enrutador admite UPnP y está habilitado. @@ -1554,20 +1936,26 @@ Mostrar si el proxy SOCKS5 predeterminado suministrado se utiliza para llegar a los pares a través de este tipo de red. - Options set in this dialog are overridden by the command line or in the configuration file: - Las opciones configuradas en este cuadro de diálogo se reemplazan por la línea de comando o en el archivo de configuración: + Language missing or translation incomplete? Help contributing translations here: +https://explore.transifex.com/dash/dash/ + ¿Falta el idioma o la traducción está incompleta? Ayuda a contribuir con traducciones aquí: +https://explore.transifex.com/dash/dash/ - 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. - Minimizar 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ú. + Third-party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items.<br/>%s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |. + URLs de terceros (por ejemplo, un explorador de bloques) que aparecen en la pestaña de transacciones como elementos del menú contextual.<br/>%s en la URL se reemplaza por el hash de la transacción. Múltiples URLs se separan por barra vertical |. - Third party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items.<br/>%s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |. - URL de terceros (por ejemplo, un explorador de bloques) que aparecen en la pestaña de transacciones como elementos del menú contextual.<br/>%s en la URL se reemplaza por hash de transacción. Varias URL están separadas por una barra vertical |. + &Third-party transaction URLs + URLs de transacciones de &terceros + + + Options set in this dialog are overridden by the command line or in the configuration file: + Las opciones configuradas en este cuadro de diálogo se reemplazan por la línea de comando o en el archivo de configuración: - &Third party transaction URLs - &URL de transacciones de terceros + 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. + Minimizar 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ú. Whether to show coin control features or not. @@ -1605,6 +1993,10 @@ Map port using &UPnP Mapear puerto usando &UPnP + + Automatically open the Dash Core client port on the router. This only works when your router supports NAT-PMP and it is enabled. The external port could be random. + Abre automáticamente el puerto del cliente Dash Core en el enrutador. Esto solo funciona cuando el enrutador admite NAT-PMP y está habilitado. El puerto externo puede ser aleatorio. + Proxy &IP: Dirección &IP del proxy: @@ -1653,6 +2045,14 @@ &Display &Interfaz + + Connect to the Dash network through a separate SOCKS5 proxy for Tor onion services. + Conéctate a la red Dash a través de un proxy SOCKS5 separado para los servicios de Tor onion. + + + Use separate SOCKS&5 proxy to reach peers via Tor onion services: + Utiliza un proxy SOCKS&5 independiente para comunicarte con tus pares a través de los servicios de Tor onion: + User Interface &language: &Idioma de la interfaz de usuario @@ -1699,14 +2099,22 @@ Confirm options reset + Window title text of pop-up window shown when the user has chosen to reset options. Confirme el restablecimiento de las opciones Client restart required to activate changes. + Text explaining that the settings changed will not come into effect until the client is restarted. Se necesita reiniciar el cliente para activar los cambios. + + Current settings will be backed up at "%1". + 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. + La configuración actual se respaldará en "%1". + Client will be shut down. Do you want to proceed? + Text asking the user to confirm if they would like to proceed with a client shutdown. El cliente se cerrará. ¿Desea proceder? @@ -1844,6 +2252,10 @@ %1 Balance %1 Saldo + + Discreet mode activated for the Overview tab. To unmask the values, uncheck Settings->Discreet mode. + Modo discreto activado para la pestaña Descripción general. Para desenmascarar los valores, desmarque Configuración->Modo discreto. + %n Rounds %n Ronda%n Rondas%n Rondas @@ -1943,7 +2355,140 @@ PSBTOperationsDialog - + + Dialog + Diálogo + + + Sign Tx + Firmar transacción + + + Broadcast Tx + Transmisión de transacción + + + Copy to Clipboard + Copiar al portapapeles + + + Save… + Guardar… + + + Close + Cerrar + + + Failed to load transaction: %1 + Error al cargar la transacción: %1 + + + Failed to sign transaction: %1 + Error al firmar la transacción: %1 + + + Cannot sign inputs while wallet is locked. + No se pueden firmar entradas mientras la billetera esté bloqueada. + + + Could not sign any more inputs. + No se pudieron firmar más entradas. + + + Signed %1 inputs, but more signatures are still required. + Se firmaron %1 entradas, pero aún se requieren más firmas. + + + Signed transaction successfully. Transaction is ready to broadcast. + La transacción se firmó correctamente. La transacción está lista para transmitirse. + + + Unknown error processing transaction. + Error desconocido al procesar transacción. + + + Transaction broadcast successfully! Transaction ID: %1 + ¡Transacción transmitida con éxito! ID de transacción: %1 + + + Transaction broadcast failed: %1 + Error en la transmisión de la transacción: %1 + + + PSBT copied to clipboard. + PSBT copiado al portapapeles. + + + Save Transaction Data + Guardar datos de transacción + + + Partially Signed Transaction (Binary) + Expanded name of the binary PSBT file format. See: BIP 174. + Transacción parcialmente firmada (binaria) + + + PSBT saved to disk. + PSBT guardado en el disco. + + + * Sends %1 to %2 + * Envía %1 a %2 + + + own address + Dirección propia + + + Unable to calculate transaction fee or total transaction amount. + No se puede calcular la comisión de transacción ni el monto total de la transacción. + + + Pays transaction fee: + Paga comisión de transacción: + + + Total Amount + Monto total + + + or + o + + + Transaction has %1 unsigned inputs. + La transacción tiene %1 entradas sin firmar. + + + Transaction is missing some information about inputs. + A la transacción le falta información sobre las entradas. + + + Transaction still needs signature(s). + La transacción aún necesita firma(s). + + + (But no wallet is loaded.) + (Pero no hay ninguna billetera cargada.) + + + (But this wallet cannot sign transactions.) + (Pero esta billetera no puede firmar transacciones). + + + (But this wallet does not have the right keys.) + (Pero esta billetera no tiene las llaves correctas.) + + + Transaction is fully signed and ready for broadcast. + La transacción está completamente firmada y lista para transmitirse. + + + Transaction status is unknown. + El estado de la transacción es desconocido. + + PaymentServer @@ -1962,6 +2507,12 @@ 'dash://' is not a valid URI. Use 'dash:' instead. 'dash://' no es un URI válido. Usa 'dash:'. + + Cannot process payment request as BIP70 is no longer supported. +Due to discontinued support, you should request the merchant to provide you with a BIP21 compatible URI or use a wallet that does continue to support BIP70. + No se puede procesar la solicitud de pago porque BIP70 ya no es compatible. +Debido a que se ha interrumpido el soporte, debes solicitarle al comerciante que te proporcione una URI compatible con BIP21 o utilizar una billetera que continúe admitiendo BIP70. + URI cannot be parsed! This can be caused by an invalid Dash address or malformed URI parameters. ¡No se puede interpretar la URI! Esto puede deberse a una dirección Dash inválida o a parámetros de URI mal formados. @@ -1983,6 +2534,26 @@ Title of Peers Table column which indicates the current latency of the connection with the peer. Ping + + Peer + Title of Peers Table column which contains a unique number used to identify a connection. + Par + + + Age + Title of Peers Table column which indicates the duration (length of time) since the peer connection started. + Edad + + + Direction + Title of Peers Table column which indicates the direction the peer connection was initiated from. + Dirección + + + Type + Title of Peers Table column which describes the type of peer connection. The "type" describes why the connection exists. + Tipo + Sent Title of Peers Table column which indicates the total amount of network information we have sent to the peer. @@ -1993,7 +2564,27 @@ Title of Peers Table column which indicates the total amount of network information we have received from the peer. Recibido - + + Address + Title of Peers Table column which contains the IP/Onion/I2P address of the connected peer. + Dirección + + + Network + Title of Peers Table column which states the network the peer connected through. + Red + + + Inbound + An Inbound Connection from a Peer. + Entrante + + + Outbound + An Outbound Connection to a Peer. + Saliente + + Proposal @@ -2044,8 +2635,193 @@ Estado + + ProposalWizard + + Create Governance Proposal + Crear propuesta de gobernanza + + + Enter proposal details + Ingresar detalles de la propuesta + + + A fee will be burned when you prepare the proposal. + Se quemará una tarifa cuando prepares la propuesta. + + + Proposal &name + &Nombre de la propuesta + + + &Description URL + URL de &descripción + + + Payment &address + &Dirección de pago + + + Payment &amount + &Monto de pago + + + The amount to request in a single payment + El monto a solicitar en un solo pago + + + &First payment + &Primer pago + + + Pa&yments + &Pagos + + + To&tal amount + Monto &total + + + Proposal &fee + &Tarifa de propuesta + + + Next + Siguiente + + + Review proposal JSON and validate. + Revisar JSON de la propuesta y validar. + + + Hex-encoded JSON + JSON codificado en hexadecimal + + + Back + Atrás + + + Validate + Validar + + + Prepare (burn fee) and wait for confirmations. + Preparar (quemar tarifa) y esperar confirmaciones. + + + Copy + Copiar + + + At 1/6 confirmations: can be relayed and queued. At 6/6: accepted and processed. + En 1/6 confirmaciones: se puede retransmitir y poner en cola. En 6/6: aceptado y procesado. + + + Confirmations progress + Progreso de confirmaciones + + + Shows progress toward the required number of confirmations for the proposal fee transaction. + Muestra el progreso hacia el número requerido de confirmaciones para la transacción de tarifa de la propuesta. + + + Estimated time remaining: - + Tiempo estimado restante: - + + + Prepare Proposal + Preparar propuesta + + + You can submit after 1 confirmation. At 6 confirmations it is accepted and processed. + Puedes enviar después de 1 confirmación. Con 6 confirmaciones se acepta y procesa. + + + Proposal ID: + ID de propuesta: + + + Submit Proposal + Enviar propuesta + + + Close + Cerrar + + + Valid + Válido + + + Invalid: %1 + Inválido: %1 + + + Burn %1 + Quemar %1 + + + Burn %1 to create the fee transaction? + ¿Quemar %1 para crear la transacción de tarifa? + + + Prepare failed + Preparación fallida + + + Confirmations: %1 / %2 required + Confirmaciones: %1 / %2 requeridas + + + Estimated time remaining: Ready + Tiempo estimado restante: Listo + + + Estimated time remaining: %n minute(s) + Tiempo estimado restante: %n minutoTiempo estimado restante: %n minutosTiempo estimado restante: %n minutos + + + Your proposal was submitted successfully. + Tu propuesta se envió exitosamente. + + + Already submitted + Ya enviado + + + This proposal has already been submitted. + Esta propuesta ya ha sido enviada. + + + Submission failed + Envío fallido + + + Proposal submitted + Propuesta enviada + + + A fee of %1 will be burned when you prepare the proposal. + Se quemará una tarifa de %1 cuando prepares la propuesta. + + + Prepare (burn %1) and wait for %2 confirmations. + Preparar (quemar %1) y esperar %2 confirmaciones. + + QObject + + Do you want to reset settings to default values, or to abort without making changes? + Explanatory text shown on startup when the settings file cannot be read. Prompts user to make a choice between resetting or aborting. + ¿Deseas restablecer la configuración a los valores predeterminados o cancelar la operación sin realizar cambios? + + + A fatal error occurred. Check that settings file is writable, or try running with -nosettings. + 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. + Se produjo un error fatal. Verifica que el archivo de configuración tenga permisos de escritura o intenta ejecutarlo con -nosettings. + Choose data directory on startup (default: %u) Escoger el directorio de datos al iniciar (predeterminado: %u) @@ -2146,6 +2922,53 @@ This can also be adjusted later in the "Appearance" tab of the preferences. Esto también se puede ajustar más adelante en la pestaña "Apariencia" de las preferencias. + + Ctrl+W + Ctrl+W + + + Unroutable + No enrutable + + + Internal + Interno + + + Inbound + An inbound connection from a peer. An inbound connection is a connection initiated by a peer. + Entrante + + + Outbound + An outbound connection to a peer. An outbound connection is a connection initiated by us. + Saliente + + + Full Relay + Peer connection type that relays all network information. + Relevo completo + + + Block Relay + Peer connection type that relays network information about blocks and not transactions or addresses. + Relé de bloque + + + Manual + Peer connection type established manually through one of several methods. + Manual + + + Feeler + Short-lived peer connection type that tests the aliveness of known addresses. + Antena + + + Address Fetch + Short-lived peer connection type that solicits known addresses from a peer. + Obtención de dirección + %1 d %1 d @@ -2207,8 +3030,8 @@ %1 B - %1 KB - %1 KB + %1 kB + %1 kB %1 MB @@ -2264,7 +3087,12 @@ Save QR Code Guardar código QR - + + PNG Image + Expanded name of the PNG file format. See: https://en.wikipedia.org/wiki/Portable_Network_Graphics. + Imagen PNG + + RPCConsole @@ -2371,6 +3199,14 @@ Version Versión + + High bandwidth BIP152 compact block relay: %1 + Relevo de bloque compacto BIP152 de alto ancho de banda: %1 + + + High Bandwidth + Gran ancho de banda + Starting Block Bloque de inicio @@ -2383,6 +3219,51 @@ Synced Blocks Bloques sincronizados + + Elapsed time since a novel block passing initial validity checks was received from this peer. + Tiempo transcurrido desde que se recibió un nuevo bloque que pasó las comprobaciones de validez iniciales de este par. + + + Last Block + Último bloque + + + Elapsed time since a novel transaction accepted into our mempool was received from this peer. + Tooltip text for the Last Transaction field in the peer details area. + Tiempo transcurrido desde que se recibió una nueva transacción aceptada en nuestro mempool desde este par. + + + Last Transaction + Última transacción + + + The mapped Autonomous System used for diversifying peer selection. + El Sistema Autónomo mapeado utilizado para diversificar la selección de pares. + + + Mapped AS + AS Mapeado + + + Whether we relay addresses to this peer. + Tooltip text for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No). + Si retransmitimos direcciones a este par. + + + Address Relay + Text title for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No). + Relevo de dirección + + + Addresses Processed + 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). + Direcciones procesadas + + + Addresses Rate-Limited + 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. + Direcciones de tarifa limitada + Rescan blockchain files 1 Reexplorar la cadena de bloques 1 @@ -2423,6 +3304,22 @@ To specify a non-default location of the blocks directory use the '%1' option. Para especificar una ubicación no predeterminada del directorio de bloques, usa la opción '%1'. + + Local Addresses + Direcciones locales + + + Network addresses that your Dash node is currently using to communicate with other nodes. + Direcciones de red que tu nodo Dash está usando actualmente para comunicarse con otros nodos. + + + Number of regular Masternodes + Número de Masternodes regulares + + + Number of EvoNodes + Número de EvoNodes + Current block height Altura de bloque actual @@ -2471,10 +3368,50 @@ PoSe Score PoSe Marcador + + The transport layer version: %1 + La versión de la capa de transporte: %1 + + + Transport + Transporte + + + The BIP324 session ID string in hex. + La cadena de identificación de sesión BIP324 en hexadecimal. + + + Session ID + Sesión ID + + + The network protocol this peer is connected through: IPv4, IPv6, Onion, I2P, or CJDNS. + El protocolo de red a través del cual está conectado este par: IPv4, IPv6, Onion, I2P o CJDNS. + + + Permissions + Permisos + + + The direction and type of peer connection: %1 + La dirección y el tipo de conexión entre pares: %1 + + + Direction/Type + Dirección/Tipo + Services Servicios + + Whether we relay transactions to this peer. + Si retransmitimos transacciones a este par. + + + Transaction Relay + Retransmisión de transacciones + Connection Time Tiempo de Conexión @@ -2511,6 +3448,16 @@ &Wallet Repair &Reparar Billetera + + The total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting). + 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). + La cantidad total de direcciones recibidas de este par que fueron procesadas (excluye las direcciones que se descartaron debido a la limitación de velocidad). + + + The total number of addresses received from this peer that were dropped (not processed) due to rate-limiting. + 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. + La cantidad total de direcciones recibidas de este par que se descartaron (no se procesaron) debido a la limitación de velocidad. + Wallet repair options. Opciones de reparación de la billetera @@ -2524,52 +3471,82 @@ -reindex: Reconstruir el índice de la cadena de bloques a partir de los archivos blk000??.dat actuales. - &Disconnect - &Desconectar + Inbound: initiated by peer + Explanatory text for an inbound peer connection. + Entrante: iniciado por pares - Ban for - Prohibido por + Outbound Full Relay: default + Explanatory text for an outbound peer connection that relays all network information. This is the default behavior for outbound connections. + Retransmisión completa de salida: predeterminada - 1 &hour - 1 &hora + Outbound Block Relay: does not relay transactions or addresses + Explanatory text for an outbound peer connection that relays network information about blocks and not transactions or addresses. + Retransmisión de bloque saliente: no retransmite transacciones ni direcciones - 1 &day - 1 &día + Outbound Manual: added using RPC %1 or %2/%3 configuration options + 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. + Manual de salida: agregado mediante las opciones de configuración RPC %1 o %2/%3 - 1 &week - 1 &semana + Outbound Feeler: short-lived, for testing addresses + Explanatory text for a short-lived outbound peer connection that is used to test the aliveness of known addresses. + Sensor de salida: de corta duración, para probar direcciones - 1 &year - 1 &año + Outbound Address Fetch: short-lived, for soliciting addresses + Explanatory text for a short-lived outbound peer connection that is used to request addresses from a peer. + Obtención de direcciones salientes: de corta duración, para solicitar direcciones - &Unban - &Levantar prohibición + To + Para + + + we selected the peer for high bandwidth relay + Seleccionamos el par para la retransmisión de alto ancho de banda - Welcome to the %1 RPC console. - Bienvenido a la consola RPC %1. + From + Desde - Use up and down arrows to navigate history, and %1 to clear screen. - Use las flechas arriba y abajo para navegar por el historial y %1 para vaciar la pantalla. + the peer selected us for high bandwidth relay + El par nos seleccionó para la retransmisión de alto ancho de banda - Type %1 for an overview of available commands. - Tipo %1 para obtener una descripción general de los comandos disponibles. + No + No - For more information on using this console type %1. - Para obtener más información sobre el uso de este tipo de consola %1. + no high bandwidth relay selected + No se ha seleccionado ningún relevo de alto ancho de banda + + + &Disconnect + &Desconectar + + + Ban for + Prohibido por - WARNING: Scammers have been active, telling users to type commands here, stealing their wallet contents. Do not use this console without fully understanding the ramifications of a command. - ADVERTENCIA: Estafadores han estado activos, diciendo a los usuarios que escriban comandos aquí, robando el contenido de su billetera. No use esta consola sin un completo entendimiento de las ramificaciones de un comando. + 1 &hour + 1 &hora + + + 1 &week + 1 &semana + + + 1 &year + 1 &año + + + &Unban + &Levantar prohibición In: @@ -2583,6 +3560,10 @@ Network activity disabled Actividad de red deshabilitada + + None + Ninguno + Total: %1 (Enabled: %2) Total: %1 (Enabled: %2) @@ -2591,10 +3572,105 @@ Executing command without any wallet Ejecutando comando sin billetera + + Ctrl++ + Main shortcut to increase the RPC console font size. + Ctrl++ + + + Ctrl+= + Secondary shortcut to increase the RPC console font size. + Ctrl+= + + + Ctrl+- + Main shortcut to decrease the RPC console font size. + Ctrl+- + + + Ctrl+_ + Secondary shortcut to decrease the RPC console font size. + Ctrl+_ + + + Ctrl+Shift+I + Ctrl+Shift+I + + + Ctrl+Shift+C + Ctrl+Shift+C + + + Ctrl+Shift+G + Ctrl+Shift+G + + + Ctrl+Shift+P + Ctrl+Shift+P + + + Ctrl+Shift+R + Ctrl+Shift+R + Executing command using "%1" wallet Ejecutando comando usando "%1" billetera + + detecting: peer could be v1 or v2 + Explanatory text for "detecting" transport type. + Detectando: el par podría ser v1 o v2 + + + v1: unencrypted, plaintext transport protocol + Explanatory text for v1 transport type. + v1: protocolo de transporte de texto simple y sin cifrar + + + v2: BIP324 encrypted transport protocol + Explanatory text for v2 transport type. + v2: Protocolo de transporte cifrado BIP324 + + + &Copy address + Context menu action to copy the address of a peer + &Copiar dirección + + + 1 d&ay + 1 d&ay + + + &Copy IP/Netmask + 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 + &Copiar IP/Máscara de red + + + 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 + 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. + Bienvenido a la consola RPC %1. +Utiliza las flechas hacia arriba y hacia 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 obtener una descripción general de los comandos disponibles. +Para obtener más información sobre el uso de esta consola, escribe %6. + +%7ADVERTENCIA: Los estafadores han estado activos, pidiendo a los usuarios que escriban comandos aquí, robando el contenido de sus billeteras. No use esta consola sin comprender completamente las ramificaciones de un comando.%8 + + + Executing… + A console message indicating an entered command is currently being executed. + Ejecutando… + + + (peer: %1) + (par: %1) + via %1 vía %1 @@ -2611,11 +3687,19 @@ Verified Masternode Masternodo verificado + + Yes + Si + Unknown Desconocido - + + Never + Nunca + + ReceiveCoinsDialog @@ -2634,6 +3718,10 @@ An optional message to attach to the payment request, which will be displayed when the request is opened.<br>Note: The message will not be sent with the payment over the Dash network. Un mensaje opcional para adjuntar con la solicitud de pago, el cual aparecerá cuando ésta sea abierta.<br>Nota: El mensaje no se enviará con el pago a la red Dash. + + 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. + Etiqueta opcional que se asocia a la nueva dirección de recepción (utilizada por ti para identificar una factura). También se adjunta a la solicitud de pago. + Use this form to request payments. All fields are <b>optional</b>. Utilice este formulario para solicitar pagos. Todos los campos son <b>opcionales</b>. @@ -2691,28 +3779,60 @@ Ingresa un mensaje para adjuntar a la solicitud de pago - Copy URI - Copiar URI + Copy &URI + Copiar &URI + + + &Copy address + &Copiar dirección - Copy address - Copiar dirección + Copy &label + Copiar &etiqueta - Copy label - Copiar etiqueta + Copy &message + Copiar &mensaje - Copy message - Copiar mensaje + Copy &amount + Copiar &monto - Copy amount - Copiar cantidad + Could not unlock wallet. + No se pudo desbloquear la billetera. - + + Could not generate new address + No se pudo generar una nueva dirección + + ReceiveRequestDialog + + Request payment to … + Solicitar pago a… + + + Address: + Dirección: + + + Amount: + Monto: + + + Label: + Etiqueta: + + + Message: + Mensaje: + + + Wallet: + Billetera: + Copy &URI Copiar &URI @@ -2765,6 +3885,34 @@ Solicitado + + RestoreWalletActivity + + Restore Wallet + Title of progress window which is displayed when wallets are being restored. + Restaurar billetera + + + Restoring Wallet <b>%1</b>… + Descriptive text of the restore wallets progress window which indicates to the user that wallets are currently being restored. + Restaurando billetera <b>%1</b>… + + + Restore wallet failed + Title of message box which is displayed when the wallet could not be restored. + Error al restaurar billetera + + + Restore wallet warning + Title of message box which is displayed when the wallet is restored with some warning. + Advertencia al restaurar billetera + + + Restore wallet message + Title of message box which is displayed when the wallet is successfully restored. + Mensaje de restauración de billetera + + SendCoinsDialog @@ -2799,10 +3947,6 @@ Fee: Comisión: - - Dust: - Polvo: - Inputs… Entradas… @@ -2827,6 +3971,14 @@ Transaction Fee: Comisión por Transacción: + + 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 dash transactions than the network can process. + Cuando el volumen de transacciones es menor que el espacio disponible en los bloques, los mineros y los nodos de retransmisión pueden imponer una comisión mínima. Pagar solo esta tarifa mínima está bien, pero ten en cuenta que esto puede provocar que la transacción nunca se confirme una vez que haya más demanda de transacciones de Dash de las que la red puede procesar. + + + A too low fee might result in a never confirming transaction (read the tooltip) + Una comisión demasiado baja puede provocar que una transacción nunca se confirme (lee la información sobre herramientas) + (Smart fee not initialized yet. This usually takes a few blocks…) (La comisión inteligente no está aún inicializada. Esto habitualmente tarda unos pocos bloques…) @@ -2919,10 +4071,6 @@ Copy bytes Copiar bytes - - Copy dust - Copiar polvo - Copy change Copiar cambio @@ -2939,10 +4087,6 @@ %1 to %2 %1 a %2 - - Are you sure you want to send? - ¿Está seguro que desea enviar? - <b>(%1 of %2 entries displayed)</b> <b>(%1 de %2 registros mostrados)</b> @@ -2955,6 +4099,18 @@ Confirm the %1 send action Confirma la acción de envío %1 + + Cr&eate Unsigned + Cr&eate Sin firmar + + + from wallet '%1' + desde billetera '%1' + + + %1 to '%2' + %1 para '%2' + %1 funds only Fondos de %1 solamente @@ -2989,7 +4145,7 @@ Click to learn more - Haz click para aprender mas + Haz clic para aprender más Total Amount @@ -3003,6 +4159,51 @@ Confirm send coins Confirmar el envío de monedas + + Save Transaction Data + Guardar datos de transacción + + + PSBT saved + PSBT guardado + + + Watch-only balance: + Saldo de solo revisión: + + + Creates a Partially Signed Blockchain Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet. + Crea una transacción de cadena de bloques parcialmente firmada (PSBT) para usar, por ejemplo, con una billetera %1 fuera de línea o una billetera de hardware compatible con PSBT. + + + Do you want to create this transaction? + 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. + ¿Quieres crear esta transacción? + + + Please, review your transaction proposal. This will produce a Partially Signed Blockchain Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet. + 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. + Por favor, revisa tu propuesta de transacción. Esto producirá una Transacción de Cadena de Bloques Parcialmente Firmada (PSBT) que puedes guardar o copiar y luego firmar con, por ejemplo, una billetera %1 fuera de línea o una billetera de hardware compatible con PSBT. + + + Please, review your transaction. You can create and send this transaction or create a Partially Signed Blockchain Transaction (PSBT), which you can save or copy and then sign with, e.g., an offline %1 wallet, or a PSBT-compatible hardware wallet. + 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. + Por favor, revisa tu transacción. Puedes crear y enviar esta transacción o crear una Transacción de Cadena de Bloques Parcialmente Firmada (PSBT), que puedes guardar o copiar y luego firmar con, por ejemplo, una billetera %1 fuera de línea o una billetera de hardware compatible con PSBT. + + + Please, review your transaction. + Text to prompt a user to review the details of the transaction they are attempting to send. + Por favor, revisa tu transacción. + + + To review recipient list click "Show Details…" + Para revisar la lista de destinatarios, haz clic en "Mostrar detalles..." + + + Partially Signed Transaction (Binary) + Expanded name of the binary PSBT file format. See: BIP 174. + Transacción parcialmente firmada (binaria) + The recipient address is not valid. Please recheck. La dirección del destinatario no es válida. Por favor, verifíquela nuevamente. @@ -3122,21 +4323,16 @@ A message that was attached to the dash: URI which will be stored with the transaction for your reference. Note: This message will not be sent over the Dash network. Un mensaje que se adjuntó al Dash: URI que será almacenada con la transacción para su referencia. Nota: Este mensaje no se enviará a través de la red Dash. + + + SendConfirmationDialog - This is an unauthenticated payment request. - Esta es una solicitud de pago no autenticada. - - - This is an authenticated payment request. - Esta es una solicitud de pago autenticada. - - - Pay To: - Pagar a: + Send + Enviar - Memo: - Memo: + Create Unsigned + Crear sin firmar @@ -3276,6 +4472,10 @@ Wallet unlock was cancelled. Se ha cancelado el desbloqueo de la billetera. + + No error + No hay error + Private key for the entered address is not available. No se dispone de la llave privada para la dirección introducida. @@ -3301,19 +4501,30 @@ La firma no coincide con el resumen del mensaje. - Message verification failed. - Ha fallado la verificación del mensaje. + Message verification failed. + Ha fallado la verificación del mensaje. + + + Message verified. + Mensaje verificado. + + + + SplashScreen + + (press q to shutdown and continue later) + (presiona q para apagar y continuar más tarde) - Message verified. - Mensaje verificado. + press q to shutdown + Presiona q para apagar TrafficGraphWidget - KB/s - KB/s + kB/s + kB/s Total @@ -3330,20 +4541,9 @@ TransactionDesc - - Open for %n more block(s) - Abrir para %n bloque másAbrir para %n bloques másAbrir para %n bloques más - - - Open until %1 - Abierto hasta %1 - - - conflicted - en conflicto - 0/unconfirmed, %1 + 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. 0/no confirmado, %1 @@ -3356,22 +4556,32 @@ abandoned + 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. Abandonado + + conflicted with a transaction with %1 confirmations + 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. + en conflicto con una transacción con %1 confirmaciones + %1/unconfirmed + 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, and still not locked via ChainLocks. %1/no confirmado %1 confirmations + 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 or locked via ChainLocks. %1 confirmaciones locked via ChainLocks + 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 and has been locked by ChainLocks. bloqueado por cerraduras de cadena verified via InstantSend + 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 has been locked by InstantSend. verificado a través de InstantSend @@ -3390,6 +4600,10 @@ Generated Generado + + Platform Transfer + Transferencia de plataforma + From De @@ -3520,14 +4734,6 @@ Address / Label Direccion / Etiqueta - - Open for %n more block(s) - Abrir para %n bloque másAbrir para %n bloques másAbrir para %n bloques más - - - Open until %1 - Abierto hasta %1 - Unconfirmed Sin confirmar @@ -3588,6 +4794,10 @@ Mined Minado + + Platform Transfer + Transferencia de plataforma + %1 Mixing Mezclar %1 @@ -3715,6 +4925,10 @@ Mined Minado + + Platform Transfer + Transferencia de plataforma + Other Otra @@ -3728,49 +4942,63 @@ Cantidad mínima - Abandon transaction - Transacción abandonada + &Copy address + &Copiar dirección - Copy address - Copiar dirección + Copy &label + Copiar &etiqueta - Copy label - Copiar etiqueta + Copy &amount + Copiar &monto - Copy amount - Copiar cantidad + Copy transaction &ID + Copiar transacción &ID - Copy transaction ID - Copiar ID de transacción + Copy &raw transaction + Copiar &procesar transacción - Copy raw transaction - Copiar transacción raw + Copy full transaction &details + Copiar la transacción completa &detalles - Copy full transaction details - Copiar todos los detalles de la transacción + &Show transaction details + &Mostrar detalles de la transacción - Edit address label - Editar etiqueta de dirección + A&bandon transaction + Transacción A&bandon - Show transaction details - Mostrar detalles de la transacción + Rese&nd transaction + Rese&nd transacción - Show address QR code - Mostrar dirección en QR + &Edit address label + &Editar etiqueta de dirección + + + Show address &QR code + Mostrar dirección &código QR + + + Show in %1 + 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. + Mostrar en %1 Export Transaction History Exportar historial de transacciones + + Comma separated file + Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values. + Archivo separado por comas + Confirmed Confirmado @@ -3849,10 +5077,54 @@ Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled. Cerrar la billetera por mucho tiempo puede resultar en tener que volver a sincronizar toda la cadena si el despeje está habilitado. - + + Close all wallets + Cerrar todas las billeteras + + + Are you sure you wish to close all wallets? + ¿Estás seguro de que deseas cerrar todas las billeteras? + + WalletFrame - + + No wallet has been loaded. +Go to File > Open Wallet to load a wallet. +- OR - + No se ha cargado ninguna billetera. +Ve a Archivo > Abrir billetera para cargar una billetera. +- OR - + + + Create a new wallet + Crear una nueva billetera + + + Error + Error + + + Unable to decode PSBT from clipboard (invalid base64) + No se puede decodificar PSBT desde el portapapeles (base64 no válido) + + + Load Transaction Data + Cargar datos de transacción + + + Partially Signed Transaction (*.psbt) + Transacción parcialmente firmada (*.psbt) + + + PSBT file must be smaller than 100 MiB + El archivo PSBT debe ser menor a 100 MiB + + + Unable to decode PSBT + No se puede decodificar PSBT + + WalletModel @@ -3878,6 +5150,11 @@ Selected amount: Cantidad seleccionada: + + Wallet Data + Name of the wallet data file format. + Datos de la billetera + Backup Wallet Copia de Seguridad de la billetera @@ -3905,14 +5182,6 @@ dash-core - - Error: Listening for incoming connections failed (listen returned error %s) - Error: Ha fallado la "escucha" de conexiones entrantes ("Escucha" ha devuelto el error %s) - - - Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee. - No se ha podido calcular la comisión. La comisión alternativa está deshabilitada. Espera unos bloques o habilitea -fallbackfee. - 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 Este error podría ocurrir si esta billetera no se cerró correctamente y se cargó por última vez usando una compilación con una versión más nueva de Berkeley DB. Si es así, utiliza el software que cargaste por última vez en esta billetera @@ -3970,16 +5239,20 @@ Error leyendo la base de datos, cerrando. - Failed to listen on any port. Use -listen=0 if you want this. - Error al escuchar cualquier puerto. Use -listen=0 si desea esto. + Error: Missing checksum + Error: falta suma de comprobación - -maxtxfee is set very high! Fees this large could be paid on a single transaction. - -maxtxfee tiene un ajuste muy elevado! Comisiones muy grandes podrían ser pagadas en una única transaccion. + Error: Unable to parse version %u as a uint32_t + Error: No se puede analizar la versión %u como uint32_t - Cannot provide specific connections and have addrman find outgoing connections at the same. - No se pueden proporcionar conexiones específicas y hacer que addrman encuentre conexiones salientes al mismo tiempo. + Error: Unable to write record to new wallet + Error: No se puede escribir el registro en la nueva billetera + + + Failed to listen on any port. Use -listen=0 if you want this. + Error al escuchar cualquier puerto. Use -listen=0 si desea esto. Found unconfirmed denominated outputs, will wait till they confirm to continue. @@ -3990,13 +5263,17 @@ Inválido -socketevents ('%s') especificado. Solo se admiten estos modos: %s - Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions) - Cantidad inválida para -maxtxfee=<amount>: '%s' (debe de ser al menos la comisión mínima de %s para evitar transacciones atascadas) + SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is supported + SQLiteDatabase: Se desconoce la versión %d del esquema de billetera SQLite. Solo se admite la versión %d Transaction index can't be disabled with governance validation enabled. Either start with -disablegovernance command line switch or enable transaction index. El índice de transacciones no se puede deshabilitar con la validación de gobernanza habilitada. Empieza con el interruptor de línea de comando -disablegovernance o habilita el índice de transacciones. + + Unsupported category-specific logging level -loglevel=%s. Expected -loglevel=<category>:<loglevel>. Valid categories: %s. Valid loglevels: %s. + Nivel de registro específico de categoría no compatible -loglevel=%s. se espera -loglevel=<category>:<loglevel>. Categorías válidas: %s. Valid loglevels: %s. + Can't mix: no compatible inputs found! No se puede mezclar: ¡fondos de entrada no compatibles! @@ -4005,6 +5282,14 @@ Entry exceeds maximum size. Entrada exceden el tamaño máximo. + + Error upgrading evo database for EHF + Error al actualizar la base de datos de Evo para EHF + + + Failed to commit Evo database + No se pudo confirmar la base de datos de Evo + Found enough users, signing ( waiting %s ) Se encontraron suficientes usuarios, firmando (esperando %s) @@ -4029,18 +5314,14 @@ Insufficient funds. Fondos insuficientes. - - Invalid amount for -discardfee=<amount>: '%s' - Cuantía inválida para -discardfee=<amount>: '%s' - - - Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s) - Cantidad inválida para -paytxfee=<amount>: '%s' (debe ser al menos %s) - Invalid minimum number of spork signers specified with -minsporkkeys Número mínimo inválido de firmantes de spork especificados con -minsporkkeys + + Listening for incoming connections failed (listen returned error %s) + Error al escuchar conexiones entrantes (la escucha devolvió el error %s) + Lock is already in place. El bloqueo ya está activo. @@ -4097,6 +5378,10 @@ Synchronizing governance objects… Sincronizando objetos de gobernanza… + + Transaction change output index out of range + El índice de salida del cambio de transacción está fuera de rango + Unable to start HTTP server. See debug log for details. No se ha podido iniciar el servidor HTTP. Ver registro de depuración para detalles. @@ -4105,6 +5390,10 @@ Unknown response. Respuesta desconocida. + + Unsupported global logging level -loglevel=%s. Valid values: %s. + Nivel de registro global no compatible: -loglevel=%s. Valores válidos: %s. + User Agent comment (%s) contains unsafe characters. El comentario del Agente de Usuario (%s) contiene caracteres inseguros. @@ -4145,17 +5434,21 @@ Make sure to encrypt your wallet and delete all non-encrypted backups after you have verified that the wallet works! ¡Asegúrate de encriptar tu billetera y eliminar todas las copias de seguridad no encriptadas después de haber verificado que la billetera funciona! + + More than one onion bind address is provided. Using %s for the automatically created Tor onion service. + Se proporciona más de una dirección de enlace Onion. Se utiliza %s para el servicio Onion de Tor creado automáticamente. + Prune configured below the minimum of %d MiB. Please use a higher number. - La Poda se ha configurado por debajo del minimo de %d MiB. Por favor utiliza un valor mas alto. + La Poda se ha configurado por debajo del mínimo de %d MiB. Por favor utiliza un valor más alto. Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node) - Poda: la ultima sincronizacion de la billetera sobrepasa los datos podados. Necesitas reindexar con -reindex (o descargar la cadena de bloques de nuevo en el caso de un nodo podado) + Poda: la última sincronización de la billetera sobrepasa los datos podados. Necesitas reindexar con -reindex (o descargar la cadena de bloques de nuevo en el caso de un nodo podado) 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 - La base de datos de bloques contiene un bloque que parece ser del futuro. Esto puede ser porque la fecha y hora de tu ordenador están mal ajustados. Reconstruye la base de datos de bloques solo si estas seguro de que la fecha y hora de tu ordenador estan ajustados correctamente. + La base de datos de bloques contiene un bloque que parece ser del futuro. Esto puede ser porque la fecha y hora de tu ordenador están mal ajustados. Reconstruye la base de datos de bloques solo si estas seguro de que la fecha y hora de tu ordenador están ajustados correctamente. The transaction amount is too small to send after the fee has been deducted @@ -4173,10 +5466,6 @@ Wallet is locked, can't replenish keypool! Automatic backups and mixing are disabled, please unlock your wallet to replenish keypool. ¡La billetera esta bloqueado, no se puede reponer keypool! Copias de seguridad automáticas y mezclado están deshabilitados, por favor desbloquee su billetera para reponer keypool. - - You need to rebuild the database using -reindex to change -timestampindex - Necesitas reconstruir la base de datos usando -reindex para cambiar -timestampindex - You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain Necesitas reconstruir la base de datos utilizando -reindex para volver al modo sin poda. Esto volverá a descargar toda la cadena de bloques @@ -4218,20 +5507,32 @@ Error al cargar %s: las claves privadas solo se pueden deshabilitar durante la creación - Error upgrading evo database - Error al actualizar la base de datos evo + Error: Couldn't create cursor into database + Error: No se pudo crear el cursor en la base de datos Error: Disk space is low for %s Error: el espacio en disco es bajo para %s - Exceeded max tries. - Se superó el máximo de intentos. + Error: Dumpfile checksum does not match. Computed %s, expected %s + Error: la suma de comprobación del archivo de volcado no coincide. Se ha calculado %s, se esperaba %s + + + Error: Got key that was not hex: %s + Error: Obtuve una clave que no era hexadecimal: %s + + + Error: Got value that was not hex: %s + Error: Obtuve un valor que no era hexadecimal: %s + + + Error: Keypool ran out, please call keypoolrefill first + Error: Keypool se agotó, llama primero a keypoolrefill - Failed to commit EvoDB - No se pudo cometer EvoDB + Error: No addresses available. + Error: No hay direcciones disponibles. Failed to create backup %s! @@ -4249,17 +5550,29 @@ Failed to rescan the wallet during initialization No se pudo volver a escanear la billetera durante la inicialización + + Failed to verify database + No se pudo verificar la base de datos + + + Fee rate (%s) is lower than the minimum fee rate setting (%s) + La tasa de comisión (%s) es inferior a la configuración de la tasa de comisión mínima (%s) + Found enough users, signing… Se encontraron suficientes usuarios, firmando… - Invalid P2P permission: '%s' - Permiso P2P no válido: '%s' + Ignoring duplicate -wallet %s. + Ignorando el duplicado -wallet %s. + + + Input not found or already spent + Entrada no encontrada o ya gastada - Invalid amount for -fallbackfee=<amount>: '%s' - Cantidad inválida para -fallbackfee=<amount>: '%s' + Invalid P2P permission: '%s' + Permiso P2P no válido: '%s' Invalid masternodeblsprivkey. Please see documentation. @@ -4281,6 +5594,10 @@ Mixing in progress… Mezclado en curso… + + No addresses available + No hay direcciones disponibles + No errors detected. No hay errores detectados. @@ -4309,6 +5626,22 @@ Prune mode is incompatible with -txindex. El modo recorte es incompatible con -txindex. + + SQLiteDatabase: Failed to execute statement to verify database: %s + SQLiteDatabase: No se pudo ejecutar la declaración para verificar la base de datos: %s + + + SQLiteDatabase: Failed to prepare statement to verify database: %s + SQLiteDatabase: No se pudo preparar la declaración para verificar la base de datos: %s + + + SQLiteDatabase: Failed to read database verification error: %s + SQLiteDatabase: Error al leer la verificación de la base de datos: %s + + + SQLiteDatabase: Unexpected application id. Expected %u, got %u + SQLiteDatabase: ID de aplicación inesperada. Se esperaba %u, se obtuvo %u + Section [%s] is not recognized. La sección [%s] no se reconoce @@ -4341,6 +5674,10 @@ This is the transaction fee you will pay if you send a transaction. Esta es la cuota de transacción que pagará si envía una transacción. + + Topping up keypool… + Recargando el pool de claves… + Transaction amounts must not be negative Los montos de transacción no deben ser negativos @@ -4369,13 +5706,17 @@ Unable to generate initial keys No se pueden generar llaves iniciales + + Unable to open %s for writing + No se puede abrir %s para escribir + Unknown -blockfilterindex value %s. Valor -blockfilterindex desconocido %s. - Upgrading UTXO database - Actualizando la base de datos UTXO + Unknown new rules activated (versionbit %i) + Nuevas reglas desconocidas activadas (versionbit %i) Verifying blocks… @@ -4394,16 +5735,12 @@ ¡No es posible crear carpeta de copia de seguridad de la billetera %s! - You can not start a masternode with wallet enabled. - No puedes iniciar un masternode con billetera habilitada. - - - You need to rebuild the database using -reindex to change -addressindex - Necesita reconstruir la base de datos usando -reindex para cambiar -addressindex + Wiping wallet transactions… + Borrando transacciones de billetera… - You need to rebuild the database using -reindex to change -spentindex - Necesita reconstruir la base de datos usando -reindex para cambiar -spentindex + You can not start a masternode with wallet enabled. + No puedes iniciar un masternode con billetera habilitada. no mixing available. @@ -4421,6 +5758,22 @@ %s uses exact denominated amounts to send funds, you might simply need to mix some more coins. %s usa cantidades denominadas exactas para enviar fondos, probablemente solo tengas que mezclar algunas otras monedas. + + -reindex-chainstate option is not compatible with -blockfilterindex. Please temporarily disable blockfilterindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes. + La opción -reindex-chainstate no es compatible con -blockfilterindex. Desactiva temporalmente blockfilterindex mientras utilizas -reindex-chainstate o reemplaza -reindex-chainstate con -reindex para reconstruir por completo todos los índices. + + + -reindex-chainstate option is not compatible with -coinstatsindex. Please temporarily disable coinstatsindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes. + La opción -reindex-chainstate no es compatible con -coinstatsindex. Desactiva temporalmente coinstatsindex mientras usas -reindex-chainstate o reemplaza -reindex-chainstate con -reindex para reconstruir por completo todos los índices. + + + -reindex-chainstate option is not compatible with -txindex. Please temporarily disable txindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes. + La opción -reindex-chainstate no es compatible con -txindex. Desactiva temporalmente txindex mientras utilizas -reindex-chainstate o reemplaza -reindex-chainstate por -reindex para reconstruir por completo todos los índices. + + + Cannot downgrade wallet from version %i to version %i. Wallet version unchanged. + No se puede degradar la billetera de la versión %i a la versión %i. La versión de la billetera no ha cambiado. + Cannot obtain a lock on data directory %s. %s is probably already running. No se puede bloquear el directorio %s. %s ya se está ejecutando. @@ -4433,21 +5786,97 @@ Error loading %s: You can't enable HD on an already existing non-HD wallet Error cargando %s: No puede habilitar HD en una billetera non-HD existente. + + 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 + Error al cargar la billetera. La billetera requiere que se descarguen bloques y el software actualmente no admite la carga de billeteras mientras se descargan bloques fuera de orden al usar snapshots de supposedutxo. La billetera debería poder cargarse correctamente después de que la sincronización de nodos alcance la altura %s + Error reading %s! All keys read correctly, but transaction data or address book entries might be missing or incorrect. Error leyendo %s!. Todas las llaves se han leído correctamente, pero los datos de transacciones o la libreta de direcciones pueden faltar o ser incorrectos. + + Error: Dumpfile format record is incorrect. Got "%s", expected "format". + Error: el registro de formato del archivo de volcado es incorrecto. Se obtuvo "%s", se esperaba "formato". + + + Error: Dumpfile identifier record is incorrect. Got "%s", expected "%s". + Error: el registro del identificador del archivo de volcado es incorrecto. Se obtuvo "%s", se esperaba "%s". + + + Error: Dumpfile version is not supported. This version of bitcoin-wallet only supports version 1 dumpfiles. Got dumpfile with version %s + 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 + + + Failed to rename invalid peers.dat file. Please move or delete it and try again. + No se pudo cambiar el nombre del archivo peers.dat no válido. Muévelo o elimínalo y vuelve a intentarlo. + + + Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable %s. + La estimación de tarifa falló. Fallbackfee está deshabilitado. Espera unos bloques o habilita %s. + + + File %s already exists. If you are sure this is what you want, move it out of the way first. + El archivo %s ya existe. Si estás seguro de que es lo que quieres, quítalo primero. + + + Incompatible options: -dnsseed=1 was explicitly specified, but -onlynet forbids connections to IPv4/IPv6 + Opciones incompatibles: -dnsseed=1 se especificó explícitamente, pero -onlynet prohíbe las conexiones a IPv4/IPv6 + Incorrect or no devnet genesis block found. Wrong datadir for devnet specified? Bloque génesis de devnet incorrecto o no encontrado. ¿Datadir equivocado para devnet? + + Invalid amount for %s=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions) + Monto inválido para %s=<amount>: '%s' (debe ser al menos la tarifa minrelay de %s para evitar transacciones atascadas) + + + 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. + Peers.dat no válido o dañado (%s). Si crees que se trata de un error, infórmalo a %s. Como solución alternativa, puedes mover el archivo (%s) (renombrar, mover o eliminar) para que se cree uno nuevo en el próximo inicio. + + + No dump file provided. To use createfromdump, -dumpfile=<filename> must be provided. + No se proporcionó ningún archivo de volcado. Para utilizar createfromdump, -archivo de volcado=<filename> debe proporcionarse. + + + No dump file provided. To use dump, -dumpfile=<filename> must be provided. + No se proporcionó ningún archivo de volcado. Para utilizar el archivo de volcado, -dumpfile=<filename> debe proporcionarse. + + + No wallet file format provided. To use createfromdump, -format=<format> must be provided. + No se proporciona ningún formato de archivo de billetera. Para usar createfromdump, -formato=<format> debe proporcionarse. + + + Outbound connections restricted to CJDNS (-onlynet=cjdns) but -cjdnsreachable is not provided + Las conexiones salientes están restringidas a CJDNS (-onlynet=cjdns) pero no se proporciona -cjdnsreachable + + + Outbound connections restricted to Tor (-onlynet=onion) but the proxy for reaching the Tor network is explicitly forbidden: -onion=0 + Las conexiones salientes están restringidas a Tor (-onlynet=onion) pero el proxy para acceder a la red Tor está explícitamente prohibido: -onion=0 + + + 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 + Las conexiones salientes están restringidas a Tor (-onlynet=onion) pero no se proporciona el proxy para llegar a la red Tor: no se proporciona ninguno de los dos: -proxy, -onion o -listenonion + + + Outbound connections restricted to i2p (-onlynet=i2p) but -i2psam is not provided + Las conexiones salientes están restringidas a i2p (-onlynet=i2p) pero no se proporciona -i2psam + Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly. Por favor, compruebe si la fecha y hora en su computadora son correctas! Si su reloj esta mal, %s no trabajara correctamente. Please contribute if you find %s useful. Visit %s for further information about the software. - Contribuya si encuentra %s de utilidad. Visite %s para mas información acerca del programa. + Contribuya si encuentra %s de utilidad. Visite %s para más información acerca del programa. + + + Prune mode is incompatible with -reindex-chainstate. Use full -reindex instead. + El modo de poda no es compatible con -reindex-chainstate. En su lugar, utiliza -reindex completo. + + + This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection. + Esta es la comisión de transacción máxima que pagas (además de la comisión normal) para priorizar la evitación del gasto parcial sobre la selección regular de monedas. This is the transaction fee you may discard if change is smaller than dust at this level @@ -4457,14 +5886,38 @@ This is the transaction fee you may pay when fee estimates are not available. Esta es la tarifa de cuota que debe pagar cuando las estimaciones de tarifas no estén disponibles. + + Transaction requires one destination of non-0 value, a non-0 feerate, or a pre-selected input + La transacción requiere un destino de valor distinto de 0, una tasa de tarifa distinta de 0 o una entrada preseleccionada + Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate. No se pueden reproducir bloques. Deberás reconstruir la base de datos utilizando -reindex-chainstate. + + Unknown wallet file format "%s" provided. Please provide one of "bdb" or "sqlite". + Se proporcionó un formato de archivo de billetera desconocido "%s". Proporciona uno de los siguientes "bdb" o "sqlite". + + + Unsupported chainstate database format found. Please restart with -reindex-chainstate. This will rebuild the chainstate database. + Se encontró un formato de base de datos chainstate no compatible. Reinicie con -reindex-chainstate. Esto reconstruirá la base de datos chainstate. + + + Warning: Dumpfile wallet format "%s" does not match command line specified format "%s". + Advertencia: el formato de billetera del archivo de volcado "%s" no coincide con el formato especificado en la línea de comando "%s". + Warning: Private keys detected in wallet {%s} with disabled private keys Advertencia: claves privadas detectadas en la billetera {%s} con claves privadas deshabilitadas + + You need to rebuild the database using -reindex to enable -timestampindex + Debes reconstruir la base de datos usando -reindex para habilitar -timestampindex + + + %s -- Incorrect seed, it should be a hex string + %s - Semilla incorrecta, debería ser una cadena hexadecimal + %s is not a valid backup folder! ¡%s no es una carpeta de copia de seguridad valida! @@ -4489,10 +5942,30 @@ -rpcport must be specified when -devnet and -server are specified -rpcport solo se debe especificar cuando -devnet y -server son especificados + + -statsbatchsize cannot be configured with a negative value. + -statsbatchsize no se puede configurar con un valor negativo. + + + -statsduration cannot be configured with a negative value. + -statsduration no se puede configurar con un valor negativo. + A fatal internal error occurred, see debug.log for details Ocurrió un error interno fatal, ver debug.log para más detalles + + Cannot create socket (socket() returned error %s) + No se puede crear el socket (socket() devolvió el error %s) + + + Cannot get socket address for %s + No se puede obtener la dirección de socket para %s + + + Cannot init Statsd client + No se puede inicializar el cliente Statsd + Cannot resolve -%s address: '%s' No se puede resolver -%s direccion: '%s' @@ -4501,10 +5974,6 @@ Cannot write to data directory '%s'; check permissions. No se puede escribir en el directorio de datos '%s'; comprobar los permisos. - - Change index out of range - Cambio de indice fuera de rango - Copyright (C) Copyright (C) @@ -4513,6 +5982,14 @@ Disk space is too low! ¡El espacio en disco es demasiado bajo! + + Dump file %s does not exist. + El archivo de volcado %s no existe. + + + Error creating %s + Error al crear %s + Error loading %s Error cargando %s @@ -4523,15 +6000,15 @@ Error loading %s: Wallet requires newer version of %s - Error cargando %s: La billetera requiere una versión mas reciente de %s + Error cargando %s: La billetera requiere una versión más reciente de %s Error loading %s: You can't disable HD on an already existing HD wallet Error cargando %s: No puede deshabilitar HD en una billetera HD existente - Error upgrading chainstate database - Error actualizando la base de datos chainstate + Error reading next record from wallet database + Error al leer el siguiente registro de la base de datos de la billetera Loading P2P addresses… @@ -4601,6 +6078,14 @@ Inputs vs outputs size mismatch. El tamaño de las entradas frente vs las salidas no coincide. + + Invalid '%s'. Allowed values: 128, 160, 192, 224, 256. + '%s' no válido. Valores permitidos: 128, 160, 192, 224, 256. + + + Invalid -i2psam address or hostname: '%s' + Dirección -i2psam o nombre de host no válidos: '%s' + Invalid -onion address or hostname: '%s' Dirección -onion o nombre de host inválido: '%s' @@ -4645,14 +6130,78 @@ %s corrupt. Try using the wallet tool dash-wallet to salvage or restoring a backup. %s corrupto. Intenta usar la herramienta de billetera dash-wallet para recuperar o restaurar una copia de seguridad. + + %s is set very high! Fees this large could be paid on a single transaction. + ¡%s está configurado muy alto! Tarifas tan grandes podrían pagarse en una sola transacción. + + + %s request to listen on port %u. This port is considered "bad" and thus it is unlikely that any Dash Core peers connect to it. See doc/p2p-bad-ports.md for details and a full list. + %s solicita escuchar en el puerto %u. Este puerto se considera "malo" y, por lo tanto, es poco probable que algún par de Dash Core se conecte a él. Consulta doc/p2p-bad-ports.md para obtener más detalles y una lista completa. + + + Cannot provide specific connections and have addrman find outgoing connections at the same time. + No se pueden proporcionar conexiones específicas y hacer que addrman encuentre conexiones salientes al mismo tiempo. + + + Failed to upgrade Evo database + Error al actualizar la base de datos Evo + + + Fee needed > fee paid + Tarifa necesaria > tarifa pagada + + + Host %s on unsupported network + Host %s en red no compatible + + + Invalid amount for %s=<amount>: '%s' (must be at least %s) + Cantidad no válida para %s=<cantidad>: '%s' (debe ser al menos %s) + + + Invalid amount for %s=<amount>: '%s' + Cantidad no válida para %s=<cantidad>: '%s' + + + Invalid port specified in %s: '%s' + Puerto no válido especificado en %s: '%s' + Last successful action was too recent. La última acción exitosa era demasiado reciente. + + Missing solving data for estimating transaction size + Faltan datos de resolución para estimar el tamaño de la transacción + + + No host specified + No se especificó host + + + No host specified, malformed URL + No se especificó host, URL mal formada + + + No text before the scheme delimiter, malformed URL + No hay texto antes del delimitador de esquema, URL mal formada + + + Port must be between %d and %d, supplied %d + El puerto debe estar entre %d y %d, se proporcionó %d + + + Socket not initialized, cannot send message + Socket no inicializado, no se puede enviar el mensaje + The source code is available from %s. El código fuente esta disponible desde %s. + + The specified config file %s does not exist + El archivo de configuración especificado %s no existe + The transaction amount is too small to pay the fee El monto de la transacción es demasiado pequeño para pagar la comisión @@ -4673,6 +6222,10 @@ Transaction fees are too high. Las comisiones por transacción son demasiado elevadas. + + Transaction needs a change address, but we can't generate it. + La transacción necesita una dirección de cambio, pero no podemos generarla. + Transaction not valid. La transacción no es válida. @@ -4693,6 +6246,18 @@ Unable to locate enough non-denominated funds for this transaction. No se pueden localizar fondos no denominados suficientes para esta transacción. + + Unable to lookup host %s + No se puede buscar el host %s + + + Unable to parse -maxuploadtarget: '%s' + No se puede analizar -maxuploadtarget: '%s' + + + Unable to send message to %s (::sendto() returned error %s) + No se puede enviar el mensaje a %s (::sendto() devolvió el error %s) + Unable to sign spork message, wrong key? No fue posible firmar el mensaje de spork, ¿llave incorrecta? @@ -4706,12 +6271,12 @@ Estado desconocido: id = %u - Unsupported logging category %s=%s. - Categoría de registro no compatible %s=%s. + Unsupported URL scheme, must begin with udp:// + Esquema de URL no compatible, debe comenzar con udp:// - Upgrading txindex database - Actualización de la base de datos txindex + Unsupported logging category %s=%s. + Categoría de registro no compatible %s=%s. Very low number of keys left: %d @@ -4741,9 +6306,25 @@ You can not disable governance validation on a masternode. No puede deshabilitar la validación de gobernanza en un masternode. + + You need to rebuild the database using -reindex to enable -addressindex + Debes reconstruir la base de datos usando -reindex para habilitar -addressindex + + + You need to rebuild the database using -reindex to enable -spentindex + Debes reconstruir la base de datos usando -reindex para habilitar -spentindex + Your entries added successfully. Sus registros se agregaron con éxito. + + Settings file could not be read + No se pudo leer el archivo de configuración + + + Settings file could not be written + No se pudo escribir el archivo de configuración + \ No newline at end of file diff --git a/src/qt/locale/dash_fi.ts b/src/qt/locale/dash_fi.ts index ec221f8b1fcf..a1c3d9566523 100644 --- a/src/qt/locale/dash_fi.ts +++ b/src/qt/locale/dash_fi.ts @@ -65,14 +65,6 @@ C&hoose V&alitse - - Sending addresses - Lähettävä osoite - - - Receiving addresses - Vastaanottava osoite - These are your Dash addresses for sending payments. Always check the amount and the receiving address before sending coins. Nämä ovat Dash osoitteesi maksujen lähetykseen. Tarkista aina lähetettävä määrä ja vastaanottajan osoite ennen kuin lähetät kolikoita. @@ -94,8 +86,8 @@ &Muokkaa - &Show address QR code - &Näytä osoitteen QR koodi + Show address &QR code + Näytä osoitteen &QR-koodi QR code @@ -105,6 +97,24 @@ Export Address List Vie osoitekirja + + Comma separated file + Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values. + Pilkulla erotettu tiedosto + + + There was an error trying to save the address list to %1. Please try again. + An error message. %1 is a stand-in argument for the name of the file we attempted to save to. + Virhe tallennettaessa osoiteluetteloa tiedostoon %1. Yritä uudelleen. + + + Sending addresses - %1 + Lähetysosoitteet - %1 + + + Receiving addresses - %1 + Vastaanotto-osoitteet - %1 + Exporting Failed Vienti epäonnistui @@ -274,10 +284,22 @@ The passphrase entered for the wallet decryption was incorrect. Annettu salasana oli väärin. + + 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 23.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. + Lompakon salauksen purkuun annettu salasana on virheellinen. Se sisältää null-merkin (eli nollatavun). Jos salasana asetettiin tämän ohjelmiston versiolla ennen 23.0, yritä uudelleen vain merkeillä ensimmäiseen null-merkkiin asti — mutta ei sitä mukaan lukien. Jos tämä onnistuu, aseta uusi salasana välttääksesi tämän ongelman tulevaisuudessa. + Wallet passphrase was successfully changed. Lompakon salasana vaihdettiin onnistuneesti. + + Passphrase change failed + Salasanan vaihto epäonnistui + + + 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 23.0, please try again with only the characters up to — but not including — the first null character. + Lompakon salauksen purkuun annettu vanha salasana on virheellinen. Se sisältää null-merkin (eli nollatavun). Jos salasana asetettiin tämän ohjelmiston versiolla ennen 23.0, yritä uudelleen vain merkeillä ensimmäiseen null-merkkiin asti — mutta ei sitä mukaan lukien. + Warning: The Caps Lock key is on! Varoitus: Caps Lock on käytössä! @@ -303,7 +325,23 @@ BitcoinApplication - + + Runaway exception + Hallitsematon poikkeus + + + A fatal error occurred. %1 can no longer continue safely and will quit. + Kriittinen virhe tapahtui. %1 ei voi enää jatkaa turvallisesti ja sulkeutuu. + + + Internal error + Sisäinen virhe + + + An internal error occurred. %1 will attempt to continue safely. This is an unexpected bug which can be reported as described below. + Sisäinen virhe tapahtui. %1 yrittää jatkaa turvallisesti. Tämä on odottamaton virhe, joka voidaan raportoida alla kuvatulla tavalla. + + BitcoinGUI @@ -330,6 +368,10 @@ Request payments (generates QR codes and dash: URIs) Pyydä maksuja (Luo QR koodit ja Dash: URIt) + + Ctrl+Q + Ctrl+Q + &Options… &Asetukset… @@ -358,6 +400,10 @@ &Verify message… &Tarkista Viesti… + + &Load PSBT from file… + &Lataa PSBT tiedostosta… + &Sending addresses &Lähettävät Osoitteet @@ -390,10 +436,6 @@ &Window &Ikkuna - - Minimize - Pienennä - Zoom Suurenna @@ -446,14 +488,6 @@ Modify configuration options for %1 Muuta %1 asetuksia - - &Show / Hide - &Näytä / Piilota - - - Show or hide the main Window - Näytä tai piilota pääikkuna - Encrypt the private keys that belong to your wallet Salaa yksityiset avaimet jotka kuuluvat lompakkoosi @@ -518,10 +552,6 @@ Show wallet repair options Näytä lompakon korjausvalinnat - - Open Wallet &Configuration File - Avaa &Asetustiedosto - Open configuration file Avaa asetustiedosto @@ -576,10 +606,40 @@ Show information about %1 Näytä tietoja %1 + + Load PSBT from &clipboard… + Lataa PSBT &leikepöydältä… + + + Open debugging and diagnostic console + Avaa virheenkorjaus- ja diagnoosikonsoli + + + Open &wallet configuration file + Avaa &lompakon asetustiedosto + + + Open a dash: URI + Avaa dash: URI + Create a new wallet Luo uusi lompakko + + Restore Wallet… + Name of the menu item that restores wallet from a backup file. + Palauta lompakko… + + + Restore a wallet from a backup file + Status tip for Restore Wallet menu item + Palauta lompakko varmuuskopiotiedostosta + + + Close all wallets + Sulje kaikki lompakot + %1 &information %1 T&ietoja @@ -588,10 +648,42 @@ Show the %1 basic information Näytä %1 perustietoja + + &Discreet mode + &Huomaamaton tila + + + Mask the values in the Overview tab + Peitä arvot Yleiskatsaus-välilehdellä + + + Wallet Data + Name of the wallet data file format. + Lompakon tiedot + + + Load Wallet Backup + The title for Restore Wallet File Windows + Lataa lompakon varmuuskopio + + + Restore Wallet + Title of pop-up window shown when the user is attempting to restore a wallet. + Palauta lompakko + + + Wallet Name + Label of the input field where the name of the wallet is entered. + Lompakon nimi + &Settings &Asetukset + + &Minimize + &Pienennä + &Help &Apua @@ -608,8 +700,17 @@ View Governance Proposals Näytä hallinnon ehdotukset + + &Hide + &Piilota + + + S&how + &Näytä + %n active connection(s) to Dash network + A substring of the tooltip. %n aktiivinen yhteys Dash verkkoon%n aktiivista yhteyttä Dash verkkoon @@ -628,10 +729,50 @@ Close Wallet… Sulje Lompakko… + + Load Partially Signed Blockchain Transaction + Lataa osittain allekirjoitettu lohkoketjutapahtuma + + + Load Partially Signed Blockchain Transaction from clipboard + Lataa osittain allekirjoitettu lohkoketjutapahtuma leikepöydältä + Create Wallet… Luo Lompakko… + + Close All Wallets… + Sulje kaikki lompakot… + + + Ctrl+Shift+D + Ctrl+Shift+D + + + Ctrl+M + Ctrl+M + + + Click for more actions. + A substring of the tooltip. "More actions" are available via the context menu. + Napsauta nähdäksesi lisää toimintoja. + + + Show Peers tab + A context menu item. The "Peers tab" is an element of the "Node window". + Näytä Peers-välilehti + + + Disable network activity + A context menu item. + Poista verkkotoiminnot käytöstä + + + Enable network activity + A context menu item. The network activity was disabled previously. + Ota verkkotoiminnot käyttöön + Syncing Headers (%1%)… Synkronoidaan otsikoita (%1%)… @@ -648,10 +789,6 @@ Processing blocks on disk… Käsitellään lohkoja levyllä… - - Reindexing blocks on disk… - Uudelleen indeksoidaan lohkoja… - Connecting to peers… Kytkeydytään peers… @@ -805,10 +942,6 @@ Coin Selection Kolikko Valinta - - Dust: - Tomu: - After Fee: Siirtomaksun jälkeen: @@ -866,28 +999,32 @@ Vahvistettu - Copy address - Kopioi osoite + Copy amount + Kopioi määrä + + + &Copy address + &Kopioi osoite - Copy label - Kopioi nimi + Copy &label + Kopioi &nimi - Copy amount - Kopioi määrä + Copy &amount + Kopioi &määrä - Copy transaction ID - Kopioi siirtotunnus + Copy transaction &ID and output index + Kopioi tapahtuman &ID ja lähtöindeksi - Lock unspent - Lukitse käyttämättömät + L&ock unspent + L&ukitse käyttämätön - Unlock unspent - Avaa lukitus käyttämättömistä + &Unlock unspent + &Avaa käyttämättömän lukitus Copy quantity @@ -905,10 +1042,6 @@ Copy bytes Kopioi tavut - - Copy dust - Kopioi tomu - Copy change Kopioi vaihtoraha @@ -921,18 +1054,6 @@ (%1 locked) (%1 lukittu) - - yes - kyllä - - - no - ei - - - This label turns red if any recipient receives an amount smaller than the current dust threshold. - Tämä nimi vaihtuu punaiseksi jos yksikään vastaanottaja saa pienemmän määrän kuin nykyinen tomun määritelty raja-arvo. - Can vary +/- %1 duff(s) per input. Voi vaihdella +/- %1 duffs per syöte. @@ -976,8 +1097,14 @@ CreateWalletActivity + + Create Wallet + Title of window indicating the progress of creation of a new wallet. + Luo lompakko + Creating Wallet <b>%1</b>… + Descriptive text of the create wallet progress window which indicates to the user which wallet is currently being created. Luodaan Lompakko <b>%1</b>… @@ -999,6 +1126,10 @@ Wallet Name Lompakon Nimi + + Wallet + Lompakko + Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice. Salaa lompakko. Lompakko salataan haluamallasi salasanallasi. @@ -1007,6 +1138,10 @@ Encrypt Wallet Salaa Lompakko + + Advanced Options + Edistyneet asetukset + 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. Poista tämän lompakon yksityisavaimet käytöstä. Lompakoissa joissa yksityisavaimet on poistettu käytöstä, ei ole yksityisiä avaimia, eikä niissä voi olla HD-siementä tai tuotuja yksityisavaimia Tämä sopii hyvin katso-vain lompakoille. @@ -1023,11 +1158,23 @@ Make Blank Wallet Luo Tyhjä Lompakko + + Use descriptors for scriptPubKey management. This feature is well-tested but still considered experimental and not recommended for use yet. + Käytä deskriptoreja scriptPubKey-hallintaan. Tämä ominaisuus on hyvin testattu, mutta sitä pidetään edelleen kokeellisena, eikä sen käyttöä suositella vielä. + + + Descriptor Wallet (EXPERIMENTAL) + Deskriptorilompakko (KOKEELLINEN) + Create Luo - + + Compiled without sqlite support (required for descriptor wallets) + Käännetty ilman sqlite-tukea (vaaditaan deskriptorilompakoille) + + EditAddressDialog @@ -1116,18 +1263,106 @@ Filter List: SuodatusLista: + + Filter proposal list + Suodata ehdotusluettelo + + + Masternode Count: + Masternoden määrä: + + + Number of masternodes this wallet can vote with (masternodes for which this wallet holds the voting key) + Masternodejen määrä, joilla tämä lompakko voi äänestää (masternodes, joiden äänestysavainta tämä lompakko hallitsee) + Proposal Count: Ehdotuksien Määrä: + + Create Proposal + Luo ehdotus + Filter by Title Suodata Otsikolla + + Unavailable + Ei saatavilla + + + A synced node and an unlocked wallet are required. + Synkronoitu node ja lukitsematon lompakko vaaditaan. + + + Vote Yes + Äänestä Kyllä + + + Vote No + Äänestä Ei + + + Vote Abstain + Tyhjää + Proposal Info: %1 Ehdotus Info: %1 + + Voting Failed + Äänestys epäonnistui + + + No wallet available. + Lompaakkoa ei saatavilla. + + + No masternode voting keys found in wallet. + Masternoden äänestysavaimia ei löytynyt lompakosta. + + + Please select a proposal to vote on. + Valitse ehdotus, josta äänestää. + + + Unable to unlock wallet. + Lompakon lukitusta ei voitu avata. + + + Unable to get masternode list. Please try again later. + Masternode-luetteloa ei voitu hakea. Yritä myöhemmin uudelleen. + + + Masternode %1 not found + Masternodea %1 ei löytynyt + + + Failed to sign vote for masternode %1 + Äänen allekirjoitus masternodelle %1 epäonnistui + + + Masternode %1: %2 + Masternode %1: %2 + + + Voted successfully %n time(s) + Äänestys onnistui %n kerranÄänestys onnistui %n kertaa + + + Failed to vote %n time(s) + Äänestys epäonnistui %n kerranÄänestys epäonnistui %n kertaa + + + Errors: + Virheet: + + + Voting Results + Äänestystulokset + HelpMessageDialog @@ -1166,10 +1401,26 @@ As this is the first time the program is launched, you can choose where %1 will store its data. Tämä on ensimmäinen kerta, kun %1 on käynnistetty, joten voit valita datahakemiston paikan. + + Limit block chain storage to + Rajoita lohkoketjun tallennustilaa + + + 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. + Tämän asetuksen palauttaminen edellyttää koko lohkoketjun uudelleenlataamista. On nopeampaa ladata ensin koko ketju ja karsia se myöhemmin. Poistaa käytöstä joitakin edistyneitä ominaisuuksia. + + + GB + GB + 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. Tämä ensimmäinen synkronointi on vaativa, ja saattaa paljastaa laitteisto-ongelmia tietokoneessasi joita ei aikaisemmin ole huomattu. Aina kun käynnistät %1, jatkuu latautuminen siitä mihin se jäi aikaisemmin. + + 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. + Kun napsautat OK, %1 aloittaa koko %4-lohkoketjun (%2 GB) lataamisen ja käsittelyn alkaen varhaisimmista tapahtumista %3:ssä, jolloin %4 alun perin käynnistettiin. + 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. Jos olet valinnut rajoitetun lohkoketjun levytilan (karsimalla), historialliset tiedot täytyy silti ladata ja prosessoida, mutta ne poistetaan jälkeenpäin jotta levytilaa säästyy. @@ -1182,6 +1433,18 @@ Use a custom data directory: Määritä oma datahakemisto: + + %n GB of space available + %n GB tilaa saatavilla%n GB tilaa saatavilla + + + (of %n GB needed) + (%n GB tarvitaan)(%n GB tarvitaan) + + + (%n GB needed for full chain) + (%n GB tarvitaan koko ketjuun)(%n GB tarvitaan koko ketjuun) + At least %1 GB of data will be stored in this directory, and it will grow over time. Vähintään %1 GB dataa tallennetaan tähän hakemistoon, ja se kasvaa ajan kuluessa. @@ -1190,6 +1453,11 @@ Approximately %1 GB of data will be stored in this directory. Arviolta %1 GB dataa tallennetaan tähän hakemistoon. + + (sufficient to restore backups %n day(s) old) + Explanatory text on the capability of the current prune target. + (riittävä palauttamaan %n päivän vanhat varmuuskopiot)(riittävä palauttamaan %n päivän vanhat varmuuskopiot) + %1 will download and store a copy of the Dash block chain. %1 lataa ja tallentaa kopion Dash lohkoketjusta. @@ -1207,6 +1475,13 @@ Virhe + + LoadWalletsActivity + + Loading wallets… + Ladataan lompakoita… + + MasternodeList @@ -1241,6 +1516,10 @@ Service Palvelu + + Type + Tyyppi + PoSe Score PoSe Pisteet @@ -1376,6 +1655,10 @@ Hide Piilota + + %1 is currently syncing. It will download headers and blocks from peers and validate them until reaching the tip of the block chain. + %1 synkronoi parhaillaan. Se lataa otsikoita ja lohkoja vertaisverkosta ja validoi ne kunnes saavuttaa lohkoketjun kärjen. + Unknown. Syncing Headers (%1, %2%)… Tuntematon. Synkronoidaan otsikoita (%1, %2%)… @@ -1391,6 +1674,11 @@ URI: URI: + + Paste address from clipboard + Tooltip text for button that allows you to paste an address that is in your clipboard. + Liitä osoite leikepöydältä + OpenWalletActivity @@ -1406,8 +1694,14 @@ default wallet oletus lompakko + + Open Wallet + Title of window indicating the progress of opening of a wallet. + Avaa lompakko + Opening Wallet <b>%1</b>… + Descriptive text of the open wallet progress window which indicates to the user which wallet is currently being opened. Avataan Lompakko <b>%1</b>… @@ -1441,6 +1735,14 @@ &Appearance &Ulkoasu + + Show the icon in the system tray. + Näytä kuvake ilmoitusalueella. + + + &Show tray icon + &Näytä ilmoitusalueen kuvake + Prune &block storage to Karsi &lohko levytila @@ -1453,10 +1755,58 @@ Reverting this setting requires re-downloading the entire blockchain. Tämän asetuksen takaisin käyttöönottaminen edellyttää koko lohkoketjun uudelleen latausta. + + 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. + Tooltip text for Options window setting that sets the size of the database cache. Explains the corresponding effects of increasing/decreasing this value. + Tietokannan välimuistin enimmäiskoko. Suurempi välimuisti voi nopeuttaa synkronointia, jonka jälkeen hyöty on vähäisempi useimmissa käyttötapauksissa. Välimuistin koon pienentäminen vähentää muistin käyttöä. Käyttämätön mempool-muisti jaetaan tälle välimuistille. + MiB MiB + + Set the number of script verification threads. Negative values correspond to the number of cores you want to leave free to the system. + 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. + Aseta skriptivarmennussäikeiden määrä. Negatiiviset arvot vastaavat niiden ytimien määrää, jotka haluat jättää järjestelmälle vapaaksi. + + + This allows you or a third party tool to communicate with the node through command-line and JSON-RPC commands. + Tooltip text for Options window setting that enables the RPC server. + Tämä mahdollistaa sinun tai kolmannen osapuolen työkalun kommunikoinnin noden kanssa komentorivin ja JSON-RPC-komentojen kautta. + + + Enable R&PC server + An Options window setting to enable the RPC server. + Ota R&PC-palvelin käyttöön + + + Whether to set subtract fee from amount as default or not. + Tooltip text for Options window setting that sets subtracting the fee from a sending amount as default. + Asetetaanko siirtomaksun vähentäminen summasta oletusarvoisesti vai ei. + + + Subtract &fee from amount by default + An Options window setting to set subtracting the fee from a sending amount as default. + Vähennä &siirtomaksu summasta oletuksena + + + Enable &PSBT controls + An options window setting to enable PSBT controls. + Ota &PSBT-hallinta käyttöön + + + Whether to show PSBT controls. + Tooltip text for options window setting that enables PSBT controls. + Näytetäänkö PSBT-hallinta. + + + Whether to keep the specified custom change address or not. + Säilytetäänkö määritetty mukautettu vaihto-osoite vai ei. + + + Keep custom change &address + Säilytä mukautettu vaihto-&osoite + Show additional tab listing all your masternodes in first sub-tab<br/>and all masternodes on the network in second sub-tab. Näytä lisävälilehti jonka ensimmäisellä alivälilehdellä näkyvät sinun masternodet<br/>ja toisella alivälilehdellä näkyvät verkon kaikki masternodet. @@ -1513,6 +1863,14 @@ Enable &multi-session Ota käyttöön &multisessio + + Use this many separate masternodes in parallel to mix funds.<br/>Note: You must use this feature carefully.<br/>Make sure you always have recent wallet (auto)backup in a safe place! + Käytä näin montaa erillistä masternodea rinnakkain varojen sekoittamiseen.<br/>Huom: Sinun täytyy käyttää tätä ominaisuutta varoen.<br/>Varmista että sinulla on aina tuore lompakon (auto)varmuuskopio turvallisessa paikassa! + + + Parallel sessions + Rinnakkaiset istunnot + Mixing rounds Sekoitus Kierrokset @@ -1525,6 +1883,30 @@ Target balance Haluttu saldo + + How many inputs of each denominated amount are created.<br/>Lower these numbers if you want fewer smaller denominations. + Kuinka monta syötettä kustakin nimellismäärästä luodaan.<br/>Laske näitä lukuja jos haluat vähemmän pienempiä nimellisarvoja. + + + Inputs per denomination + Syötteet nimellisarvoa kohti + + + Try to create at least this many inputs for each denominated amount.<br/>Lower this number if you want fewer smaller denominations. + Yritä luoda vähintään näin monta syötettä kullekin nimellismäärälle.<br/>Laske tätä lukua jos haluat vähemmän pienempiä nimellisarvoja. + + + Target + Tavoite + + + Create up to this many inputs for each denominated amount.<br/>Lower this number if you want fewer smaller denominations. + Luo enintään näin monta syötettä kullekin nimellismäärälle.<br/>Laske tätä lukua jos haluat vähemmän pienempiä nimellisarvoja. + + + Maximum + Maksimi + Automatically open the Dash Core client port on the router. This only works when your router supports UPnP and it is enabled. Avaa automaattisesti Dash Core asiakasohjelmalle portti reitittimeen. Tämä toimii vain jos reitittimesi tukee UPnP:tä ja se on käytössä. @@ -1554,20 +1936,26 @@ Näyttää onko oletus SOCKS5 proxy käytössä peers:ien tavoittamiseen tämän verkkotyypin kautta. - Options set in this dialog are overridden by the command line or in the configuration file: - Asetukset tässä dialogissa ylikirjoitetaan joko komentorivin tai asetustiedostosta: + Language missing or translation incomplete? Help contributing translations here: +https://explore.transifex.com/dash/dash/ + Kieli puuttuu tai käännös on keskeneräinen? Auta käännösten tekemisessä täällä: +https://explore.transifex.com/dash/dash/ - 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. - Ikkunaa suljettaessa pienennä ohjelman ikkuna lopettamatta itse ohjelmaa. Kun tämä asetus on valittuna, ohjelman voi sulkea vain valitsemalla Lopeta ohjelman valikosta. + Third-party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items.<br/>%s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |. + Kolmannen osapuolen URL:t (esim. lohkoselain), jotka näkyvät tapahtumat-välilehdellä kontekstivalikon kohteina.<br/>%s URL:ssa korvataan tapahtuman hajautusarvolla. Useat URL:t erotetaan pystyviivalla |. + + + &Third-party transaction URLs + &Kolmannen osapuolen tapahtuma-URL:t - Third party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items.<br/>%s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |. - Ulkopuoliset URL-osoitteet (esim. lohkoselain) jotka esiintyvät tapahtumat-välilehdellä valikossa.<br/>%s URL osoitteessa korvataan siirtotunnuksen tarkisteella. Useampi URL osoite on eroteltu pystyviivalla |. + Options set in this dialog are overridden by the command line or in the configuration file: + Asetukset tässä dialogissa ylikirjoitetaan joko komentorivin tai asetustiedostosta: - &Third party transaction URLs - &Kolmannen osapuolen siirtotapahtuma URL:t + 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. + Ikkunaa suljettaessa pienennä ohjelman ikkuna lopettamatta itse ohjelmaa. Kun tämä asetus on valittuna, ohjelman voi sulkea vain valitsemalla Lopeta ohjelman valikosta. Whether to show coin control features or not. @@ -1605,6 +1993,10 @@ Map port using &UPnP Kartoita portti käyttäen &UPnP:tä + + Automatically open the Dash Core client port on the router. This only works when your router supports NAT-PMP and it is enabled. The external port could be random. + Avaa Dash Core -asiakasportti reitittimessä automaattisesti. Tämä toimii vain jos reitittimesi tukee NAT-PMP:tä ja se on käytössä. Ulkoinen portti voi olla satunnainen. + Proxy &IP: Proxy &IP @@ -1654,11 +2046,19 @@ &Käyttöliittymä - User Interface &language: - &Käyttöliittymän kieli + Connect to the Dash network through a separate SOCKS5 proxy for Tor onion services. + Yhdistä Dash-verkkoon erillisen SOCKS5-välityspalvelimen kautta Tor onion -palveluita varten. - The user interface language can be set here. This setting will take effect after restarting %1. + Use separate SOCKS&5 proxy to reach peers via Tor onion services: + Käytä erillistä SOCKS&5-välityspalvelinta tavoittaaksesi vertaisverkon kautta Tor onion -palvelut: + + + User Interface &language: + &Käyttöliittymän kieli + + + The user interface language can be set here. This setting will take effect after restarting %1. Tässä voit määritellä käyttöliittymän kielen. Muutokset astuvat voimaan seuraavan kerran, kun %1 käynnistetään. @@ -1699,14 +2099,22 @@ Confirm options reset + Window title text of pop-up window shown when the user has chosen to reset options. Vahvista asetusten palautus Client restart required to activate changes. + Text explaining that the settings changed will not come into effect until the client is restarted. Ohjelman uudelleen käynnistys aktivoi muutokset käyttöön. + + Current settings will be backed up at "%1". + 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. + Nykyiset asetukset varmuuskopioidaan sijaintiin "%1". + Client will be shut down. Do you want to proceed? + Text asking the user to confirm if they would like to proceed with a client shutdown. Ohjelma suljetaan, haluatko jatkaa? @@ -1844,6 +2252,10 @@ %1 Balance %1 Saldo + + Discreet mode activated for the Overview tab. To unmask the values, uncheck Settings->Discreet mode. + Huomaamaton tila aktivoitu Yhteenveto-välilehdelle. Poistaaksesi arvojen peittämisen, poista valinta Asetukset->Huomaamaton tila. + %n Rounds %n Kierros%n Kierrosta @@ -1943,7 +2355,140 @@ PSBTOperationsDialog - + + Dialog + Dialogi + + + Sign Tx + Allekirjoita tapahtuma + + + Broadcast Tx + Lähetä tapahtuma + + + Copy to Clipboard + Kopioi leikepöydälle + + + Save… + Tallenna… + + + Close + Sulje + + + Failed to load transaction: %1 + Tapahtuman lataaminen epäonnistui: %1 + + + Failed to sign transaction: %1 + Tapahtuman allekirjoitus epäonnistui: %1 + + + Cannot sign inputs while wallet is locked. + Syötteitä ei voida allekirjoittaa kun lompakko on lukittu. + + + Could not sign any more inputs. + Enempää syötteitä ei voitu allekirjoittaa. + + + Signed %1 inputs, but more signatures are still required. + Allekirjoitettiin %1 syötettä, mutta lisää allekirjoituksia vaaditaan vielä. + + + Signed transaction successfully. Transaction is ready to broadcast. + Tapahtuma allekirjoitettiin onnistuneesti. Tapahtuma on valmis lähetettäväksi. + + + Unknown error processing transaction. + Tuntematon virhe käsiteltäessä tapahtumaa. + + + Transaction broadcast successfully! Transaction ID: %1 + Tapahtuma lähetetty onnistuneesti! Tapahtuma ID: %1 + + + Transaction broadcast failed: %1 + Tapahtuman lähettäminen epäonnistui: %1 + + + PSBT copied to clipboard. + PSBT kopioitu leikepöydälle. + + + Save Transaction Data + Tallenna tapahtumatiedot + + + Partially Signed Transaction (Binary) + Expanded name of the binary PSBT file format. See: BIP 174. + Osittain allekirjoitettu tapahtuma (binääri) + + + PSBT saved to disk. + PSBT tallennettu levylle. + + + * Sends %1 to %2 + * Lähettää %1 osoitteeseen %2 + + + own address + oma osoite + + + Unable to calculate transaction fee or total transaction amount. + Siirtomaksua tai tapahtuman kokonaismäärää ei voida laskea. + + + Pays transaction fee: + Maksaa siirtomaksun: + + + Total Amount + Kokonaismäärä + + + or + tai + + + Transaction has %1 unsigned inputs. + Tapahtumalla on %1 allekirjoittamatonta syötettä. + + + Transaction is missing some information about inputs. + Tapahtumasta puuttuu joitakin tietoja syötteistä. + + + Transaction still needs signature(s). + Tapahtuma tarvitsee vielä allekirjoituksen/allekirjoituksia. + + + (But no wallet is loaded.) + (Mutta lompakkoa ei ole ladattu.) + + + (But this wallet cannot sign transactions.) + (Mutta tämä lompakko ei voi allekirjoittaa tapahtumia.) + + + (But this wallet does not have the right keys.) + (Mutta tällä lompakolla ei ole oikeita avaimia.) + + + Transaction is fully signed and ready for broadcast. + Tapahtuma on täysin allekirjoitettu ja valmis lähetettäväksi. + + + Transaction status is unknown. + Tapahtuman tila on tuntematon. + + PaymentServer @@ -1962,6 +2507,12 @@ 'dash://' is not a valid URI. Use 'dash:' instead. 'dash://' ei ole validi URI. Käytä sen sijaan 'dash:'. + + Cannot process payment request as BIP70 is no longer supported. +Due to discontinued support, you should request the merchant to provide you with a BIP21 compatible URI or use a wallet that does continue to support BIP70. + Maksupyyntöä ei voida käsitellä, koska BIP70:ää ei enää tueta. +Tuen lopettamisen vuoksi sinun tulisi pyytää kauppiasta toimittamaan sinulle BIP21-yhteensopiva URI tai käyttää lompakkoa, joka edelleen tukee BIP70:ää. + URI cannot be parsed! This can be caused by an invalid Dash address or malformed URI parameters. URI:a ei voida jäsentää! Tämä voi johtua virheellisestä Dash osoitteesta tai virheellisestä URI:n muuttujasta. @@ -1983,6 +2534,26 @@ Title of Peers Table column which indicates the current latency of the connection with the peer. Ping + + Peer + Title of Peers Table column which contains a unique number used to identify a connection. + Vertaisverto + + + Age + Title of Peers Table column which indicates the duration (length of time) since the peer connection started. + Ikä + + + Direction + Title of Peers Table column which indicates the direction the peer connection was initiated from. + Suunta + + + Type + Title of Peers Table column which describes the type of peer connection. The "type" describes why the connection exists. + Tyyppi + Sent Title of Peers Table column which indicates the total amount of network information we have sent to the peer. @@ -1993,7 +2564,27 @@ Title of Peers Table column which indicates the total amount of network information we have received from the peer. Vastaanotettu - + + Address + Title of Peers Table column which contains the IP/Onion/I2P address of the connected peer. + Osoite + + + Network + Title of Peers Table column which states the network the peer connected through. + Verkko + + + Inbound + An Inbound Connection from a Peer. + Saapuva + + + Outbound + An Outbound Connection to a Peer. + Lähtevä + + Proposal @@ -2044,8 +2635,193 @@ Tila + + ProposalWizard + + Create Governance Proposal + Luo hallintoehdotus + + + Enter proposal details + Syötä ehdotuksen tiedot + + + A fee will be burned when you prepare the proposal. + Maksu poltetaan kun valmistat ehdotuksen. + + + Proposal &name + Ehdotuksen &nimi + + + &Description URL + &Kuvaus URL + + + Payment &address + Maksu&osoite + + + Payment &amount + Maksun &määrä + + + The amount to request in a single payment + Yhdessä maksussa pyydettävä määrä + + + &First payment + &Ensimmäinen maksu + + + Pa&yments + Ma&ksut + + + To&tal amount + Kokona&ismäärä + + + Proposal &fee + Ehdotuksen &maksu + + + Next + Seuraava + + + Review proposal JSON and validate. + Tarkista ehdotuksen JSON ja vahvista. + + + Hex-encoded JSON + Hex-koodattu JSON + + + Back + Takaisin + + + Validate + Vahvista + + + Prepare (burn fee) and wait for confirmations. + Valmistele (polta maksu) ja odota vahvistuksia. + + + Copy + Kopioi + + + At 1/6 confirmations: can be relayed and queued. At 6/6: accepted and processed. + 1/6 vahvistuksella: voidaan välittää ja jonottaa. 6/6: hyväksytty ja käsitelty. + + + Confirmations progress + Vahvistusten edistyminen + + + Shows progress toward the required number of confirmations for the proposal fee transaction. + Näyttää edistymisen kohti vaadittujen vahvistusten määrää ehdotusmaksutapahtumalle. + + + Estimated time remaining: - + Arvioitu jäljellä oleva aika: - + + + Prepare Proposal + Valmistele ehdotus + + + You can submit after 1 confirmation. At 6 confirmations it is accepted and processed. + Voit lähettää 1 vahvistuksen jälkeen. 6 vahvistuksella se hyväksytään ja käsitellään. + + + Proposal ID: + Ehdotus ID: + + + Submit Proposal + Lähetä ehdotus + + + Close + Sulje + + + Valid + Kelvollinen + + + Invalid: %1 + Virheellinen: %1 + + + Burn %1 + Polta %1 + + + Burn %1 to create the fee transaction? + Poltetaanko %1 maksutapahtuman luomiseksi? + + + Prepare failed + Valmistelu epäonnistui + + + Confirmations: %1 / %2 required + Vahvistukset: %1 / %2 vaaditaan + + + Estimated time remaining: Ready + Arvioitu jäljellä oleva aika: Valmis + + + Estimated time remaining: %n minute(s) + Arvioitu jäljellä oleva aika: %n minuuttiArvioitu jäljellä oleva aika: %n minuuttia + + + Your proposal was submitted successfully. + Ehdotuksesi lähetettiin onnistuneesti. + + + Already submitted + Jo lähetetty + + + This proposal has already been submitted. + Tämä ehdotus on jo lähetetty. + + + Submission failed + Lähetys epäonnistui + + + Proposal submitted + Ehdotus lähetetty + + + A fee of %1 will be burned when you prepare the proposal. + Maksu %1 poltetaan kun valmistat ehdotuksen. + + + Prepare (burn %1) and wait for %2 confirmations. + Valmistele (polta %1) ja odota %2 vahvistusta. + + QObject + + Do you want to reset settings to default values, or to abort without making changes? + Explanatory text shown on startup when the settings file cannot be read. Prompts user to make a choice between resetting or aborting. + Haluatko palauttaa asetukset oletusarvoihin vai keskeyttää tekemättä muutoksia? + + + A fatal error occurred. Check that settings file is writable, or try running with -nosettings. + 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. + Kriittinen virhe tapahtui. Tarkista että asetustiedosto on kirjoitettavissa, tai yritä ajaa -nosettings-valinnalla. + Choose data directory on startup (default: %u) Valitse datahakemisto käynnistyksessä (oletus: %u) @@ -2146,6 +2922,53 @@ This can also be adjusted later in the "Appearance" tab of the preferences. Tätä voidaan säätää myös myöhemmin asetusten "Ulkoasu" välilehdellä. + + Ctrl+W + Ctrl+W + + + Unroutable + Ei reititetty + + + Internal + Sisäinen + + + Inbound + An inbound connection from a peer. An inbound connection is a connection initiated by a peer. + Saapuva + + + Outbound + An outbound connection to a peer. An outbound connection is a connection initiated by us. + Lähtevä + + + Full Relay + Peer connection type that relays all network information. + Täysi välitys + + + Block Relay + Peer connection type that relays network information about blocks and not transactions or addresses. + Lohkovälitys + + + Manual + Peer connection type established manually through one of several methods. + Manuaalinen + + + Feeler + Short-lived peer connection type that tests the aliveness of known addresses. + Tunnustelija + + + Address Fetch + Short-lived peer connection type that solicits known addresses from a peer. + Osoitehaku + %1 d %1 d @@ -2207,8 +3030,8 @@ %1 B - %1 KB - %1 KB + %1 kB + %1 kB %1 MB @@ -2264,7 +3087,12 @@ Save QR Code Tallenna QR Koodi - + + PNG Image + Expanded name of the PNG file format. See: https://en.wikipedia.org/wiki/Portable_Network_Graphics. + PNG-kuva + + RPCConsole @@ -2371,6 +3199,14 @@ Version Versio + + High bandwidth BIP152 compact block relay: %1 + Korkea kaistanleveys BIP152 tiivistetty lohkovälitys: %1 + + + High Bandwidth + Korkea kaistanleveys + Starting Block Aloituslohko @@ -2383,6 +3219,51 @@ Synced Blocks Synkronoidut lohkot + + Elapsed time since a novel block passing initial validity checks was received from this peer. + Kulunut aika siitä kun uusi lohko, joka läpäisi alustavat kelpoisuustarkistukset, vastaanotettiin tältä vertaiselta. + + + Last Block + Viimeisin lohko + + + Elapsed time since a novel transaction accepted into our mempool was received from this peer. + Tooltip text for the Last Transaction field in the peer details area. + Kulunut aika siitä kun uusi tapahtuma, joka hyväksyttiin mempooliimme, vastaanotettiin tältä vertaiselta. + + + Last Transaction + Viimeisin tapahtuma + + + The mapped Autonomous System used for diversifying peer selection. + Kartoitettu autonominen järjestelmä, jota käytetään vertaisvalinnan monipuolistamiseen. + + + Mapped AS + Kartoitettu AS + + + Whether we relay addresses to this peer. + Tooltip text for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No). + Välitetäänkö osoitteita tälle vertaiselle. + + + Address Relay + Text title for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No). + Osoitevälitys + + + Addresses Processed + 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). + Käsitellyt osoitteet + + + Addresses Rate-Limited + 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. + Nopeusrajoitetut osoitteet + Rescan blockchain files 1 Skannaa lohkoketju tiedostot 1 uudelleen @@ -2423,6 +3304,22 @@ To specify a non-default location of the blocks directory use the '%1' option. Määrittääksesi ei oletus hakemiston sijainnin lohkoille käytä '%1' asetusta. + + Local Addresses + Paikalliset osoitteet + + + Network addresses that your Dash node is currently using to communicate with other nodes. + Verkko-osoitteet, joita Dash-solmusi käyttää tällä hetkellä kommunikoidakseen muiden solmujen kanssa. + + + Number of regular Masternodes + Tavallisten Masternodejen määrä + + + Number of EvoNodes + EvoNodejen määrä + Current block height Nykyinen lohkomäärä @@ -2471,10 +3368,50 @@ PoSe Score PoSe Pisteet + + The transport layer version: %1 + Kuljetuskerroksen versio: %1 + + + Transport + Kuljetuskerros + + + The BIP324 session ID string in hex. + BIP324-istunnon ID-merkkijono heksana. + + + Session ID + Istunto ID + + + The network protocol this peer is connected through: IPv4, IPv6, Onion, I2P, or CJDNS. + Verkkoprotokolla, jonka kautta tämä vertainen on yhteydessä: IPv4, IPv6, Onion, I2P tai CJDNS. + + + Permissions + Käyttöoikeudet + + + The direction and type of peer connection: %1 + Vertaisyhteyden suunta ja tyyppi: %1 + + + Direction/Type + Suunta/Tyyppi + Services Palvelut + + Whether we relay transactions to this peer. + Välitetäänkö tapahtumia tälle vertaiselle. + + + Transaction Relay + Tapahtumien välitys + Connection Time Yhteysaika @@ -2511,6 +3448,16 @@ &Wallet Repair &Lompakon Korjaus + + The total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting). + 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). + Tältä vertaiselta vastaanotettujen osoitteiden kokonaismäärä, jotka käsiteltiin (ei sisällä osoitteita, jotka hylättiin nopeusrajoituksen vuoksi). + + + The total number of addresses received from this peer that were dropped (not processed) due to rate-limiting. + 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. + Tältä vertaiselta vastaanotettujen osoitteiden kokonaismäärä, jotka hylättiin (ei käsitelty) nopeusrajoituksen vuoksi. + Wallet repair options. Lompakon korjausvalinnat @@ -2524,52 +3471,82 @@ -reindex: Rakenna uudelleen lohkoketjun indeksi nykyisistä blk000??.dat tiedostoista. - &Disconnect - &Katkaise yhteys + Inbound: initiated by peer + Explanatory text for an inbound peer connection. + Saapuva: vertaisen aloittama - Ban for - Estolistaan + Outbound Full Relay: default + Explanatory text for an outbound peer connection that relays all network information. This is the default behavior for outbound connections. + Lähtevä täysi välitys: oletus - 1 &hour - 1 &tunniksi + Outbound Block Relay: does not relay transactions or addresses + Explanatory text for an outbound peer connection that relays network information about blocks and not transactions or addresses. + Lähtevä lohkovälitys: ei välitä tapahtumia tai osoitteita - 1 &day - 1 &päiväksi + Outbound Manual: added using RPC %1 or %2/%3 configuration options + 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. + Lähtevä manuaalinen: lisätty käyttäen RPC %1 tai %2/%3 konfigurointiasetuksia - 1 &week - 1 &viikoksi + Outbound Feeler: short-lived, for testing addresses + Explanatory text for a short-lived outbound peer connection that is used to test the aliveness of known addresses. + Lähtevä tunnustelija: lyhytikäinen, osoitteiden testaamiseen - 1 &year - 1 &vuodeksi + Outbound Address Fetch: short-lived, for soliciting addresses + Explanatory text for a short-lived outbound peer connection that is used to request addresses from a peer. + Lähtevä osoitehaku: lyhytikäinen, osoitteiden pyytämiseen - &Unban - &Poista estolistalta + To + Kohteeseen - Welcome to the %1 RPC console. - Tervetuloa %1 RPC konsoliin. + we selected the peer for high bandwidth relay + valitsimme vertaisen korkeakaistaiseen välitykseen - Use up and down arrows to navigate history, and %1 to clear screen. - Ylös- ja alas-nuolet selaavat historiaa ja %1 tyhjentää ruudun. + From + Lähteestä - Type %1 for an overview of available commands. - Kirjoita %1 saadaksesi yleiskuvan käytettävissä olevista komennoista. + the peer selected us for high bandwidth relay + vertainen valitsi meidät korkeakaistaiseen välitykseen - For more information on using this console type %1. - Saadaksesi lisätietoja konsolin käytöstä kirjoita %1. + No + Ei - WARNING: Scammers have been active, telling users to type commands here, stealing their wallet contents. Do not use this console without fully understanding the ramifications of a command. - VAROITUS: Huijarit ovat olleet aktiivisia, kertoen käyttäjille komentoja tänne varastaen lompakon sisällön. Älä käytä tätä konsolia ymmärtämättä täysin komennon vaikutuksia. + no high bandwidth relay selected + ei korkeakaistaista välitystä valittuna + + + &Disconnect + &Katkaise yhteys + + + Ban for + Estolistaan + + + 1 &hour + 1 &tunniksi + + + 1 &week + 1 &viikoksi + + + 1 &year + 1 &vuodeksi + + + &Unban + &Poista estolistalta In: @@ -2583,6 +3560,10 @@ Network activity disabled Verkkotoiminnot ei käytössä + + None + Ei mitään + Total: %1 (Enabled: %2) Yhteensä: %1 (Käytössä: %2) @@ -2591,10 +3572,105 @@ Executing command without any wallet Suoritetaan komento ilman lompakkoa + + Ctrl++ + Main shortcut to increase the RPC console font size. + Ctrl++ + + + Ctrl+= + Secondary shortcut to increase the RPC console font size. + Ctrl+= + + + Ctrl+- + Main shortcut to decrease the RPC console font size. + Ctrl+- + + + Ctrl+_ + Secondary shortcut to decrease the RPC console font size. + Ctrl+_ + + + Ctrl+Shift+I + Ctrl+Shift+I + + + Ctrl+Shift+C + Ctrl+Shift+C + + + Ctrl+Shift+G + Ctrl+Shift+G + + + Ctrl+Shift+P + Ctrl+Shift+P + + + Ctrl+Shift+R + Ctrl+Shift+R + Executing command using "%1" wallet Suoritetaan komento käyttäen "%1" lompakkoa + + detecting: peer could be v1 or v2 + Explanatory text for "detecting" transport type. + tunnistamassa: vertainen voi olla v1 tai v2 + + + v1: unencrypted, plaintext transport protocol + Explanatory text for v1 transport type. + v1: salaamaton, selkotekstikuljetusprotokolla + + + v2: BIP324 encrypted transport protocol + Explanatory text for v2 transport type. + v2: BIP324 salattu kuljetusprotokolla + + + &Copy address + Context menu action to copy the address of a peer + &Kopioi osoite + + + 1 d&ay + 1 p&äiväksi + + + &Copy IP/Netmask + 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 + &Kopioi IP/Verkkopeite + + + 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 + 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. + Tervetuloa %1 RPC-konsoliin. +Käytä ylös ja alas nuolia selaamaan historiaa, ja %2 tyhjentääksesi näytön. +Käytä %3 ja %4 suurentaaksesi tai pienentääksesi fonttikokoa. +Kirjoita %5 saadaksesi yleiskatsauksen käytettävissä olevista komennoista. +Lisätietoja tämän konsolin käytöstä saat kirjoittamalla %6. + +%7VAROITUS: Huijarit ovat olleet aktiivisia, käskien käyttäjiä kirjoittamaan komentoja tähän ja varastavat heidän lompakkonsa sisällön. Älä käytä tätä konsolia ymmärtämättä täysin komennon seurauksia.%8 + + + Executing… + A console message indicating an entered command is currently being executed. + Suoritetaan… + + + (peer: %1) + (vertainen: %1) + via %1 kautta %1 @@ -2611,11 +3687,19 @@ Verified Masternode Vahvistettu Masternode + + Yes + Kyllä + Unknown Tuntematon - + + Never + Ei koskaan + + ReceiveCoinsDialog @@ -2634,6 +3718,10 @@ An optional message to attach to the payment request, which will be displayed when the request is opened.<br>Note: The message will not be sent with the payment over the Dash network. Valinnainen viesti liitettäväksi maksupyyntöön, joka näytetään kun pyyntö on avattu.<br>Huomio: Viestiä ei lähetetä maksun mukana Dash verkkoon. + + 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. + Valinnainen nimike liitettäväksi uuteen vastaanotto-osoitteeseen (käytät sitä laskun tunnistamiseen). Se liitetään myös maksupyyntöön. + Use this form to request payments. All fields are <b>optional</b>. Käytä tätä lomaketta maksupyyntöihin. Kaikki kentät ovat <b>valinnaisia</b>. @@ -2691,28 +3779,60 @@ Kirjoita viesti jonka haluat liittää maksupyyntöön - Copy URI - Kopioi URI + Copy &URI + Kopioi &URI - Copy address - Kopioi osoite + &Copy address + &Kopioi osoite - Copy label - Kopioi nimi + Copy &label + Kopioi &nimike - Copy message - Kopioi viesti + Copy &message + Kopioi &viesti - Copy amount - Kopioi määrä + Copy &amount + Kopioi &määrä + + + Could not unlock wallet. + Lompakon avaaminen epäonnistui. + + + Could not generate new address + Uuden osoitteen luominen epäonnistui - + ReceiveRequestDialog + + Request payment to … + Pyydä maksua osoitteeseen … + + + Address: + Osoite: + + + Amount: + Määrä: + + + Label: + Nimike: + + + Message: + Viesti: + + + Wallet: + Lompakko: + Copy &URI Kopioi &URI @@ -2765,6 +3885,34 @@ Pyydetty + + RestoreWalletActivity + + Restore Wallet + Title of progress window which is displayed when wallets are being restored. + Palauta lompakko + + + Restoring Wallet <b>%1</b>… + Descriptive text of the restore wallets progress window which indicates to the user that wallets are currently being restored. + Palautetaan lompakkoa <b>%1</b>… + + + Restore wallet failed + Title of message box which is displayed when the wallet could not be restored. + Lompakon palautus epäonnistui + + + Restore wallet warning + Title of message box which is displayed when the wallet is restored with some warning. + Lompakon palautusvaroitus + + + Restore wallet message + Title of message box which is displayed when the wallet is successfully restored. + Lompakon palautusviesti + + SendCoinsDialog @@ -2799,10 +3947,6 @@ Fee: Siirtomaksu: - - Dust: - Tomu: - Inputs… Sisääntulot… @@ -2827,6 +3971,14 @@ Transaction Fee: Siirtomaksu: + + 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 dash transactions than the network can process. + Kun siirtotapahtumien määrä on pienempi kuin lohkoissa oleva tila, louhijat ja välittävät solmut voivat pakottaa vähimmäismaksun. Vain tämän vähimmäismaksun maksaminen on ihan hyvä, mutta huomaa että tämä voi johtaa tapahtumaan jota ei koskaan vahvisteta, kun dash-tapahtumien kysyntä ylittää verkon kapasiteetin. + + + A too low fee might result in a never confirming transaction (read the tooltip) + Liian pieni maksu voi johtaa tapahtumaan jota ei koskaan vahvisteta (lue työkaluvihje) + (Smart fee not initialized yet. This usually takes a few blocks…) (Älykästä siirtomaksua ei ole alustettu vielä. Tämä kestää yleensä muutaman lohkon…) @@ -2919,10 +4071,6 @@ Copy bytes Kopioi tavut - - Copy dust - Kopioi tomu - Copy change Kopioi vaihtoraha @@ -2939,10 +4087,6 @@ %1 to %2 %1 -> %2 - - Are you sure you want to send? - Haluatko varmasti lähettää? - <b>(%1 of %2 entries displayed)</b> <b>(Näytetään %1 / %2 merkintää)</b> @@ -2955,6 +4099,18 @@ Confirm the %1 send action Vahvista %1 lähetys + + Cr&eate Unsigned + L&uo allekirjoittamaton + + + from wallet '%1' + lompakosta '%1' + + + %1 to '%2' + %1 osoitteeseen '%2' + %1 funds only Vain %1 varat @@ -3003,6 +4159,51 @@ Confirm send coins Hyväksy lähettäminen + + Save Transaction Data + Tallenna tapahtumatiedot + + + PSBT saved + PSBT tallennettu + + + Watch-only balance: + Vain seuranta -saldo: + + + Creates a Partially Signed Blockchain Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet. + Luo osittain allekirjoitetun lohkoketjutapahtuman (PSBT) käytettäväksi esim. offline-%1-lompakon kanssa tai PSBT-yhteensopivan laitteistolompakon kanssa. + + + Do you want to create this transaction? + 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. + Haluatko luoda tämän tapahtuman? + + + Please, review your transaction proposal. This will produce a Partially Signed Blockchain Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet. + 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. + Tarkista tapahtumaehdotuksesi. Tämä luo osittain allekirjoitetun lohkoketjutapahtuman (PSBT), jonka voit tallentaa tai kopioida ja sitten allekirjoittaa esim. offline-%1-lompakolla tai PSBT-yhteensopivalla laitteistolompakolla. + + + Please, review your transaction. You can create and send this transaction or create a Partially Signed Blockchain Transaction (PSBT), which you can save or copy and then sign with, e.g., an offline %1 wallet, or a PSBT-compatible hardware wallet. + 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. + Tarkista tapahtumasi. Voit luoda ja lähettää tämän tapahtuman tai luoda osittain allekirjoitetun lohkoketjutapahtuman (PSBT), jonka voit tallentaa tai kopioida ja sitten allekirjoittaa esim. offline-%1-lompakolla tai PSBT-yhteensopivalla laitteistolompakolla. + + + Please, review your transaction. + Text to prompt a user to review the details of the transaction they are attempting to send. + Tarkista tapahtumasi. + + + To review recipient list click "Show Details…" + Vastaanottajaluettelon tarkastelemiseksi napsauta "Näytä yksityiskohdat…" + + + Partially Signed Transaction (Binary) + Expanded name of the binary PSBT file format. See: BIP 174. + Osittain allekirjoitettu tapahtuma (binääri) + The recipient address is not valid. Please recheck. Vastaanottajan osoite on virheellinen. Tarkista osoite. @@ -3122,21 +4323,16 @@ A message that was attached to the dash: URI which will be stored with the transaction for your reference. Note: This message will not be sent over the Dash network. Viesti joka liitettiin Dash: URI joka tallenetaan siirtotapahtuman kanssa viitteeksi sinulle. Huomio: Tätä viestiä ei lähetetä Dash verkkoon. + + + SendConfirmationDialog - This is an unauthenticated payment request. - Tämä on vahvistamaton maksupyyntö - - - This is an authenticated payment request. - Tämä on vahvistettu maksupyyntö. - - - Pay To: - Saaja: + Send + Lähetä - Memo: - Muistio: + Create Unsigned + Luo allekirjoittamaton @@ -3276,6 +4472,10 @@ Wallet unlock was cancelled. Lompakon lukituksen avaus peruttiin. + + No error + Ei virhettä + Private key for the entered address is not available. Yksityistä avainta annetulle osoitteelle ei ole saatavilla. @@ -3309,11 +4509,22 @@ Viesti vahvistettu. + + SplashScreen + + (press q to shutdown and continue later) + (paina q sammuttaaksesi ja jatkaaksesi myöhemmin) + + + press q to shutdown + paina q sammuttaaksesi + + TrafficGraphWidget - KB/s - KB/s + kB/s + kB/s Total @@ -3330,20 +4541,9 @@ TransactionDesc - - Open for %n more block(s) - Avoinna %n lisälohkolleAvoinna %n lisälohkolle - - - Open until %1 - Lukitsematta %1 asti - - - conflicted - ristiriitainen - 0/unconfirmed, %1 + 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. 0/vahvistamaton, %1 @@ -3356,22 +4556,32 @@ abandoned + 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. hylätty + + conflicted with a transaction with %1 confirmations + 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. + ristiriidassa tapahtuman kanssa, jolla on %1 vahvistusta + %1/unconfirmed + 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, and still not locked via ChainLocks. %1/vahvistamaton %1 confirmations + 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 or locked via ChainLocks. %1 vahvistusta locked via ChainLocks + 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 and has been locked by ChainLocks. lukittu ChainLocks:illa verified via InstantSend + 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 has been locked by InstantSend. vahvistettu InstantSend:illä @@ -3390,6 +4600,10 @@ Generated Luotu + + Platform Transfer + Alustansiirto + From Lähettäjä @@ -3520,14 +4734,6 @@ Address / Label Osoite / Nimi - - Open for %n more block(s) - Avoinna %n lisälohkolleAvoinna %n lisälohkolle - - - Open until %1 - Lukitsematta %1 asti - Unconfirmed Vahvistamaton @@ -3588,6 +4794,10 @@ Mined Louhittu + + Platform Transfer + Alustansiirto + %1 Mixing %1 Sekoitus @@ -3715,6 +4925,10 @@ Mined Louhittu + + Platform Transfer + Alustansiirto + Other Muu @@ -3728,49 +4942,63 @@ Minimimäärä - Abandon transaction - Hylätty siirtotapahtuma + &Copy address + &Kopioi osoite - Copy address - Kopioi osoite + Copy &label + Kopioi &nimike - Copy label - Kopioi nimi + Copy &amount + Kopioi &määrä - Copy amount - Kopioi määrä + Copy transaction &ID + Kopioi tapahtuman &ID + + + Copy &raw transaction + Kopioi &raaka tapahtuma - Copy transaction ID - Kopioi siirtotunnus + Copy full transaction &details + Kopioi tapahtuman täydet &tiedot - Copy raw transaction - Kopioi käsittelemätön siirtotapahtuma + &Show transaction details + &Näytä tapahtuman tiedot - Copy full transaction details - Kopioi siirtotapahtuman yksityiskohdat + A&bandon transaction + H&ylkää tapahtuma - Edit address label - Muokkaa osoitteen nimeä + Rese&nd transaction + Lähetä tapahtuma &uudelleen - Show transaction details - Näytä siirtotapahtuman yksityiskohdat + &Edit address label + &Muokkaa osoitteen nimikettä - Show address QR code - Näytä osoitteen QR koodi + Show address &QR code + Näytä osoitteen &QR-koodi + + + Show in %1 + 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. + Näytä %1:ssä Export Transaction History Vie siirtotapahtumien historia + + Comma separated file + Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values. + Pilkuilla eroteltu tiedosto + Confirmed Vahvistettu @@ -3849,10 +5077,54 @@ Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled. Lompakon sulkeminen liian pitkäksi ajaksi voi johtaa siihen, että koko ketju on synkronoitava uudelleen, jos karsiminen on käytössä. - + + Close all wallets + Sulje kaikki lompakot + + + Are you sure you wish to close all wallets? + Haluatko varmasti sulkea kaikki lompakot? + + WalletFrame - + + No wallet has been loaded. +Go to File > Open Wallet to load a wallet. +- OR - + Lompakkoa ei ole ladattu. +Siirry Tiedosto > Avaa lompakko ladataksesi lompakon. +- TAI - + + + Create a new wallet + Luo uusi lompakko + + + Error + Virhe + + + Unable to decode PSBT from clipboard (invalid base64) + PSBT:n purkaminen leikepöydältä epäonnistui (virheellinen base64) + + + Load Transaction Data + Lataa tapahtumatiedot + + + Partially Signed Transaction (*.psbt) + Osittain allekirjoitettu tapahtuma (*.psbt) + + + PSBT file must be smaller than 100 MiB + PSBT-tiedoston on oltava pienempi kuin 100 MiB + + + Unable to decode PSBT + PSBT:n purkaminen epäonnistui + + WalletModel @@ -3878,6 +5150,11 @@ Selected amount: Valittu määrä: + + Wallet Data + Name of the wallet data file format. + Lompakkodata + Backup Wallet Varmuuskopioi lompakko @@ -3905,14 +5182,6 @@ dash-core - - Error: Listening for incoming connections failed (listen returned error %s) - Virhe: Sisääntulevien yhteyksien kuuntelu epäonnistui (kuuntelu palautti virheen %s) - - - Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee. - Siirtomaksun arvio epäonnistui. Varasiirtomaksu ei ole käytössä. Odota muutama lohko tai ota käyttöön -fallbackfee - 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 Tämä virhe saattaa ilmetä, jos tätä lompakkoa ei sammutettu kunnolla ja se ladattiin viimeksi Berkeley DB:n uudemmalla versiolla. Jos näin on, käytä ohjelmistoa joka latasi tämän lompakon viimeksi @@ -3970,16 +5239,20 @@ Virhe luettaessa tietokantaa, ohjelma suljetaan. - Failed to listen on any port. Use -listen=0 if you want this. - Ei onnistuttu kuuntelemaan mitään porttia. Käytä -listen=0 jos haluat tätä. + Error: Missing checksum + Virhe: Tarkistussumma puuttuu + + + Error: Unable to parse version %u as a uint32_t + Virhe: Versiota %u ei voitu jäsentää uint32_t:ksi - -maxtxfee is set very high! Fees this large could be paid on a single transaction. - -maxtxfee on asetettu erittäin korkeaksi! Näin isot siirtomaksut voitaisiin maksaa yhdessä siirtotapahtumassa. + Error: Unable to write record to new wallet + Virhe: Tietueen kirjoittaminen uuteen lompakkoon epäonnistui - Cannot provide specific connections and have addrman find outgoing connections at the same. - Ei voida tarjota tiettyjä yhteyksiä ja addrman voi löytää lähteviä yhteyksiä samaan aikaan. + Failed to listen on any port. Use -listen=0 if you want this. + Ei onnistuttu kuuntelemaan mitään porttia. Käytä -listen=0 jos haluat tätä. Found unconfirmed denominated outputs, will wait till they confirm to continue. @@ -3990,13 +5263,17 @@ Virheellinen -socketevents ('%s') määritelty. Vain nämä tilat ovat tuettuja: %s - Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions) - Virheellinen määrä -maxtxfee=<amount>: '%s' (oltava vähintään minimi välitysmaksun verran %s:sta välttääksesi jumissa olevia siirtotapahtumia) + SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is supported + SQLiteDatabase: Tuntematon sqlite-lompakkoskeeman versio %d. Vain versio %d on tuettu Transaction index can't be disabled with governance validation enabled. Either start with -disablegovernance command line switch or enable transaction index. Siirtotapahtumaindeksiä ei voi poistaa käytöstä jos hallinnon vahvistus on käytössä. Joko käynnistä -disablegovernance komentorivin valinnalla tai ota käyttöön siirtotapahtumaindeksi. + + Unsupported category-specific logging level -loglevel=%s. Expected -loglevel=<category>:<loglevel>. Valid categories: %s. Valid loglevels: %s. + Ei-tuettu kategoriakohtainen lokitaso -loglevel=%s. Odotettu -loglevel=<category>:<loglevel>. Kelvolliset kategoriat: %s. Kelvolliset lokitasot: %s. + Can't mix: no compatible inputs found! Ei voida sekoittaa: yhteensopivia syötteitä ei löytynyt! @@ -4005,6 +5282,14 @@ Entry exceeds maximum size. Merkintä ylittää maksimin. + + Error upgrading evo database for EHF + Virhe päivitettäessä evo-tietokantaa EHF:ää varten + + + Failed to commit Evo database + Evo-tietokannan tallentaminen epäonnistui + Found enough users, signing ( waiting %s ) Löytyi tarpeeksi käyttäjiä, kirjaudutaan ( odotetaan %s ) @@ -4029,18 +5314,14 @@ Insufficient funds. Saldo ei riitä. - - Invalid amount for -discardfee=<amount>: '%s' - Virheellinen määrä -discardfee=<amount>: '%s' - - - Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s) - Virheellinen määrä -paytxfee=<amount>: '%s' (oltava vähintään %s) - Invalid minimum number of spork signers specified with -minsporkkeys Virheellinen minimi määrä spork allekirjoittajia määritelty -minsporkkeys + + Listening for incoming connections failed (listen returned error %s) + Saapuvien yhteyksien kuuntelu epäonnistui (listen palautti virheen %s) + Lock is already in place. On jo lukittu. @@ -4097,6 +5378,10 @@ Synchronizing governance objects… Ladataan hallinnon objekteja… + + Transaction change output index out of range + Tapahtuman vaihtorahalähdön indeksi on sallitun alueen ulkopuolella + Unable to start HTTP server. See debug log for details. HTTP palvelinta ei voitu käynnistää. Katso debug.log lisätietoja. @@ -4105,6 +5390,10 @@ Unknown response. Tuntematon vastaus. + + Unsupported global logging level -loglevel=%s. Valid values: %s. + Ei-tuettu globaali lokitaso -loglevel=%s. Kelvolliset arvot: %s. + User Agent comment (%s) contains unsafe characters. Käyttäjä toimijan kommentti (%s) sisältää ei suositeltuja merkkejä. @@ -4145,6 +5434,10 @@ Make sure to encrypt your wallet and delete all non-encrypted backups after you have verified that the wallet works! Muista salata lompakkosi ja poistaa kaikki salaamattomat varmistukset sen jälkeen kun olet todennut että lompakko toimii! + + More than one onion bind address is provided. Using %s for the automatically created Tor onion service. + Useampi kuin yksi onion-sidontaosoite on annettu. Käytetään %s automaattisesti luotua Tor onion -palvelua varten. + Prune configured below the minimum of %d MiB. Please use a higher number. Karsinta asetettu alle minimin %d MiB. Käytä isompaa arvoa. @@ -4174,10 +5467,6 @@ Vähennä uakommenttien määrää tai kokoa. Wallet is locked, can't replenish keypool! Automatic backups and mixing are disabled, please unlock your wallet to replenish keypool. Lompakko on lukittu, osoitevarannon täydentäminen ei onnistu! Automaattinen varmistus ja sekoitus ei ole käytössä, avaa lompakon lukitus täydentääksesi osoitevarannon. - - You need to rebuild the database using -reindex to change -timestampindex - Sinun tulee uudelleen rakentaa tietokanta käyttäen -reindex vaihtaen -timestampindex - You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain Sinun tulee uudelleen rakentaa tietokanta käyttäen -reindex palataksesi takaisin 'ei karsita' tilaan. Tämä aiheuttaa koko lohkoketjun uudelleen lataamisen @@ -4219,20 +5508,32 @@ Vähennä uakommenttien määrää tai kokoa. Virhe ladatessa %s: Yksityisavaimet voivat olla ainoastaan pois käytöstä luomisen aikana - Error upgrading evo database - Virhe evo tietokannan päivityksessä + Error: Couldn't create cursor into database + Virhe: Tietokantakursoria ei voitu luoda Error: Disk space is low for %s Virhe: Levytila on alhainen %s - Exceeded max tries. - Maksimi yritykset ylitetty. + Error: Dumpfile checksum does not match. Computed %s, expected %s + Virhe: Dump-tiedoston tarkistussumma ei täsmää. Laskettu %s, odotettu %s + + + Error: Got key that was not hex: %s + Virhe: Saatiin avain joka ei ollut heksadesimaali: %s + + + Error: Got value that was not hex: %s + Virhe: Saatiin arvo joka ei ollut heksadesimaali: %s + + + Error: Keypool ran out, please call keypoolrefill first + Virhe: Avainvaranto loppui, kutsu ensin keypoolrefill - Failed to commit EvoDB - EvoDB liitäntä epäonnistui + Error: No addresses available. + Virhe: Osoitteita ei saatavilla. Failed to create backup %s! @@ -4250,17 +5551,29 @@ Vähennä uakommenttien määrää tai kokoa. Failed to rescan the wallet during initialization Lompakon uudelleen skannaaminen epäonnistui alustuksen aikana + + Failed to verify database + Tietokannan varmennus epäonnistui + + + Fee rate (%s) is lower than the minimum fee rate setting (%s) + Maksutaso (%s) on pienempi kuin vähimmäismaksutasoasetus (%s) + Found enough users, signing… Löytyi tarpeeksi käyttäjiä, kirjaudutaan… - Invalid P2P permission: '%s' - Virheellinen P2P oikeus: '%s' + Ignoring duplicate -wallet %s. + Ohitetaan duplikaatti -wallet %s. + + + Input not found or already spent + Syötettä ei löytynyt tai se on jo käytetty - Invalid amount for -fallbackfee=<amount>: '%s' - Virheellinen määrä -fallbackfee=<amount>: '%s' + Invalid P2P permission: '%s' + Virheellinen P2P oikeus: '%s' Invalid masternodeblsprivkey. Please see documentation. @@ -4282,6 +5595,10 @@ Vähennä uakommenttien määrää tai kokoa. Mixing in progress… Sekoitus käynnissä… + + No addresses available + Osoitteita ei saatavilla + No errors detected. Virheitä ei havaittu. @@ -4310,6 +5627,22 @@ Vähennä uakommenttien määrää tai kokoa. Prune mode is incompatible with -txindex. Karsintatila on epäyhteensopiva -txindex kanssa. + + SQLiteDatabase: Failed to execute statement to verify database: %s + SQLiteDatabase: Tietokannan varmennuslauseen suorittaminen epäonnistui: %s + + + SQLiteDatabase: Failed to prepare statement to verify database: %s + SQLiteDatabase: Tietokannan varmennuslauseen valmistelu epäonnistui: %s + + + SQLiteDatabase: Failed to read database verification error: %s + SQLiteDatabase: Tietokannan varmennusvirheen lukeminen epäonnistui: %s + + + SQLiteDatabase: Unexpected application id. Expected %u, got %u + SQLiteDatabase: Odottamaton sovellustunniste. Odotettu %u, saatu %u + Section [%s] is not recognized. Osio [%s] ei ole tunnistettavissa. @@ -4342,6 +5675,10 @@ Vähennä uakommenttien määrää tai kokoa. This is the transaction fee you will pay if you send a transaction. Tämä on lähetyksestä maksettava maksu jonka maksat + + Topping up keypool… + Täydennetään avainvarantoa… + Transaction amounts must not be negative Lähetyksen määrä tulee olla positiivinen @@ -4370,13 +5707,17 @@ Vähennä uakommenttien määrää tai kokoa. Unable to generate initial keys Aloitusavaimia ei voitu luoda + + Unable to open %s for writing + Tiedoston %s avaaminen kirjoittamista varten epäonnistui + Unknown -blockfilterindex value %s. Tuntematon -blockfilterindex arvo %s. - Upgrading UTXO database - Päivitetään UTXO tietokantaa + Unknown new rules activated (versionbit %i) + Tuntemattomat uudet säännöt aktivoitu (versiobitti %i) Verifying blocks… @@ -4395,16 +5736,12 @@ Vähennä uakommenttien määrää tai kokoa. Varmistushakemiston luonti epäonnistui %s! - You can not start a masternode with wallet enabled. - Et voi käynnistää masternodea kun lompakko on käytössä. - - - You need to rebuild the database using -reindex to change -addressindex - Sinun tulee uudelleen rakentaa tietokanta käyttäen -reindex vaihtaen -addressindex + Wiping wallet transactions… + Pyyhitään lompakon tapahtumia… - You need to rebuild the database using -reindex to change -spentindex - Sinun tulee uudelleen rakentaa tietokanta käyttäen -reindex vaihtaen -spentindex + You can not start a masternode with wallet enabled. + Et voi käynnistää masternodea kun lompakko on käytössä. no mixing available. @@ -4422,6 +5759,22 @@ Vähennä uakommenttien määrää tai kokoa. %s uses exact denominated amounts to send funds, you might simply need to mix some more coins. %s käyttää tarkalleen denominoituja määriä lähettäessään varoja, saatat tarvita sekoittaa lisää kolikoita. + + -reindex-chainstate option is not compatible with -blockfilterindex. Please temporarily disable blockfilterindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes. + -reindex-chainstate-asetus ei ole yhteensopiva -blockfilterindex kanssa. Poista blockfilterindex väliaikaisesti käytöstä käyttäessäsi -reindex-chainstate, tai korvaa -reindex-chainstate -reindex:llä uudelleenrakentaaksesi kaikki indeksit täysin. + + + -reindex-chainstate option is not compatible with -coinstatsindex. Please temporarily disable coinstatsindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes. + -reindex-chainstate-asetus ei ole yhteensopiva -coinstatsindex kanssa. Poista coinstatsindex väliaikaisesti käytöstä käyttäessäsi -reindex-chainstate, tai korvaa -reindex-chainstate -reindex:llä uudelleenrakentaaksesi kaikki indeksit täysin. + + + -reindex-chainstate option is not compatible with -txindex. Please temporarily disable txindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes. + -reindex-chainstate-asetus ei ole yhteensopiva -txindex kanssa. Poista txindex väliaikaisesti käytöstä käyttäessäsi -reindex-chainstate, tai korvaa -reindex-chainstate -reindex:llä uudelleenrakentaaksesi kaikki indeksit täysin. + + + Cannot downgrade wallet from version %i to version %i. Wallet version unchanged. + Lompakon versiota ei voida alentaa versiosta %i versioon %i. Lompakon versio ei muuttunut. + Cannot obtain a lock on data directory %s. %s is probably already running. Ei voida lukita datahakemistoa %s. %s on luultavasti jo käynnissä. @@ -4434,14 +5787,82 @@ Vähennä uakommenttien määrää tai kokoa. Error loading %s: You can't enable HD on an already existing non-HD wallet Virhe ladatessa %s: Et voi ottaa käyttöön HD:tä jo olemassa olevassa ei-HD lompakossa + + 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 + Virhe ladattaessa lompakkoa. Lompakko vaatii lohkojen lataamista, eikä ohjelmisto tue tällä hetkellä lompakon lataamista kun lohkoja ladataan epäjärjestyksessä käytettäessä assumeutxo-tilannevedoksia. Lompakon pitäisi latautua onnistuneesti kun noden synkronointi saavuttaa korkeuden %s + Error reading %s! All keys read correctly, but transaction data or address book entries might be missing or incorrect. Virhe luettaessa %s! Avaimet luetttiin oikein, mutta rahansiirtotiedot tai osoitekirjan sisältö saattavat olla puutteellisia tai vääriä. + + Error: Dumpfile format record is incorrect. Got "%s", expected "format". + Virhe: Vedostiedoston muoto on virheellinen. Saatiin "%s", odotettiin "format". + + + Error: Dumpfile identifier record is incorrect. Got "%s", expected "%s". + Virhe: Vedostiedoston tunniste on virheellinen. Saatiin "%s", odotettiin "%s". + + + Error: Dumpfile version is not supported. This version of bitcoin-wallet only supports version 1 dumpfiles. Got dumpfile with version %s + Virhe: Vedostiedoston versiota ei tueta. Tämä bitcoin-wallet-versio tukee vain version 1 vedostiedostoja. Saatiin vedostiedosto versiolla %s + + + Failed to rename invalid peers.dat file. Please move or delete it and try again. + Virheellisen peers.dat-tiedoston nimeäminen epäonnistui. Siirrä tai poista se ja yritä uudelleen. + + + Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable %s. + Siirtomaksun arviointi epäonnistui. Varamaksu on poistettu käytöstä. Odota muutama lohko tai ota %s käyttöön. + + + File %s already exists. If you are sure this is what you want, move it out of the way first. + Tiedosto %s on jo olemassa. Jos olet varma että tämä on mitä haluat, siirrä se ensin pois tieltä. + + + Incompatible options: -dnsseed=1 was explicitly specified, but -onlynet forbids connections to IPv4/IPv6 + Yhteensopimattomat asetukset: -dnsseed=1 määritettiin selvästi, mutta -onlynet kieltää yhteydet IPv4/IPv6:een + Incorrect or no devnet genesis block found. Wrong datadir for devnet specified? Väärä tai ei devnet alkuperäinen lohko löydetty. Väärä data hakemisto devnet verkolle? + + Invalid amount for %s=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions) + Virheellinen määrä kohteelle %s=<amount>: '%s' (täytyy olla vähintään minrelay-maksu %s jumittuneiden tapahtumien estämiseksi) + + + 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. + Virheellinen tai vioittunut peers.dat (%s). Jos uskot tämän olevan bugi, ilmoita siitä osoitteeseen %s. Kiertotienä voit siirtää tiedoston (%s) pois tieltä (nimeä uudelleen, siirrä tai poista) jotta uusi luodaan seuraavassa käynnistyksessä. + + + No dump file provided. To use createfromdump, -dumpfile=<filename> must be provided. + Vedostiedostoa ei annettu. Käyttääksesi createfromdump, -dumpfile=<filename> täytyy antaa. + + + No dump file provided. To use dump, -dumpfile=<filename> must be provided. + Vedostiedostoa ei annettu. Käyttääksesi dump, -dumpfile=<filename> täytyy antaa. + + + No wallet file format provided. To use createfromdump, -format=<format> must be provided. + Lompakkotiedoston muotoa ei annettu. Käyttääksesi createfromdump, -format=<format> täytyy antaa. + + + Outbound connections restricted to CJDNS (-onlynet=cjdns) but -cjdnsreachable is not provided + Lähtevät yhteydet rajoitettu CJDNS:ään (-onlynet=cjdns) mutta -cjdnsreachable ei ole annettu + + + Outbound connections restricted to Tor (-onlynet=onion) but the proxy for reaching the Tor network is explicitly forbidden: -onion=0 + Lähtevät yhteydet rajoitettu Toriin (-onlynet=onion) mutta välityspalvelin Tor-verkkoon pääsemiseksi on nimenomaisesti kielletty: -onion=0 + + + 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 + Lähtevät yhteydet rajoitettu Toriin (-onlynet=onion) mutta välityspalvelinta Tor-verkkoon pääsemiseksi ei ole annettu: yhtään -proxy, -onion tai -listenonion ei ole määritetty + + + Outbound connections restricted to i2p (-onlynet=i2p) but -i2psam is not provided + Lähtevät yhteydet rajoitettu i2p:hen (-onlynet=i2p) mutta -i2psam ei ole annettu + Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly. Tarkistathan että tietokoneesi päivämäärä ja kellonaika ovat oikeassa! Jos kellosi on väärässä, %s ei toimi oikein. @@ -4450,6 +5871,14 @@ Vähennä uakommenttien määrää tai kokoa. Please contribute if you find %s useful. Visit %s for further information about the software. Ole hyvä ja avusta, jos %s on mielestäsi hyödyllinen. Vieraile %s saadaksesi lisää tietoa ohjelmistosta. + + Prune mode is incompatible with -reindex-chainstate. Use full -reindex instead. + Karsintatila on epäyhteensopiva -reindex-chainstate kanssa. Käytä täyttä -reindex sen sijaan. + + + This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection. + Tämä on maksimi siirtomaksu jonka maksat (normaalin maksun lisäksi) priorisoidaksesi osittaisen käytön välttämisen tavallisen kolikon valinnan sijaan. + This is the transaction fee you may discard if change is smaller than dust at this level Tämä on siirtomaksun määrä jonka saatat hylätä jos vaihtoraha on pienempi kuin tomu tällä tasolla @@ -4458,14 +5887,38 @@ Vähennä uakommenttien määrää tai kokoa. This is the transaction fee you may pay when fee estimates are not available. Tämä on siirtomaksu jonka saatat maksaa jos siirtomaksun arviota ei ole mahdollista saada. + + Transaction requires one destination of non-0 value, a non-0 feerate, or a pre-selected input + Tapahtuma vaatii yhden kohteen, jolla on muu kuin 0 arvo, muun kuin 0 maksutason tai esivalitun syötteen + Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate. Ei voitu toistaa lohkoja. Sinun tulee uudelleen rakentaa tietokanta käyttäen -reindex-chainstate. + + Unknown wallet file format "%s" provided. Please provide one of "bdb" or "sqlite". + Tuntematon lompakon tiedostomuoto "%s" annettu. Anna joko "bdb" tai "sqlite". + + + Unsupported chainstate database format found. Please restart with -reindex-chainstate. This will rebuild the chainstate database. + Havaittiin ei-tuettu ketjutilan tietokantamuoto. Käynnistä uudelleen -reindex-chainstate:lla. Tämä rakentaa ketjutilan tietokannan uudelleen. + + + Warning: Dumpfile wallet format "%s" does not match command line specified format "%s". + Varoitus: Dump-tiedoston lompakon muoto "%s" ei vastaa komentoriviltä määriteltyä muotoa "%s". + Warning: Private keys detected in wallet {%s} with disabled private keys Varoitus: Lompakossa {%s} havaittiin yksityisavaimet , jotka on poistettu käytöstä + + You need to rebuild the database using -reindex to enable -timestampindex + Sinun täytyy rakentaa tietokanta uudelleen käyttäen -reindex ottaaksesi -timestampindex käyttöön + + + %s -- Incorrect seed, it should be a hex string + %s -- Virheellinen siemen, sen pitäisi olla heksadesimaalimerkkijono + %s is not a valid backup folder! %s ei ole pätevä varmistus hakemisto! @@ -4490,10 +5943,30 @@ Vähennä uakommenttien määrää tai kokoa. -rpcport must be specified when -devnet and -server are specified -rpcport täytyy määritellä kun -devnet ja -server on määritelty + + -statsbatchsize cannot be configured with a negative value. + -statsbatchsize ei voida määrittää negatiivisella arvolla. + + + -statsduration cannot be configured with a negative value. + -statsduration ei voida määrittää negatiivisella arvolla. + A fatal internal error occurred, see debug.log for details Vakava sisäinen virhe, katso debug.log lisätietoja + + Cannot create socket (socket() returned error %s) + Socketin luonti epäonnistui (socket() palautti virheen %s) + + + Cannot get socket address for %s + Socket-osoitetta ei saada %s:lle + + + Cannot init Statsd client + Statsd-asiakasta ei voida alustaa + Cannot resolve -%s address: '%s' -%s -osoitteen '%s' selvittäminen epäonnistui @@ -4502,10 +5975,6 @@ Vähennä uakommenttien määrää tai kokoa. Cannot write to data directory '%s'; check permissions. Ei voida kirjoittaa datahakemistoon '%s'; tarkista oikeudet. - - Change index out of range - Vaihtoindeksi on rajojen ulkopuolella - Copyright (C) Tekijänoikeus (C) @@ -4514,6 +5983,14 @@ Vähennä uakommenttien määrää tai kokoa. Disk space is too low! Levytila on alhainen! + + Dump file %s does not exist. + Dump-tiedostoa %s ei ole olemassa. + + + Error creating %s + Virhe luodessa %s + Error loading %s Virhe ladattaessa %s @@ -4531,8 +6008,8 @@ Vähennä uakommenttien määrää tai kokoa. Virhe ladatessa %s: Et voi poistaa käytöstä HD:tä jo olemassa olevassa HD lompakossa - Error upgrading chainstate database - Virhe ketjutilan tietokannan päivityksessä + Error reading next record from wallet database + Virhe luettaessa seuraavaa tietuetta lompakon tietokannasta Loading P2P addresses… @@ -4602,6 +6079,14 @@ Vähennä uakommenttien määrää tai kokoa. Inputs vs outputs size mismatch. Syötteet vs lähdöt koko ei täsmää. + + Invalid '%s'. Allowed values: 128, 160, 192, 224, 256. + Virheellinen '%s'. Sallitut arvot: 128, 160, 192, 224, 256. + + + Invalid -i2psam address or hostname: '%s' + Virheellinen -i2psam osoite tai isäntänimi: '%s' + Invalid -onion address or hostname: '%s' Virheellinen -onion osoite tai isäntänimi: '%s' @@ -4646,14 +6131,78 @@ Vähennä uakommenttien määrää tai kokoa. %s corrupt. Try using the wallet tool dash-wallet to salvage or restoring a backup. %s vioittunut. Yritä käyttää lompakkotyökalua dash-wallet pelastaaksesi tai palauttaaksesi varmuuskopion. + + %s is set very high! Fees this large could be paid on a single transaction. + %s on asetettu erittäin korkeaksi! Näin suuret maksut voidaan maksaa yhdellä tapahtumalla. + + + %s request to listen on port %u. This port is considered "bad" and thus it is unlikely that any Dash Core peers connect to it. See doc/p2p-bad-ports.md for details and a full list. + %s pyyntö kuunnella portissa %u. Tätä porttia pidetään "huonona" ja siksi on epätodennäköistä että mikään Dash Core -vertainen yhdistää siihen. Katso doc/p2p-bad-ports.md yksityiskohtia ja täydellistä listaa varten. + + + Cannot provide specific connections and have addrman find outgoing connections at the same time. + Ei voida tarjota tiettyjä yhteyksiä ja antaa addrmanin etsiä lähteviä yhteyksiä samanaikaisesti. + + + Failed to upgrade Evo database + Evo-tietokannan päivittäminen epäonnistui + + + Fee needed > fee paid + Tarvittava maksu > maksettu maksu + + + Host %s on unsupported network + Isäntä %s ei-tuetussa verkossa + + + Invalid amount for %s=<amount>: '%s' (must be at least %s) + Virheellinen määrä %s=<amount>: '%s' (on oltava vähintään %s) + + + Invalid amount for %s=<amount>: '%s' + Virheellinen määrä %s=<amount>: '%s' + + + Invalid port specified in %s: '%s' + Virheellinen portti määritelty %s: '%s' + Last successful action was too recent. Viimeinen onnistunut tapahtuma oli liian äskettäin. + + Missing solving data for estimating transaction size + Ratkaisutiedot puuttuvat tapahtuman koon arvioimiseksi + + + No host specified + Isäntää ei määritelty + + + No host specified, malformed URL + Isäntää ei määritelty, virheellinen URL + + + No text before the scheme delimiter, malformed URL + Ei tekstiä ennen kaavaerotinta, virheellinen URL + + + Port must be between %d and %d, supplied %d + Portin on oltava välillä %d ja %d, annettu %d + + + Socket not initialized, cannot send message + Sockettia ei ole alustettu, viestiä ei voida lähettää + The source code is available from %s. Lähdekoodi löytyy %s. + + The specified config file %s does not exist + Määriteltyä konfigurointitiedostoa %s ei ole olemassa + The transaction amount is too small to pay the fee Siirtomäärä on liian pieni siirtomaksun maksamiseen @@ -4674,6 +6223,10 @@ Vähennä uakommenttien määrää tai kokoa. Transaction fees are too high. Siirtotapahtuman siirtomaksu on liian iso. + + Transaction needs a change address, but we can't generate it. + Tapahtuma tarvitsee vaihtoraha-osoitteen, mutta emme voi luoda sitä. + Transaction not valid. Siirtotapahtuma ei ole voimassa. @@ -4694,6 +6247,18 @@ Vähennä uakommenttien määrää tai kokoa. Unable to locate enough non-denominated funds for this transaction. Ei tarpeeksi ei-denominoituja varoja tälle siirtotapahtumalle. + + Unable to lookup host %s + Ei voida hakea isäntää %s + + + Unable to parse -maxuploadtarget: '%s' + Ei voida jäsentää -maxuploadtarget: '%s' + + + Unable to send message to %s (::sendto() returned error %s) + Ei voida lähettää viestiä kohteeseen %s (::sendto() palautti virheen %s) + Unable to sign spork message, wrong key? En voida allekirjoittaa spork viestiä, väärä avain? @@ -4707,12 +6272,12 @@ Vähennä uakommenttien määrää tai kokoa. Tuntematon tila: id = %u - Unsupported logging category %s=%s. - Ei tuettu lokikategoria %s=%s. + Unsupported URL scheme, must begin with udp:// + Ei-tuettu URL-kaava, täytyy alkaa udp:// - Upgrading txindex database - Päivitetään txindex tietokantaa + Unsupported logging category %s=%s. + Ei tuettu lokikategoria %s=%s. Very low number of keys left: %d @@ -4742,9 +6307,25 @@ Vähennä uakommenttien määrää tai kokoa. You can not disable governance validation on a masternode. Et voi poistaa käytöstä hallinnon vahvistusta masternodesta. + + You need to rebuild the database using -reindex to enable -addressindex + Sinun täytyy rakentaa tietokanta uudelleen käyttämällä -reindex ottaaksesi käyttöön -addressindex + + + You need to rebuild the database using -reindex to enable -spentindex + Sinun täytyy rakentaa tietokanta uudelleen käyttämällä -reindex ottaaksesi käyttöön -spentindex + Your entries added successfully. Merkinnnät lisätty onnistuneesti. + + Settings file could not be read + Asetustiedostoa ei voitu lukea + + + Settings file could not be written + Asetustiedostoa ei voitu kirjoittaa + \ No newline at end of file diff --git a/src/qt/locale/dash_fr.ts b/src/qt/locale/dash_fr.ts index 7e5197adf01a..0aa91fd2dca1 100644 --- a/src/qt/locale/dash_fr.ts +++ b/src/qt/locale/dash_fr.ts @@ -65,14 +65,6 @@ C&hoose C&hoisir - - Sending addresses - Adresses d'envoi - - - Receiving addresses - Adresses de réception - These are your Dash addresses for sending payments. Always check the amount and the receiving address before sending coins. Voici vos adresses Dash pour l'envoi de paiements. Vérifiez toujours le montant et l'adresse de réception avant d'envoyer de l'argent. @@ -115,6 +107,14 @@ An error message. %1 is a stand-in argument for the name of the file we attempted to save to. Une erreur s'est produite en essayant de sauvegarder la liste d'adresses sur %1. Veuillez réessayer. + + Sending addresses - %1 + Adresses d'envoi - %1 + + + Receiving addresses - %1 + Adresses de réception - %1 + Exporting Failed L'exportation a échoué @@ -284,10 +284,22 @@ The passphrase entered for the wallet decryption was incorrect. La phrase de passe saisie pour déchiffrer le portefeuille est incorrecte. + + 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 23.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. + La phrase de passe saisie pour le déchiffrement du portefeuille est incorrecte. Elle contient un caractère nul (c'est-à-dire un octet zéro). Si la phrase de passe a été définie avec une version de ce logiciel antérieure à 23.0, veuillez réessayer avec uniquement les caractères jusqu'au — mais sans inclure — le premier caractère nul. Si cela fonctionne, veuillez définir une nouvelle phrase de passe pour éviter ce problème à l'avenir. + Wallet passphrase was successfully changed. La phrase de passe du portefeuille a été modifiée avec succès. + + Passphrase change failed + Échec du changement de phrase de passe + + + 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 23.0, please try again with only the characters up to — but not including — the first null character. + L'ancienne phrase de passe saisie pour le déchiffrement du portefeuille est incorrecte. Elle contient un caractère nul (c'est-à-dire un octet zéro). Si la phrase de passe a été définie avec une version de ce logiciel antérieure à 23.0, veuillez réessayer avec uniquement les caractères jusqu'au — mais sans inclure — le premier caractère nul. + Warning: The Caps Lock key is on! Attention : la touche Verr. Maj. est activée ! @@ -392,10 +404,6 @@ &Load PSBT from file… Charger PSBT depuis fichier… - - Load PSBT from clipboard… - Charger PSBT depuis le presse-papiers… - &Sending addresses Envoyer des adresses @@ -428,10 +436,6 @@ &Window Fenêtre - - Minimize - Minimiser - Zoom Zoom @@ -484,14 +488,6 @@ Modify configuration options for %1 Modifier les options de configuration de %1 - - &Show / Hide - &Afficher / Cacher - - - Show or hide the main Window - Afficher ou masquer la fenêtre principale - Encrypt the private keys that belong to your wallet Chiffrer les clefs privées de votre portefeuille @@ -556,10 +552,6 @@ Show wallet repair options Afficher les options de réparation du portefeuille - - Open Wallet &Configuration File - Ouvrir le fichier de &configuration du portefeuille - Open configuration file Ouvrir le fichier de configuration @@ -614,10 +606,18 @@ Show information about %1 Afficher les informations sur %1 + + Load PSBT from &clipboard… + Charger une PSBT depuis le presse-papiers… + Open debugging and diagnostic console Ouvrir la console de débogage et de diagnostic + + Open &wallet configuration file + Ouvrir le fichier de configuration du portefeuille + Open a dash: URI Ouvrir une URI dash: @@ -626,6 +626,16 @@ Create a new wallet Créer un nouveau portefeuille + + Restore Wallet… + Name of the menu item that restores wallet from a backup file. + Restaurer le portefeuille… + + + Restore a wallet from a backup file + Status tip for Restore Wallet menu item + Restaurer un portefeuille à partir d'un fichier de sauvegarde + Close all wallets Fermer tous les portefeuilles @@ -646,10 +656,34 @@ Mask the values in the Overview tab Masquer les valeurs dans l'onglet Vue d'ensemble + + Wallet Data + Name of the wallet data file format. + Données du portefeuille + + + Load Wallet Backup + The title for Restore Wallet File Windows + Charger la sauvegarde du portefeuille + + + Restore Wallet + Title of pop-up window shown when the user is attempting to restore a wallet. + Restaurer le portefeuille + + + Wallet Name + Label of the input field where the name of the wallet is entered. + Nom du portefeuille + &Settings &Réglages + + &Minimize + &Réduire + &Help &Aide @@ -666,6 +700,14 @@ View Governance Proposals Voir les propositions de gouvernance + + &Hide + &Masquer + + + S&how + &Afficher + %n active connection(s) to Dash network A substring of the tooltip. @@ -687,6 +729,14 @@ Close Wallet… Fermer le portefeuille… + + Load Partially Signed Blockchain Transaction + Charger transaction de blockchain partiellement signée + + + Load Partially Signed Blockchain Transaction from clipboard + Charger transaction de blockchain partiellement signée depuis le presse-papier + Create Wallet… Créer un portefeuille… @@ -739,10 +789,6 @@ Processing blocks on disk… Traitement des blocs sur le disque… - - Reindexing blocks on disk… - Réindexation des blocs sur le disque… - Connecting to peers… Connexion aux pairs… @@ -896,10 +942,6 @@ Coin Selection Sélection des pièces - - Dust: - Poussière : - After Fee: Avec les frais déduits : @@ -1000,10 +1042,6 @@ Copy bytes Copier les octets - - Copy dust - Copier la poussière - Copy change Copier la monnaie rendue @@ -1016,18 +1054,6 @@ (%1 locked) (%1 verrouillés) - - yes - oui - - - no - non - - - This label turns red if any recipient receives an amount smaller than the current dust threshold. - Cette étiquette devient rouge si l'un des destinataires reçoit un montant inférieur au niveau de "poussière". - Can vary +/- %1 duff(s) per input. Peut varier de ± %1 duff(s) par entrée. @@ -1241,18 +1267,102 @@ Filter proposal list Filtrer la liste des propositions + + Masternode Count: + Nombre de masternodes : + + + Number of masternodes this wallet can vote with (masternodes for which this wallet holds the voting key) + Nombre de masternodes avec lesquels ce portefeuille peut voter (masternodes pour lesquels ce portefeuille détient la clé de vote) + Proposal Count: Nombre de propositions : + + Create Proposal + Créer une proposition + Filter by Title Filtrer par titre + + Unavailable + Indisponible + + + A synced node and an unlocked wallet are required. + Un nœud synchronisé et un portefeuille déverrouillé sont requis. + + + Vote Yes + Voter Oui + + + Vote No + Voter Non + + + Vote Abstain + Voter Abstention + Proposal Info: %1 Information sur proposition : %1 + + Voting Failed + Échec du vote + + + No wallet available. + Aucun portefeuille disponible. + + + No masternode voting keys found in wallet. + Aucune clé de vote de masternode trouvée dans le portefeuille. + + + Please select a proposal to vote on. + Veuillez sélectionner une proposition sur laquelle voter. + + + Unable to unlock wallet. + Impossible de déverrouiller le portefeuille. + + + Unable to get masternode list. Please try again later. + Impossible d'obtenir la liste des masternodes. Veuillez réessayer plus tard. + + + Masternode %1 not found + Masternode %1 introuvable + + + Failed to sign vote for masternode %1 + Échec de la signature du vote pour le masternode %1 + + + Masternode %1: %2 + Masternode %1 : %2 + + + Voted successfully %n time(s) + Voté avec succès %n foisVoté avec succès %n foisVoté avec succès %n fois + + + Failed to vote %n time(s) + Échec du vote %n foisÉchec du vote %n foisÉchec du vote %n fois + + + Errors: + Erreurs : + + + Voting Results + Résultats du vote + HelpMessageDialog @@ -1323,13 +1433,17 @@ Use a custom data directory: Utiliser un répertoire de données personnalisé : - - (of %1 GB needed) - (de %1 Go nécessaire) + + %n GB of space available + %n Go d'espace disponible%n Go d'espace disponible%n Go d'espace disponible - - (%1 GB needed for full chain) - (%1 Go nécessaires pour la chaîne entière) + + (of %n GB needed) + (sur %n Go nécessaire)(sur %n Go nécessaires)(sur %n Go nécessaires) + + + (%n GB needed for full chain) + (%n Go nécessaire pour la chaîne complète)(%n Go nécessaires pour la chaîne complète)(%n Go nécessaires pour la chaîne complète) At least %1 GB of data will be stored in this directory, and it will grow over time. @@ -1361,6 +1475,13 @@ Erreur + + LoadWalletsActivity + + Loading wallets… + Chargement des portefeuilles… + + MasternodeList @@ -1553,6 +1674,11 @@ URI: URI : + + Paste address from clipboard + Tooltip text for button that allows you to paste an address that is in your clipboard. + Coller l'adresse depuis le presse-papiers + OpenWalletActivity @@ -1663,6 +1789,16 @@ An Options window setting to set subtracting the fee from a sending amount as default. &Frais soustraits au total par défaut + + Enable &PSBT controls + An options window setting to enable PSBT controls. + Activer les contrôles &PSBT + + + Whether to show PSBT controls. + Tooltip text for options window setting that enables PSBT controls. + S'il faut afficher ou non les contrôles PSBT. + Whether to keep the specified custom change address or not. S'il faut garder ou non l'adresse personnalisée de monnaie spécifiée. @@ -1806,20 +1942,20 @@ https://explore.transifex.com/dash/dash/ https://explore.transifex.com/dash/dash/ - Options set in this dialog are overridden by the command line or in the configuration file: - Les options choisies dans ce dialogue sont remplacées par la ligne de commande ou dans le fichier de configuration : + Third-party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items.<br/>%s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |. + URL tierces (par ex. un explorateur de blocs) qui apparaissent dans l'onglet des transactions comme éléments de menu contextuel.<br/>%s dans l'URL est remplacé par le hachage de transaction. Plusieurs URL sont séparées par une barre verticale |. - 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. - Minimiser l'application (au lieu de la quitter) quand la fenêtre est fermée. Si cette option est activée, l'application se fermera uniquement en passant par le menu Quitter. + &Third-party transaction URLs + URL de &transaction tierces - Third party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items.<br/>%s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |. - URLs de tierce partie (par ex. : un explorateur de blocs) affichées dans l'onglet Transactions comme menu contextuel.<br/>%s dans l'URL est remplacé par le hash de transaction. Les URLs multiples sont séparées par une barre verticale |. + Options set in this dialog are overridden by the command line or in the configuration file: + Les options choisies dans ce dialogue sont remplacées par la ligne de commande ou dans le fichier de configuration : - &Third party transaction URLs - URLs de transaction &Tierces + 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. + Minimiser l'application (au lieu de la quitter) quand la fenêtre est fermée. Si cette option est activée, l'application se fermera uniquement en passant par le menu Quitter. Whether to show coin control features or not. @@ -1963,14 +2099,22 @@ https://explore.transifex.com/dash/dash/ Confirm options reset + Window title text of pop-up window shown when the user has chosen to reset options. Confirmer la réinitialisation des options Client restart required to activate changes. + Text explaining that the settings changed will not come into effect until the client is restarted. Le redémarrage du client est nécessaire pour activer les changements. + + Current settings will be backed up at "%1". + 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. + Les paramètres actuels seront sauvegardés dans "%1". + Client will be shut down. Do you want to proceed? + Text asking the user to confirm if they would like to proceed with a client shutdown. Le logiciel va être fermé. Voulez-vous continuer ? @@ -2243,6 +2387,10 @@ https://explore.transifex.com/dash/dash/ Failed to sign transaction: %1 Échec de la signature de la transaction : %1 + + Cannot sign inputs while wallet is locked. + Impossible de signer des entrées quand le portefeuille est verrouillé. + Could not sign any more inputs. Impossible de signer plus d'entrées. @@ -2487,6 +2635,181 @@ En raison d'un support interrompu, vous devriez demander au vendeur de vous comm État + + ProposalWizard + + Create Governance Proposal + Créer une proposition de gouvernance + + + Enter proposal details + Entrer les détails de la proposition + + + A fee will be burned when you prepare the proposal. + Des frais seront brûlés lorsque vous préparerez la proposition. + + + Proposal &name + &Nom de la proposition + + + &Description URL + URL de &description + + + Payment &address + &Adresse de paiement + + + Payment &amount + &Montant du paiement + + + The amount to request in a single payment + Le montant à demander en un seul paiement + + + &First payment + &Premier paiement + + + Pa&yments + Pa&iements + + + To&tal amount + Montant to&tal + + + Proposal &fee + &Frais de proposition + + + Next + Suivant + + + Review proposal JSON and validate. + Examiner le JSON de la proposition et valider. + + + Hex-encoded JSON + JSON encodé en hexadécimal + + + Back + Retour + + + Validate + Valider + + + Prepare (burn fee) and wait for confirmations. + Préparer (brûler les frais) et attendre les confirmations. + + + Copy + Copier + + + At 1/6 confirmations: can be relayed and queued. At 6/6: accepted and processed. + À 1/6 confirmations : peut être relayé et mis en file d'attente. À 6/6 : accepté et traité. + + + Confirmations progress + Progression des confirmations + + + Shows progress toward the required number of confirmations for the proposal fee transaction. + Affiche la progression vers le nombre requis de confirmations pour la transaction de frais de proposition. + + + Estimated time remaining: - + Temps restant estimé : - + + + Prepare Proposal + Préparer la proposition + + + You can submit after 1 confirmation. At 6 confirmations it is accepted and processed. + Vous pouvez soumettre après 1 confirmation. À 6 confirmations, elle est acceptée et traitée. + + + Proposal ID: + ID de proposition : + + + Submit Proposal + Soumettre la proposition + + + Close + Fermer + + + Valid + Valide + + + Invalid: %1 + Invalide : %1 + + + Burn %1 + Brûler %1 + + + Burn %1 to create the fee transaction? + Brûler %1 pour créer la transaction de frais ? + + + Prepare failed + Échec de la préparation + + + Confirmations: %1 / %2 required + Confirmations : %1 / %2 requises + + + Estimated time remaining: Ready + Temps restant estimé : Prêt + + + Estimated time remaining: %n minute(s) + Temps restant estimé : %n minuteTemps restant estimé : %n minutesTemps restant estimé : %n minutes + + + Your proposal was submitted successfully. + Votre proposition a été soumise avec succès. + + + Already submitted + Déjà soumise + + + This proposal has already been submitted. + Cette proposition a déjà été soumise. + + + Submission failed + Échec de la soumission + + + Proposal submitted + Proposition soumise + + + A fee of %1 will be burned when you prepare the proposal. + Des frais de %1 seront brûlés lorsque vous préparerez la proposition. + + + Prepare (burn %1) and wait for %2 confirmations. + Préparer (brûler %1) et attendre %2 confirmations. + + QObject @@ -2876,14 +3199,6 @@ En raison d'un support interrompu, vous devriez demander au vendeur de vous comm Version Version - - Whether the peer requested us to relay transactions. - Si le pair nous a demandés de relayer des transactions. - - - Wants Tx Relay - Souhaite un relais de transaction - High bandwidth BIP152 compact block relay: %1 Relais de bloc compact BIP152 haute bande passante : %1 @@ -2989,6 +3304,14 @@ En raison d'un support interrompu, vous devriez demander au vendeur de vous comm To specify a non-default location of the blocks directory use the '%1' option. Pour indiquer une localisation non-défaut du répertoire de blocs, utilisez l'option '%1'. + + Local Addresses + Adresses locales + + + Network addresses that your Dash node is currently using to communicate with other nodes. + Adresses réseau que votre nœud Dash utilise actuellement pour communiquer avec d'autres nœuds. + Number of regular Masternodes Nombre de masternodes standard @@ -3081,6 +3404,14 @@ En raison d'un support interrompu, vous devriez demander au vendeur de vous comm Services Services + + Whether we relay transactions to this peer. + Si nous relayons les transactions vers ce pair. + + + Transaction Relay + Relais de transaction + Connection Time Temps de connexion @@ -3229,6 +3560,10 @@ En raison d'un support interrompu, vous devriez demander au vendeur de vous comm Network activity disabled Activité réseau désactivée + + None + Aucun + Total: %1 (Enabled: %2) Total : %1 (Activé : %2) @@ -3550,6 +3885,34 @@ Pour plus d'informations sur l'utilisation de cette console, tapez %6. Demandée + + RestoreWalletActivity + + Restore Wallet + Title of progress window which is displayed when wallets are being restored. + Restaurer le portefeuille + + + Restoring Wallet <b>%1</b>… + Descriptive text of the restore wallets progress window which indicates to the user that wallets are currently being restored. + Restauration du portefeuille <b>%1</b>… + + + Restore wallet failed + Title of message box which is displayed when the wallet could not be restored. + Échec de la restauration du portefeuille + + + Restore wallet warning + Title of message box which is displayed when the wallet is restored with some warning. + Avertissement de restauration du portefeuille + + + Restore wallet message + Title of message box which is displayed when the wallet is successfully restored. + Message de restauration du portefeuille + + SendCoinsDialog @@ -3584,10 +3947,6 @@ Pour plus d'informations sur l'utilisation de cette console, tapez %6. Fee: Frais : - - Dust: - Poussière: - Inputs… Entrées… @@ -3712,10 +4071,6 @@ Pour plus d'informations sur l'utilisation de cette console, tapez %6. Copy bytes Copier les octets - - Copy dust - Copier poussière - Copy change Copier la monnaie @@ -3724,10 +4079,6 @@ Pour plus d'informations sur l'utilisation de cette console, tapez %6. %1 (%2 blocks) %1 (%2 blocs) - - This will produce a Partially Signed Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet. - Cela produira une transaction partiellement signée (PSBT) que vous pouvez enregistrer ou copier, puis signer avec (par exemple) un portefeuille %1 hors ligne, ou un portefeuille matériel compatible PSBT. - using utiliser @@ -3736,10 +4087,6 @@ Pour plus d'informations sur l'utilisation de cette console, tapez %6. %1 to %2 %1 à %2 - - Are you sure you want to send? - Êtes-vous sûr de vouloir envoyer ? - <b>(%1 of %2 entries displayed)</b> <b>(%1 sur %2 entrées affichées)</b> @@ -3764,10 +4111,6 @@ Pour plus d'informations sur l'utilisation de cette console, tapez %6. %1 to '%2' %1 à '%2' - - Do you want to draft this transaction? - Voulez-vous créer un brouillon de cette transaction ? - %1 funds only Fonds %1 seulement @@ -3816,14 +4159,6 @@ Pour plus d'informations sur l'utilisation de cette console, tapez %6. Confirm send coins Confirmer l’envoi des fonds - - Confirm transaction proposal - Confirmer la proposition de transaction - - - Create Unsigned - Créer non-signée - Save Transaction Data Enregistrer les données de transaction @@ -3837,8 +4172,28 @@ Pour plus d'informations sur l'utilisation de cette console, tapez %6. Solde à consultation seule : - Send - Envoyer + Creates a Partially Signed Blockchain Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet. + Crée une transaction de blockchain partiellement signée (PSBT) pour utilisation avec, par ex., un portefeuille %1 hors ligne, ou un portefeuille matériel compatible PSBT. + + + Do you want to create this transaction? + 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. + Voulez-vous créer cette transaction ? + + + Please, review your transaction proposal. This will produce a Partially Signed Blockchain Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet. + 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. + Veuillez examiner votre proposition de transaction. Cela produira une transaction de blockchain partiellement signée (PSBT) que vous pouvez enregistrer ou copier puis signer avec par ex. un portefeuille %1 hors ligne, ou un portefeuille matériel compatible PSBT. + + + Please, review your transaction. You can create and send this transaction or create a Partially Signed Blockchain Transaction (PSBT), which you can save or copy and then sign with, e.g., an offline %1 wallet, or a PSBT-compatible hardware wallet. + 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. + Veuillez examiner votre transaction. Vous pouvez créer et envoyer cette transaction ou créer une transaction de blockchain partiellement signée (PSBT), que vous pouvez enregistrer ou copier puis signer avec, par ex., un portefeuille %1 hors ligne, ou un portefeuille matériel compatible PSBT. + + + Please, review your transaction. + Text to prompt a user to review the details of the transaction they are attempting to send. + Veuillez examiner votre transaction. To review recipient list click "Show Details…" @@ -3968,21 +4323,16 @@ Pour plus d'informations sur l'utilisation de cette console, tapez %6. A message that was attached to the dash: URI which will be stored with the transaction for your reference. Note: This message will not be sent over the Dash network. Un message joint à l'URI Dash qui sera sauvegardé avec la transaction pour référence. Note : ce message ne sera pas envoyé à travers le réseau Dash. + + + SendConfirmationDialog - This is an unauthenticated payment request. - Ceci est une demande de paiement non authentifiée. - - - This is an authenticated payment request. - Ceci est une demande de paiement authentifiée. - - - Pay To: - Payer à : + Send + Envoyer - Memo: - Mémo : + Create Unsigned + Créer non signée @@ -4191,20 +4541,9 @@ Pour plus d'informations sur l'utilisation de cette console, tapez %6. TransactionDesc - - Open for %n more block(s) - Ouvert pour %n bloc de plusOuvert pour %n blocs de plusOuvert pour %n blocs de plus - - - Open until %1 - Ouvert jusqu'à %1 - - - conflicted - en conflit - 0/unconfirmed, %1 + 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. 0/non confirmée, %1 @@ -4217,22 +4556,32 @@ Pour plus d'informations sur l'utilisation de cette console, tapez %6. abandoned + 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. abandonné + + conflicted with a transaction with %1 confirmations + 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. + en conflit avec une transaction avec %1 confirmations + %1/unconfirmed + 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, and still not locked via ChainLocks. %1/non confirmée %1 confirmations + 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 or locked via ChainLocks. %1 confirmations locked via ChainLocks + 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 and has been locked by ChainLocks. verrouillé avec ChainLocks verified via InstantSend + 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 has been locked by InstantSend. vérifié avec InstantSend @@ -4385,14 +4734,6 @@ Pour plus d'informations sur l'utilisation de cette console, tapez %6. Address / Label Adresse / Étiquette - - Open for %n more block(s) - Ouvert pour %n bloc de plusOuvert pour %n blocs de plusOuvert pour %n blocs de plus - - - Open until %1 - Ouvert jusqu'à %1 - Unconfirmed Non confirmé @@ -4644,6 +4985,11 @@ Pour plus d'informations sur l'utilisation de cette console, tapez %6. Show address &QR code Afficher le &QR-code de l'adresse + + Show in %1 + 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. + Afficher dans %1 + Export Transaction History Exporter l'historique des transactions @@ -4836,10 +5182,6 @@ Allez à Fichier > Ouvrir le portefeuille pour charger un portefeuille. dash-core - - Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee. - Échec de l'estimation des frais. Les frais de secours sont désactivés. Laissez passer quelques blocs ou activez -fallbackfee. - 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 Cette erreur pourrait survenir si le portefeuille n'était pas proprement fermé et avait été dernièrement chargé depuis une version plus récente de Berkeley DB. Si c'est le cas, veuillez utiliser le logiciel qui a été le plus récent à charger ce portefeuille @@ -4912,10 +5254,6 @@ Allez à Fichier > Ouvrir le portefeuille pour charger un portefeuille. Failed to listen on any port. Use -listen=0 if you want this. Échec de l'écoute sur un port quelconque. Utilisez -listen=0 si vous voulez ceci. - - -maxtxfee is set very high! Fees this large could be paid on a single transaction. - -maxtxfee est réglée sur un montant très élevé ! Ces frais aussi élevés peuvent être payés sur une transaction unique. - Found unconfirmed denominated outputs, will wait till they confirm to continue. Détection de sorties de coupures non confirmées, attente de leur confirmation pour continuer. @@ -4924,10 +5262,6 @@ Allez à Fichier > Ouvrir le portefeuille pour charger un portefeuille. Invalid -socketevents ('%s') specified. Only these modes are supported: %s Les -socketevents ('%s') spécifiés ne sont pas valides. Seuls ces modes sont compatibles : %s - - Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions) - Montant invalide pour -maxtxfee=<montant> : « %s » (doit être au moins du montant de frais minrelay de %s pour éviter des transactions bloquées) - SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is supported SQLiteDatabase : version %d de portefeuille sqlite inconnue. Seule la version %d est supportée @@ -4936,6 +5270,10 @@ Allez à Fichier > Ouvrir le portefeuille pour charger un portefeuille. Transaction index can't be disabled with governance validation enabled. Either start with -disablegovernance command line switch or enable transaction index. L'index de transaction ne peut pas être désactivé lorsque la validation de gouvernance est activée. Démarrez en ligne de commande avec l'argument -disablegovernance, ou bien activez l'index de transaction. + + Unsupported category-specific logging level -loglevel=%s. Expected -loglevel=<category>:<loglevel>. Valid categories: %s. Valid loglevels: %s. + Niveau de journal (spécifique à une catégorie) non supporté : -loglevel=%s. Attendu : -loglevel=<category>:<loglevel>. Catégories valides : %s. Niveaux de journal valides : %s. + Can't mix: no compatible inputs found! Impossible de mélanger : pas d'entrées compatibles trouvées ! @@ -4944,6 +5282,14 @@ Allez à Fichier > Ouvrir le portefeuille pour charger un portefeuille. Entry exceeds maximum size. L'entrée dépasse la taille maximale. + + Error upgrading evo database for EHF + Erreur lors de la mise à jour de la base de données Evo pour EHF + + + Failed to commit Evo database + Échec de la validation de la base de données Evo + Found enough users, signing ( waiting %s ) Nombre suffisant d'utilisateurs trouvé, signature ( attente %s ) @@ -4968,18 +5314,14 @@ Allez à Fichier > Ouvrir le portefeuille pour charger un portefeuille. Insufficient funds. Fonds insuffisants - - Invalid amount for -discardfee=<amount>: '%s' - Montant invalide pour -discardfee=<montant> : « %s » - - - Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s) - Montant invalide pour -paytxfee=<montant> : « %s » (minimum possible: %s) - Invalid minimum number of spork signers specified with -minsporkkeys Le nombre minimal de signataires spork spécifié avec -minsporkkeys est invalide + + Listening for incoming connections failed (listen returned error %s) + Échec de l'écoute des connexions entrantes (erreur retournée : %s) + Lock is already in place. Verrou déjà en place. @@ -5036,6 +5378,10 @@ Allez à Fichier > Ouvrir le portefeuille pour charger un portefeuille. Synchronizing governance objects… Synchronisation des objets de gouvernance… + + Transaction change output index out of range + Index de sortie de monnaie de transaction hors de la gamme + Unable to start HTTP server. See debug log for details. Impossible de démarrer le serveur HTTP. Voir le journal de déboguage pour les détails. @@ -5044,6 +5390,10 @@ Allez à Fichier > Ouvrir le portefeuille pour charger un portefeuille. Unknown response. Réponse inconnue. + + Unsupported global logging level -loglevel=%s. Valid values: %s. + Niveau de journal global non supporté : -loglevel=%s. Valeurs valides : %s. + User Agent comment (%s) contains unsafe characters. Le commentaire User Agent (%s) contient des caractères dangereux. @@ -5108,10 +5458,6 @@ Allez à Fichier > Ouvrir le portefeuille pour charger un portefeuille. Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments. La taille totale de la chaîne de version réseau (%i) dépasse la taille maximum (%i). Réduisez le nombre ou la taille des uacomments. - - Transaction needs a change address, but we can't generate it. Please call keypoolrefill first. - La transaction nécessite une adresse de monnaie rendue, mais nous ne pouvons pas la générer. Veuillez appeler d'abord keypoolrefill. - WARNING! Failed to replenish keypool, please unlock your wallet to do so. ATTENTION ! Impossible de réalimenter la série de clefs. Veuillez déverrouiller votre portefeuille pour cela. @@ -5188,10 +5534,6 @@ Allez à Fichier > Ouvrir le portefeuille pour charger un portefeuille. Error: No addresses available. Erreur : aucune adresse disponible. - - Exceeded max tries. - Le nombre maximal d'essais est dépassé. - Failed to create backup %s! La création de la sauvegarde %s a échoué ! @@ -5232,10 +5574,6 @@ Allez à Fichier > Ouvrir le portefeuille pour charger un portefeuille. Invalid P2P permission: '%s' Autorisation P2P invalide : '%s' - - Invalid amount for -fallbackfee=<amount>: '%s' - Montant invalide pour -fallbackfee=<montant> : « %s » - Invalid masternodeblsprivkey. Please see documentation. masternodeblsprivkey invalide. Veuillez vous référer à la documentation. @@ -5372,10 +5710,6 @@ Allez à Fichier > Ouvrir le portefeuille pour charger un portefeuille. Unable to open %s for writing Impossible d'ouvrir %s pour y écrire - - Unable to parse -maxuploadtarget: '%s' (possible integer overflow?) - Impossible de traiter -maxuploadtarge : '%s' (débordement d'entier ?) - Unknown -blockfilterindex value %s. Valeur inconnue de -blockfilterindex %s. @@ -5384,10 +5718,6 @@ Allez à Fichier > Ouvrir le portefeuille pour charger un portefeuille. Unknown new rules activated (versionbit %i) Nouvelles règles inconnues activées (versionbit %i) - - Upgrading UTXO database - Mise à niveau de la base de données UTXO - Verifying blocks… Vérification des blocs en cours… @@ -5448,10 +5778,6 @@ Allez à Fichier > Ouvrir le portefeuille pour charger un portefeuille. Cannot obtain a lock on data directory %s. %s is probably already running. Impossible d’obtenir un verrou sur le répertoire de données %s. %s fonctionne probablement déjà. - - Cannot upgrade a non HD wallet from version %i to version %i which is non-HD wallet. Use upgradetohd RPC - Impossible de monter un portefeuille non-HD de la version %i à la version %i qui est un portefeuille non-HD. Utilisez RPC upgradetohd - Distributed under the MIT software license, see the accompanying file %s or %s Distribué sous la licence MIT d’utilisation d’un logiciel. Consulter le fichier joint %s ou %s @@ -5484,6 +5810,10 @@ Allez à Fichier > Ouvrir le portefeuille pour charger un portefeuille. Failed to rename invalid peers.dat file. Please move or delete it and try again. Impossible de renommer le fichier invalide peers.dat. Veuillez le déplacer, ou bien effacez-le et réessayez. + + Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable %s. + L'estimation des frais a échoué. Fallbackfee est désactivé. Attendez quelques blocs ou activez %s. + File %s already exists. If you are sure this is what you want, move it out of the way first. Le fichier %s existe déjà. Si vous êtes sûr que c'est ce que vous souhaitez, sortez-le d'abord. @@ -5496,6 +5826,10 @@ Allez à Fichier > Ouvrir le portefeuille pour charger un portefeuille. Incorrect or no devnet genesis block found. Wrong datadir for devnet specified? Le bloc de genèse devnet est incorrect ou introuvable. Mauvais répertoire de données pour devnet ? + + Invalid amount for %s=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions) + Montant invalide pour %s=<montant> : '%s' (doit être au moins les frais minrelay de %s pour éviter les transactions bloquées) + 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. peers.dat invalide ou corrompu (%s). Si vous pensez que c'est un bug, veuillez le signaler à %s. Comme contournement, vous pouvez déplacer ailleurs le fichier %s (renommez-le, déplacez-le ou effacez-le) pour qu'un nouveau soit créé au prochain démarrage. @@ -5512,6 +5846,10 @@ Allez à Fichier > Ouvrir le portefeuille pour charger un portefeuille. No wallet file format provided. To use createfromdump, -format=<format> must be provided. Aucun format de fichier portefeuille fourni. Pour utiliser createfromdump, -format=<format> doit être fourni. + + Outbound connections restricted to CJDNS (-onlynet=cjdns) but -cjdnsreachable is not provided + Connexions sortantes restreintes à CJDNS (-onlynet=cjdns) mais -cjdnsreachable n'est pas fourni + Outbound connections restricted to Tor (-onlynet=onion) but the proxy for reaching the Tor network is explicitly forbidden: -onion=0 Connexions sortantes restreintes à Tor (-onlynet=onion) mais le proxy pour atteindre le réseau Tor est explicitement interdit : -onion=0 @@ -5520,6 +5858,10 @@ Allez à Fichier > Ouvrir le portefeuille pour charger un portefeuille. 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 Connexions sortantes restreintes à Tor (-onlynet=onion) mais le proxy pour atteindre le réseau Tor n'est pas indiqué : aucun -proxy, -onion ou -listenonion n'est fourni + + Outbound connections restricted to i2p (-onlynet=i2p) but -i2psam is not provided + Connexions sortantes restreintes à i2p (-onlynet=i2p) mais -i2psam n'est pas fourni + Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly. 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. @@ -5532,10 +5874,6 @@ Allez à Fichier > Ouvrir le portefeuille pour charger un portefeuille. Prune mode is incompatible with -reindex-chainstate. Use full -reindex instead. Le mode prune est incompatible avec -reindex-chainstate. Utilisez à la place -reindex. - - The block index db contains a legacy 'txindex'. To clear the occupied disk space, run a full -reindex, otherwise ignore this error. This error message will not be displayed again. - La base de données d'index de blocs comporte un ancien 'txindex'. Pour vider l'espace-disque occupé, lancez un -reindex intégral, ou bien ignorez cette erreur. Ce message d'erreur ne sera plus affiché. - This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection. Ceci sont les frais de transaction maximaux que vous payez (en addition des frais normaux) pour prioriser l'évitement de dépense partielle sur le choix normal de pièces. @@ -5548,6 +5886,10 @@ Allez à Fichier > Ouvrir le portefeuille pour charger un portefeuille. This is the transaction fee you may pay when fee estimates are not available. Il s’agit des frais de transaction que vous pourriez payer si aucune estimation de frais n’est proposée. + + Transaction requires one destination of non-0 value, a non-0 feerate, or a pre-selected input + La transaction nécessite une destination de valeur non nulle, un taux de frais non nul, ou une entrée présélectionnée + Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate. Impossible de repasser les blocs. Vous devez reconstruire la base de données en utilisant -reindex-chainstate. @@ -5556,6 +5898,10 @@ Allez à Fichier > Ouvrir le portefeuille pour charger un portefeuille. Unknown wallet file format "%s" provided. Please provide one of "bdb" or "sqlite". Format de fichier portefeuille "%s" inconnu. Veuillez fournir "bdb" ou "sqlite". + + Unsupported chainstate database format found. Please restart with -reindex-chainstate. This will rebuild the chainstate database. + Format de base de données chainstate non pris en charge trouvé. Veuillez redémarrer avec -reindex-chainstate. Cela reconstruira la base de données chainstate. + Warning: Dumpfile wallet format "%s" does not match command line specified format "%s". Avertissement : le format de portefeuille dumpfile "%s" ne correspond pas au format "%s" spécifié en ligne de commande. @@ -5596,10 +5942,30 @@ Allez à Fichier > Ouvrir le portefeuille pour charger un portefeuille. -rpcport must be specified when -devnet and -server are specified -rpcport doit être spécifié si -devnet et -server le sont déjà + + -statsbatchsize cannot be configured with a negative value. + -statsbatchsize ne peut pas être configuré avec une valeur négative. + + + -statsduration cannot be configured with a negative value. + -statsduration ne peut pas être configuré avec une valeur négative. + A fatal internal error occurred, see debug.log for details Une erreur interne fatale s'est produite. Voir debug.log pour les détails + + Cannot create socket (socket() returned error %s) + Impossible de créer le socket (socket() a renvoyé l'erreur %s) + + + Cannot get socket address for %s + Impossible d'obtenir l'adresse du socket pour %s + + + Cannot init Statsd client + Impossible d'initialiser le client Statsd + Cannot resolve -%s address: '%s' Impossible de résoudre l’adresse -%s : « %s » @@ -5644,10 +6010,6 @@ Allez à Fichier > Ouvrir le portefeuille pour charger un portefeuille. Error reading next record from wallet database Erreur à la lecture de l'enregistrement suivant sur la base de données du portefeuille - - Error upgrading chainstate database - Erreur de mise à niveau de la base de données d’état de la chaîne - Loading P2P addresses… Chargement des adresses P2P… @@ -5768,10 +6130,70 @@ Allez à Fichier > Ouvrir le portefeuille pour charger un portefeuille. %s corrupt. Try using the wallet tool dash-wallet to salvage or restoring a backup. %s corrompu. Essayez d'utiliser l'outil de portefeuille dash-wallet pour réparer, ou restaurer une sauvegarde. + + %s is set very high! Fees this large could be paid on a single transaction. + %s est défini très haut ! Des frais aussi importants pourraient être payés sur une seule transaction. + + + %s request to listen on port %u. This port is considered "bad" and thus it is unlikely that any Dash Core peers connect to it. See doc/p2p-bad-ports.md for details and a full list. + Requête %s pour écouter le port %u. Ce port est considéré "mauvais" et il est donc improbable que des pairs Dash Core s'y connectent. Voir doc/p2p-bad-ports.md pour détails et liste. + + + Cannot provide specific connections and have addrman find outgoing connections at the same time. + Impossible de fournir des connexions spécifiques pendant que addrman trouve des connexions de sortie. + + + Failed to upgrade Evo database + Échec de la mise à niveau de la base de données Evo + + + Fee needed > fee paid + Frais nécessaires > frais payés + + + Host %s on unsupported network + Hôte %s sur un réseau non pris en charge + + + Invalid amount for %s=<amount>: '%s' (must be at least %s) + Montant invalide pour %s=<montant> : '%s' (doit être au moins %s) + + + Invalid amount for %s=<amount>: '%s' + Montant invalide pour %s=<montant> : '%s' + + + Invalid port specified in %s: '%s' + Port invalide spécifié dans %s : '%s' + Last successful action was too recent. La dernière action réussie est trop récente. + + Missing solving data for estimating transaction size + Données de résolution manquantes pour estimer la taille de la transaction + + + No host specified + Aucun hôte spécifié + + + No host specified, malformed URL + Aucun hôte spécifié, URL mal formée + + + No text before the scheme delimiter, malformed URL + Aucun texte avant le délimiteur de schéma, URL mal formée + + + Port must be between %d and %d, supplied %d + Le port doit être entre %d et %d, fourni %d + + + Socket not initialized, cannot send message + Socket non initialisé, impossible d'envoyer le message + The source code is available from %s. Le code source se trouve sur %s. @@ -5800,6 +6222,10 @@ Allez à Fichier > Ouvrir le portefeuille pour charger un portefeuille. Transaction fees are too high. Les frais de transaction sont trop élevés. + + Transaction needs a change address, but we can't generate it. + La transaction nécessite une adresse de monnaie, mais nous ne pouvons pas la générer. + Transaction not valid. Transaction invalide. @@ -5820,6 +6246,18 @@ Allez à Fichier > Ouvrir le portefeuille pour charger un portefeuille. Unable to locate enough non-denominated funds for this transaction. Impossible de trouver pour cette transaction suffisamment de fonds hors coupures. + + Unable to lookup host %s + Impossible de rechercher l'hôte %s + + + Unable to parse -maxuploadtarget: '%s' + Impossible d'analyser -maxuploadtarget : '%s' + + + Unable to send message to %s (::sendto() returned error %s) + Impossible d'envoyer le message à %s (::sendto() a renvoyé l'erreur %s) + Unable to sign spork message, wrong key? Impossible de signer le message spork, mauvaise clef ? @@ -5832,6 +6270,10 @@ Allez à Fichier > Ouvrir le portefeuille pour charger un portefeuille. Unknown state: id = %u État inconnu : id = %u + + Unsupported URL scheme, must begin with udp:// + Schéma d'URL non pris en charge, doit commencer par udp:// + Unsupported logging category %s=%s. Catégorie de journalisation non supportée %s=%s. diff --git a/src/qt/locale/dash_it.ts b/src/qt/locale/dash_it.ts index e769b3ba2ae6..5d2781416b10 100644 --- a/src/qt/locale/dash_it.ts +++ b/src/qt/locale/dash_it.ts @@ -65,14 +65,6 @@ C&hoose Sc&egli - - Sending addresses - Indirizzi d'invio - - - Receiving addresses - Indirizzi di ricezione - These are your Dash addresses for sending payments. Always check the amount and the receiving address before sending coins. Questi sono i tuoi indirizzi Dash per inviare i pagamenti. Controlla sempre l'ammontare e l'indirizzo di destinazione prima di inviare i dash. @@ -115,6 +107,14 @@ An error message. %1 is a stand-in argument for the name of the file we attempted to save to. Si è verificato un errore durante il tentativo di salvare l'elenco di indirizzi in %1. Per favore riprova. + + Sending addresses - %1 + Indirizzi di invio - %1 + + + Receiving addresses - %1 + Indirizzi di ricezione - %1 + Exporting Failed Esportazione Fallita. @@ -284,10 +284,22 @@ The passphrase entered for the wallet decryption was incorrect. La passphrase inserita per la decrittazione del portafoglio è errata. + + 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 23.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. + La passphrase inserita per la decrittazione del portafoglio non è corretta. Contiene un carattere nullo (cioè un byte zero). Se la passphrase è stata impostata con una versione di questo software precedente alla 23.0, riprova con solo i caratteri fino a — ma senza includere — il primo carattere nullo. Se ha successo, imposta una nuova passphrase per evitare questo problema in futuro. + Wallet passphrase was successfully changed. Passphrases del portafoglio modificata con successo. + + Passphrase change failed + Modifica passphrase fallita + + + 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 23.0, please try again with only the characters up to — but not including — the first null character. + La vecchia passphrase inserita per la decrittazione del portafoglio non è corretta. Contiene un carattere nullo (cioè un byte zero). Se la passphrase è stata impostata con una versione di questo software precedente alla 23.0, riprova con solo i caratteri fino a — ma senza includere — il primo carattere nullo. + Warning: The Caps Lock key is on! Attenzione: il tasto Blocco maiuscole è attivo! @@ -392,10 +404,6 @@ &Load PSBT from file… &Carica PSBT dal file… - - Load PSBT from clipboard… - Carica PSBT dagli appunti… - &Sending addresses &Indirizzi di invio @@ -428,10 +436,6 @@ &Window &Finestra - - Minimize - Minimizzare - Zoom Ingrandisci @@ -484,14 +488,6 @@ Modify configuration options for %1 Modifica le opzioni di configurazione per %1 - - &Show / Hide - &Mostra / Nascondi - - - Show or hide the main Window - Mostra o nascondi la Finestra principale - Encrypt the private keys that belong to your wallet Cifra le chiavi private che appartengono al tuo portafoglio @@ -556,10 +552,6 @@ Show wallet repair options Mostrare le opzioni per riparare il portafoglio - - Open Wallet &Configuration File - Apri il &Configuration File del Portafoglio - Open configuration file Apri il file di configurazione @@ -614,10 +606,18 @@ Show information about %1 Mostra informazioni %1 + + Load PSBT from &clipboard… + Carica PSBT dagli appunti… + Open debugging and diagnostic console Aprire la console di debug e diagnostica + + Open &wallet configuration file + Apri file di configurazione del portafoglio + Open a dash: URI Apri un dash: URI @@ -626,6 +626,16 @@ Create a new wallet Crea un nuovo portafoglio + + Restore Wallet… + Name of the menu item that restores wallet from a backup file. + Ripristina portafoglio… + + + Restore a wallet from a backup file + Status tip for Restore Wallet menu item + Ripristina un portafoglio da un file di backup + Close all wallets Chiudi tutti i Wallet… @@ -646,10 +656,34 @@ Mask the values in the Overview tab Maschera i valori nella scheda Panoramica + + Wallet Data + Name of the wallet data file format. + Dati portafoglio + + + Load Wallet Backup + The title for Restore Wallet File Windows + Carica backup portafoglio + + + Restore Wallet + Title of pop-up window shown when the user is attempting to restore a wallet. + Ripristina portafoglio + + + Wallet Name + Label of the input field where the name of the wallet is entered. + Nome portafoglio + &Settings &Impostazioni + + &Minimize + &Riduci a icona + &Help &Aiuto @@ -666,6 +700,14 @@ View Governance Proposals Visualizza le Proposte di Governance + + &Hide + &Nascondi + + + S&how + &Mostra + %n active connection(s) to Dash network A substring of the tooltip. @@ -687,6 +729,14 @@ Close Wallet… Chiudi Portafoglio… + + Load Partially Signed Blockchain Transaction + Carica Transazione Blockchain Parzialmente Firmata + + + Load Partially Signed Blockchain Transaction from clipboard + Carica la Transazione Blockchain Parzialmente Firmata dagli appunti + Create Wallet… Crea portafoglio… @@ -739,10 +789,6 @@ Processing blocks on disk… Elaborazione dei blocchi su disco… - - Reindexing blocks on disk… - Re-indicizzazione blocchi su disco… - Connecting to peers… Connessione ai peers @@ -896,10 +942,6 @@ Coin Selection Selezione Moneta - - Dust: - Infinitesimale: - After Fee: Dopo Commissione: @@ -1000,10 +1042,6 @@ Copy bytes Copia byte - - Copy dust - Copia infinitesimale - Copy change Copia resto @@ -1016,18 +1054,6 @@ (%1 locked) (%1 bloccato) - - yes - - - - no - no - - - This label turns red if any recipient receives an amount smaller than the current dust threshold. - Questa etichetta diventerà rossa se uno qualsiasi dei destinatari riceverà un importo inferiore alla corrente soglia minima per la movimentazione della valuta. - Can vary +/- %1 duff(s) per input. Può variare di +/- %1 duff per input. @@ -1241,18 +1267,102 @@ Filter proposal list Filtra l'elenco delle proposal + + Masternode Count: + Conteggio Masternode: + + + Number of masternodes this wallet can vote with (masternodes for which this wallet holds the voting key) + Numero di masternode con cui questo portafoglio può votare (masternode per i quali questo portafoglio detiene la chiave di voto) + Proposal Count: Conteggio delle proposte: + + Create Proposal + Crea proposta + Filter by Title Filtra per Titolo + + Unavailable + Non disponibile + + + A synced node and an unlocked wallet are required. + È richiesto un nodo sincronizzato e un portafoglio sbloccato. + + + Vote Yes + Vota Sì + + + Vote No + Vota No + + + Vote Abstain + Vota Astenuto + Proposal Info: %1 Informazioni sulla proposta: %1 + + Voting Failed + Votazione fallita + + + No wallet available. + Nessun portafoglio disponibile. + + + No masternode voting keys found in wallet. + Nessuna chiave di voto masternode trovata nel portafoglio. + + + Please select a proposal to vote on. + Seleziona una proposta su cui votare. + + + Unable to unlock wallet. + Impossibile sbloccare il portafoglio. + + + Unable to get masternode list. Please try again later. + Impossibile ottenere l'elenco dei masternode. Riprova più tardi. + + + Masternode %1 not found + Masternode %1 non trovato + + + Failed to sign vote for masternode %1 + Impossibile firmare il voto per il masternode %1 + + + Masternode %1: %2 + Masternode %1: %2 + + + Voted successfully %n time(s) + Votato con successo %n voltaVotato con successo %n volteVotato con successo %n volte + + + Failed to vote %n time(s) + Impossibile votare %n voltaImpossibile votare %n volteImpossibile votare %n volte + + + Errors: + Errori: + + + Voting Results + Risultati della votazione + HelpMessageDialog @@ -1323,13 +1433,17 @@ Use a custom data directory: Usa una cartella dati personalizzata: - - (of %1 GB needed) - (di %1 GB necessari) + + %n GB of space available + %n GB di spazio disponibile%n GB di spazio disponibili%n GB di spazio disponibili - - (%1 GB needed for full chain) - (%1 GB necessario per la catena completa) + + (of %n GB needed) + (di %n GB necessario)(di %n GB necessari)(di %n GB necessari) + + + (%n GB needed for full chain) + (%n GB necessario per la catena completa)(%n GB necessari per la catena completa)(%n GB necessari per la catena completa) At least %1 GB of data will be stored in this directory, and it will grow over time. @@ -1361,6 +1475,13 @@ Errore + + LoadWalletsActivity + + Loading wallets… + Caricamento portafogli… + + MasternodeList @@ -1553,6 +1674,11 @@ URI: URI: + + Paste address from clipboard + Tooltip text for button that allows you to paste an address that is in your clipboard. + Incolla l'indirizzo dagli appunti + OpenWalletActivity @@ -1663,6 +1789,16 @@ An Options window setting to set subtracting the fee from a sending amount as default. Sottrai &commissione dall'importo per impostazione predefinita + + Enable &PSBT controls + An options window setting to enable PSBT controls. + Abilita controlli &PSBT + + + Whether to show PSBT controls. + Tooltip text for options window setting that enables PSBT controls. + Se mostrare i controlli PSBT. + Whether to keep the specified custom change address or not. Indica se mantenere o meno l'indirizzo di modifica personalizzato specificato. @@ -1806,20 +1942,20 @@ https://explore.transifex.com/dash/dash/ https://explore.transifex.com/dash/dash/ - Options set in this dialog are overridden by the command line or in the configuration file: - Le opzioni impostate in questa finestra di dialogo sono sovrascritte dalla riga di comando o nel file di configurazione: + Third-party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items.<br/>%s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |. + URL di terze parti (ad es. un block explorer) che appaiono nella scheda transazioni come voci del menu contestuale.<br/>%s nell'URL viene sostituito dall'hash della transazione. URL multipli sono separati da barra verticale |. - 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. - Riduci ad icona invece di uscire dall'applicazione quando la finestra viene chiusa. Attivando questa opzione l'applicazione terminerà solo dopo aver selezionato Esci dal menu File. + &Third-party transaction URLs + URL di &transazione di terze parti - Third party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items.<br/>%s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |. - URL di terze parti (es: un block explorer) che appaiono nella tabella delle transazioni come voci nel menu contestuale. <br/>%s nell'URL è sostituito dall'hash della transazione. Più URL vengono separati da una barra verticale |. + Options set in this dialog are overridden by the command line or in the configuration file: + Le opzioni impostate in questa finestra di dialogo sono sovrascritte dalla riga di comando o nel file di configurazione: - &Third party transaction URLs - &URL transazioni di terze parti + 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. + Riduci ad icona invece di uscire dall'applicazione quando la finestra viene chiusa. Attivando questa opzione l'applicazione terminerà solo dopo aver selezionato Esci dal menu File. Whether to show coin control features or not. @@ -1963,14 +2099,22 @@ https://explore.transifex.com/dash/dash/ Confirm options reset + Window title text of pop-up window shown when the user has chosen to reset options. Conferma ripristino opzioni Client restart required to activate changes. + Text explaining that the settings changed will not come into effect until the client is restarted. È necessario un riavvio del client per rendere attivi i cambiamenti. + + Current settings will be backed up at "%1". + 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. + Le impostazioni correnti verranno salvate in "%1". + Client will be shut down. Do you want to proceed? + Text asking the user to confirm if they would like to proceed with a client shutdown. Il client sarà arrestato. Si desidera procedere? @@ -2243,6 +2387,10 @@ https://explore.transifex.com/dash/dash/ Failed to sign transaction: %1 Impossibile firmare la transazione: %1 + + Cannot sign inputs while wallet is locked. + Impossibile firmare gli input mentre il wallet è bloccato. + Could not sign any more inputs. Impossibile firmare altri input. @@ -2487,6 +2635,181 @@ A causa dell'interruzione del supporto, dovresti richiedere al commerciante di f Stato + + ProposalWizard + + Create Governance Proposal + Crea proposta di governance + + + Enter proposal details + Inserisci i dettagli della proposta + + + A fee will be burned when you prepare the proposal. + Una commissione verrà bruciata quando prepari la proposta. + + + Proposal &name + &Nome proposta + + + &Description URL + URL &descrizione + + + Payment &address + &Indirizzo di pagamento + + + Payment &amount + I&mporto del pagamento + + + The amount to request in a single payment + L'importo da richiedere in un singolo pagamento + + + &First payment + &Primo pagamento + + + Pa&yments + Paga&menti + + + To&tal amount + Importo to&tale + + + Proposal &fee + &Commissione della proposta + + + Next + Avanti + + + Review proposal JSON and validate. + Rivedi il JSON della proposta e convalida. + + + Hex-encoded JSON + JSON codificato in esadecimale + + + Back + Indietro + + + Validate + Convalida + + + Prepare (burn fee) and wait for confirmations. + Prepara (brucia commissione) e attendi le conferme. + + + Copy + Copia + + + At 1/6 confirmations: can be relayed and queued. At 6/6: accepted and processed. + A 1/6 conferme: può essere inoltrato e accodato. A 6/6: accettato ed elaborato. + + + Confirmations progress + Progresso delle conferme + + + Shows progress toward the required number of confirmations for the proposal fee transaction. + Mostra il progresso verso il numero richiesto di conferme per la transazione della commissione della proposta. + + + Estimated time remaining: - + Tempo stimato rimanente: - + + + Prepare Proposal + Prepara proposta + + + You can submit after 1 confirmation. At 6 confirmations it is accepted and processed. + Puoi inviare dopo 1 conferma. A 6 conferme viene accettato ed elaborato. + + + Proposal ID: + ID proposta: + + + Submit Proposal + Invia proposta + + + Close + Chiudi + + + Valid + Valido + + + Invalid: %1 + Non valido: %1 + + + Burn %1 + Brucia %1 + + + Burn %1 to create the fee transaction? + Bruciare %1 per creare la transazione della commissione? + + + Prepare failed + Preparazione fallita + + + Confirmations: %1 / %2 required + Conferme: %1 / %2 richieste + + + Estimated time remaining: Ready + Tempo stimato rimanente: Pronto + + + Estimated time remaining: %n minute(s) + Tempo stimato rimanente: %n minutoTempo stimato rimanente: %n minutiTempo stimato rimanente: %n minuti + + + Your proposal was submitted successfully. + La tua proposta è stata inviata con successo. + + + Already submitted + Già inviato + + + This proposal has already been submitted. + Questa proposta è già stata inviata. + + + Submission failed + Invio fallito + + + Proposal submitted + Proposta inviata + + + A fee of %1 will be burned when you prepare the proposal. + Una commissione di %1 verrà bruciata quando prepari la proposta. + + + Prepare (burn %1) and wait for %2 confirmations. + Prepara (brucia %1) e attendi %2 conferme. + + QObject @@ -2876,14 +3199,6 @@ A causa dell'interruzione del supporto, dovresti richiedere al commerciante di f Version Versione - - Whether the peer requested us to relay transactions. - Se il peer ci ha richiesto di inoltrare le transazioni. - - - Wants Tx Relay - Necessario il relè Tx - High bandwidth BIP152 compact block relay: %1 Relè a blocco compatto BIP152 a larghezza di banda elevata: %1 @@ -2989,6 +3304,14 @@ A causa dell'interruzione del supporto, dovresti richiedere al commerciante di f To specify a non-default location of the blocks directory use the '%1' option. Per specificare una posizione non predefinita della directory dei blocchi, utilizzare l'opzione '%1'. + + Local Addresses + Indirizzi locali + + + Network addresses that your Dash node is currently using to communicate with other nodes. + Indirizzi di rete che il tuo nodo Dash sta attualmente utilizzando per comunicare con altri nodi. + Number of regular Masternodes Numero di Masternode regolari @@ -3081,6 +3404,14 @@ A causa dell'interruzione del supporto, dovresti richiedere al commerciante di f Services Servizi + + Whether we relay transactions to this peer. + Se inoltriamo le transazioni a questo peer. + + + Transaction Relay + Inoltro delle transazioni + Connection Time Tempo di connessione @@ -3229,6 +3560,10 @@ A causa dell'interruzione del supporto, dovresti richiedere al commerciante di f Network activity disabled Attività di rete disabilitata + + None + Nessuno + Total: %1 (Enabled: %2) Totale: %1 (Abilitato: %2) @@ -3550,6 +3885,34 @@ Per ulteriori informazioni sull'utilizzo di questa console, digitare %6. Richiesto + + RestoreWalletActivity + + Restore Wallet + Title of progress window which is displayed when wallets are being restored. + Ripristina portafoglio + + + Restoring Wallet <b>%1</b>… + Descriptive text of the restore wallets progress window which indicates to the user that wallets are currently being restored. + Ripristino portafoglio <b>%1</b>… + + + Restore wallet failed + Title of message box which is displayed when the wallet could not be restored. + Ripristino portafoglio fallito + + + Restore wallet warning + Title of message box which is displayed when the wallet is restored with some warning. + Avviso ripristino portafoglio + + + Restore wallet message + Title of message box which is displayed when the wallet is successfully restored. + Messaggio ripristino portafoglio + + SendCoinsDialog @@ -3584,10 +3947,6 @@ Per ulteriori informazioni sull'utilizzo di questa console, digitare %6. Fee: Commissione: - - Dust: - Infinitesimale: - Inputs… Input… @@ -3712,10 +4071,6 @@ Per ulteriori informazioni sull'utilizzo di questa console, digitare %6. Copy bytes Copia byte - - Copy dust - Copia infinitesimale - Copy change Copia resto @@ -3724,10 +4079,6 @@ Per ulteriori informazioni sull'utilizzo di questa console, digitare %6. %1 (%2 blocks) %1 (%2 bloccare) - - This will produce a Partially Signed Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet. - Ciò produrrà una transazione parzialmente firmata (PSBT) che potrai salvare o copiare e quindi firmare con, ad es., un wallet %1 offline o un wallet hardware compatibile con PSBT. - using utilizzando @@ -3736,10 +4087,6 @@ Per ulteriori informazioni sull'utilizzo di questa console, digitare %6. %1 to %2 %1 a %2 - - Are you sure you want to send? - Sei sicuro di voler inviare? - <b>(%1 of %2 entries displayed)</b> <b>(%1 of %2 entries displayed)</b> @@ -3764,10 +4111,6 @@ Per ulteriori informazioni sull'utilizzo di questa console, digitare %6. %1 to '%2' %1 a '%2' - - Do you want to draft this transaction? - Vuoi la bozza di questa transazione? - %1 funds only Solo fondi %1 @@ -3816,14 +4159,6 @@ Per ulteriori informazioni sull'utilizzo di questa console, digitare %6. Confirm send coins Conferma l'invio di dash - - Confirm transaction proposal - Conferma la proposta di transazione - - - Create Unsigned - Crea senza Firma - Save Transaction Data Salva i Dati della Transazione @@ -3837,8 +4172,28 @@ Per ulteriori informazioni sull'utilizzo di questa console, digitare %6. Watch-only saldo: - Send - Invia + Creates a Partially Signed Blockchain Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet. + Crea una Transazione Blockchain Parzialmente Firmata (PSBT - Partially Signed Blockchain Transaction) da utilizzare, ad esempio, con un wallet %1 offline o un wallet hardware compatibile con PSBT. + + + Do you want to create this transaction? + 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. + Vuoi creare questa transazione? + + + Please, review your transaction proposal. This will produce a Partially Signed Blockchain Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet. + 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. + Rivedi la tua proposta di transazione. Questo produrrà una Transazione Blockchain Parzialmente Firmata (PSBT) che puoi salvare o copiare e poi firmare con ad es. un portafoglio %1 offline o un portafoglio hardware compatibile con PSBT. + + + Please, review your transaction. You can create and send this transaction or create a Partially Signed Blockchain Transaction (PSBT), which you can save or copy and then sign with, e.g., an offline %1 wallet, or a PSBT-compatible hardware wallet. + 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. + Rivedi la tua transazione. Puoi creare e inviare questa transazione o creare una Transazione Blockchain Parzialmente Firmata (PSBT), che puoi salvare o copiare e poi firmare con, ad es., un portafoglio %1 offline o un portafoglio hardware compatibile con PSBT. + + + Please, review your transaction. + Text to prompt a user to review the details of the transaction they are attempting to send. + Rivedi la tua transazione. To review recipient list click "Show Details…" @@ -3968,21 +4323,16 @@ Per ulteriori informazioni sull'utilizzo di questa console, digitare %6. A message that was attached to the dash: URI which will be stored with the transaction for your reference. Note: This message will not be sent over the Dash network. Un messaggio allegato con l'URI dash che verrà memorizzato nella transazione per il tuo referente. Nota: questo messaggio non verrà inviato attraverso il network Dash. + + + SendConfirmationDialog - This is an unauthenticated payment request. - Questa è una richiesta di pagamento non autenticata. - - - This is an authenticated payment request. - Questa è una richiesta di pagamento autenticata. - - - Pay To: - Pagare a: + Send + Invia - Memo: - Memo: + Create Unsigned + Crea non firmato @@ -4191,20 +4541,9 @@ Per ulteriori informazioni sull'utilizzo di questa console, digitare %6. TransactionDesc - - Open for %n more block(s) - Aperto per %n blocco in piúAperto per %n blocchi in piúAperto per %n blocchi in piú - - - Open until %1 - Aperto fino a %1 - - - conflicted - in conflitto - 0/unconfirmed, %1 + 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. 0/non confermati, %1 @@ -4217,22 +4556,32 @@ Per ulteriori informazioni sull'utilizzo di questa console, digitare %6. abandoned + 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. Abbandonato + + conflicted with a transaction with %1 confirmations + 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. + in conflitto con una transazione con %1 conferme + %1/unconfirmed + 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, and still not locked via ChainLocks. %1/non confermato %1 confirmations + 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 or locked via ChainLocks. %1 conferme locked via ChainLocks + 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 and has been locked by ChainLocks. bloccati tramite ChainLocks verified via InstantSend + 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 has been locked by InstantSend. verificati tramite InstantSend @@ -4385,14 +4734,6 @@ Per ulteriori informazioni sull'utilizzo di questa console, digitare %6. Address / Label Indirizzo / Etichetta - - Open for %n more block(s) - Aperto per %n blocco in piúAperto per %n blocchi in piúAperto per %n blocchi in piú - - - Open until %1 - Aperto fino a %1 - Unconfirmed Non confermato @@ -4644,6 +4985,11 @@ Per ulteriori informazioni sull'utilizzo di questa console, digitare %6. Show address &QR code Mostra indirizzo e codice &QR + + Show in %1 + 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. + Mostra in %1 + Export Transaction History Esporta lo storico delle transazioni @@ -4836,10 +5182,6 @@ Vai su File > Apri Wallet per caricare un Wallet. dash-core - - Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee. - Stima della tariffa non riuscita. La commissione di riserva è disabilitata. Attendi qualche blocco o abilita -fallbackfee. - 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 Questo errore potrebbe verificarsi se questo portafoglio non è stato arrestato in modo corretto ed è stato caricato l'ultima volta utilizzando una build con una versione più recente di Berkeley DB. In tal caso, utilizzare l'ultimo software che ha caricato questo portafoglio @@ -4912,10 +5254,6 @@ Vai su File > Apri Wallet per caricare un Wallet. Failed to listen on any port. Use -listen=0 if you want this. Nessuna porta disponibile per l'ascolto. Usa -listen=0 se vuoi procedere comunque. - - -maxtxfee is set very high! Fees this large could be paid on a single transaction. - -maxtxfee è impostato a molto alto! Commissioni così alte possono venir pagate anche su una singola transazione. - Found unconfirmed denominated outputs, will wait till they confirm to continue. Trovati output denominati non confermati, in attesa delle conferme per continuare. @@ -4924,10 +5262,6 @@ Vai su File > Apri Wallet per caricare un Wallet. Invalid -socketevents ('%s') specified. Only these modes are supported: %s Specificato -socketevents ('%s') non valido. Sono supportate solo queste modalità: %s - - Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions) - Importo non valido per -maxtxfee=<amount>: '%s' (deve essere almeno pari alla commissione 'minrelay fee' di %s per prevenire transazioni bloccate) - SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is supported SQLiteDatabase: schema del wallet sqlite alla versione sconosciuta %d. È supportata solo la versione %d @@ -4936,6 +5270,10 @@ Vai su File > Apri Wallet per caricare un Wallet. Transaction index can't be disabled with governance validation enabled. Either start with -disablegovernance command line switch or enable transaction index. L'indice di transazione non può essere disabilitato con la convalida della governance abilitata. Inizia con l'opzione della riga di comando -disablegovernance o abilita l'indice delle transazioni. + + Unsupported category-specific logging level -loglevel=%s. Expected -loglevel=<category>:<loglevel>. Valid categories: %s. Valid loglevels: %s. + Livello di registrazione specifico della categoria non supportato -loglevel=%s. Previsto -loglevel=<category>:<loglevel>. Categorie valide: %s. Livelli di registrazione validi: %s. + Can't mix: no compatible inputs found! Impossibile effettuare il mixing: nessun input compatibile trovato! @@ -4944,6 +5282,14 @@ Vai su File > Apri Wallet per caricare un Wallet. Entry exceeds maximum size. L'ingresso supera la dimensione massima. + + Error upgrading evo database for EHF + Errore durante l'aggiornamento del database evo per EHF + + + Failed to commit Evo database + Impossibile eseguire il database Evo + Found enough users, signing ( waiting %s ) Trovati utenti sufficienti, firma (in attesa di %s) @@ -4968,18 +5314,14 @@ Vai su File > Apri Wallet per caricare un Wallet. Insufficient funds. Fondi insufficienti. - - Invalid amount for -discardfee=<amount>: '%s' - Importo non valido per -discardfee=<amount>: '%s' - - - Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s) - Importo non valido per -paytxfee=<amount>: '%s' (deve essere almeno %s) - Invalid minimum number of spork signers specified with -minsporkkeys Numero minimo non valido di firmatari di spork specificato con -minsporkkeys + + Listening for incoming connections failed (listen returned error %s) + L'ascolto delle connessioni in arrivo non è riuscito (l'ascolto ha restituito l'errore %s) + Lock is already in place. Il blocco è già presente. @@ -5036,6 +5378,10 @@ Vai su File > Apri Wallet per caricare un Wallet. Synchronizing governance objects… Sincronizzazione degli oggetti di governance … + + Transaction change output index out of range + Indice di output della modifica della transazione fuori intervallo + Unable to start HTTP server. See debug log for details. Impossibile avviare il server HTTP. Dettagli nel log di debug. @@ -5044,6 +5390,10 @@ Vai su File > Apri Wallet per caricare un Wallet. Unknown response. Risposta sconosciuta. + + Unsupported global logging level -loglevel=%s. Valid values: %s. + Livello di registrazione globale non supportato -loglevel=%s. Valori validi: %s. + User Agent comment (%s) contains unsafe characters. Il commento del User Agent (%s) contiene caratteri non sicuri. @@ -5108,10 +5458,6 @@ Vai su File > Apri Wallet per caricare un Wallet. Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments. La lunghezza totale della stringa di network version (%i) eccede la lunghezza massima (%i). Ridurre il numero o la dimensione di uacomments. - - Transaction needs a change address, but we can't generate it. Please call keypoolrefill first. - La transazione richiede un indirizzo di modifica, ma non possiamo generarlo. Per favore chiama prima KeypoolRefill. - WARNING! Failed to replenish keypool, please unlock your wallet to do so. ATTENZIONE! Impossibile riempire il keypool, per favore sblocca il tuo portafoglio per farlo .. @@ -5188,10 +5534,6 @@ Vai su File > Apri Wallet per caricare un Wallet. Error: No addresses available. Errore: nessun indirizzo disponibile. - - Exceeded max tries. - Numero massimo di tentativi superato. - Failed to create backup %s! Impossibile creare il backup %s! @@ -5232,10 +5574,6 @@ Vai su File > Apri Wallet per caricare un Wallet. Invalid P2P permission: '%s' Autorizzazione P2P non valida: '%s' - - Invalid amount for -fallbackfee=<amount>: '%s' - Importo non valido per -fallbackfee=<amount>: '%s' - Invalid masternodeblsprivkey. Please see documentation. Invalid masternodeblsprivkey. Per favore vedi documentazione. @@ -5372,10 +5710,6 @@ Vai su File > Apri Wallet per caricare un Wallet. Unable to open %s for writing Impossibile aprire %s in scrittura - - Unable to parse -maxuploadtarget: '%s' (possible integer overflow?) - Impossibile analizzare -maxuploadtarget: '%s' (possibile overflow del numero intero?) - Unknown -blockfilterindex value %s. Sconosciuto - valore blockfilterindex %s. @@ -5384,10 +5718,6 @@ Vai su File > Apri Wallet per caricare un Wallet. Unknown new rules activated (versionbit %i) Nuove regole sconosciute attivate (versione bit %i) - - Upgrading UTXO database - Aggiornamento del database UTXO - Verifying blocks… Verifica blocchi… @@ -5448,10 +5778,6 @@ Vai su File > Apri Wallet per caricare un Wallet. Cannot obtain a lock on data directory %s. %s is probably already running. Non è possibile ottenere i dati sulla cartella %s. Probabilmente %s è già in esecuzione. - - Cannot upgrade a non HD wallet from version %i to version %i which is non-HD wallet. Use upgradetohd RPC - Impossibile aggiornare un portafoglio non HD dalla versione %i alla versione %i che è un portafoglio non HD. Utilizza l'RPC upgradetohd - Distributed under the MIT software license, see the accompanying file %s or %s Distribuito sotto licenza MIT del software, si veda il file %s o %s incluso @@ -5484,6 +5810,10 @@ Vai su File > Apri Wallet per caricare un Wallet. Failed to rename invalid peers.dat file. Please move or delete it and try again. Impossibile rinominare il file peers.dat non valido. Spostalo o eliminalo e riprova. + + Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable %s. + Stima della commissione fallita. Fallbackfee è disabilitato. Attendi alcuni blocchi o abilita %s. + File %s already exists. If you are sure this is what you want, move it out of the way first. Il file %s esiste già. Se sei sicuro che questo sia ciò che desideri, spostalo prima di mezzo. @@ -5496,6 +5826,10 @@ Vai su File > Apri Wallet per caricare un Wallet. Incorrect or no devnet genesis block found. Wrong datadir for devnet specified? Rilevato blocco genesi di devnet errato o inesistente. È stato specificato un datadir errato per devnet? + + Invalid amount for %s=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions) + Importo non valido per %s=<amount>: '%s' (deve essere almeno la commissione minrelay di %s per evitare transazioni bloccate) + 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. Peers.dat (%s) non valido o danneggiato. Se ritieni che questo sia un bug, segnalalo a %s. Come soluzione alternativa, è possibile spostare il file (%s) da parte (rinominarlo, spostarlo o eliminarlo) per crearne uno nuovo al successivo avvio. @@ -5512,6 +5846,10 @@ Vai su File > Apri Wallet per caricare un Wallet. No wallet file format provided. To use createfromdump, -format=<format> must be provided. Nessun formato di file del portafoglio fornito. Per utilizzare createfromdump, -format=<format> deve essere fornito. + + Outbound connections restricted to CJDNS (-onlynet=cjdns) but -cjdnsreachable is not provided + Connessioni in uscita limitate a CJDNS (-onlynet=cjdns) ma -cjdnsreachable non è fornito + Outbound connections restricted to Tor (-onlynet=onion) but the proxy for reaching the Tor network is explicitly forbidden: -onion=0 Connessioni in uscita limitate a Tor (-onlynet=onion) ma il proxy per raggiungere la rete Tor è esplicitamente vietato: -onion=0 @@ -5520,6 +5858,10 @@ Vai su File > Apri Wallet per caricare un Wallet. 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 Connessioni in uscita limitate a Tor (-onlynet=onion) ma non viene fornito il proxy per raggiungere la rete Tor: non viene fornito nessuno tra -proxy, -onion o -listenonion + + Outbound connections restricted to i2p (-onlynet=i2p) but -i2psam is not provided + Connessioni in uscita limitate a i2p (-onlynet=i2p) ma -i2psam non è fornito + Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly. Per favore controllare che la data del computer e l'ora siano corrette! Se il vostro orologio è sbagliato %s non funzionerà correttamente. @@ -5532,10 +5874,6 @@ Vai su File > Apri Wallet per caricare un Wallet. Prune mode is incompatible with -reindex-chainstate. Use full -reindex instead. La modalità Prune è incompatibile con -reindex-chainstate. Utilizzare invece full -reindex. - - The block index db contains a legacy 'txindex'. To clear the occupied disk space, run a full -reindex, otherwise ignore this error. This error message will not be displayed again. - Il database dell'indice del blocco contiene un "txindex" legacy. Per liberare lo spazio su disco occupato, esegui un -reindex completo, altrimenti ignora questo errore. Questo messaggio di errore non verrà più visualizzato. - This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection. Questa è la commissione di transazione massima che paghi (in aggiunta alla commissione normale) per dare priorità all'elusione della spesa parziale rispetto alla normale selezione delle monete. @@ -5548,6 +5886,10 @@ Vai su File > Apri Wallet per caricare un Wallet. This is the transaction fee you may pay when fee estimates are not available. Questo è il costo di transazione che potresti pagare quando le stime della fee non sono disponibili. + + Transaction requires one destination of non-0 value, a non-0 feerate, or a pre-selected input + La transazione richiede una destinazione di valore diverso da 0, una feerate diversa da 0 o un input preselezionato + Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate. Impossibile riprodurre i blocchi. Dovrai ricostruire il database usando -reindex-chainstate. @@ -5556,6 +5898,10 @@ Vai su File > Apri Wallet per caricare un Wallet. Unknown wallet file format "%s" provided. Please provide one of "bdb" or "sqlite". Formato file portafoglio sconosciuto "%s" fornito. Fornisci uno tra "bdb" o "sqlite". + + Unsupported chainstate database format found. Please restart with -reindex-chainstate. This will rebuild the chainstate database. + Trovato formato database chainstate non supportato. Riavvia con -reindex-chainstate. Questo ricostruirà il database chainstate. + Warning: Dumpfile wallet format "%s" does not match command line specified format "%s". Avviso: il formato del portafoglio dumpfile "%s" non corrisponde al formato "%s" specificato dalla riga di comando. @@ -5596,10 +5942,30 @@ Vai su File > Apri Wallet per caricare un Wallet. -rpcport must be specified when -devnet and -server are specified -rpcport deve essere specificato quando -devnet e -server sono specificati + + -statsbatchsize cannot be configured with a negative value. + -statsbatchsize non può essere configurato con un valore negativo. + + + -statsduration cannot be configured with a negative value. + -statsduration non può essere configurato con un valore negativo. + A fatal internal error occurred, see debug.log for details Si è verificato un errore interno irreversibile, vedere debug.log per i dettagli + + Cannot create socket (socket() returned error %s) + Impossibile creare socket (socket() ha restituito l'errore %s) + + + Cannot get socket address for %s + Impossibile ottenere l'indirizzo socket per %s + + + Cannot init Statsd client + Impossibile inizializzare il client Statsd + Cannot resolve -%s address: '%s' Impossobile risolvere l'indirizzo -%s: '%s' @@ -5644,10 +6010,6 @@ Vai su File > Apri Wallet per caricare un Wallet. Error reading next record from wallet database Errore durante la lettura del record successivo dal database del portafoglio - - Error upgrading chainstate database - Errore durante l'aggiornamento del database chainstate - Loading P2P addresses… Caricamento indirizzi P2P… @@ -5768,10 +6130,70 @@ Vai su File > Apri Wallet per caricare un Wallet. %s corrupt. Try using the wallet tool dash-wallet to salvage or restoring a backup. %s danneggiato. Prova a utilizzare lo strumento portafoglio dash-wallet per salvare o ripristinare un backup. + + %s is set very high! Fees this large could be paid on a single transaction. + %s è impostato molto alto! Commissioni così elevate potrebbero essere pagate in una singola transazione. + + + %s request to listen on port %u. This port is considered "bad" and thus it is unlikely that any Dash Core peers connect to it. See doc/p2p-bad-ports.md for details and a full list. + %s richiesta di ascolto sulla porta %u. Questa porta è considerata "cattiva" e quindi è improbabile che qualsiasi peer di Dash Core vi si connetta. Consultare doc/p2p-bad-ports.md per i dettagli e un elenco completo. + + + Cannot provide specific connections and have addrman find outgoing connections at the same time. + Non è possibile fornire connessioni specifiche e far sì che addrman trovi contemporaneamente le connessioni in uscita. + + + Failed to upgrade Evo database + Impossibile aggiornare il database Evo + + + Fee needed > fee paid + Commissione necessaria > commissione pagata + + + Host %s on unsupported network + Host %s su rete non supportata + + + Invalid amount for %s=<amount>: '%s' (must be at least %s) + Importo non valido per %s=<amount>: '%s' (deve essere almeno %s) + + + Invalid amount for %s=<amount>: '%s' + Importo non valido per %s=<amount>: '%s' + + + Invalid port specified in %s: '%s' + Porta non valida specificata in %s: '%s' + Last successful action was too recent. Ultima azione successo era troppo recente. + + Missing solving data for estimating transaction size + Dati di risoluzione mancanti per la stima della dimensione della transazione + + + No host specified + Nessun host specificato + + + No host specified, malformed URL + Nessun host specificato, URL malformato + + + No text before the scheme delimiter, malformed URL + Nessun testo prima del delimitatore dello schema, URL malformato + + + Port must be between %d and %d, supplied %d + La porta deve essere tra %d e %d, fornito %d + + + Socket not initialized, cannot send message + Socket non inizializzato, impossibile inviare il messaggio + The source code is available from %s. Il codice sorgente è disponibile in %s @@ -5800,6 +6222,10 @@ Vai su File > Apri Wallet per caricare un Wallet. Transaction fees are too high. Le commissioni della transazione sono troppo alte. + + Transaction needs a change address, but we can't generate it. + La transazione necessita di un indirizzo di resto, ma non possiamo generarlo. + Transaction not valid. Transazione non valida @@ -5820,6 +6246,18 @@ Vai su File > Apri Wallet per caricare un Wallet. Unable to locate enough non-denominated funds for this transaction. Impossibile trovare fondi non denominati sufficienti per questa transazione. + + Unable to lookup host %s + Impossibile cercare l'host %s + + + Unable to parse -maxuploadtarget: '%s' + Impossibile analizzare -maxuploadtarget: '%s' + + + Unable to send message to %s (::sendto() returned error %s) + Impossibile inviare il messaggio a %s (::sendto() ha restituito l'errore %s) + Unable to sign spork message, wrong key? Impossibile firmare messaggio Spork, chiave sbagliata? @@ -5832,6 +6270,10 @@ Vai su File > Apri Wallet per caricare un Wallet. Unknown state: id = %u Stato sconosciuto: id =%u + + Unsupported URL scheme, must begin with udp:// + Schema URL non supportato, deve iniziare con udp:// + Unsupported logging category %s=%s. Categoria di registrazione non supportata %s=%s. diff --git a/src/qt/locale/dash_ja.ts b/src/qt/locale/dash_ja.ts index 3dd1da7d7d35..2417997daede 100644 --- a/src/qt/locale/dash_ja.ts +++ b/src/qt/locale/dash_ja.ts @@ -15,7 +15,7 @@ &New - 新規(&N) + 新規 (&N) Copy the currently selected address to the system clipboard @@ -23,7 +23,7 @@ &Copy - コピー(&C) + コピー (&C) Show QR code for the currently selected address @@ -31,7 +31,7 @@ &Show QR code - &QRコードを表示 + QRコードを表示する (&S) Delete the currently selected address from the list @@ -39,7 +39,7 @@ &Delete - 削除(&D) + 削除 (&D) Export the data in the current tab to a file @@ -51,7 +51,7 @@ C&lose - 閉じる(&C) + 閉じる (&L) Choose the address to send coins to @@ -63,15 +63,7 @@ C&hoose - 選択(&H) - - - Sending addresses - 送金アドレス - - - Receiving addresses - 受取アドレス + 選択 (&H) These are your Dash addresses for sending payments. Always check the amount and the receiving address before sending coins. @@ -83,7 +75,7 @@ &Copy Address - アドレスをコピー (&C) + アドレスをコピー (&A) Copy &Label @@ -94,8 +86,8 @@ 編集 (&E) - &Show address QR code - &アドレスのQRコードを表示 + Show address &QR code + アドレスとQRコードを表示する (&Q) QR code @@ -105,6 +97,24 @@ Export Address List アドレスのリストをエクスポート + + Comma separated file + Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values. + カンマ区切りのファイル + + + There was an error trying to save the address list to %1. Please try again. + An error message. %1 is a stand-in argument for the name of the file we attempted to save to. + アドレスリストを%1に保存しようとした際にエラーが発生しました。もう一度お試しください。 + + + Sending addresses - %1 + 送信アドレス - %1 + + + Receiving addresses - %1 + 受信アドレス - %1 + Exporting Failed エクスポート失敗 @@ -200,7 +210,7 @@ Unlock wallet - ウォレットをアンロック + ウォレットをアンロックする Change passphrase @@ -274,10 +284,22 @@ The passphrase entered for the wallet decryption was incorrect. 入力されたウォレットの暗号化解除のパスフレーズが正しくありません。 + + 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 23.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. + ウォレットの復号に入力されたパスフレーズが正しくありません。null文字(ゼロバイト)が含まれています。23.0より前のバージョンのソフトウェアでパスフレーズを設定した場合は、最初のnull文字の前まで(null文字は含めず)の文字のみで再試行してください。成功した場合は、今後この問題を回避するために新しいパスフレーズを設定してください。 + Wallet passphrase was successfully changed. ウォレットのパスフレーズが変更されました。 + + Passphrase change failed + パスフレーズの変更に失敗しました + + + 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 23.0, please try again with only the characters up to — but not including — the first null character. + ウォレットの復号に入力された古いパスフレーズが正しくありません。null文字(ゼロバイト)が含まれています。23.0より前のバージョンのソフトウェアでパスフレーズを設定した場合は、最初のnull文字の前まで(null文字は含めず)の文字のみで再試行してください。 + Warning: The Caps Lock key is on! 警告:Caps Lockキーがオンになっています! @@ -303,12 +325,28 @@ BitcoinApplication - + + Runaway exception + ランナウェイの例外 + + + A fatal error occurred. %1 can no longer continue safely and will quit. + 重大なエラーが発生しました。%1は安全に継続できなくなったため、中止します。 + + + Internal error + 内部エラー + + + An internal error occurred. %1 will attempt to continue safely. This is an unexpected bug which can be reported as described below. + 内部エラーが発生しました。%1が安全に続行できるよう試みます。これは想定外のバグであり、下記の手順で報告できます。 + + BitcoinGUI &Overview - 概要(&O) + 概要 (&O) Show general overview of wallet @@ -316,7 +354,7 @@ &Send - 送金 (&S) + 送金する (&S) Send coins to a Dash address @@ -324,23 +362,27 @@ &Receive - 受取 (&R) + 入金する (&R) Request payments (generates QR codes and dash: URIs) 送金を要求 (QRコードとdash:URIを生成) + + Ctrl+Q + Ctrl+Q + &Options… オプション… (&O) &Encrypt Wallet… - ウォレットの暗号化… (&E) + ウォレットを暗号化する… (&E) &Backup Wallet… - ウォレットのバックアップ… (&B) + ウォレットをバックアップする… (&B) &Change Passphrase… @@ -348,15 +390,19 @@ &Unlock Wallet… - ウォレットをアンロック…(&U) + ウォレットをアンロックする… (&U) Sign &message… - メッセージの署名… (&M) + メッセージを署名する… (&M) &Verify message… - メッセージの検証… (&V) + メッセージを検証する… (&V) + + + &Load PSBT from file… + ファイルからPSBTをロード... (&L) &Sending addresses @@ -390,10 +436,6 @@ &Window ウインドウ (&W) - - Minimize - 最小化する - Zoom ズーム @@ -404,7 +446,7 @@ &Transactions - トランザクション(&T) + トランザクション (&T) Browse transaction history @@ -412,7 +454,7 @@ &Masternodes - マスターノード(&M) + マスターノード (&M) Browse masternodes @@ -420,7 +462,7 @@ E&xit - 終了(&X) + 終了 (&X) Quit application @@ -428,7 +470,7 @@ About &Qt - Qtについて(&Q) + Qtについて (&Q) Show information about Qt @@ -446,14 +488,6 @@ Modify configuration options for %1 %1 の設定を変更 - - &Show / Hide - 表示/非表示 (&S) - - - Show or hide the main Window - メインウインドウを表示または非表示 - Encrypt the private keys that belong to your wallet あなたのウォレットの秘密鍵を暗号化 @@ -468,11 +502,11 @@ Unlock wallet - ウォレットをアンロック + ウォレットをアンロックする &Lock Wallet - ウォレットをロック(&L) + ウォレットをロックする (&L) Sign messages with your Dash addresses to prove you own them @@ -492,11 +526,11 @@ &Debug console - デバッグコンソール(&D) + デバッグコンソール (&D) &Network Monitor - ネットワークモニタ(&N) + ネットワークモニター (&N) Show network monitor @@ -504,7 +538,7 @@ &Peers list - ネットワークのピアのリスト(&P) + ピアのリスト (&P) Show peers info @@ -512,23 +546,19 @@ Wallet &Repair - ウォレットの修復(&R) + ウォレットの修復 (&R) Show wallet repair options ウォレットの修復オプションを表示 - - Open Wallet &Configuration File - ウォレット設定ファイルを開く(&C) - Open configuration file 設定ファイルを開く Show Automatic &Backups - 自動バックアップを表示(&B) + 自動バックアップを表示 (&B) Show automatically created wallet backups @@ -569,31 +599,93 @@ &File - ファイル(&F) + ファイル (&F) Show information about %1 %1の情報を表示する + + Load PSBT from &clipboard… + クリップボードからPSBTを読み込む(&C)… + + + Open debugging and diagnostic console + デバッグおよび診断コンソールを開く + + + Open &wallet configuration file + ウォレット設定ファイルを開く(&W) + + + Open a dash: URI + dashを開く: URI + Create a new wallet 新しいウォレットを作成する + + Restore Wallet… + Name of the menu item that restores wallet from a backup file. + ウォレットを復元… + + + Restore a wallet from a backup file + Status tip for Restore Wallet menu item + バックアップファイルからウォレットを復元する + + + Close all wallets + 全てのウォレットを閉じる + %1 &information - %1と情報 + %1の情報 (&I) Show the %1 basic information %1の基本情報を表示する + + &Discreet mode + 非表示モード (&D) + + + Mask the values in the Overview tab + 概要タブの値を非表示にする(&M) + + + Wallet Data + Name of the wallet data file format. + ウォレットデータ + + + Load Wallet Backup + The title for Restore Wallet File Windows + ウォレットバックアップを読み込む + + + Restore Wallet + Title of pop-up window shown when the user is attempting to restore a wallet. + ウォレットを復元 + + + Wallet Name + Label of the input field where the name of the wallet is entered. + ウォレット名 + &Settings - 設定(&S) + 設定 (&S) + + + &Minimize + 最小化(&M) &Help - ヘルプ(&H) + ヘルプ (&H) Tabs toolbar @@ -601,14 +693,23 @@ &Governance - ガバナンス(&G) + ガバナンス (&G) View Governance Proposals ガバナンス提案を見る + + &Hide + 非表示(&H) + + + S&how + 表示(&H) + %n active connection(s) to Dash network + A substring of the tooltip. %n アクティブコネクション @@ -625,12 +726,52 @@ Close Wallet… - ウォレットを閉じる… + ウォレットを閉じます… + + + Load Partially Signed Blockchain Transaction + 一部署名済みのブロックチェーン取引をロード + + + Load Partially Signed Blockchain Transaction from clipboard + クリップボードから一部署名済みのブロックチェーン取引をロード Create Wallet… ウォレットを作成する… + + Close All Wallets… + 全てのウォレットを閉じます... + + + Ctrl+Shift+D + Ctrl+Shift+D + + + Ctrl+M + Ctrl+M + + + Click for more actions. + A substring of the tooltip. "More actions" are available via the context menu. + その他の操作を行う場合はクリックします。 + + + Show Peers tab + A context menu item. The "Peers tab" is an element of the "Node window". + ピアのタブを表示する + + + Disable network activity + A context menu item. + ネットワーク接続を無効にする + + + Enable network activity + A context menu item. The network activity was disabled previously. + ネットワーク接続を有効にする + Syncing Headers (%1%)… ヘッダーを同期しています (%1%)… @@ -647,10 +788,6 @@ Processing blocks on disk… ディスク上のブロックを処理中… - - Reindexing blocks on disk… - ディスク上のブロックのインデックスを再作成中… - Connecting to peers… ピアに接続中… @@ -804,10 +941,6 @@ Coin Selection コイン選択 - - Dust: - ダスト: - After Fee: 手数料差引後: @@ -865,28 +998,32 @@ 検証済み - Copy address - アドレスをコピー + Copy amount + 金額をコピー - Copy label - ラベルをコピー + &Copy address + アドレスをコピー (&A) - Copy amount - 金額をコピー + Copy &label + ラベルをコピー (&L) + + + Copy &amount + 金額をコピー (&A) - Copy transaction ID - 取引 ID をコピー + Copy transaction &ID and output index + 取引IDとアウトプットインデックスをコピー (&I) - Lock unspent - 未送金トランザクションをロック + L&ock unspent + 未使用分をロック (&U) - Unlock unspent - 未送金トランザクションをアンロック + &Unlock unspent + 未使用分をロック解除 (&U) Copy quantity @@ -904,10 +1041,6 @@ Copy bytes バイト数をコピー - - Copy dust - ダストをコピー - Copy change チェンジアドレスをコピー @@ -920,18 +1053,6 @@ (%1 locked) (%1 がロック中) - - yes - はい - - - no - いいえ - - - This label turns red if any recipient receives an amount smaller than the current dust threshold. - 受取額が現在のダスト閾値を下回る場合にはこのラベルは赤くなります。 - Can vary +/- %1 duff(s) per input. インプットごとに +/- %1 duff(s) が変更可能 @@ -975,8 +1096,14 @@ CreateWalletActivity + + Create Wallet + Title of window indicating the progress of creation of a new wallet. + ウォレットを作成する + Creating Wallet <b>%1</b>… + Descriptive text of the create wallet progress window which indicates to the user which wallet is currently being created. ウォレット<b>%1</b>を作成… @@ -998,6 +1125,10 @@ Wallet Name ウォレット名 + + Wallet + ウォレット + Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice. ウォレットを暗号化します。ウォレットは、お客様が選んだパスフレーズで暗号化されます。 @@ -1006,6 +1137,10 @@ Encrypt Wallet ウォレットを暗号化する + + Advanced Options + 高機能オプション + 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. このウォレットのプライベートキーを無効にします。プライベートキーを無効にしたウォレットは、プライベートキーを持たず、HDシードやインポートされたプライベートキーを持つことができなくなります。これは時計専用のウォレットに最適です。 @@ -1022,11 +1157,23 @@ Make Blank Wallet ブランクウォレットを作成する + + Use descriptors for scriptPubKey management. This feature is well-tested but still considered experimental and not recommended for use yet. + ScriptPubKeyの管理には、Descriptorを使用してください。この機能は十分にテストされていますが、まだ実験的なものと見なされており、現時点では使用は推奨されていません。 + + + Descriptor Wallet (EXPERIMENTAL) + Descriptor Wallet (試験的) + Create 作成 - + + Compiled without sqlite support (required for descriptor wallets) + SQLiteのサポートなしでコンパイル (Descriptor Walletには必須) + + EditAddressDialog @@ -1035,7 +1182,7 @@ &Label - ラベル(&L) + ラベル (&L) The label associated with this address list entry @@ -1115,18 +1262,106 @@ Filter List: フィルターリスト: + + Filter proposal list + 提案リストを絞り込む + + + Masternode Count: + マスターノード数: + + + Number of masternodes this wallet can vote with (masternodes for which this wallet holds the voting key) + このウォレットで投票できるマスターノードの数(このウォレットが投票キーを保持しているマスターノード) + Proposal Count: 提案回数: + + Create Proposal + 提案を作成 + Filter by Title タイトルで絞り込む + + Unavailable + 利用不可 + + + A synced node and an unlocked wallet are required. + 同期されたノードとロック解除されたウォレットが必要です。 + + + Vote Yes + 賛成票を投じる + + + Vote No + 反対票を投じる + + + Vote Abstain + 棄権票を投じる + Proposal Info: %1 提案情報:%1 + + Voting Failed + 投票に失敗しました + + + No wallet available. + ウォレットが利用できません。 + + + No masternode voting keys found in wallet. + ウォレットにマスターノード投票キーが見つかりません。 + + + Please select a proposal to vote on. + 投票する提案を選択してください。 + + + Unable to unlock wallet. + ウォレットのロックを解除できません。 + + + Unable to get masternode list. Please try again later. + マスターノードリストを取得できません。後でもう一度お試しください。 + + + Masternode %1 not found + マスターノード %1 が見つかりません + + + Failed to sign vote for masternode %1 + マスターノード %1 の投票への署名に失敗しました + + + Masternode %1: %2 + マスターノード %1: %2 + + + Voted successfully %n time(s) + %n 回の投票に成功しました + + + Failed to vote %n time(s) + %n 回の投票に失敗しました + + + Errors: + エラー: + + + Voting Results + 投票結果 + HelpMessageDialog @@ -1166,10 +1401,26 @@ As this is the first time the program is launched, you can choose where %1 will store its data. これは本プログラムの最初の起動です。%1 がデータを保存する場所を選択して下さい。 + + Limit block chain storage to + ブロックチェーンのストレージを制限する + + + 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. + この設定を元に戻すには、ブロックチェーン全体を再ダウンロードする必要があります。最初にブロックチェーン全体をダウンロードし、その後で削除する方が早いです。一部の高度な機能を無効にします。 + + + GB + GB + 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. この初期同期には多大なリソースを消費し、あなたのコンピュータでこれまで見つからなかったハードウェア上の問題が発生する場合があります。%1 を実行する度に、中断された時点からダウンロードを再開します。 + + 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. + OKをクリックすると、%4が最初にローンチされた際に、%3内の最も古い取引から始まり、%1が%4のブロックチェーン(%2GB)全体をダウンロードおよび処理します。 + 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. ブロックチェーンの保存容量に制限を設けることを選択した場合 (剪定) にも、過去のデータのダウンロードおよび処理が必要になります。しかし、これらのデータはディスク使用量を低く抑えるために、後で削除されます。 @@ -1182,6 +1433,18 @@ Use a custom data directory: 任意のデータディレクトリを使用: + + %n GB of space available + %n GB の空き容量があります + + + (of %n GB needed) + (必要な %n GB のうち) + + + (%n GB needed for full chain) + (完全なチェーンには %n GB が必要です) + At least %1 GB of data will be stored in this directory, and it will grow over time. 少なくとも%1GBのデータをこのディレクトリに保存する必要があります。またこのデータは時間とともに増加していきます。 @@ -1190,6 +1453,11 @@ Approximately %1 GB of data will be stored in this directory. おおむね%1GBのデータがこのディレクトリに保存されます。 + + (sufficient to restore backups %n day(s) old) + Explanatory text on the capability of the current prune target. + (%n日前のバックアップを復元するのに十分) + %1 will download and store a copy of the Dash block chain. %1はDashのブロックチェーンの複製をダウンロードし保存します。 @@ -1207,6 +1475,13 @@ エラー + + LoadWalletsActivity + + Loading wallets… + ウォレットを読み込んでいます… + + MasternodeList @@ -1241,6 +1516,10 @@ Service サービス + + Type + タイプ + PoSe Score PoSeスコア @@ -1376,6 +1655,10 @@ Hide 非表示 + + %1 is currently syncing. It will download headers and blocks from peers and validate them until reaching the tip of the block chain. + %1は現在同期中です。ピアからヘッダーとブロックをダウンロードし、ブロックチェーンの先端に到達するまでそれらを検証します。 + Unknown. Syncing Headers (%1, %2%)… 不明。ヘッダー(%1、%2%)を同期中… @@ -1391,6 +1674,11 @@ URI: URI: + + Paste address from clipboard + Tooltip text for button that allows you to paste an address that is in your clipboard. + クリップボードからアドレスを貼り付け + OpenWalletActivity @@ -1406,8 +1694,14 @@ default wallet デフォルトのウォレット + + Open Wallet + Title of window indicating the progress of opening of a wallet. + ウォレットを開く + Opening Wallet <b>%1</b>… + Descriptive text of the open wallet progress window which indicates to the user which wallet is currently being opened. <b>%1</b>のウォレットを開封中… @@ -1427,7 +1721,7 @@ Number of script &verification threads - スクリプト検証用スレッド数 (&V) + スクリプト検証用スレッドの数 (&V) (0 = auto, <0 = leave that many cores free) @@ -1439,7 +1733,15 @@ &Appearance - アピアランス(&A) + アピアランス (&A) + + + Show the icon in the system tray. + システムトレーにアイコンを表示します。 + + + &Show tray icon + トレーアイコンを表示 (&T) Prune &block storage to @@ -1453,10 +1755,58 @@ Reverting this setting requires re-downloading the entire blockchain. この設定を元に戻すには、ブロックチェーン全体を再ダウンロードする必要があります。 + + 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. + Tooltip text for Options window setting that sets the size of the database cache. Explains the corresponding effects of increasing/decreasing this value. + データベースキャッシュのサイズが最大です。キャッシュを大きくするとより高速に同期できますが、ほとんどの使用事例ではその効果はあまり顕著ではありません。キャッシュサイズを小さくすると、メモリ使用量が減少します。未使用のメンプールのメモリは、このキャッシュと共有されます。 + MiB MiB + + Set the number of script verification threads. Negative values correspond to the number of cores you want to leave free to the system. + 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. + スクリプト検証のスレッドの数を設定します。負の値は、システムに空けておきたいコアの数に相当します。 + + + This allows you or a third party tool to communicate with the node through command-line and JSON-RPC commands. + Tooltip text for Options window setting that enables the RPC server. + これにより、お客様または第三者のツールがコマンドラインおよびJSON-RPCコマンドを通じてノードと通信できるようになります。 + + + Enable R&PC server + An Options window setting to enable the RPC server. + RPCサーバーを有効化 (&R) + + + Whether to set subtract fee from amount as default or not. + Tooltip text for Options window setting that sets subtracting the fee from a sending amount as default. + 金額から差し引く料金をデフォルトで設定するか。 + + + Subtract &fee from amount by default + An Options window setting to set subtracting the fee from a sending amount as default. + デフォルトで金額から手数料を差し引く (&F) + + + Enable &PSBT controls + An options window setting to enable PSBT controls. + PSBT コントロールを有効化(&P) + + + Whether to show PSBT controls. + Tooltip text for options window setting that enables PSBT controls. + PSBT コントロールを表示するかどうか。 + + + Whether to keep the specified custom change address or not. + 指定したカスタム変更のアドレスを保存するか。 + + + Keep custom change &address + カスタム変更のアドレスを保存する (&K) + Show additional tab listing all your masternodes in first sub-tab<br/>and all masternodes on the network in second sub-tab. あなたのすべてのマスターノードをリストしている追加のタブを最初のサブタブに表示し<br/>すべてのマスターノードを次のサブタブに表示 @@ -1511,7 +1861,15 @@ Enable &multi-session - マルチセッションを有効にする + マルチセッションを有効化する (&M) + + + Use this many separate masternodes in parallel to mix funds.<br/>Note: You must use this feature carefully.<br/>Make sure you always have recent wallet (auto)backup in a safe place! + この多くの個別のマスターノードを並列で使用して資金をミキシングします。<br/>注意事項: この機能は慎重に使用してください。<br/>常に最新のウォレットの(自動)バックアップを安全な場所に保管してください。 + + + Parallel sessions + パラレルセッション Mixing rounds @@ -1525,13 +1883,37 @@ Target balance 対象残高 + + How many inputs of each denominated amount are created.<br/>Lower these numbers if you want fewer smaller denominations. + 各額面の金額の入力が作成された数です。<br/>小額のものを減らしたい場合は、この数値を下げてください。 + + + Inputs per denomination + デノミネーションごとのインプット + + + Try to create at least this many inputs for each denominated amount.<br/>Lower this number if you want fewer smaller denominations. + 各額面の金額に対して、最低でもこれだけ多くの入力を作成するようにしてください。<br/>小額のものを減らしたい場合は、この数値を下げてください。 + + + Target + ターゲット + + + Create up to this many inputs for each denominated amount.<br/>Lower this number if you want fewer smaller denominations. + 各額面の金額に対して、これだけ多くの入力を作成します。<br/>小額のものを減らしたい場合は、この数値を下げてください。 + + + Maximum + 最大 + Automatically open the Dash Core client port on the router. This only works when your router supports UPnP and it is enabled. 自動的にルーターのDash Core クライアントポートを開放します。これはルーターがUPnP機能をサポートしておりUPnP機能が有効な場合にのみ機能します。 Map port using NA&T-PMP - NA&T-PMPを使用したマップポート + NAT-PMPを使用したマップポート (&M) Accept connections from outside. @@ -1539,7 +1921,7 @@ Allow incomin&g connections - 受信接続を許可する + 受信接続を許可する (&I) Connect to the Dash network through a SOCKS5 proxy. @@ -1547,12 +1929,26 @@ &Connect through SOCKS5 proxy (default proxy): - SOCKS5プロキシ(デフォルトプロキシ)経由で接続: (&C) + SOCKS5プロキシ(デフォルトプロキシ)経由で接続: (&C) Shows if the supplied default SOCKS5 proxy is used to reach peers via this network type. 指定されたデフォルトのSOCKS5プロキシを使用して、このネットワークタイプ経由でピアに到達するかどうかを表示。 + + Language missing or translation incomplete? Help contributing translations here: +https://explore.transifex.com/dash/dash/ + 言語が抜けていたり、翻訳が不十分である場合、以下のリンクから翻訳の作成にご協力ください。 +https://explore.transifex.com/dash/dash/ + + + Third-party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items.<br/>%s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |. + トランザクションタブにコンテキストメニュー項目として表示されるサードパーティURL(例:ブロックエクスプローラー)。<br/>URLの %s はトランザクションハッシュに置き換えられます。複数のURLは縦棒 | で区切ります。 + + + &Third-party transaction URLs + サードパーティトランザクションURL(&T) + Options set in this dialog are overridden by the command line or in the configuration file: このダイアログで設定されたオプションは、コマンドラインまたは設定ファイルによって上書きされます。 @@ -1562,16 +1958,8 @@ ウィンドウを閉じる際にアプリケーションを終了するのではなく最小化します。このオプションが有効の場合、メニューから終了を選択した場合にのみアプリケーションは閉じられます。 - Third party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items.<br/>%s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |. - メニューアイテムとしてトランザクションタブに表示されるサードパーティのURL (例 ブロックエクスプローラー) :<br/>%s はトランザクションハッシュに置き換えられます。複数のURLは"|"によって区切られます。 - - - &Third party transaction URLs - サードパーティのトランザクションURL(&T) - - - Whether to show coin control features or not. - コインコントロール機能の表示/非表示 + Whether to show coin control features or not. + コインコントロール機能の表示/非表示 Automatically start %1 after logging in to the system. @@ -1579,15 +1967,15 @@ &Start %1 on system login - システムログイン時に %1 を起動 (&S) + システムログイン時に%1を起動する (&S) Enable coin &control features - コインコントロール機能を有効化 (&C) + コインコントロール機能を有効化する (&C) &Spend unconfirmed change - 未検証のチェンジを使用 (&S) + 未検証の通貨を使用する (&S) This setting determines the amount of individual masternodes that an input will be mixed through.<br/>More rounds of mixing gives a higher degree of privacy, but also costs more in fees. @@ -1603,11 +1991,15 @@ Map port using &UPnP - UPnPを使ってポートを割り当て (&U) + UPnPを使ってポートを割り当てる (&U) + + + Automatically open the Dash Core client port on the router. This only works when your router supports NAT-PMP and it is enabled. The external port could be random. + ルーター上でDashコアのクライアントポートを自動的に開きます。これは、ルーターがNAT-PMPをサポートしており、有効になっている場合にのみ機能します。外部ポートはランダムになる可能性があります。 Proxy &IP: - プロキシの IP:(&I)  + プロキシのIP: (&I) IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1) @@ -1615,7 +2007,7 @@ &Port: - ポート :(&P) + ポート: (&P) Port of the proxy (e.g. 9050) @@ -1643,7 +2035,7 @@ &Minimize to the tray instead of the taskbar - タスクバーの代わりにトレイに最小化 (&M) + タスクバーの代わりにトレーに最小化 (&M) M&inimize on close @@ -1653,9 +2045,17 @@ &Display 表示 (&D) + + Connect to the Dash network through a separate SOCKS5 proxy for Tor onion services. + Torオニオンサービス用の個別のSOCKS5プロキシを経由して、Dashネットワークに接続します。 + + + Use separate SOCKS&5 proxy to reach peers via Tor onion services: + 別個のSOCKS5プロキシを使用して、Torオニオンサービス経由でピアに接続: (&S) + User Interface &language: - ユーザインターフェースの言語 :(&L) + ユーザーインターフェースの言語: (&L) The user interface language can be set here. This setting will take effect after restarting %1. @@ -1663,7 +2063,7 @@ &Unit to show amounts in: - 表示する単位 :(&U) + 表示する通貨単位: (&U) Choose the default subdivision unit to show in the interface and when sending coins. @@ -1683,7 +2083,7 @@ &OK - OK(&O) + OK (&O) &Cancel @@ -1699,14 +2099,22 @@ Confirm options reset + Window title text of pop-up window shown when the user has chosen to reset options. オプションのリセットの確認 Client restart required to activate changes. + Text explaining that the settings changed will not come into effect until the client is restarted. 変更を有効にするにはクライアントを再起動する必要があります。 + + Current settings will be backed up at "%1". + 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. + 現在の設定は「%1」にバックアップされます。 + Client will be shut down. Do you want to proceed? + Text asking the user to confirm if they would like to proceed with a client shutdown. クライアントを終了します。続行してもよろしいですか? @@ -1844,6 +2252,10 @@ %1 Balance %1の残額 + + Discreet mode activated for the Overview tab. To unmask the values, uncheck Settings->Discreet mode. + 概要タブでDiscreetモードが有効になっています。値のマスキングを解除するには、設定->Discreetモードのチェックを外します。 + %n Rounds %n ラウンド @@ -1943,7 +2355,140 @@ PSBTOperationsDialog - + + Dialog + ダイアログ + + + Sign Tx + 取引に署名 + + + Broadcast Tx + 取引を送信 + + + Copy to Clipboard + クリップボードにコピー + + + Save… + 保存中... + + + Close + 閉じる + + + Failed to load transaction: %1 + 取引のロードに失敗しました: %1 + + + Failed to sign transaction: %1 + 取引の署名に失敗しました: %1 + + + Cannot sign inputs while wallet is locked. + ウォレットがロックされていると、インプットに署名できません。 + + + Could not sign any more inputs. + これ以上のインプットに署名できませんでした。 + + + Signed %1 inputs, but more signatures are still required. + %1のインプットに署名しましたが、その他の署名も必要です。 + + + Signed transaction successfully. Transaction is ready to broadcast. + 取引に正常に署名しました。取引を送信できます。 + + + Unknown error processing transaction. + 取引の処理中に、不明なエラーが発生しました。 + + + Transaction broadcast successfully! Transaction ID: %1 + 取引を正常に送信しました。取引ID: %1 + + + Transaction broadcast failed: %1 + 取引の送信に失敗しました: %1 + + + PSBT copied to clipboard. + PSBTをクリップボードにコピーしました。 + + + Save Transaction Data + 取引データを保存 + + + Partially Signed Transaction (Binary) + Expanded name of the binary PSBT file format. See: BIP 174. + 一部署名された取引 (バイナリー) + + + PSBT saved to disk. + PSBTをディスクに保存しました。 + + + * Sends %1 to %2 + *%1を%2に送金する + + + own address + 自分のアドレス + + + Unable to calculate transaction fee or total transaction amount. + 取引手数料または取引総額を計算できません。 + + + Pays transaction fee: + 取引手数料を支払う: + + + Total Amount + 総額 + + + or + または + + + Transaction has %1 unsigned inputs. + 取引には、%1の未署名のインプットがあります。 + + + Transaction is missing some information about inputs. + 取引には、インプットに関する情報が一部不足しています。 + + + Transaction still needs signature(s). + 取引にはさらに署名が必要です。 + + + (But no wallet is loaded.) + (しかし、ウォレットがロードされていません。) + + + (But this wallet cannot sign transactions.) + (しかし、このウォレットでは取引に署名できません。) + + + (But this wallet does not have the right keys.) + (しかし、このウォレットには正しいキーがありません。) + + + Transaction is fully signed and ready for broadcast. + 取引は全て署名済みで、送信できます。 + + + Transaction status is unknown. + 取引ステータスは不明です。 + + PaymentServer @@ -1962,6 +2507,12 @@ 'dash://' is not a valid URI. Use 'dash:' instead. 「dash://」は有効なURIではありません。代わりに「dash:」を使ってください。 + + Cannot process payment request as BIP70 is no longer supported. +Due to discontinued support, you should request the merchant to provide you with a BIP21 compatible URI or use a wallet that does continue to support BIP70. + BIP70がもうサポートされていないため、支払いリクエストを処理できません。 +サポートが終了したため、BIP21対応のURIを提示するよう販売者に要請するか、BIP70のサポートを継続しているウォレットを使用してください。 + URI cannot be parsed! This can be caused by an invalid Dash address or malformed URI parameters. URI を解析できません! これは無効な Dash アドレスあるいは不正な形式の URI パラメーターによって引き起こされた可能性があります。 @@ -1983,6 +2534,26 @@ Title of Peers Table column which indicates the current latency of the connection with the peer. Ping + + Peer + Title of Peers Table column which contains a unique number used to identify a connection. + ピア + + + Age + Title of Peers Table column which indicates the duration (length of time) since the peer connection started. + エイジ + + + Direction + Title of Peers Table column which indicates the direction the peer connection was initiated from. + 動向 + + + Type + Title of Peers Table column which describes the type of peer connection. The "type" describes why the connection exists. + タイプ + Sent Title of Peers Table column which indicates the total amount of network information we have sent to the peer. @@ -1993,7 +2564,27 @@ Title of Peers Table column which indicates the total amount of network information we have received from the peer. 受け取りました - + + Address + Title of Peers Table column which contains the IP/Onion/I2P address of the connected peer. + アドレス + + + Network + Title of Peers Table column which states the network the peer connected through. + ネットワーク + + + Inbound + An Inbound Connection from a Peer. + インバウンド + + + Outbound + An Outbound Connection to a Peer. + アウトバウンド + + Proposal @@ -2044,8 +2635,193 @@ ステータス + + ProposalWizard + + Create Governance Proposal + ガバナンス提案を作成 + + + Enter proposal details + 提案の詳細を入力 + + + A fee will be burned when you prepare the proposal. + 提案を準備する際に手数料がバーン(焼却)されます。 + + + Proposal &name + 提案名(&N) + + + &Description URL + 説明 URL(&D) + + + Payment &address + 支払アドレス(&A) + + + Payment &amount + 支払金額(&A) + + + The amount to request in a single payment + 1回の支払いで要求する金額 + + + &First payment + 初回支払(&F) + + + Pa&yments + 支払回数(&Y) + + + To&tal amount + 合計金額(&T) + + + Proposal &fee + 提案手数料(&F) + + + Next + 次へ + + + Review proposal JSON and validate. + 提案JSONを確認して検証します。 + + + Hex-encoded JSON + 16進数エンコードされたJSON + + + Back + 戻る + + + Validate + 検証 + + + Prepare (burn fee) and wait for confirmations. + 準備(手数料をバーン)して承認を待ちます。 + + + Copy + コピー + + + At 1/6 confirmations: can be relayed and queued. At 6/6: accepted and processed. + 1/6承認時:リレーおよびキュー可能。6/6時:承認され処理されます。 + + + Confirmations progress + 承認の進行状況 + + + Shows progress toward the required number of confirmations for the proposal fee transaction. + 提案手数料トランザクションに必要な承認数への進行状況を表示します。 + + + Estimated time remaining: - + 推定残り時間: - + + + Prepare Proposal + 提案を準備 + + + You can submit after 1 confirmation. At 6 confirmations it is accepted and processed. + 1承認後に提出できます。6承認で承認され処理されます。 + + + Proposal ID: + 提案 ID: + + + Submit Proposal + 提案を提出 + + + Close + 閉じる + + + Valid + 有効 + + + Invalid: %1 + 無効: %1 + + + Burn %1 + %1 をバーン + + + Burn %1 to create the fee transaction? + 手数料トランザクションを作成するために %1 をバーンしますか? + + + Prepare failed + 準備に失敗しました + + + Confirmations: %1 / %2 required + 承認: %1 / %2 必要 + + + Estimated time remaining: Ready + 推定残り時間: 準備完了 + + + Estimated time remaining: %n minute(s) + 推定残り時間: %n 分 + + + Your proposal was submitted successfully. + 提案が正常に提出されました。 + + + Already submitted + すでに提出済み + + + This proposal has already been submitted. + この提案はすでに提出されています。 + + + Submission failed + 提出に失敗しました + + + Proposal submitted + 提案が提出されました + + + A fee of %1 will be burned when you prepare the proposal. + 提案を準備する際に %1 の手数料がバーンされます。 + + + Prepare (burn %1) and wait for %2 confirmations. + 準備(%1 をバーン)して %2 承認を待ちます。 + + QObject + + Do you want to reset settings to default values, or to abort without making changes? + Explanatory text shown on startup when the settings file cannot be read. Prompts user to make a choice between resetting or aborting. + 設定をデフォルト値にリセットしますか、それとも変更せずに中止しますか。 + + + A fatal error occurred. Check that settings file is writable, or try running with -nosettings. + 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. + 重大なエラーが発生しました。設定ファイルが書き込み可能なことを確認するか、-nosettingsを追記して実行してください。 + Choose data directory on startup (default: %u) 起動時にデータディレクトリを選択する(デフォルト:%u) @@ -2146,6 +2922,53 @@ This can also be adjusted later in the "Appearance" tab of the preferences. これは、初期設定の「表示」タブで後で調整することも可能です。 + + Ctrl+W + Ctrl+W + + + Unroutable + ルート化不可 + + + Internal + 内部 + + + Inbound + An inbound connection from a peer. An inbound connection is a connection initiated by a peer. + インバウンド + + + Outbound + An outbound connection to a peer. An outbound connection is a connection initiated by us. + アウトバウンド + + + Full Relay + Peer connection type that relays all network information. + フルリレー + + + Block Relay + Peer connection type that relays network information about blocks and not transactions or addresses. + ブロックリレー + + + Manual + Peer connection type established manually through one of several methods. + マニュアル + + + Feeler + Short-lived peer connection type that tests the aliveness of known addresses. + フィーラー + + + Address Fetch + Short-lived peer connection type that solicits known addresses from a peer. + アドレスフェッチ + %1 d %1日 @@ -2207,8 +3030,8 @@ %1 B - %1 KB - %1 KB + %1 kB + %1 kB %1 MB @@ -2235,18 +3058,18 @@ &Save Image… - 画像を保存…(&S) + 画像を保存する… (&S) QRImageWidget &Save Image… - 画像を保存… (&S) + 画像を保存する… (&S) &Copy Image - 画像をコピー(&C) + 画像をコピー (&C) Resulting URI too long, try to reduce the text for label / message. @@ -2264,7 +3087,12 @@ Save QR Code QR コードの保存 - + + PNG Image + Expanded name of the PNG file format. See: https://en.wikipedia.org/wiki/Portable_Network_Graphics. + PNG画像 + + RPCConsole @@ -2371,6 +3199,14 @@ Version バージョン + + High bandwidth BIP152 compact block relay: %1 + 高帯域幅BIP152のコンパクトブロックリレー: %1 + + + High Bandwidth + 高帯域幅 + Starting Block 開始ブロック @@ -2383,6 +3219,51 @@ Synced Blocks 同期済みブロック + + Elapsed time since a novel block passing initial validity checks was received from this peer. + 新規ブロックが初期の有効性チェックをクリアした後に、このピアから受信した経過時間。 + + + Last Block + 最後のブロック + + + Elapsed time since a novel transaction accepted into our mempool was received from this peer. + Tooltip text for the Last Transaction field in the peer details area. + 新規取引がメンプールで承認された後に、このピアから受信した経過時間 + + + Last Transaction + 前回の取引 + + + The mapped Autonomous System used for diversifying peer selection. + マッピングされた自律システムは、ピア選択の分散化に使用されます。 + + + Mapped AS + マッピングされた自律システム + + + Whether we relay addresses to this peer. + Tooltip text for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No). + このピアにアドレスをリレーするか。 + + + Address Relay + Text title for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No). + アドレスリレー + + + Addresses Processed + 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). + アドレスが処理されました + + + Addresses Rate-Limited + 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. + アドレスはレートで制限されました + Rescan blockchain files 1 ブロックチェーンファイル1の再スキャンをする @@ -2423,6 +3304,22 @@ To specify a non-default location of the blocks directory use the '%1' option. ブロックディレクトリのデフォルトでない場所を指定するには、「%1」のオプションを使用します。 + + Local Addresses + ローカルアドレス + + + Network addresses that your Dash node is currently using to communicate with other nodes. + あなたの Dash ノードが他のノードとの通信に現在使用しているネットワークアドレス。 + + + Number of regular Masternodes + レギュラーマスターノードの数 + + + Number of EvoNodes + Evoノードの数 + Current block height 現在のブロックの高さ @@ -2461,20 +3358,60 @@ &Reset - &リセット + リセット (&R) Node Type - ノードの種類 + ノードのタイプ PoSe Score PoSeスコア + + The transport layer version: %1 + トランスポートレイヤーのバージョン: %1 + + + Transport + トランスポート + + + The BIP324 session ID string in hex. + BIP324のセッションIDの文字列(16進数)。 + + + Session ID + セッションID + + + The network protocol this peer is connected through: IPv4, IPv6, Onion, I2P, or CJDNS. + このピアが接続しているネットワークプロトコル: IPv4、IPv6、Onion、I2P、またはCJDNS。 + + + Permissions + 許可 + + + The direction and type of peer connection: %1 + ピア接続の動向とタイプ: %1 + + + Direction/Type + 動向/タイプ + Services サービス + + Whether we relay transactions to this peer. + このピアにトランザクションをリレーするかどうか。 + + + Transaction Relay + トランザクションリレー + Connection Time 接続時間 @@ -2509,7 +3446,17 @@ &Wallet Repair - ウォレット修復(&W) + ウォレットの修復 (&W) + + + The total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting). + 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). + このピアから受信したアドレスのうち、処理されたアドレスの総数(レート制限によりドロップされたアドレスは除く)。 + + + The total number of addresses received from this peer that were dropped (not processed) due to rate-limiting. + 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. + このピアから受信したアドレスのうち、レート制限によりドロップされた(処理されなかった)アドレスの総数。 Wallet repair options. @@ -2524,52 +3471,82 @@ -reindex: 現在の blk000??.dat ファイルからブロックチェーンインデックスをリビルドします - &Disconnect - 切断 (&D) + Inbound: initiated by peer + Explanatory text for an inbound peer connection. + インバウンド: ピアから発信 - Ban for - Banする: + Outbound Full Relay: default + Explanatory text for an outbound peer connection that relays all network information. This is the default behavior for outbound connections. + アウトバウンドのフルリレー: デフォルト - 1 &hour - 1時間 (&H) + Outbound Block Relay: does not relay transactions or addresses + Explanatory text for an outbound peer connection that relays network information about blocks and not transactions or addresses. + アウトバウンドのブロックリレー: 取引やアドレスをリレーしない - 1 &day - 1日 (&D) + Outbound Manual: added using RPC %1 or %2/%3 configuration options + 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. + アウトバウンドのマニュアル: RPCの%1または%2と%3の構成オプションを使用して追加 - 1 &week - 1週間 (&W) + Outbound Feeler: short-lived, for testing addresses + Explanatory text for a short-lived outbound peer connection that is used to test the aliveness of known addresses. + アウトバウンドのフィーラー: 一過性のもの、アドレスのテスト用 - 1 &year - 1年 (&Y) + Outbound Address Fetch: short-lived, for soliciting addresses + Explanatory text for a short-lived outbound peer connection that is used to request addresses from a peer. + アウトバウンドのアドレスフェッチ: 一過性のもの、アドレスの勧誘用 - &Unban - Banを解除する (&U) + To + + + + we selected the peer for high bandwidth relay + 高帯域幅のリレー用にピアを選択しました + + + From + から + + + the peer selected us for high bandwidth relay + 高帯域幅のリレー用に選択されたピア + + + No + いいえ - Welcome to the %1 RPC console. - %1 RPCコンソールへようこそ。 + no high bandwidth relay selected + 高帯域幅のリレーが選択されていません - Use up and down arrows to navigate history, and %1 to clear screen. - 上下の矢印を使用して履歴をナビゲートし、 %1 を使用して画面をクリアします。 + &Disconnect + 切断する (&D) - Type %1 for an overview of available commands. - 利用可能なコマンドの概要については、%1と入力してください。 + Ban for + Banする: - For more information on using this console type %1. - このコンソールの使用に関する詳細は、%1と入力してください。 + 1 &hour + 1時間 (&H) - WARNING: Scammers have been active, telling users to type commands here, stealing their wallet contents. Do not use this console without fully understanding the ramifications of a command. - 警告:詐欺師は常にアクティブであり、ユーザーにここへのコマンドを入力させ、ウォレットの中身を盗みます。 コマンドの影響を完全に理解せずにこのコンソールを使用しないでください。 + 1 &week + 1週間 (&W) + + + 1 &year + 1年 (&Y) + + + &Unban + Banを解除する (&U) In: @@ -2583,6 +3560,10 @@ Network activity disabled ネットワーク活動は無効化されました + + None + なし + Total: %1 (Enabled: %2) 合計: %1 (有効: %2) @@ -2591,10 +3572,105 @@ Executing command without any wallet ウォレットなしでコマンドを実行する + + Ctrl++ + Main shortcut to increase the RPC console font size. + Ctrl++ + + + Ctrl+= + Secondary shortcut to increase the RPC console font size. + Ctrl+= + + + Ctrl+- + Main shortcut to decrease the RPC console font size. + Ctrl+- + + + Ctrl+_ + Secondary shortcut to decrease the RPC console font size. + Ctrl+_ + + + Ctrl+Shift+I + Ctrl+Shift+I + + + Ctrl+Shift+C + Ctrl+Shift+C + + + Ctrl+Shift+G + Ctrl+Shift+G + + + Ctrl+Shift+P + Ctrl+Shift+P + + + Ctrl+Shift+R + Ctrl+Shift+R + Executing command using "%1" wallet 「%1」のウォレットを使用してコマンドを実行する + + detecting: peer could be v1 or v2 + Explanatory text for "detecting" transport type. + 検出: ピアはバージョン1またはバージョン2の可能性があります + + + v1: unencrypted, plaintext transport protocol + Explanatory text for v1 transport type. + バージョン1: 暗号化されていないプレーンテキストのトランスポートプロトコル + + + v2: BIP324 encrypted transport protocol + Explanatory text for v2 transport type. + バージョン2: BIP324で暗号化されたトランスポートプロトコル + + + &Copy address + Context menu action to copy the address of a peer + アドレスをコピー (&A) + + + 1 d&ay + 1日 (&D) + + + &Copy IP/Netmask + 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 + IP/Netmaskをコピー (&C) + + + 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 + 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. + %1のRPCコンソールへようこそ。 +上下の矢印で履歴を参照し、%2で画面をクリアします。 +%3と%4を使用して、フォントサイズを拡大または縮小します。 +%5を入力すると、利用可能なコマンドの概要が表示されます。 +このコンソールの使い方の詳細については、%6を入力してください。 + +%7警告: 詐欺師が活動しており、ユーザーにここでコマンドを入力し、ウォレットの中身を盗むよう指示する手口があります。コマンドの内容を十分に理解しないまま、このコンソールを使用しないでください。%8 + + + Executing… + A console message indicating an entered command is currently being executed. + 実行中... + + + (peer: %1) + (ピア: %1) + via %1 %1経由 @@ -2611,11 +3687,19 @@ Verified Masternode 認証済のマスターノード + + Yes + はい + Unknown 不明 - + + Never + いいえ + + ReceiveCoinsDialog @@ -2634,13 +3718,17 @@ An optional message to attach to the payment request, which will be displayed when the request is opened.<br>Note: The message will not be sent with the payment over the Dash network. 支払いリクエストが開始された時に表示される、支払いリクエストに添付される任意のメッセージです。注意:このメッセージはDashネットワークを通じて支払いと共に送信されるわけではありません。 + + 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. + 新しい受信アドレスに紐づけるオプションのラベル(請求書の識別に使用できます)。支払いリクエストにも添付されます。 + Use this form to request payments. All fields are <b>optional</b>. このフォームを使用して支払いのリクエストを行いましょう。すべての項目は<b>任意入力</b>です。 &Label: - ラベル (&L) + ラベル: (&L) An optional amount to request. Leave this empty or zero to not request a specific amount. @@ -2648,11 +3736,11 @@ &Amount: - 総額 (&A) + 総額: (&A) &Create new receiving address - 新しい受取アドレスを作成(&C) + 新しい受取アドレスを作成する (&C) Clear all fields of the form. @@ -2691,35 +3779,67 @@ 支払いリクエストに添付するメッセージを入力します - Copy URI - URI をコピー + Copy &URI + URIをコピー (&U) - Copy address - アドレスをコピー + &Copy address + アドレスをコピー (&A) - Copy label - ラベルをコピーする + Copy &label + ラベルをコピー (&L) - Copy message - メッセージをコピー + Copy &message + メッセージをコピー (&M) - Copy amount - 総額のコピー + Copy &amount + 金額をコピー (&A) + + + Could not unlock wallet. + ウォレットのロックを解除できませんでした - + + Could not generate new address + 新しいアドレスを作成できませんでした + + ReceiveRequestDialog + + Request payment to … + 支払いのリクエスト中... + + + Address: + アドレス: + + + Amount: + 金額: + + + Label: + ラベル: + + + Message: + メッセージ: + + + Wallet: + ウォレット: + Copy &URI URI をコピー (&U) Copy &Address - アドレスをコピー(&A) + アドレスをコピー (&A) &Save Image… @@ -2765,6 +3885,34 @@ リクエスト完了 + + RestoreWalletActivity + + Restore Wallet + Title of progress window which is displayed when wallets are being restored. + ウォレットを復元 + + + Restoring Wallet <b>%1</b>… + Descriptive text of the restore wallets progress window which indicates to the user that wallets are currently being restored. + ウォレット <b>%1</b> を復元中… + + + Restore wallet failed + Title of message box which is displayed when the wallet could not be restored. + ウォレットの復元に失敗しました + + + Restore wallet warning + Title of message box which is displayed when the wallet is restored with some warning. + ウォレット復元の警告 + + + Restore wallet message + Title of message box which is displayed when the wallet is successfully restored. + ウォレット復元メッセージ + + SendCoinsDialog @@ -2799,10 +3947,6 @@ Fee: 手数料: - - Dust: - ダスト: - Inputs… インプット… @@ -2827,6 +3971,14 @@ Transaction Fee: トランザクション手数料: + + 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 dash transactions than the network can process. + 取引量がブロックの空き容量よりも少ない場合、マイナーや リレーするノードは最低手数料を強制することがあります。この最低手数料のみを支払うことは全く問題ありませんが、ネットワークが処理できる量よりもDashの取引の需要が多くなると、確認されない取引になる可能性があることに留意してください。 + + + A too low fee might result in a never confirming transaction (read the tooltip) + 手数料が低すぎると、取引が確定しない場合があります(ツールチップを参照してください) + (Smart fee not initialized yet. This usually takes a few blocks…) (スマート手数料はまだ初期化されていません。これには約数ブロックほどかかります…) @@ -2877,7 +4029,7 @@ S&end - 送金 (&E) + 送金 (&S) Clear all fields of the form. @@ -2893,7 +4045,7 @@ Add &Recipient - 受取人を追加 (&R) + 受取人を追加する (&R) Balance: @@ -2905,11 +4057,11 @@ Copy amount - 総額のコピー + 金額をコピー Copy fee - 手数料をコピーす + 手数料をコピー Copy after fee @@ -2919,10 +4071,6 @@ Copy bytes バイト数をコピー - - Copy dust - ダストをコピー - Copy change チェンジをコピー @@ -2939,22 +4087,30 @@ %1 to %2 %1 から %2 - - Are you sure you want to send? - 送ってよろしいですか? - <b>(%1 of %2 entries displayed)</b> <b>(%1 /%2 項目を表示)</b> S&end mixed funds - ミックスファンドを送金する + ミックスファンドを送金する (&S) Confirm the %1 send action %1の送金処理を確認 + + Cr&eate Unsigned + 未署名を作成する (&C) + + + from wallet '%1' + 「%1」のウォレットから + + + %1 to '%2' + %1から「%2」へ + %1 funds only %1の資金のみ @@ -3001,7 +4157,52 @@ Confirm send coins - 送金確認 + 送金を確認する + + + Save Transaction Data + 取引データを保存する + + + PSBT saved + PSBTが保存されました + + + Watch-only balance: + 閲覧のみの残高: + + + Creates a Partially Signed Blockchain Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet. + 一部署名済みのブロックチェーン取引(PSBT)を生成し、オフラインの%1のウォレットやPSBT対応のハードウェアウォレットで使用します。 + + + Do you want to create this transaction? + 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. + このトランザクションを作成しますか? + + + Please, review your transaction proposal. This will produce a Partially Signed Blockchain Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet. + 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. + トランザクション提案を確認してください。これにより部分署名ブロックチェーントランザクション(PSBT)が生成されます。保存またはコピーして、オフラインの %1 ウォレットやPSBT対応のハードウェアウォレットで署名できます。 + + + Please, review your transaction. You can create and send this transaction or create a Partially Signed Blockchain Transaction (PSBT), which you can save or copy and then sign with, e.g., an offline %1 wallet, or a PSBT-compatible hardware wallet. + 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. + トランザクションを確認してください。このトランザクションを作成して送信するか、部分署名ブロックチェーントランザクション(PSBT)を作成できます。PSBTは保存またはコピーして、オフラインの %1 ウォレットやPSBT対応のハードウェアウォレットで署名できます。 + + + Please, review your transaction. + Text to prompt a user to review the details of the transaction they are attempting to send. + トランザクションを確認してください。 + + + To review recipient list click "Show Details…" + 受取人リストを確認するには、「詳細を表示…」をクリックします + + + Partially Signed Transaction (Binary) + Expanded name of the binary PSBT file format. See: BIP 174. + 一部署名された取引 (バイナリー) The recipient address is not valid. Please recheck. @@ -3060,7 +4261,7 @@ SendCoinsEntry Pay &To: - 送り先: (&T) + 送金先: (&T) The Dash address to send the payment to @@ -3096,7 +4297,7 @@ A&mount: - 金額: (&M) + 金額: (&A) The amount to send in the selected unit @@ -3108,7 +4309,7 @@ S&ubtract fee from amount - 総額から手数料を差し引いて送金(&U) + 総額から手数料を差し引く (&S) Use available balance @@ -3122,21 +4323,16 @@ A message that was attached to the dash: URI which will be stored with the transaction for your reference. Note: This message will not be sent over the Dash network. Dash: URIに添付されていたメッセージです。これは参照用としてトランザクションとともに保存されます。注意:このメッセージはDashネットワークを経由して送信されるわけではありません。 + + + SendConfirmationDialog - This is an unauthenticated payment request. - これは未認証の支払いリクエストです。 - - - This is an authenticated payment request. - これは認証済みの支払いリクエストです。 - - - Pay To: - 支払い先: + Send + 送信 - Memo: - メモ: + Create Unsigned + 未署名を作成 @@ -3158,7 +4354,7 @@ &Sign Message - メッセージの署名 (&S) + メッセージを署名する (&S) You can sign messages/agreements with your addresses to prove you can receive Dash 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. @@ -3202,7 +4398,7 @@ Sign &Message - メッセージの署名 (&M) + メッセージを署名する (&M) Reset all sign message fields @@ -3214,7 +4410,7 @@ &Verify Message - メッセージの検証 (&V) + メッセージを検証する (&V) 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! @@ -3238,7 +4434,7 @@ Verify &Message - メッセージの検証 (&M) + メッセージを検証する (&M) Reset all verify message fields @@ -3276,6 +4472,10 @@ Wallet unlock was cancelled. ウォレットのアンロックはキャンセルされました。 + + No error + エラーなし + Private key for the entered address is not available. 入力されたアドレスのプライベートキーは利用できません。 @@ -3301,19 +4501,30 @@ 署名はメッセージダイジェストと一致しませんでした。 - Message verification failed. - メッセージの検証に失敗しました。 + Message verification failed. + メッセージの検証に失敗しました。 + + + Message verified. + メッセージは検証されました。 + + + + SplashScreen + + (press q to shutdown and continue later) + (Qを押してシャットダウンし、後で続ける) - Message verified. - メッセージは検証されました。 + press q to shutdown + Qを押してシャットダウンする TrafficGraphWidget - KB/s - KB/秒 + kB/s + kB/秒 Total @@ -3330,20 +4541,9 @@ TransactionDesc - - Open for %n more block(s) - %n 以上のブロックをオープン - - - Open until %1 - %1 までオープン - - - conflicted - コンフリクト発生 - 0/unconfirmed, %1 + 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. 0/未確認、%1 @@ -3356,22 +4556,32 @@ abandoned + 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. 中止 + + conflicted with a transaction with %1 confirmations + 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. + %1 承認のトランザクションと競合しています + %1/unconfirmed + 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, and still not locked via ChainLocks. %1/未確認 %1 confirmations + 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 or locked via ChainLocks. %1の確認 locked via ChainLocks + 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 and has been locked by ChainLocks. チェーンロックでロック中 verified via InstantSend + 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 has been locked by InstantSend. InstantSendで検証済み @@ -3390,6 +4600,10 @@ Generated 生成済 + + Platform Transfer + プラットフォーム送金 + From 送信元 @@ -3520,14 +4734,6 @@ Address / Label アドレス / ラベル - - Open for %n more block(s) - %n 以上のブロックをオープン - - - Open until %1 - %1 までオープン - Unconfirmed 未検証 @@ -3588,6 +4794,10 @@ Mined マイニング済 + + Platform Transfer + プラットフォーム送金 + %1 Mixing %1 ミキシング @@ -3715,6 +4925,10 @@ Mined 採掘済 + + Platform Transfer + プラットフォーム送金 + Other その他 @@ -3728,49 +4942,63 @@ 最小の額 - Abandon transaction - トランザクション中止 + &Copy address + アドレスをコピー (&A) - Copy address - アドレスをコピー + Copy &label + ラベルをコピー (&L) - Copy label - ラベルをコピー + Copy &amount + 金額をコピー (&A) - Copy amount - 総額のコピー + Copy transaction &ID + 取引IDをコピー (&T) + + + Copy &raw transaction + RAW取引をコピー (&R) - Copy transaction ID - トランザクションIDをコピー + Copy full transaction &details + 全ての取引詳細をコピー (&F) - Copy raw transaction - 原トランザクションをコピー + &Show transaction details + 取引明細を表示する (&S) - Copy full transaction details - トランザクションの詳細すべてをコピー + A&bandon transaction + 取引を破棄する (&A) - Edit address label - アドレスのラベルを編集 + Rese&nd transaction + 取引を再送信する (&R) - Show transaction details - トランザクションの詳細を表示 + &Edit address label + アドレスのラベルを編集する (&E) - Show address QR code - アドレスのQRコードを表示 + Show address &QR code + アドレスのQRコードを表示する (&Q) + + + Show in %1 + 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. + %1 で表示 Export Transaction History トランザクション履歴をエクスポート + + Comma separated file + Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values. + カンマ区切りのファイル + Confirmed 検証済 @@ -3849,10 +5077,54 @@ Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled. ウォレットを長時間閉じると、プルーニングが有効な場合、チェーン全体を再同期しなければならないことがあります。 - + + Close all wallets + 全てのウォレットを閉じる + + + Are you sure you wish to close all wallets? + 本当に全てのウォレットを閉じてよろしいですか。 + + WalletFrame - + + No wallet has been loaded. +Go to File > Open Wallet to load a wallet. +- OR - + ウォレットは読み込まれていません。 +ファイル > ウォレットを開くからウォレットを読み込んでください。 +- または - + + + Create a new wallet + 新しいウォレットを作成する + + + Error + エラー + + + Unable to decode PSBT from clipboard (invalid base64) + クリップボードからPSBTをデコードできません(無効なBase64) + + + Load Transaction Data + 取引データをロードする + + + Partially Signed Transaction (*.psbt) + 一部署名された取引 (バイナリー) + + + PSBT file must be smaller than 100 MiB + PSBTファイルは100MiB未満でなければなりません + + + Unable to decode PSBT + PSBTをデコードできません + + WalletModel @@ -3878,6 +5150,11 @@ Selected amount: 選択した額: + + Wallet Data + Name of the wallet data file format. + ウォレットのデータ + Backup Wallet ウォレットのバックアップ @@ -3905,14 +5182,6 @@ dash-core - - Error: Listening for incoming connections failed (listen returned error %s) - エラー: 受信中の接続をリッスンするのに失敗しました (エラー %s ) - - - Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee. - 料金の見積もりに失敗しました。フォールバックフィーは無効です。数ブロック待つか、-fallbackfeeを有効にしてください。 - 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 このエラーは、このウォレットが正常にシャットダウンされず、Berkeley DBの新しいバージョンを含むビルドを使用して直前にロードされた場合に発生する可能性があります。その場合は、このウォレットを直前にロードしたソフトウェアを使用してください。 @@ -3970,16 +5239,20 @@ データベースの読み込みエラー。シャットダウンします。 - Failed to listen on any port. Use -listen=0 if you want this. - ポートのリッスンに失敗しました。必要であれば -listen=0 を使用してください。 + Error: Missing checksum + エラー: チェックサムがありません + + + Error: Unable to parse version %u as a uint32_t + エラー: バージョン%uをuint32_tとして解析できません - -maxtxfee is set very high! Fees this large could be paid on a single transaction. - -maxtxfee が非常に高く設定されています!ひとつのトランザクションでこの量の手数料が支払われてしまうことがあります。 + Error: Unable to write record to new wallet + エラー: 新しいウォレットに記録を書き込めません - Cannot provide specific connections and have addrman find outgoing connections at the same. - 特定の接続を提供し、同時にアドルマンに発信接続を探させることができません。 + Failed to listen on any port. Use -listen=0 if you want this. + ポートのリッスンに失敗しました。必要であれば -listen=0 を使用してください。 Found unconfirmed denominated outputs, will wait till they confirm to continue. @@ -3990,13 +5263,17 @@ 無効な-socketevents(「%s」)が指定されました。これらのモード(%s)のみサポートされています。 - Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions) - -maxtxfee=<amount> の数量の指定が無効です: '%s' (トランザクションが詰まってしまうのを防ぐため、少なくとも %s の最小中継手数料を指定しなければいけません) + SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is supported + SQLiteのデータベース: SQLiteのウォレットスキーマのバージョン%dが不明です。サポートされているのはバージョン%dのみです Transaction index can't be disabled with governance validation enabled. Either start with -disablegovernance command line switch or enable transaction index. ガバナンス検証を有効にした状態で、取引インデックスを無効化することはできません。-disablegovernanceのコマンドラインスイッチで開始するか、取引インデックスを有効にしてください。 + + Unsupported category-specific logging level -loglevel=%s. Expected -loglevel=<category>:<loglevel>. Valid categories: %s. Valid loglevels: %s. + サポートされていないカテゴリ固有のログレベル: -loglevel=%s。想定されているものは、-loglevel=<category>:<loglevel>。有効なカテゴリ: %s。有効なログレベル: %s。 + Can't mix: no compatible inputs found! ミキシング不可: 互換性のあるインプットが見つかりません @@ -4005,6 +5282,14 @@ Entry exceeds maximum size. エントリーが最大サイズを超えました。 + + Error upgrading evo database for EHF + EHF用のEvoデータベースのアップグレードにエラーが発生しました + + + Failed to commit Evo database + Evoデータベースのコミットに失敗しました + Found enough users, signing ( waiting %s ) 充分なユーザーを発見しました、サインしています ( 待機中 %s ) @@ -4029,18 +5314,14 @@ Insufficient funds. 残高が不足しています - - Invalid amount for -discardfee=<amount>: '%s' - -ディスカードフィー=<amount>の額: '%s' が無効です - - - Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s) - -paytxfee=<amount> に対する無効な数量です: '%s' (少なくとも %s でなければいけません) - Invalid minimum number of spork signers specified with -minsporkkeys -minsporkkeysで指定されたスポーク署名者の最小数が無効です + + Listening for incoming connections failed (listen returned error %s) + 着信接続の受信に失敗しました(受信にエラー%sが返されました) + Lock is already in place. すでにロックされています @@ -4097,6 +5378,10 @@ Synchronizing governance objects… ガバナンスオブジェクトを同期中… + + Transaction change output index out of range + 取引変更の出力インデックスが範囲外です + Unable to start HTTP server. See debug log for details. HTTPサーバを開始できませんでした。詳細はデバッグログをご確認ください。 @@ -4105,6 +5390,10 @@ Unknown response. 不明なレスポンス + + Unsupported global logging level -loglevel=%s. Valid values: %s. + -loglevel=%sのグローバルログレベルがサポートされていません。有効な値: %s。 + User Agent comment (%s) contains unsafe characters. ユーザーエージェントのコメント (%s) には安全でない文字が含まれています。 @@ -4145,6 +5434,10 @@ Make sure to encrypt your wallet and delete all non-encrypted backups after you have verified that the wallet works! ウォレットが動作することを確認したら、必ずウォレットを暗号化し、暗号化されていないバックアップをすべて削除してください! + + More than one onion bind address is provided. Using %s for the automatically created Tor onion service. + 複数のTorオニオンバインドアドレスが提供されています。自動的に作成されたTorオニオンサービスには、%sを使用します。 + Prune configured below the minimum of %d MiB. Please use a higher number. 剪定が最小値の %d MiB以下に設定されています。もっと大きな値を使用してください。 @@ -4173,10 +5466,6 @@ Wallet is locked, can't replenish keypool! Automatic backups and mixing are disabled, please unlock your wallet to replenish keypool. ウォレットがロックされているのでキープールを補充できません!自動バックアップとミキシングが無効なので、ウォレットをアンロックしてキープールを補充してください。 - - You need to rebuild the database using -reindex to change -timestampindex - -timestampindexを変更するには、-reindexを使用してデータベースを再構築する必要があります。 - You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain 非剪定モードに戻るためには-reindexオプションを使用してデータベースを再構築する必要があります。これによりブロックチェーン全体の再ダウンロードが行われます。 @@ -4218,20 +5507,32 @@ %sの読み込みエラー:プライベートキーは作成時にのみ無効化できます。 - Error upgrading evo database - Evoデータベースのアップグレードエラー + Error: Couldn't create cursor into database + エラー: データベースにカーソルを作成できませんでした Error: Disk space is low for %s エラー:%sのディスク容量が不足しています - Exceeded max tries. - 最大試行回数を超えました。 + Error: Dumpfile checksum does not match. Computed %s, expected %s + エラー: ダンプファイルのチェックサムが一致しません。算出されたものは%s、一致するものは%sです + + + Error: Got key that was not hex: %s + エラー: 16進数ではないキーを検出しました: %s + + + Error: Got value that was not hex: %s + エラー: 16進数ではない値を検出しました: %s + + + Error: Keypool ran out, please call keypoolrefill first + エラー: キープールが切れました。まずは、keypoolrefillに連絡してください。 - Failed to commit EvoDB - EvoDBのコミットに失敗しました + Error: No addresses available. + エラー: 利用可能なアドレスがありません。 Failed to create backup %s! @@ -4249,17 +5550,29 @@ Failed to rescan the wallet during initialization 初期化中にウォレットの再スキャンに失敗しました + + Failed to verify database + データベースの検証に失敗しました + + + Fee rate (%s) is lower than the minimum fee rate setting (%s) + 料金レート(%s)が、最低料金レートの設定(%s)よりも低いです + Found enough users, signing… 充分なユーザーを発見しました、サインしています - Invalid P2P permission: '%s' - 無効なP2P許可:「%s」 + Ignoring duplicate -wallet %s. + 重複した-wallet %sを無視します。 + + + Input not found or already spent + 入力内容が見つからないか、すでに使用済みです - Invalid amount for -fallbackfee=<amount>: '%s' - 無効な額 -fallbackfee=<amount>: '%s' + Invalid P2P permission: '%s' + 無効なP2P許可:「%s」 Invalid masternodeblsprivkey. Please see documentation. @@ -4281,6 +5594,10 @@ Mixing in progress… ミキシング中… + + No addresses available + 利用可能なアドレスがありません + No errors detected. エラーは検出されていません。 @@ -4309,6 +5626,22 @@ Prune mode is incompatible with -txindex. 剪定モードは-txindexと互換性がありません。 + + SQLiteDatabase: Failed to execute statement to verify database: %s + SQLiteのデータベース: データベースの検証文の実行に失敗しました: %s + + + SQLiteDatabase: Failed to prepare statement to verify database: %s + SQLiteのデータベース: データベースの検証文の準備に失敗しました: %s + + + SQLiteDatabase: Failed to read database verification error: %s + SQLiteのデータベース: データベースの検証エラーを読み取れませんでした: %s + + + SQLiteDatabase: Unexpected application id. Expected %u, got %u + SQLiteのデータベース: アプリケーションIDが一致しません。%uを想定していましたが、%uが入力されました。 + Section [%s] is not recognized. [%s]のセクションは認識されません。 @@ -4341,6 +5674,10 @@ This is the transaction fee you will pay if you send a transaction. これは取引を送信する場合に支払う取引手数料です。 + + Topping up keypool… + キープールをチャージ中... + Transaction amounts must not be negative トランザクションの総額はマイナスではあってはいけません。。 @@ -4369,13 +5706,17 @@ Unable to generate initial keys 初期キーが生成できません + + Unable to open %s for writing + %sを書き込みで開けません + Unknown -blockfilterindex value %s. %sは、不明な-blockfilterindexの値です。 - Upgrading UTXO database - UTXOデータベースを更新しています + Unknown new rules activated (versionbit %i) + 不明な新しい規則が有効化されました(バージョンビット%i) Verifying blocks… @@ -4394,16 +5735,12 @@ ウォレットバックアップフォルダー作成不可 %s! - You can not start a masternode with wallet enabled. - ウォレットを有効にした状態でマスターノードを起動することはできません。 - - - You need to rebuild the database using -reindex to change -addressindex - -addressindexを変更するために、-reindexを使用してデータベースを再構築する必要があります + Wiping wallet transactions… + ウォレットの取引履歴を消去中… - You need to rebuild the database using -reindex to change -spentindex - -spentindexを変更するために、-reindexを使用してデータベースを再構築する必要があります + You can not start a masternode with wallet enabled. + ウォレットを有効にした状態でマスターノードを起動することはできません。 no mixing available. @@ -4421,6 +5758,22 @@ %s uses exact denominated amounts to send funds, you might simply need to mix some more coins. %sは正確に換算した金額を送金するため、単純にいくらかのコインをミキシングする必要があるかもしれません。 + + -reindex-chainstate option is not compatible with -blockfilterindex. Please temporarily disable blockfilterindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes. + -reindex-chainstateのオプションは-blockfilterindexと互換性がありません。-reindex-chainstateを使用する際は、一時的にblockfilterindexを無効にしてください。また、全てのインデックスを完全に再構築するには、-reindex-chainstateを-reindexに置き換えてください。 + + + -reindex-chainstate option is not compatible with -coinstatsindex. Please temporarily disable coinstatsindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes. + -reindex-chainstateのオプションは-coinstatsindexと互換性がありません。-reindex-chainstateを使用する際は、一時的にcoinstatsindexを無効にしてください。また、全てのインデックスを完全に再構築するには、-reindex-chainstateを-reindexに置き換えてください。 + + + -reindex-chainstate option is not compatible with -txindex. Please temporarily disable txindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes. + -reindex-chainstateのオプションは-txindexと互換性がありません。-reindex-chainstateを使用する際は、一時的にtxindexを無効にしてください。また、全てのインデックスを完全に再構築するには、-reindex-chainstateを-reindexに置き換えてください。 + + + Cannot downgrade wallet from version %i to version %i. Wallet version unchanged. + ウォレットをバージョン%iからバージョン%iにダウングレードできません。ウォレットのバージョンは変更されません。 + Cannot obtain a lock on data directory %s. %s is probably already running. データディレクトリ %s のロックを取得することができません。おそらく %s は実行中です。 @@ -4433,14 +5786,82 @@ Error loading %s: You can't enable HD on an already existing non-HD wallet %s読み込みエラー: 既存の非HDウォレット上でHDを有効化できません + + 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 + ウォレットのロード中にエラーが発生しました。ウォレットはブロックをダウンロードする必要があり、assumeutxoのスナップショットを使用している場合、ブロックが順番通りにダウンロードされていない状態でのウォレットのロードはソフトウェアで現在サポートされていません。ノードの同期が%sの高さに達すると、ウォレットは正常にロードできるようになります。 + Error reading %s! All keys read correctly, but transaction data or address book entries might be missing or incorrect. %s の読み込みエラー! すべてのキーは正しく読み取れますが、トランザクションデータやアドレス帳のエントリが失われたか、正しくない可能性があります。 + + Error: Dumpfile format record is incorrect. Got "%s", expected "format". + エラー: ダンプファイルの形式記録が正しくありません。「%s」を取得しましたが、「format」が求められています。 + + + Error: Dumpfile identifier record is incorrect. Got "%s", expected "%s". + エラー: ダンプファイルの識別記録が正しくありません。「%s」を取得しましたが、「%s」が適切です。 + + + Error: Dumpfile version is not supported. This version of bitcoin-wallet only supports version 1 dumpfiles. Got dumpfile with version %s + エラー: ダンプファイルのバージョンがサポートされていません。このバージョンのbitcoin-wallet は、バージョン1のダンプファイルのみをサポートしていますが、バージョン%sのダンプファイルを取得してしまいました。 + + + Failed to rename invalid peers.dat file. Please move or delete it and try again. + 無効なpeers.datファイルの名前を変更できませんでした。peers.datファイルを移動または削除してから、再度お試しください。 + + + Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable %s. + 手数料の推定に失敗しました。フォールバック手数料が無効になっています。数ブロック待つか %s を有効にしてください。 + + + File %s already exists. If you are sure this is what you want, move it out of the way first. + %sのファイルはすでに存在しています。本当にファイルを希望する場合は、先に既存のものを移動させてください。 + + + Incompatible options: -dnsseed=1 was explicitly specified, but -onlynet forbids connections to IPv4/IPv6 + 互換性のないオプション: -dnsseed=1が明示的に指定されましたが、-onlynetがIPv4/IPv6への接続を禁止しています。 + Incorrect or no devnet genesis block found. Wrong datadir for devnet specified? 無効なdevnetジェネシスブロックが発見されたか、またはdevnetジェネシスブロックが発見されません。 特定のdevnet用のデータディレクトリが間違ってませんか? + + Invalid amount for %s=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions) + %s=<amount> の金額が無効です:「%s」(トランザクションのスタックを防ぐため、少なくとも %s の最小リレー手数料が必要です) + + + 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. + peers.dat(%s)が無効または破損しています。これがバグだと思われる場合は、%sに報告してください。対処法として、ファイル(%s)を移動(名前の変更、移動、または削除)して、次回起動する際に新しいファイルを作成できるようにします。 + + + No dump file provided. To use createfromdump, -dumpfile=<filename> must be provided. + ダンプファイルは提供されていません。createfromdumpを使用するには、-dumpfile=<filename>を提示する必要があります。 + + + No dump file provided. To use dump, -dumpfile=<filename> must be provided. + ダンプファイルは提供されていません。dumpを使用するには、-dumpfile=<filename>を提示する必要があります。 + + + No wallet file format provided. To use createfromdump, -format=<format> must be provided. + ウォレットファイルのフォーマットは提供されていません。createfromdumpを使用するには、-format=<format>を提示する必要があります。 + + + Outbound connections restricted to CJDNS (-onlynet=cjdns) but -cjdnsreachable is not provided + アウトバウンド接続はCJDNS(-onlynet=cjdns)に制限されていますが、-cjdnsreachableが指定されていません + + + Outbound connections restricted to Tor (-onlynet=onion) but the proxy for reaching the Tor network is explicitly forbidden: -onion=0 + アウトバウンド接続はTor(-onlynet=onion)に制限されていますが、Torネットワークに接続するプロキシは明示的に禁止されています(-onion=0)。 + + + 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 + アウトバウンド接続はTor(-onlynet=onion)に制限されていますが、Torネットワークに接続するプロキシは提供されておらず、-proxy、-onion、-listenonionのいずれも指定されていません。 + + + Outbound connections restricted to i2p (-onlynet=i2p) but -i2psam is not provided + アウトバウンド接続はi2p(-onlynet=i2p)に制限されていますが、-i2psamが指定されていません + Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly. あなたのPCの日付と時刻が正しいことを確認して下さい! もしあなたの時計が正しくなければ %s が正確に動作しません。 @@ -4449,6 +5870,14 @@ Please contribute if you find %s useful. Visit %s for further information about the software. %s が有用だと感じられた方はぜひプロジェクトへの貢献をお願いします。ソフトウェアのより詳細な情報については %s をご覧ください。 + + Prune mode is incompatible with -reindex-chainstate. Use full -reindex instead. + Pruneモードは、-reindex-chainstateと互換性がありません。代わりに-reindexをフルで使用してください。 + + + This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection. + これは、(通常の料金に加えて)支払うことになる最大の手数料であり、通常の硬貨の選択よりも部分使用の回避を優先する際に発生します。 + This is the transaction fee you may discard if change is smaller than dust at this level これはこのレベルでお釣りがダストよりも少額の場合に破棄できる取引手数料です @@ -4457,14 +5886,38 @@ This is the transaction fee you may pay when fee estimates are not available. これは手数料の推定機能が利用できない場合に支払うトランザクション手数料です。 + + Transaction requires one destination of non-0 value, a non-0 feerate, or a pre-selected input + トランザクションには、非ゼロ値の宛先、非ゼロの手数料率、または事前選択された入力のいずれかが必要です + Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate. ブロックを再生できません。 -reindex-chainstateを使用してデータベースを再構築する必要があります。 + + Unknown wallet file format "%s" provided. Please provide one of "bdb" or "sqlite". + 不明なウォレットファイルの形式「%s」が提供されました。「bdb」または「sqlite」のいずれかを提供してください。 + + + Unsupported chainstate database format found. Please restart with -reindex-chainstate. This will rebuild the chainstate database. + サポートされていないチェーンステートデータベース形式が見つかりました。-reindex-chainstateで再起動してください。これによりチェーンステートデータベースが再構築されます。 + + + Warning: Dumpfile wallet format "%s" does not match command line specified format "%s". + 警告: ダンプファイルのウォレット形式「%s」は、コマンドラインで指定された形式「%s」と一致しません。 + Warning: Private keys detected in wallet {%s} with disabled private keys 警告:プライベートキーが、無効化されたものと一緒にウォレット{%s}で検出されました + + You need to rebuild the database using -reindex to enable -timestampindex + -timestampindexを有効にするには、-reindexを使用してデータベースを再構築する必要があります + + + %s -- Incorrect seed, it should be a hex string + %s -- シードが正しくありません。16進数の文字列でなければなりません。 + %s is not a valid backup folder! %s は無効なバックアップフォルダーです! @@ -4489,10 +5942,30 @@ -rpcport must be specified when -devnet and -server are specified -rpcport は、 -devnet と -server が指定されたとき指定しなければなりません。 + + -statsbatchsize cannot be configured with a negative value. + -statsbatchsizeは負の値で設定できません。 + + + -statsduration cannot be configured with a negative value. + -statsdurationは負の値で設定できません。 + A fatal internal error occurred, see debug.log for details 致命的な内部エラーが発生しました。詳細は、debug.logを参照してください。 + + Cannot create socket (socket() returned error %s) + ソケットを作成できません(socket() がエラー %s を返しました) + + + Cannot get socket address for %s + %s のソケットアドレスを取得できません + + + Cannot init Statsd client + Statsd クライアントを初期化できません + Cannot resolve -%s address: '%s' -%s アドレス '%s' を解決できません @@ -4501,10 +5974,6 @@ Cannot write to data directory '%s'; check permissions. 「%s」のデータディレクトリに書き込めません。権限を確認してください。 - - Change index out of range - チェンジインデックスが範囲外です - Copyright (C) Copyright (C) @@ -4513,9 +5982,17 @@ Disk space is too low! ディスク容量が少なすぎます。 + + Dump file %s does not exist. + %sのダンプファイルは存在しません。 + + + Error creating %s + %sの作成にエラーが発生しました + Error loading %s - %s 読み込みエラー + %sの読み込みにエラーが発生しました Error loading %s: Wallet corrupted @@ -4530,8 +6007,8 @@ 読み込みエラー %s: 既存のHDウォレット上のHDを無効化できません - Error upgrading chainstate database - チェーンステートデータベースのアップグレードエラー + Error reading next record from wallet database + ウォレットのデータベースから次の記録を読み込む際に、エラーが発生しました Loading P2P addresses… @@ -4601,6 +6078,14 @@ Inputs vs outputs size mismatch. インプットとアウトプットのサイズがミスマッチです。 + + Invalid '%s'. Allowed values: 128, 160, 192, 224, 256. + 無効な「%s」です。有効値は、128、160、192、224、256です。 + + + Invalid -i2psam address or hostname: '%s' + 無効な-i2psamアドレスまたはホスト名: 「%s」 + Invalid -onion address or hostname: '%s' 無効な -onion アドレスまたはホスト名: '%s' @@ -4645,14 +6130,78 @@ %s corrupt. Try using the wallet tool dash-wallet to salvage or restoring a backup. %sが破損しています。ウォレットツールのdash-walletを使用してサルベージするか、バックアップを復元してみてください。 + + %s is set very high! Fees this large could be paid on a single transaction. + %s が非常に高く設定されています!このような高額な手数料は、単一のトランザクションで支払われる可能性があります。 + + + %s request to listen on port %u. This port is considered "bad" and thus it is unlikely that any Dash Core peers connect to it. See doc/p2p-bad-ports.md for details and a full list. + %sは、ポート%uで受信するよう要求しています。このポートは「悪い」と見なされるため、Dashコアのピアが接続することはまずありません。詳細および全体リストについては、doc/p2p-bad-ports.mdを参照してください。 + + + Cannot provide specific connections and have addrman find outgoing connections at the same time. + 指定した接続を提供できない上、addrmanで送信接続を検出することもできません。 + + + Failed to upgrade Evo database + Evo データベースのアップグレードに失敗しました + + + Fee needed > fee paid + 必要な手数料 > 支払われた手数料 + + + Host %s on unsupported network + ホスト %s はサポートされていないネットワーク上にあります + + + Invalid amount for %s=<amount>: '%s' (must be at least %s) + %s=<amount> の金額が無効です:「%s」(少なくとも %s が必要です) + + + Invalid amount for %s=<amount>: '%s' + %s=<amount> の金額が無効です:「%s」 + + + Invalid port specified in %s: '%s' + %s で指定されたポートが無効です:「%s」 + Last successful action was too recent. 直近の成功したアクションが最新過ぎでした。 + + Missing solving data for estimating transaction size + トランザクションサイズを推定するための解決データが不足しています + + + No host specified + ホストが指定されていません + + + No host specified, malformed URL + ホストが指定されていません、不正な形式のURL + + + No text before the scheme delimiter, malformed URL + スキーム区切り文字の前にテキストがありません、不正な形式のURL + + + Port must be between %d and %d, supplied %d + ポートは %d から %d の間でなければなりません、指定されたのは %d です + + + Socket not initialized, cannot send message + ソケットが初期化されていません、メッセージを送信できません + The source code is available from %s. ソースコードは %s より入手可能です。 + + The specified config file %s does not exist + 指定した%sという構成ファイルは存在しません + The transaction amount is too small to pay the fee トランザクションの金額が小さすぎて手数料を支払えません @@ -4673,6 +6222,10 @@ Transaction fees are too high. トランザクション手数料が高すぎます + + Transaction needs a change address, but we can't generate it. + トランザクションにはおつりアドレスが必要ですが、生成できません。 + Transaction not valid. トランザクションが無効です @@ -4693,6 +6246,18 @@ Unable to locate enough non-denominated funds for this transaction. この取引に十分な外貨建ての資金を確保できません。 + + Unable to lookup host %s + ホスト %s を検索できません + + + Unable to parse -maxuploadtarget: '%s' + -maxuploadtarget を解析できません:「%s」 + + + Unable to send message to %s (::sendto() returned error %s) + %s にメッセージを送信できません(::sendto() がエラー %s を返しました) + Unable to sign spork message, wrong key? スポークメッセージに署名できません、キーが間違ってませんか? @@ -4706,12 +6271,12 @@ 未知の状態: id = %u - Unsupported logging category %s=%s. - サポートされていないロギングカテゴリ %s=%s. + Unsupported URL scheme, must begin with udp:// + サポートされていないURLスキームです、udp:// で始まる必要があります - Upgrading txindex database - txindexデータベースのアップグレード + Unsupported logging category %s=%s. + サポートされていないロギングカテゴリ %s=%s. Very low number of keys left: %d @@ -4741,9 +6306,25 @@ You can not disable governance validation on a masternode. マスターノードでガバナンスの検証を無効化することはできません。 + + You need to rebuild the database using -reindex to enable -addressindex + -addressindexを有効にするには、-reindexを使用してデータベースを再構築する必要があります + + + You need to rebuild the database using -reindex to enable -spentindex + -spentindexを有効にするには、-reindexを使用してデータベースを再構築する必要があります + Your entries added successfully. あなたの追加エントリーは成功しました。 + + Settings file could not be read + 設定ファイルが読み込めませんでした + + + Settings file could not be written + 設定ファイルが書き込めませんでした + \ No newline at end of file diff --git a/src/qt/locale/dash_ko.ts b/src/qt/locale/dash_ko.ts index 42fc395f8406..b624d8d483f9 100644 --- a/src/qt/locale/dash_ko.ts +++ b/src/qt/locale/dash_ko.ts @@ -65,14 +65,6 @@ C&hoose 선택 (&H) - - Sending addresses - 보내기 주소 - - - Receiving addresses - 받기 주소 - These are your Dash addresses for sending payments. Always check the amount and the receiving address before sending coins. 송금을 위한 대시 주소입니다. 코인을 보내기 전에 항상 금액과 받는 주소를 확인하세요. @@ -94,8 +86,8 @@ 편집(&E) - &Show address QR code - 주소 QR 코드(&S) + Show address &QR code + 주소와 QR 코드 보기(&Q) QR code @@ -105,6 +97,24 @@ Export Address List 주소 목록 추출 + + Comma separated file + Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values. + 쉼표로 구분된 파일 + + + There was an error trying to save the address list to %1. Please try again. + An error message. %1 is a stand-in argument for the name of the file we attempted to save to. + %1에 주소 목록을 저장하는 동안 오류가 발생했습니다. 다시 시도해주세요. + + + Sending addresses - %1 + 보내는 주소 - %1 + + + Receiving addresses - %1 + 받는 주소 - %1 + Exporting Failed 추출에 실패하였습니다. @@ -274,10 +284,22 @@ The passphrase entered for the wallet decryption was incorrect. 지갑 해독을 위해 입력한 암호문이 틀립니다. + + 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 23.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. + 지갑 복호화를 위해 입력한 암호가 올바르지 않습니다. null 문자(즉, 0바이트)가 포함되어 있습니다. 23.0 이전 버전의 소프트웨어에서 암호를 설정한 경우, 첫 번째 null 문자까지(null 문자는 포함하지 않음)의 문자만 사용하여 다시 시도하십시오. 성공하면 향후 이 문제를 방지하기 위해 새 암호를 설정하십시오. + Wallet passphrase was successfully changed. 지갑 암호문이 성공적으로 변경되었습니다. + + Passphrase change failed + 암호 변경 실패 + + + 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 23.0, please try again with only the characters up to — but not including — the first null character. + 지갑 복호화를 위해 입력한 이전 암호가 올바르지 않습니다. null 문자(즉, 0바이트)가 포함되어 있습니다. 23.0 이전 버전의 소프트웨어에서 암호를 설정한 경우, 첫 번째 null 문자까지(null 문자는 포함하지 않음)의 문자만 사용하여 다시 시도하십시오. + Warning: The Caps Lock key is on! 경고: Caps Lock키가 켜져있습니다! @@ -303,7 +325,23 @@ BitcoinApplication - + + Runaway exception + 런어웨이 예외 + + + A fatal error occurred. %1 can no longer continue safely and will quit. + 치명적인 오류가 발생하였습니다. 더 이상 %1 가 안전하지 않을 수 있으며 곧 종료될 예정입니다. + + + Internal error + 내부 오류 + + + An internal error occurred. %1 will attempt to continue safely. This is an unexpected bug which can be reported as described below. + 내부 오류가 발생했습니다. %1 는 계속해서 안전성을 유지하려 할 것입니다. 이는 예상하지 못한 버그로, 아래에 설명된 바와 같이 보고될 예정입니다. + + BitcoinGUI @@ -330,6 +368,10 @@ Request payments (generates QR codes and dash: URIs) 지불 요청하기 (QR코드와 대시 URI가 생성됩니다.) + + Ctrl+Q + Ctrl+Q + &Options… 옵션(&O) @@ -358,6 +400,10 @@ &Verify message… 메시지 검증…(&V) + + &Load PSBT from file… + 파일에서 PSBT 불러오기(&L)... + &Sending addresses 보내기 주소(&S) @@ -390,10 +436,6 @@ &Window 창(&W) - - Minimize - 최소화 - Zoom @@ -446,14 +488,6 @@ Modify configuration options for %1 %1 설정 옵션 수정 - - &Show / Hide - 보이기 / 숨기기(&S) - - - Show or hide the main Window - 메인창 보이기 또는 숨기기 - Encrypt the private keys that belong to your wallet 지갑에 해당하는 개인 키 암호화하기 @@ -518,10 +552,6 @@ Show wallet repair options 지갑 복구 옵션을 표시합니다. - - Open Wallet &Configuration File - 지갑 설정 파일 열기(&C) - Open configuration file 설정 파일을 엽니다. @@ -576,10 +606,40 @@ Show information about %1 %1에 관한 정보를 표시합니다 + + Load PSBT from &clipboard… + 클립보드에서 PSBT 불러오기(&C)… + + + Open debugging and diagnostic console + 디버깅 및 진단 콘솔 열기 + + + Open &wallet configuration file + 지갑 설정 파일 열기(&W) + + + Open a dash: URI + 대시: URI 열기 + Create a new wallet 새로운 지갑 생성하기 + + Restore Wallet… + Name of the menu item that restores wallet from a backup file. + 지갑 복원… + + + Restore a wallet from a backup file + Status tip for Restore Wallet menu item + 백업 파일에서 지갑 복원 + + + Close all wallets + 모든 지갑 닫기 + %1 &information %1 정보 @@ -588,10 +648,42 @@ Show the %1 basic information %1 기본 정보를 보여줍니다 + + &Discreet mode + 비공개 모드(&D) + + + Mask the values in the Overview tab + 전체보기 탭에서 값 가리기 + + + Wallet Data + Name of the wallet data file format. + 지갑 데이터 + + + Load Wallet Backup + The title for Restore Wallet File Windows + 지갑 백업 불러오기 + + + Restore Wallet + Title of pop-up window shown when the user is attempting to restore a wallet. + 지갑 복원 + + + Wallet Name + Label of the input field where the name of the wallet is entered. + 지갑 이름 + &Settings 설정(&S) + + &Minimize + 최소화(&M) + &Help 도움말(&H) @@ -608,8 +700,17 @@ View Governance Proposals 거버넌스 제안서 보기 + + &Hide + 숨기기(&H) + + + S&how + 표시(&H) + %n active connection(s) to Dash network + A substring of the tooltip. 대시 네트워크의 활성 연결 수는 %n 입니다. @@ -628,10 +729,50 @@ Close Wallet… 지갑을 닫습니다… + + Load Partially Signed Blockchain Transaction + 일부 서명된 블록체인 거래 불러오기 + + + Load Partially Signed Blockchain Transaction from clipboard + 클립보드에서 일부 서명된 블록체인 거래 불러오기 + Create Wallet… 지갑을 생성합니다… + + Close All Wallets… + 모든 지갑을 닫습니다... + + + Ctrl+Shift+D + Ctrl+Shift+D + + + Ctrl+M + Ctrl+M + + + Click for more actions. + A substring of the tooltip. "More actions" are available via the context menu. + 더 많은 동작을 원하면 클릭하세요. + + + Show Peers tab + A context menu item. The "Peers tab" is an element of the "Node window". + 피어 탭 표시하기 + + + Disable network activity + A context menu item. + 네트워크 활동 사용 중지하기 + + + Enable network activity + A context menu item. The network activity was disabled previously. + 네트워크 활동 사용하기 + Syncing Headers (%1%)… 헤더 동기화중 (%1%)… @@ -648,10 +789,6 @@ Processing blocks on disk… 디스크에서 블록 처리중… - - Reindexing blocks on disk… - 디스크에서 블록 다시 색인중… - Connecting to peers… 피어에 연결중… @@ -805,10 +942,6 @@ Coin Selection 코인 선택 - - Dust: - 더스트: - After Fee: 수수료 이후: @@ -866,28 +999,32 @@ 확인됨 - Copy address - 주소 복사 + Copy amount + 거래액 복사 + + + &Copy address + 주소 복사(&C) - Copy label - 라벨 복사 + Copy &label + 라벨 복사(&l) - Copy amount - 거래액 복사 + Copy &amount + 금액 복사(&a) - Copy transaction ID - 거래 아이디 복사 + Copy transaction &ID and output index + 거래 아이디(&ID) 및 아웃풋 인덱스 복사 - Lock unspent - 사용되지 않은 주소 잠금 + L&ock unspent + 사용하지 않은 주소 잠금(&L) - Unlock unspent - 사용되지 않은 주소 잠금 해제 + &Unlock unspent + 사용하지 않은 주소 잠금 해제(&U) Copy quantity @@ -905,10 +1042,6 @@ Copy bytes 바이트 복사 - - Copy dust - 더스트 복사 - Copy change 잔돈 복사 @@ -921,18 +1054,6 @@ (%1 locked) (%1 잠금) - - yes - - - - no - 아니오 - - - This label turns red if any recipient receives an amount smaller than the current dust threshold. - 수령인이 현재 더스트 임계값보다 작은 양을 수신하면 이 라벨이 빨간색으로 변합니다. - Can vary +/- %1 duff(s) per input. 입력당 +/- %1 더프가 달라질 수 있습니다. @@ -976,8 +1097,14 @@ CreateWalletActivity + + Create Wallet + Title of window indicating the progress of creation of a new wallet. + 지갑 생성하기 + Creating Wallet <b>%1</b>… + Descriptive text of the create wallet progress window which indicates to the user which wallet is currently being created. 지갑 <b>%1</b> 생성중… @@ -999,6 +1126,10 @@ Wallet Name 지갑 이름 + + Wallet + 지갑 + Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice. 지갑을 암호화합니다. 이 지갑은 귀하가 선택한 암호를 통해 암호화됩니다. @@ -1007,6 +1138,10 @@ Encrypt Wallet 지갑 암호화 + + Advanced Options + 향상된 옵션 + 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. 이 지갑에 대한 개인 키를 해제합니다. 개인 키가 해제된 지갑은 더이상 개인 키를 갖지 않게 되며 HD 시드나 불러온 개인 키를 가질 수 없습니다. 해당 기능은 읽기 전용 지갑에 적합합니다. @@ -1023,11 +1158,23 @@ Make Blank Wallet 빈 지갑 만들기 + + Use descriptors for scriptPubKey management. This feature is well-tested but still considered experimental and not recommended for use yet. + scriptPubKey 설정을 위해 설명자를 사용합니다. 이 기능은 테스트를 마쳤으나 실험적인 것으로 간주되어 아직 사용을 권장하지 않습니다. + + + Descriptor Wallet (EXPERIMENTAL) + 설명자 지갑 (실험) + Create 생성하기 - + + Compiled without sqlite support (required for descriptor wallets) + SQL라이트 지원 없이 컴파일 (설명자 지갑에 필요) + + EditAddressDialog @@ -1116,18 +1263,106 @@ Filter List: 필터 목록: + + Filter proposal list + 제안서 목록 필터 + + + Masternode Count: + 마스터노드 수: + + + Number of masternodes this wallet can vote with (masternodes for which this wallet holds the voting key) + 이 지갑으로 투표할 수 있는 마스터노드 수(이 지갑이 투표 키를 보유한 마스터노드) + Proposal Count: 제안서 수: + + Create Proposal + 제안서 작성 + Filter by Title 제목으로 필터 + + Unavailable + 사용 불가 + + + A synced node and an unlocked wallet are required. + 동기화된 노드와 잠금 해제된 지갑이 필요합니다. + + + Vote Yes + 찬성 투표 + + + Vote No + 반대 투표 + + + Vote Abstain + 기권 투표 + Proposal Info: %1 제안서 정보: %1 + + Voting Failed + 투표 실패 + + + No wallet available. + 사용 가능한 지갑이 없습니다. + + + No masternode voting keys found in wallet. + 지갑에서 마스터노드 투표 키를 찾을 수 없습니다. + + + Please select a proposal to vote on. + 투표할 제안서를 선택하십시오. + + + Unable to unlock wallet. + 지갑 잠금을 해제할 수 없습니다. + + + Unable to get masternode list. Please try again later. + 마스터노드 목록을 가져올 수 없습니다. 나중에 다시 시도하십시오. + + + Masternode %1 not found + 마스터노드 %1을 찾을 수 없습니다 + + + Failed to sign vote for masternode %1 + 마스터노드 %1에 대한 투표 서명 실패 + + + Masternode %1: %2 + 마스터노드 %1: %2 + + + Voted successfully %n time(s) + %n번 성공적으로 투표했습니다 + + + Failed to vote %n time(s) + %n번 투표 실패 + + + Errors: + 오류: + + + Voting Results + 투표 결과 + HelpMessageDialog @@ -1166,10 +1401,26 @@ As this is the first time the program is launched, you can choose where %1 will store its data. 프로그램을 처음으로 실행합니다. 어디에 %1 데이터를 저장 할 지 선택할 수 있습니다. + + Limit block chain storage to + 다음으로 블록체인 저장을 제한하기 + + + 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. + 이 설정을 되돌리기 위해서는 전체 블록체인을 다시 다운받아야 합니다. 전체 블록체인을 다운받은 이후 정리하는 것이 더 빠릅니다. 일부 고급 기능을 비활성화합니다. + + + GB + GB + 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. 초기 동기화는 매우 오래 걸리며 이전에는 본 적 없는 하드웨어 문제가 발생할 수 있습니다. %1을 실행할 때마다 중단 된 곳에서 다시 계속 다운로드 됩니다. + + 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. + 확인을 클릭하면 %1이 %4를 처음 시작할 때 %3의 가장 빠른 거래부터 전체 %4 블록 체인(%2GB)을 다운로드하고 처리하기 시작합니다. + 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. 블록 체인 저장 영역 (블록축소)을 제한하도록 선택한 경우, 이력 데이터는 계속해서 다운로드 및 처리 되어야 하지만 차후 디스크 용량을 줄이기 위해 삭제됩니다. @@ -1182,6 +1433,18 @@ Use a custom data directory: 사용자 설정 데이터 디렉토리 사용하기 + + %n GB of space available + %n GB의 공간 사용 가능 + + + (of %n GB needed) + (필요한 %n GB 중) + + + (%n GB needed for full chain) + (전체 체인에 %n GB 필요) + At least %1 GB of data will be stored in this directory, and it will grow over time. 최소 %1 GB의 데이터가 이 디렉토리에 저장되며 시간이 지남에 따라 증가할 것입니다. @@ -1190,6 +1453,11 @@ Approximately %1 GB of data will be stored in this directory. 약 %1 GB의 데이터가 이 디렉토리에 저장됩니다. + + (sufficient to restore backups %n day(s) old) + Explanatory text on the capability of the current prune target. + (%n일 전 백업을 복원하기에 충분) + %1 will download and store a copy of the Dash block chain. %1은 비트코인 블록체인의 사본을 다운로드하여 저장합니다. @@ -1207,6 +1475,13 @@ 오류 + + LoadWalletsActivity + + Loading wallets… + 지갑 불러오는 중… + + MasternodeList @@ -1241,6 +1516,10 @@ Service 서비스 + + Type + 유형 + PoSe Score PoSe 스코어 @@ -1376,6 +1655,10 @@ Hide 숨기기 + + %1 is currently syncing. It will download headers and blocks from peers and validate them until reaching the tip of the block chain. + 현지 %1이 동기화중입니다. 피어에서 헤더 및 블록을 다운로드하고 블록체인의 끝에 도달할 때까지 유효성을 검사합니다. + Unknown. Syncing Headers (%1, %2%)… 알 수 없음. 헤더 동기화중 (%1, %2%)… @@ -1391,6 +1674,11 @@ URI: URI: + + Paste address from clipboard + Tooltip text for button that allows you to paste an address that is in your clipboard. + 클립보드에서 주소 붙여넣기 + OpenWalletActivity @@ -1406,8 +1694,14 @@ default wallet 기본 지갑 + + Open Wallet + Title of window indicating the progress of opening of a wallet. + 지갑 열기 + Opening Wallet <b>%1</b>… + Descriptive text of the open wallet progress window which indicates to the user which wallet is currently being opened. 지갑 <b>%1</b> 여는 중… @@ -1441,6 +1735,14 @@ &Appearance 외관(&A) + + Show the icon in the system tray. + 시스템 트레이에서 아이콘 보기 + + + &Show tray icon + 트레이 아이콘 보기(&S) + Prune &block storage to 블록 스토리지 정렬(&b) @@ -1453,10 +1755,58 @@ Reverting this setting requires re-downloading the entire blockchain. 이 설정을 되돌리면 전체 블록체인을 다시 다운받아야 합니다. + + 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. + Tooltip text for Options window setting that sets the size of the database cache. Explains the corresponding effects of increasing/decreasing this value. + 최대 데이터베이스 캐시 크기. 캐시가 클 수록 더 빠른 동기화를 지원하지만, 대부분의 사용 사례에서 그 장점이 덜 부각됩니다. 캐시 크기를 줄이면 메모리 사용이 감소합니다. 사용되지 않은 멤풀 메모리는 이 캐시에 공유됩니다. + MiB MiB + + Set the number of script verification threads. Negative values correspond to the number of cores you want to leave free to the system. + 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. + 스크립트 인증 스레드의 갯수 설정. 음수값은 시스템에 여유롭게 남기기를 원하는 코어의 숫자에 상응합니다. + + + This allows you or a third party tool to communicate with the node through command-line and JSON-RPC commands. + Tooltip text for Options window setting that enables the RPC server. + 이로써 당신 혹은 제3자 도구가 명령줄 및 JSON-RPC 명령을 통해 노드와 커뮤니케이션할 수 있게 됩니다. + + + Enable R&PC server + An Options window setting to enable the RPC server. + R&PC 서버 활성화 + + + Whether to set subtract fee from amount as default or not. + Tooltip text for Options window setting that sets subtracting the fee from a sending amount as default. + 금액에서 수수료를 차감하는 것을 기본값으로 할 지의 여부 + + + Subtract &fee from amount by default + An Options window setting to set subtracting the fee from a sending amount as default. + 기본값으로 금액에서 수수료를 차감(&f) + + + Enable &PSBT controls + An options window setting to enable PSBT controls. + PSBT 컨트롤 활성화(&P) + + + Whether to show PSBT controls. + Tooltip text for options window setting that enables PSBT controls. + PSBT 컨트롤을 표시할지 여부. + + + Whether to keep the specified custom change address or not. + 지정된 사용자 변경 주소를 유지할 지의 여부. + + + Keep custom change &address + 사용자 변경 주소 유지(&a) + Show additional tab listing all your masternodes in first sub-tab<br/>and all masternodes on the network in second sub-tab. 추가적인 탭 목록을 보여줍니다. 당신의 모든 마스터노드는 첫 번째 서브 탭에 표시되고,<br/> 네트워크상의 전체 마스터노드는 두 번째 서브 탭에 표시됩니다. @@ -1513,6 +1863,14 @@ Enable &multi-session 멀티 세션 활성화(&m) + + Use this many separate masternodes in parallel to mix funds.<br/>Note: You must use this feature carefully.<br/>Make sure you always have recent wallet (auto)backup in a safe place! + 이 숫자의 마스터노드를 병렬로 사용하여 자금을 믹싱합니다. <br/>주의: 이 기능을 사용할 때에는 주의하십시오. <br/>언제나 안전한 장소에 최신 지갑 (자동) 백업이 설정되어 있는지 확인하세요! + + + Parallel sessions + 병렬 세션 + Mixing rounds 믹싱 라운드 @@ -1525,6 +1883,30 @@ Target balance 타깃 잔고 + + How many inputs of each denominated amount are created.<br/>Lower these numbers if you want fewer smaller denominations. + 각 단위 금액이 생성되는 입력 수. <br/>이 숫자가 줄어들 수록 작은 화폐 단위가 줄어듭니다. + + + Inputs per denomination + 단위 금액당 입력수 + + + Try to create at least this many inputs for each denominated amount.<br/>Lower this number if you want fewer smaller denominations. + 각 화폐 단위 금액에 대해 최소한 이정도의 입력값을 생성하세요. <br/>이 숫자가 줄어들 수록 작은 화폐 단위가 줄어듭니다. + + + Target + 타깃 + + + Create up to this many inputs for each denominated amount.<br/>Lower this number if you want fewer smaller denominations. + 각 화폐 단위 금액에 대해 최대 이 정도의 입력값을 생성하세요. <br/>이 숫자를 줄어들 수록 작은 화폐 단위가 줄어듭니다. + + + Maximum + 최대 + Automatically open the Dash Core client port on the router. This only works when your router supports UPnP and it is enabled. 라우터에서 대시 코어 클라이언트를 자동으로 엽니다. 이 기능은 당신의 라우터가 UPnP를 지원하고 해당 기능이 작동하는 경우에만 가능합니다. @@ -1554,20 +1936,26 @@ 선택된 기본 SOCKS5 프록시가 이 네트워크 유형을 통해 피어에 연결하는 경우에 보여주기 - Options set in this dialog are overridden by the command line or in the configuration file: - 이 대화의 옵션 세트는 명령줄에 의해, 혹은 설정 파일에서 중단됩니다: + Language missing or translation incomplete? Help contributing translations here: +https://explore.transifex.com/dash/dash/ + 언어가 지원되지 않거나 번역이 불완전한가요? 이곳에서 번역에 참여하세요: +https://explore.transifex.com/dash/dash/ - 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. - 창이 닫히는 경우 종료하지 않고 축소합니다. 이 옵션을 활성화하면 메뉴에서 종료를 선택하는 경우에만 어플리케이션이 종료됩니다. + Third-party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items.<br/>%s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |. + 거래 탭에서 컨텍스트 메뉴 항목으로 표시되는 서드파티 URL(예: 블록 탐색기).<br/>URL의 %s는 거래 해시로 대체됩니다. 여러 URL은 수직 바 |로 구분됩니다. - Third party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items.<br/>%s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |. - 거래 탭에 강조 표시된 메뉴 항목으로 나타나는 제3자 URL(예: 블록 탐색기). <br/>해당 URL의 %s 는 거래 해시에 의해 대체됩니다. 다중 URL은 수직 바 | 에 의해 분리됩니다. + &Third-party transaction URLs + 서드파티 거래 URL(&T) - &Third party transaction URLs - 제3자 거래 URL(&T) + Options set in this dialog are overridden by the command line or in the configuration file: + 이 대화의 옵션 세트는 명령줄에 의해, 혹은 설정 파일에서 중단됩니다: + + + 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. + 창이 닫히는 경우 종료하지 않고 축소합니다. 이 옵션을 활성화하면 메뉴에서 종료를 선택하는 경우에만 어플리케이션이 종료됩니다. Whether to show coin control features or not. @@ -1605,6 +1993,10 @@ Map port using &UPnP UPnP를 사용하는 맵 포트(&U) + + Automatically open the Dash Core client port on the router. This only works when your router supports NAT-PMP and it is enabled. The external port could be random. + 라우터에서 대시 코어 클라이언트 포트를 자동으로 엽니다. 이 기능은 당신의 라우터가 NAT-PMP를 지원하고 활성화되어 있는 경우에만 작동합니다. 이 외부 포트는 무작위일 수 있습니다. + Proxy &IP: 프록시 IP:(&i) @@ -1653,6 +2045,14 @@ &Display 디스플레이(&D) + + Connect to the Dash network through a separate SOCKS5 proxy for Tor onion services. + Tor 어니언 서비스를 위한 별도의 SOCKS5 프록시를 통해 대시 네트워크에 연결합니다 + + + Use separate SOCKS&5 proxy to reach peers via Tor onion services: + Tor 어니언 서비스를 통해 피어에 도달하기 위해서는 별도의 SOCKS&5 프록시를 사용하세요 + User Interface &language: 사용자 인터페이스 언어:(&l) @@ -1699,14 +2099,22 @@ Confirm options reset + Window title text of pop-up window shown when the user has chosen to reset options. 옵션 초기화 확인 Client restart required to activate changes. + Text explaining that the settings changed will not come into effect until the client is restarted. 변경 사항을 적용하기 위해서는 프로그램 종료 후 재시작 하여야 합니다. + + Current settings will be backed up at "%1". + 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. + 현재 설정이 "%1"에 백업됩니다. + Client will be shut down. Do you want to proceed? + Text asking the user to confirm if they would like to proceed with a client shutdown. 클라이언트가 종료됩니다, 계속 진행하시겠습니까? @@ -1844,6 +2252,10 @@ %1 Balance %1 잔고 + + Discreet mode activated for the Overview tab. To unmask the values, uncheck Settings->Discreet mode. + 이 전체보기 탭을 위해 비공개 모드가 활성화되었습니다. 값을 보려면 설정->비공개 모드 설정을 해제하세요. + %n Rounds &n 라운드 @@ -1943,7 +2355,140 @@ PSBTOperationsDialog - + + Dialog + 대화 + + + Sign Tx + Tx 서명 + + + Broadcast Tx + Tx 브로드캐스트 + + + Copy to Clipboard + 클립보드에 복사하기 + + + Save… + 저장합니다... + + + Close + 닫기 + + + Failed to load transaction: %1 + 거래를 불러오는 데 실패했습니다: %1 + + + Failed to sign transaction: %1 + 거래에 서명하는 데 실패했습니다: %1 + + + Cannot sign inputs while wallet is locked. + 지갑이 잠긴 상태에서 입력값에 서명할 수 없습니다. + + + Could not sign any more inputs. + 더 이상 입력값에 서명할 수 없습니다. + + + Signed %1 inputs, but more signatures are still required. + %1 입력값에 서명했으나, 더 많은 서명이 필요합니다. + + + Signed transaction successfully. Transaction is ready to broadcast. + 성공적으로 거래에 서명했습니다. 거래를 브로드캐스트 할 준비를 마쳤습니다. + + + Unknown error processing transaction. + 거래를 처리하는 도중 알 수 없는 오류 + + + Transaction broadcast successfully! Transaction ID: %1 + 거래를 브로드캐스트하는 데 성공했습니다! 거래 ID: %1 + + + Transaction broadcast failed: %1 + 거래 브로드캐스트 실패: %1 + + + PSBT copied to clipboard. + PSBT가 클립보드에 복사되었습니다. + + + Save Transaction Data + 거래 데이터 저장하기 + + + Partially Signed Transaction (Binary) + Expanded name of the binary PSBT file format. See: BIP 174. + 일부 서명된 거래 (2진수) + + + PSBT saved to disk. + PSBT가 디스크에 저장되었습니다. + + + * Sends %1 to %2 + * %1을 %2에 보냅니다 + + + own address + 자신의 주소 + + + Unable to calculate transaction fee or total transaction amount. + 거래 수수료 혹은 전체 거래 금액을 계산할 수 없습니다. + + + Pays transaction fee: + 거래 수수료 지불하기: + + + Total Amount + 전체 금액 + + + or + 혹은 + + + Transaction has %1 unsigned inputs. + 거래에 %1개의 서명되지 않은 입력값이 있습니다. + + + Transaction is missing some information about inputs. + 거래의 입력값에 대한 일부 정보가 누락되었습니다. + + + Transaction still needs signature(s). + 거래에 아직 서명(들)이 필요합니다. + + + (But no wallet is loaded.) + (그러나 불러온 지갑이 없습니다.) + + + (But this wallet cannot sign transactions.) + (그러나 이 지갑은 거래에 서명할 수 없습니다.) + + + (But this wallet does not have the right keys.) + (그러나 이 지갑은 올바른 키가 없습니다.) + + + Transaction is fully signed and ready for broadcast. + 거래가 모두 서명되어 브로드캐스트할 준비를 미쳤습니다. + + + Transaction status is unknown. + 거래 상태를 알 수 없습니다. + + PaymentServer @@ -1962,6 +2507,12 @@ 'dash://' is not a valid URI. Use 'dash:' instead. 'dash://' 는 유효하지 않은 URI 입니다. 'dash:' 를 사용하세요. + + Cannot process payment request as BIP70 is no longer supported. +Due to discontinued support, you should request the merchant to provide you with a BIP21 compatible URI or use a wallet that does continue to support BIP70. + BIP70이 더이상 지원되지 않아 지불 요청을 처리할 수 없습니다. +지원이 계속되지 않는 이유로, 판매자에게 BIP21 호환 가능한 URI의 제공 혹은 BIP70을 계속해서 지원하는 지갑을 사용하도록 요청해야 합니다. + URI cannot be parsed! This can be caused by an invalid Dash address or malformed URI parameters. URI를 분석할 수 없습니다! 대시 주소가 유효하지 않거나 URI 파라미터 구성에 오류가 존재할 수 있습니다. @@ -1983,6 +2534,26 @@ Title of Peers Table column which indicates the current latency of the connection with the peer. Ping + + Peer + Title of Peers Table column which contains a unique number used to identify a connection. + 피어 + + + Age + Title of Peers Table column which indicates the duration (length of time) since the peer connection started. + 지속시간 + + + Direction + Title of Peers Table column which indicates the direction the peer connection was initiated from. + 방향 + + + Type + Title of Peers Table column which describes the type of peer connection. The "type" describes why the connection exists. + 유형 + Sent Title of Peers Table column which indicates the total amount of network information we have sent to the peer. @@ -1993,7 +2564,27 @@ Title of Peers Table column which indicates the total amount of network information we have received from the peer. 받음 - + + Address + Title of Peers Table column which contains the IP/Onion/I2P address of the connected peer. + 주소 + + + Network + Title of Peers Table column which states the network the peer connected through. + 네트워크 + + + Inbound + An Inbound Connection from a Peer. + 인바운드 + + + Outbound + An Outbound Connection to a Peer. + 아웃바운드 + + Proposal @@ -2044,8 +2635,193 @@ 상태 + + ProposalWizard + + Create Governance Proposal + 거버넌스 제안서 작성 + + + Enter proposal details + 제안서 세부 정보 입력 + + + A fee will be burned when you prepare the proposal. + 제안서를 준비할 때 수수료가 소각됩니다. + + + Proposal &name + 제안서 이름(&N) + + + &Description URL + 설명 URL(&D) + + + Payment &address + 지급 주소(&A) + + + Payment &amount + 지급 금액(&A) + + + The amount to request in a single payment + 단일 지급으로 요청할 금액 + + + &First payment + 첫 번째 지급(&F) + + + Pa&yments + 지급 횟수(&Y) + + + To&tal amount + 총 금액(&T) + + + Proposal &fee + 제안서 수수료(&F) + + + Next + 다음 + + + Review proposal JSON and validate. + 제안서 JSON을 검토하고 유효성을 검사합니다. + + + Hex-encoded JSON + 16진수 인코딩 JSON + + + Back + 뒤로 + + + Validate + 검증 + + + Prepare (burn fee) and wait for confirmations. + 준비(수수료 소각)하고 확인을 기다립니다. + + + Copy + 복사 + + + At 1/6 confirmations: can be relayed and queued. At 6/6: accepted and processed. + 1/6 확인: 릴레이 및 대기열 가능. 6/6: 수락 및 처리됨. + + + Confirmations progress + 확인 진행 상황 + + + Shows progress toward the required number of confirmations for the proposal fee transaction. + 제안서 수수료 거래에 필요한 확인 수에 대한 진행 상황을 표시합니다. + + + Estimated time remaining: - + 예상 남은 시간: - + + + Prepare Proposal + 제안서 준비 + + + You can submit after 1 confirmation. At 6 confirmations it is accepted and processed. + 1번 확인 후 제출할 수 있습니다. 6번 확인되면 수락 및 처리됩니다. + + + Proposal ID: + 제안서 ID: + + + Submit Proposal + 제안서 제출 + + + Close + 닫기 + + + Valid + 유효함 + + + Invalid: %1 + 유효하지 않음: %1 + + + Burn %1 + %1 소각 + + + Burn %1 to create the fee transaction? + 수수료 거래를 생성하기 위해 %1을 소각하시겠습니까? + + + Prepare failed + 준비 실패 + + + Confirmations: %1 / %2 required + 확인: %1 / %2 필요 + + + Estimated time remaining: Ready + 예상 남은 시간: 준비됨 + + + Estimated time remaining: %n minute(s) + 예상 남은 시간: %n분 + + + Your proposal was submitted successfully. + 제안서가 성공적으로 제출되었습니다. + + + Already submitted + 이미 제출됨 + + + This proposal has already been submitted. + 이 제안서는 이미 제출되었습니다. + + + Submission failed + 제출 실패 + + + Proposal submitted + 제안서 제출됨 + + + A fee of %1 will be burned when you prepare the proposal. + 제안서를 준비할 때 %1의 수수료가 소각됩니다. + + + Prepare (burn %1) and wait for %2 confirmations. + 준비(%1 소각)하고 %2번 확인을 기다립니다. + + QObject + + Do you want to reset settings to default values, or to abort without making changes? + Explanatory text shown on startup when the settings file cannot be read. Prompts user to make a choice between resetting or aborting. + 설정을 기본값으로 재설정하시겠습니까, 혹은 변경 사항 없이 중단하시겠습니까? + + + A fatal error occurred. Check that settings file is writable, or try running with -nosettings. + 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. + 치명적인 오류가 발생했습니다. 설정 파일이 쓰기 가능한지 확인하시거나, -nosetting으로 실행해보세요. + Choose data directory on startup (default: %u) 실행시 데이터 디렉토리 선택하기 (기본값: %u) @@ -2146,6 +2922,53 @@ This can also be adjusted later in the "Appearance" tab of the preferences. 이는 이후 "외관" 탭에서 선호에 따라 다시 조정할 수 있습니다. + + Ctrl+W + Ctrl+W + + + Unroutable + 라우팅 할 수 없음 + + + Internal + 내부 + + + Inbound + An inbound connection from a peer. An inbound connection is a connection initiated by a peer. + 인바운드 + + + Outbound + An outbound connection to a peer. An outbound connection is a connection initiated by us. + 아웃바운드 + + + Full Relay + Peer connection type that relays all network information. + 전체 릴레이 + + + Block Relay + Peer connection type that relays network information about blocks and not transactions or addresses. + 블록 릴레이 + + + Manual + Peer connection type established manually through one of several methods. + 수동 + + + Feeler + Short-lived peer connection type that tests the aliveness of known addresses. + 필러 + + + Address Fetch + Short-lived peer connection type that solicits known addresses from a peer. + 주소 불러오기 + %1 d %1 일 @@ -2207,8 +3030,8 @@ %1 B - %1 KB - %1 KB + %1 kB + %1 kB %1 MB @@ -2264,7 +3087,12 @@ Save QR Code QR 코드 저장 - + + PNG Image + Expanded name of the PNG file format. See: https://en.wikipedia.org/wiki/Portable_Network_Graphics. + PNG 이미지 + + RPCConsole @@ -2371,6 +3199,14 @@ Version 버전 + + High bandwidth BIP152 compact block relay: %1 + 고 대역폭 BIP152 컴팩트 블록 릴레이: %1 + + + High Bandwidth + 고 대역폭 + Starting Block 블록 시작 @@ -2383,6 +3219,51 @@ Synced Blocks 동기화 된 블록 + + Elapsed time since a novel block passing initial validity checks was received from this peer. + 이 피어에서 초기 유효성 검사를 통과한 신규 블록을 받은 후 경과된 시간. + + + Last Block + 마지막 블록 + + + Elapsed time since a novel transaction accepted into our mempool was received from this peer. + Tooltip text for the Last Transaction field in the peer details area. + 피어로부터 멤풀에 수락된 새로운 트랜잭션이 수신된 후 경과된 시간. + + + Last Transaction + 마지막 거래 + + + The mapped Autonomous System used for diversifying peer selection. + 매핑된 자율 시스템은 피어 선택을 다양화하기 위해 사용됩니다. + + + Mapped AS + 매핑된 AS + + + Whether we relay addresses to this peer. + Tooltip text for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No). + 이 피어에 주소를 릴레이 할 지의 여부. + + + Address Relay + Text title for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No). + 주소 릴레이 + + + Addresses Processed + 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). + 처리된 주소 + + + Addresses Rate-Limited + 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. + 요율이 제한된 주소 + Rescan blockchain files 1 블록체인 파일 1 재스캔 @@ -2423,6 +3304,22 @@ To specify a non-default location of the blocks directory use the '%1' option. 블록 디렉토리의 지정되지 않은 로케이션을 특정하기 위해서는 '%1' 옵션을 사용하세요. + + Local Addresses + 로컬 주소 + + + Network addresses that your Dash node is currently using to communicate with other nodes. + 귀하의 Dash 노드가 다른 노드와 통신하기 위해 현재 사용 중인 네트워크 주소입니다. + + + Number of regular Masternodes + 일반 마스터노드 수 + + + Number of EvoNodes + 에보노드 수 + Current block height 현재의 블록 높이 @@ -2471,10 +3368,50 @@ PoSe Score PoSe 스코어 + + The transport layer version: %1 + 전송 레이어 버전: %1 + + + Transport + 전송 + + + The BIP324 session ID string in hex. + 16진수로 표현한 BIP324 세션 ID 스트링. + + + Session ID + 세션 ID + + + The network protocol this peer is connected through: IPv4, IPv6, Onion, I2P, or CJDNS. + 이 피어가 연결되는데 쓰인 네트워크 프로토콜: Pv4, IPv6, Onion, I2P, 혹은 CJDNS. + + + Permissions + 허가 + + + The direction and type of peer connection: %1 + 피어 연결의 방향 및 유형: %1 + + + Direction/Type + 방향/유형 + Services 서비스 + + Whether we relay transactions to this peer. + 이 피어에 거래를 릴레이하는지 여부. + + + Transaction Relay + 거래 릴레이 + Connection Time 접속 시간 @@ -2511,6 +3448,16 @@ &Wallet Repair 지갑 복구(&W) + + The total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting). + 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). + 이 피어에서 수신된 주소의 전체 처리된 수 (요율 제한으로 인해 삭제된 주소는 제외). + + + The total number of addresses received from this peer that were dropped (not processed) due to rate-limiting. + 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. + 이 피어에서 수신된 주소 중 요율 제한으로 인해 (처리되지 않고) 취소된 전체 수. + Wallet repair options. 지갑 복구 옵션 @@ -2524,52 +3471,82 @@ -reindex: 현재의 blk000??.dat 파일로부터 블록체인 인덱스를 재구성합니다. - &Disconnect - 접속 끊기(&D) + Inbound: initiated by peer + Explanatory text for an inbound peer connection. + 인바운드: 피어에 의해 시작됨 - Ban for - 추방 + Outbound Full Relay: default + Explanatory text for an outbound peer connection that relays all network information. This is the default behavior for outbound connections. + 아웃바운드 전체 릴레이: 기본값 - 1 &hour - 1시간(&h) + Outbound Block Relay: does not relay transactions or addresses + Explanatory text for an outbound peer connection that relays network information about blocks and not transactions or addresses. + 아웃바운드 블록 릴레이: 거래 혹은 주소를 릴레이하지 않음 - 1 &day - 1일(&d) + Outbound Manual: added using RPC %1 or %2/%3 configuration options + 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. + 수동 아웃바운드: RPC %1 혹은 %2/%3 설정 옵션을 사용해 추가됨 - 1 &week - 1주(&w) + Outbound Feeler: short-lived, for testing addresses + Explanatory text for a short-lived outbound peer connection that is used to test the aliveness of known addresses. + 아웃바운드 필러: 주소 테스트를 위한 단기용 - 1 &year - 1년(&y) + Outbound Address Fetch: short-lived, for soliciting addresses + Explanatory text for a short-lived outbound peer connection that is used to request addresses from a peer. + 아웃바운드 주소 가져오기: 주소를 불러오기 위한 단기용 - &Unban - 추방 취소(&U) + To + 다음에게 - Welcome to the %1 RPC console. - %1 RPC 콘솔에 오신걸 환영합니다 + we selected the peer for high bandwidth relay + 고 대역폭 릴레이를 위해 피어를 선택하였습니다 - Use up and down arrows to navigate history, and %1 to clear screen. - 기록을 찾아보려면 위 아래 화살표 키를, 화면을 지우려면 %1 키를 사용하십시오. + From + 다음으로부터 + + + the peer selected us for high bandwidth relay + 고 대역폭 릴레이를 위해 피어가 우리럴 선택사였습니다 - Type %1 for an overview of available commands. - 사용 가능한 명령을 둘러보시려면 %1을 입력하십시오. + No + 아니오 - For more information on using this console type %1. - 이 콘솔을 사용하기 위한 더 많은 정보를 둘러보시려면 %1을 입력하십시오. + no high bandwidth relay selected + 고 대역폭 릴레이가 선택되지 않았습니다 - WARNING: Scammers have been active, telling users to type commands here, stealing their wallet contents. Do not use this console without fully understanding the ramifications of a command. - 주의: 사기범들이 사용자들에게 이곳에 명령을 입력하도록 유도하면서 지갑의 내용물을 탈취할 수 있습니다. 명령의 결과에 관해 충분히 숙지하기 전에는 이 콘솔을 사용하지 마십시오. + &Disconnect + 접속 끊기(&D) + + + Ban for + 추방 + + + 1 &hour + 1시간(&h) + + + 1 &week + 1주(&w) + + + 1 &year + 1년(&y) + + + &Unban + 추방 취소(&U) In: @@ -2583,6 +3560,10 @@ Network activity disabled 네트워크 활동 비활성화 + + None + 없음 + Total: %1 (Enabled: %2) 전체: %1 (가능: %2) @@ -2591,10 +3572,105 @@ Executing command without any wallet 지갑 없이 명령 수행하기 + + Ctrl++ + Main shortcut to increase the RPC console font size. + Ctrl++ + + + Ctrl+= + Secondary shortcut to increase the RPC console font size. + Ctrl+= + + + Ctrl+- + Main shortcut to decrease the RPC console font size. + Ctrl+- + + + Ctrl+_ + Secondary shortcut to decrease the RPC console font size. + Ctrl+_ + + + Ctrl+Shift+I + Ctrl+Shift+I + + + Ctrl+Shift+C + Ctrl+Shift+C + + + Ctrl+Shift+G + Ctrl+Shift+G + + + Ctrl+Shift+P + Ctrl+Shift+P + + + Ctrl+Shift+R + Ctrl+Shift+R + Executing command using "%1" wallet "%1" 지갑을 이용하여 명령 수행하기 + + detecting: peer could be v1 or v2 + Explanatory text for "detecting" transport type. + 삭제중: 피어는 v1 혹은 v2일 수 있습니다 + + + v1: unencrypted, plaintext transport protocol + Explanatory text for v1 transport type. + v1: 암호화되지 않음, 일반 텍스트 전송 프로토콜 + + + v2: BIP324 encrypted transport protocol + Explanatory text for v2 transport type. + v2: BIP324 암호화된 전송 프로토콜 + + + &Copy address + Context menu action to copy the address of a peer + 주소 복사(&C) + + + 1 d&ay + 1일 (&d) + + + &Copy IP/Netmask + 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 + IP/넷마스크 복사(&C) + + + 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 + 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. + %1 RPC 콘솔에 오신 것을 환영합니다. +위 아래 화살표를 사용하여 내역을 탐색하시고, %2를 사용하여 화면을 지우세요. +%3과 %4를 사용하여 폰트 사이즈를 줄이거나 늘릴 수 있습니다. +%5를 입력하여 사용 가능한 명령어를 확인하세요. +이 콘솔의 사용에 관한 더 많은 정보를 원하시는 경우 %6를 입력하세요. + +%7경고: 사기꾼들이 사용자에게 이곳에 명령어를 입력하도록 하여 지갑의 내용물을 훔치는 경우가 발생하고 있습니다. 명령의 결과를 완전히 이해하지 않은 경우 콘솔을 사용하지 마십시오.%8 + + + Executing… + A console message indicating an entered command is currently being executed. + 실행중... + + + (peer: %1) + (피어: %1) + via %1 %1 경유 @@ -2611,11 +3687,19 @@ Verified Masternode 인증된 마스터노드 + + Yes + + Unknown 알 수 없음 - + + Never + 아니오 + + ReceiveCoinsDialog @@ -2634,6 +3718,10 @@ An optional message to attach to the payment request, which will be displayed when the request is opened.<br>Note: The message will not be sent with the payment over the Dash network. 지불 요청에 메시지를 첨부할 지 선택할 수 있습니다. 해당 메세지는 지불 요청이 열릴 때 표시될 것 입니다. 메모: 이 메시지는 대시 네트워크로 전송되지 않습니다. + + 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. + 새로운 받기 주소와 연관된 레벨 옵션 (인보이스를 식별하기 위해 사용됨). 이는 또한 지불 요청에 첨부되어 있습니다. + Use this form to request payments. All fields are <b>optional</b>. 지급을 요청하기 위해 아래 형식을 사용하세요. 모든입력 값은 <b>선택 사항</b> 입니다. @@ -2691,28 +3779,60 @@ 지불 요청에 첨부되는 메시지를 입력하세요 - Copy URI - URI 복사 + Copy &URI + URI 복사(&U) + + + &Copy address + 주소 복사(&C) - Copy address - 주소 복사 + Copy &label + 라벨 복사(&l) - Copy label - 라벨 복사 + Copy &message + 메시지 복사(&m) - Copy message - 메시지 복사 + Copy &amount + 금액 복사(&a) - Copy amount - 거래액 복사 + Could not unlock wallet. + 지갑을 잠금 해제 할 수 없습니다. + + + Could not generate new address + 새 주소를 생성할 수 없습니다 - + ReceiveRequestDialog + + Request payment to … + 다음에 지불을 요청합니다 + + + Address: + 주소: + + + Amount: + 금액: + + + Label: + 라벨: + + + Message: + 메시지: + + + Wallet: + 지갑: + Copy &URI URI 복사(&U) @@ -2765,6 +3885,34 @@ 요청됨 + + RestoreWalletActivity + + Restore Wallet + Title of progress window which is displayed when wallets are being restored. + 지갑 복원 + + + Restoring Wallet <b>%1</b>… + Descriptive text of the restore wallets progress window which indicates to the user that wallets are currently being restored. + 지갑 <b>%1</b> 복원 중… + + + Restore wallet failed + Title of message box which is displayed when the wallet could not be restored. + 지갑 복원 실패 + + + Restore wallet warning + Title of message box which is displayed when the wallet is restored with some warning. + 지갑 복원 경고 + + + Restore wallet message + Title of message box which is displayed when the wallet is successfully restored. + 지갑 복원 메시지 + + SendCoinsDialog @@ -2799,10 +3947,6 @@ Fee: 수수료: - - Dust: - 더스트: - Inputs… 입력… @@ -2827,6 +3971,14 @@ Transaction Fee: 거래 수수료: + + 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 dash transactions than the network can process. + 거래량이 블록 내 공간보다 적은 경우, 채굴자 및 노드 중계자가 최소 수수료를 실시할 수 있습니다. 이 최소 수수료를 지불하는 것은 괜찮지만, 네트워크가 처리할 수 있는 것보다 대시 거래에 대한 수요가 많으면 거래가 확인되지 않을 수 있다는 점에 유의하시기 바랍니다. + + + A too low fee might result in a never confirming transaction (read the tooltip) + 수수료가 너무 적으면 거래 승인이 이루어지지 않을 수 있습니다 (도구팁을 확인하세요) + (Smart fee not initialized yet. This usually takes a few blocks…) (Smart fee가 아직 초기화 되지 않았습니다. 이 과정에는 수 블록이 소요됩니다…) @@ -2919,10 +4071,6 @@ Copy bytes bytes 복사 - - Copy dust - 더스트 복사 - Copy change 잔돈 복사 @@ -2939,10 +4087,6 @@ %1 to %2 %1을(를) %2(으)로 - - Are you sure you want to send? - 정말로 보내시겠습니까? - <b>(%1 of %2 entries displayed)</b> <b>(%2 중 %1 입력값 표시됨)</b> @@ -2955,6 +4099,18 @@ Confirm the %1 send action %1 전송 액션 확인 + + Cr&eate Unsigned + 미서명 생성하기(&e) + + + from wallet '%1' + 지갑 '%1' 으로부터 + + + %1 to '%2' + %1 를 '%2'로 + %1 funds only %1 자금만 @@ -3003,6 +4159,51 @@ Confirm send coins 코인 전송 확인 + + Save Transaction Data + 거래 데이터 저장하기 + + + PSBT saved + PSBT 저장됨 + + + Watch-only balance: + 읽기 전용 잔고: + + + Creates a Partially Signed Blockchain Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet. + 오프라인 %1 지갑 혹은 PSBT-호환 가능한 하드웨어 지갑을 사용하여 일부 서명된 블록체인 거래(PSBT)를 생성합니다. + + + Do you want to create this transaction? + 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. + 이 거래를 생성하시겠습니까? + + + Please, review your transaction proposal. This will produce a Partially Signed Blockchain Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet. + 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. + 거래 제안서를 검토하십시오. 이는 부분 서명된 블록체인 거래(PSBT)를 생성하며, 저장하거나 복사한 후 오프라인 %1 지갑 또는 PSBT 호환 하드웨어 지갑으로 서명할 수 있습니다. + + + Please, review your transaction. You can create and send this transaction or create a Partially Signed Blockchain Transaction (PSBT), which you can save or copy and then sign with, e.g., an offline %1 wallet, or a PSBT-compatible hardware wallet. + 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. + 거래를 검토하십시오. 이 거래를 생성하여 전송하거나 부분 서명된 블록체인 거래(PSBT)를 생성할 수 있습니다. PSBT는 저장하거나 복사한 후 오프라인 %1 지갑 또는 PSBT 호환 하드웨어 지갑으로 서명할 수 있습니다. + + + Please, review your transaction. + Text to prompt a user to review the details of the transaction they are attempting to send. + 거래를 검토하십시오. + + + To review recipient list click "Show Details…" + 영수증 리스트를 확인하려면 "세부 내역 보기..."를 클릭하세요 + + + Partially Signed Transaction (Binary) + Expanded name of the binary PSBT file format. See: BIP 174. + 일부 서명된 거래 (2진수) + The recipient address is not valid. Please recheck. 수령인의 주소가 정확하지 않습니다. 다시 확인하세요. @@ -3122,21 +4323,16 @@ A message that was attached to the dash: URI which will be stored with the transaction for your reference. Note: This message will not be sent over the Dash network. 대시: URI에 첨부된 메시지는 거래와 함께 참고용으로 저장됩니다. 주의: 이 메시지는 대시 네트워크로 전송되지 않습니다. + + + SendConfirmationDialog - This is an unauthenticated payment request. - 인증 되지 않은 지급 요청입니다. - - - This is an authenticated payment request. - 인증된 지급 요청 입니다. - - - Pay To: - 송금 대상: + Send + 보내기 - Memo: - 메모: + Create Unsigned + 서명되지 않은 거래 생성 @@ -3276,6 +4472,10 @@ Wallet unlock was cancelled. 지갑 잠금 해제를 취소했습니다. + + No error + 오류 없음 + Private key for the entered address is not available. 입력한 주소에 대한 개인 키를 사용할 수 없습니다. @@ -3305,15 +4505,26 @@ 메시지 검증에 실패했습니다. - Message verified. - 메시지를 검증했습니다. + Message verified. + 메시지를 검증했습니다. + + + + SplashScreen + + (press q to shutdown and continue later) + (q를 눌러 종료하고 나중에 계속하기) + + + press q to shutdown + q를 눌러 종료하기 TrafficGraphWidget - KB/s - KB/s + kB/s + kB/s Total @@ -3330,20 +4541,9 @@ TransactionDesc - - Open for %n more block(s) - %n 개의 블록을 더 엽니다. - - - Open until %1 - %1 까지 열림 - - - conflicted - 충돌 - 0/unconfirmed, %1 + 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. 0/미승인, %1 @@ -3356,22 +4556,32 @@ abandoned + 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. 버려진 + + conflicted with a transaction with %1 confirmations + 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. + %1번 확인된 거래와 충돌 + %1/unconfirmed + 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, and still not locked via ChainLocks. %1/미확인 %1 confirmations + 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 or locked via ChainLocks. %1 확인 locked via ChainLocks + 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 and has been locked by ChainLocks. 체인락스로 잠김 verified via InstantSend + 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 has been locked by InstantSend. 인스턴트샌드를 통해 검증됨 @@ -3390,6 +4600,10 @@ Generated 생성됨 + + Platform Transfer + 플랫폼 전송 + From 으로부터 @@ -3520,14 +4734,6 @@ Address / Label 주소 / 라벨 - - Open for %n more block(s) - %n 개의 블록을 더 엽니다. - - - Open until %1 - %1 까지 열림 - Unconfirmed 미확인 @@ -3588,6 +4794,10 @@ Mined 채굴 + + Platform Transfer + 플랫폼 전송 + %1 Mixing %1 믹싱 @@ -3715,6 +4925,10 @@ Mined 채굴 + + Platform Transfer + 플랫폼 전송 + Other 기타 @@ -3728,49 +4942,63 @@ 최소 거래액 - Abandon transaction - 중단된 거래 + &Copy address + 주소 복사(&C) - Copy address - 주소 복사 + Copy &label + 라벨 복사(&l) - Copy label - 라벨 복사 + Copy &amount + 금액 복사(&a) - Copy amount - 거래액 복사 + Copy transaction &ID + 거래 ID 복사(&I) - Copy transaction ID - 거래 아이디 복사 + Copy &raw transaction + 원 거래 복사(&r) - Copy raw transaction - 원 거래 복사 + Copy full transaction &details + 전체 거래 세부 내역 복사(&d) - Copy full transaction details - 거래 세부 내역 복사 + &Show transaction details + 거래 세부내역 보기(&S) - Edit address label - 주소 라벨 편집 + A&bandon transaction + 거래 중단하기(&b) - Show transaction details - 거래 세부 내역 보기 + Rese&nd transaction + 거래 다시 전송하기(&n) - Show address QR code - 주소 QR 코드 보이기 + &Edit address label + 주소 라벨 편집(&E) + + + Show address &QR code + 주소 QR 코드 보기(&Q) + + + Show in %1 + 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. + %1에서 표시 Export Transaction History 거래 기록 내보내기 + + Comma separated file + Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values. + 쉼표로 구분된 파일 + Confirmed 확인 완료 @@ -3849,10 +5077,54 @@ Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled. 지갑을 닫는 데 너무 오랜 시간이 걸리는 경우 정리가 활성화될 때 전체 체인을 다시 동기화해야 할 수 있습니다. - + + Close all wallets + 모든 지갑 닫기 + + + Are you sure you wish to close all wallets? + 모든 지갑을 정말 닫으시겠습니까? + + WalletFrame - + + No wallet has been loaded. +Go to File > Open Wallet to load a wallet. +- OR - + 불러온 지갑이 없습니다. +파일>지갑 열기로 가서 지갑을 불러오세요. +- 혹은 - + + + Create a new wallet + 새로운 지갑 생성하기 + + + Error + 오류 + + + Unable to decode PSBT from clipboard (invalid base64) + 클립보드에서 PSBT 를 디코드할 수 없습니다 (유효하지 않은 base64) + + + Load Transaction Data + 거래 데이터 불러오기 + + + Partially Signed Transaction (*.psbt) + 일부 서명된 거래 (*.psbt) + + + PSBT file must be smaller than 100 MiB + PSBT 파일은 100 MiB보다 작아야 합니다 + + + Unable to decode PSBT + PSBT 디코드 할 수 없음 + + WalletModel @@ -3878,6 +5150,11 @@ Selected amount: 선택된 금액: + + Wallet Data + Name of the wallet data file format. + 지갑 데이터 + Backup Wallet 지갑 백업 @@ -3905,14 +5182,6 @@ dash-core - - Error: Listening for incoming connections failed (listen returned error %s) - 오류: 들어오는 연결을 수신하는 데 실패했습니다 (수신 반환 오류 %s) - - - Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee. - 수수료 측정에 실패했습니다. Fallbackfee가 비활성화 되었습니다. 수 블록을 기다리거나 Fallbackfee를 활성화하세요. - 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 이 오류는 이 지갑이 완전히 종료되지 않은 채 마지막으로 로딩하면서 최신 버전의 Berkeley DB로 빌드를 사용한 경우 발생할 수 있습니다. 이와 같은 경우 이 지갑을 마지막으로 로딩한 소프트웨어를 사용하십시오. @@ -3970,16 +5239,20 @@ 데이터베이스를 불러오는 데 오류가 발생하였습니다. 곧 종료됩니다. - Failed to listen on any port. Use -listen=0 if you want this. - 포트를 감지하는 데 실패하였습니다. 이를 진행하시려면 -listen=0 을 사용하세요. + Error: Missing checksum + 오류: 체크섬 누락 - -maxtxfee is set very high! Fees this large could be paid on a single transaction. - -maxtxfee 값이 너무 크게 설정 되었습니다! 이 거래에 너무 큰 수수료가 지불 됩니다. + Error: Unable to parse version %u as a uint32_t + 오류: 파스 버전 %u를 uint32_t로 파스할 수 없음 - Cannot provide specific connections and have addrman find outgoing connections at the same. - 특정 연결을 제공하면서 addrman이 외부로 향하는 연결을 찾도록 동시에 설정할 수 없습니다. + Error: Unable to write record to new wallet + 오류: 새로운 지갑에 기록을 쓸 수 없음 + + + Failed to listen on any port. Use -listen=0 if you want this. + 포트를 감지하는 데 실패하였습니다. 이를 진행하시려면 -listen=0 을 사용하세요. Found unconfirmed denominated outputs, will wait till they confirm to continue. @@ -3990,13 +5263,17 @@ 유효하지 않은 -socketevent ('%s')가 지정되었습니다. 이들 모드만이 지원됩니다: %s - Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions) - 다음을 위한 금액이 유효하지 않습니다 -maxtxfee=<amount>: '%s' (거래가 막히는 상황을 방지하게 위해 적어도 %s 의 최소 중계 수수료를 지정해야 합니다) + SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is supported + SQLiteDaraBase: 알 수 없는 sqlite 지갑 스키마 버전 %d. 버전 %d 지원만 가능합니다 Transaction index can't be disabled with governance validation enabled. Either start with -disablegovernance command line switch or enable transaction index. 거버넌스 유효성 검사가 활성화된 경우 거래 색인을 비활성화할 수 없습니다. -disablegovernance 명령어 스위치로 시작하거나 거래 인덱스를 활성화하여 시작하세요. + + Unsupported category-specific logging level -loglevel=%s. Expected -loglevel=<category>:<loglevel>. Valid categories: %s. Valid loglevels: %s. + 지원하지 않는 카테고리별 로깅 수준 -loglevel=%s. 예상되는 -loglevel=<category>:<loglevel>. 유효한 카테고리: %s. 유효한 로그레벨: %s. + Can't mix: no compatible inputs found! 믹스할 수 없습니다: 호환 가능한 입력값을 찾을 수 없습니다! @@ -4005,6 +5282,14 @@ Entry exceeds maximum size. 입력값이 최대치를 초과하였습니다. + + Error upgrading evo database for EHF + EHF를 위한 에볼루션 데이터베이스 업그레이드 오류 + + + Failed to commit Evo database + 에볼루션 데이터베이스 커밋 실패 + Found enough users, signing ( waiting %s ) 충분한 사용자를 감지하였습니다. 신호를 보내는 중입니다. ( %s 기다리기 ) @@ -4029,18 +5314,14 @@ Insufficient funds. 잔고가 충분하지 않습니다. - - Invalid amount for -discardfee=<amount>: '%s' - -discardfee=1: '%s' 에 대한 유효하지 않은 금액 - - - Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s) - 유효하지 않은 금액입니다. -paytxfee=<amount>: '%s' (최소 %s 이상이어야 합니다) - Invalid minimum number of spork signers specified with -minsporkkeys -minsporkkeys로 지정된 스포크 서명자의 최소 숫자가 유효하지 않습니다. + + Listening for incoming connections failed (listen returned error %s) + 들어오는 연결 수신 실패 (수신 반환 오류 %s) + Lock is already in place. 이미 잠금 상태입니다. @@ -4097,6 +5378,10 @@ Synchronizing governance objects… 거버넌스 객체 동기화중… + + Transaction change output index out of range + 범위 밖의 거래 변경 아웃풋 인덱스 + Unable to start HTTP server. See debug log for details. HTTP 서버를 시작할 수 없습니다. 자세한 사항은 디버그 로그를 확인 하세요. @@ -4105,6 +5390,10 @@ Unknown response. 알 수 없는 반응. + + Unsupported global logging level -loglevel=%s. Valid values: %s. + 지원되지 않는 글로벌 로깅 레벨 -loglevel=%s. 유효한 값: %s. + User Agent comment (%s) contains unsafe characters. 사용자 정의 코멘트 (%s)에 안전하지 못한 글자가 포함되어 있습니다. @@ -4145,6 +5434,10 @@ Make sure to encrypt your wallet and delete all non-encrypted backups after you have verified that the wallet works! 해당 지갑이 작동하는 지 여부를 확인한 이후에는 당신의 지갑을 암호화하고, 암호화하지 않은 지갑 백업은 지워야 한다는 점을 주의하세요! + + More than one onion bind address is provided. Using %s for the automatically created Tor onion service. + 하나 이상의 어니언 바인드 주소가 제공됩니다. 토르 어니언 서버를 자동으로 생성하기위해 %s를 사용합니다. + Prune configured below the minimum of %d MiB. Please use a higher number. 축소 환경이 최소치인 %d MiB 이하로 설정되어 있습니다. 더 높은 값을 사용하십시오. @@ -4173,10 +5466,6 @@ Wallet is locked, can't replenish keypool! Automatic backups and mixing are disabled, please unlock your wallet to replenish keypool. 지갑이 잠금 상태 입니다. 키풀을 보충할 수 없습니다! 자동 백업과 믹싱이 비활성화 됩니다. 키풀 보충을 위해서는 지갑을 잠금 해제 하세요. - - You need to rebuild the database using -reindex to change -timestampindex - -timestampindex를 변경하기 위해서는 -reindex 체인 상태를 사용하여 데이터를 재구성해야 합니다. - You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain 축소 모드를 해제하고 데이터베이스를 재구성 하기 위해 -reindex를 사용해야 합니다. 이 명령은 모든 블록체인을 다시 다운로드 할 것 입니다. @@ -4218,20 +5507,32 @@ %s 로딩 오류: 개인 키는 생성 중에만 해제될 수 있습니다 - Error upgrading evo database - 에볼루션 데이터베이스 업그레이드 중 오류가 발생했습니다 + Error: Couldn't create cursor into database + 오류: 데이터베이스에 커서를 생성할 수 없음 Error: Disk space is low for %s 에러: %s를 위한 디스크 공간이 부족합니다 - Exceeded max tries. - 최대 시도 횟수를 초과하였습니다. + Error: Dumpfile checksum does not match. Computed %s, expected %s + 오류: 덤프파일 체크섬이 일치하지 않음. 계산된 %s, 예상된 %s + + + Error: Got key that was not hex: %s + 오류: 16진수가 아닌 키를 얻음: %s + + + Error: Got value that was not hex: %s + 오류: 16진수가 아닌 값을 얻음: %s + + + Error: Keypool ran out, please call keypoolrefill first + 오류: 키풀이 소진되었습니다. 우선 키풀리필을 호출하세요 - Failed to commit EvoDB - EvoDB를 수행하는 데 실패하였습니다 + Error: No addresses available. + 오류: 이용할 수 있는 주소가 없습니다. Failed to create backup %s! @@ -4249,17 +5550,29 @@ Failed to rescan the wallet during initialization 초기치 설정 중 지갑을 재 스캔하는 데 실패하였습니다 + + Failed to verify database + 데이터 베이스 식별 실패 + + + Fee rate (%s) is lower than the minimum fee rate setting (%s) + 수수료 요율 (%s) 이 최소 수수료 설정 (%s) 보다 낮습니다 + Found enough users, signing… 충분한 사용자를 감지하였습니다. 신호를 보내는 중입니다… - Invalid P2P permission: '%s' - 유효하지 않은 P2P 허용: '%s' + Ignoring duplicate -wallet %s. + 중복 -wallet %s 를 무시합니다. + + + Input not found or already spent + 입력을 찾을 수 없거나 이미 사용됨 - Invalid amount for -fallbackfee=<amount>: '%s' - 유효하지 않은 금액 -fallbackfee=<amount>: '%s' + Invalid P2P permission: '%s' + 유효하지 않은 P2P 허용: '%s' Invalid masternodeblsprivkey. Please see documentation. @@ -4281,6 +5594,10 @@ Mixing in progress… 믹싱이 진행 중입니다… + + No addresses available + 사용 가능한 주소 없음 + No errors detected. 에러가 감지되지 않았습니다. @@ -4309,6 +5626,22 @@ Prune mode is incompatible with -txindex. 블록 축소 모드는 -txindex와 호환되지 않습니다. + + SQLiteDatabase: Failed to execute statement to verify database: %s + SQLiteDatabase: 데이터베이스를 식별하기 위해 명령을 실행하는데 실패했습니다: %s + + + SQLiteDatabase: Failed to prepare statement to verify database: %s + SQLiteDatabase: 데이터베이스를 식별하기 위해 명령을 준비하는 데 실패했습니다: %s + + + SQLiteDatabase: Failed to read database verification error: %s + SQLiteDatabase: 데이터베이스 식별 에러를 읽는 데 실패했습니다: %s + + + SQLiteDatabase: Unexpected application id. Expected %u, got %u + SQLiteDatabase: 예상하지 못한 어플리케이션 id. 예상된 %u, 획득 %u + Section [%s] is not recognized. 섹션 [%s]이 인식되지 않습니다. @@ -4341,6 +5674,10 @@ This is the transaction fee you will pay if you send a transaction. 당신의 거래를 처리하는 데 필요한 거래 수수료입니다. + + Topping up keypool… + 키풀 채우는 중... + Transaction amounts must not be negative 거래 금액은 반드시 정수여야 합니다. @@ -4369,13 +5706,17 @@ Unable to generate initial keys 초기 키를 생성할 수 없습니다. + + Unable to open %s for writing + 작성을 위해 %s를 열 수 없음 + Unknown -blockfilterindex value %s. 알 수 없는 -blockfilterindex 값 %s. - Upgrading UTXO database - UTXO 데이터베이스 업그레이드 + Unknown new rules activated (versionbit %i) + 알 수 없는 새로운 규칙이 활성화됨 (versionbit %i) Verifying blocks… @@ -4394,16 +5735,12 @@ 지갑 백업 폴더 %s 를 생성할 수 없었습니다! - You can not start a masternode with wallet enabled. - 지갑이 활성화된 상태에서는 마스터노드를 실행할 수 없습니다. - - - You need to rebuild the database using -reindex to change -addressindex - -addressindex를 변경하기 위해서는 -reindex 체인 상태를 사용하여 데이터를 재구성해야 합니다. + Wiping wallet transactions… + 지갑 거래 지우는 중... - You need to rebuild the database using -reindex to change -spentindex - -spentindex를 변경하기 위해서는 -reindex 체인 상태를 사용하여 데이터를 재구성해야 합니다. + You can not start a masternode with wallet enabled. + 지갑이 활성화된 상태에서는 마스터노드를 실행할 수 없습니다. no mixing available. @@ -4421,6 +5758,22 @@ %s uses exact denominated amounts to send funds, you might simply need to mix some more coins. %s는 송금을 위하여 정확한 분할 단위 금액을 사용합니다. 단순히 더 많은 코인을 믹싱함으로써 문제를 해결할 수 있을 지도 모릅니다. + + -reindex-chainstate option is not compatible with -blockfilterindex. Please temporarily disable blockfilterindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes. + -reindex-chainstate 옵션이 -blockfilterindex와 호환되지 않습니다. -reindex-chainstate를 사용하는 동안 일시적으로 blockfilterindex를 비활성화하거나, -reindex-chainstate를 -reindex로 대체하여 모든 인덱스를 완전히 재구성하십시오. + + + -reindex-chainstate option is not compatible with -coinstatsindex. Please temporarily disable coinstatsindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes. + -reindex-chainstate 옵션이 -coinstatsindex와 호환되지 않습니다. -reindex-chainstate를 사용하는 동안 일시적으로 coinstatsindex를 비활성화하거나, -reindex-chainstate를 -reindex로 대체하여 모든 인덱스를 완전히 재구성하십시오. + + + -reindex-chainstate option is not compatible with -txindex. Please temporarily disable txindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes. + -reindex-chainstate 옵션이 -txindex와 호환되지 않습니다. -reindex-chainstate를 사용하는 동안 일시적으로 txindex를 비활성화하거나, -reindex-chainstate를 -reindex로 대체하여 모든 인덱스를 완전히 재구성하십시오. + + + Cannot downgrade wallet from version %i to version %i. Wallet version unchanged. + 지갑을 버전 %i에서 버전 %i로 다운그레이드 할 수 없습니다. 지갑 버전이 변경되지 않았습니다. + Cannot obtain a lock on data directory %s. %s is probably already running. %s 데이터 디렉토리에 잠금을 설정 할 수 없습니다. %s가 이미 실행 중인 것으로 보입니다. @@ -4433,14 +5786,82 @@ Error loading %s: You can't enable HD on an already existing non-HD wallet %s 로딩 에러: HD 지갑이 아닌 경우 HD를 활성화 할 수 없습니다. + + 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 + 지갑 로딩 오류. 지갑을 이용하려면 블록을 다운로드해야 하며, 현재 소프트웨어는 블록이 assumeutxo 스냅샷을 사용할 때 순서대로 다운로드 되는 동안 지갑 로딩을 지원하지 않습니다. 지갑은 노드 동기화가 높이 %s에 다다랐을 때 성공적으로 로딩할 수 있습니다. + Error reading %s! All keys read correctly, but transaction data or address book entries might be missing or incorrect. %s 불러오기 오류 입니다. 주소 키는 모두 정확하게 읽혔으나 거래 데이터 혹은 주소록에서 누락이나 오류가 존재할 수 있습니다. + + Error: Dumpfile format record is incorrect. Got "%s", expected "format". + 오류: 덤프파일 포맷 기록이 정확하지 않습니다. "%s" 획득, 예상된 "format". + + + Error: Dumpfile identifier record is incorrect. Got "%s", expected "%s". + 오류: 덤프파일 식별기 기록이 정확하지 않습니다. "%s" 획득, 예상된 "%s". + + + Error: Dumpfile version is not supported. This version of bitcoin-wallet only supports version 1 dumpfiles. Got dumpfile with version %s + 오류: 덤프파일 버전이 지원되지 않습니다. 이 버전의 비트코인 지갑은 버전 1 덤프파일만을 지원합니다. 버전 %s 덤프파일 획득 + + + Failed to rename invalid peers.dat file. Please move or delete it and try again. + 유효하지 않은 피어의 이름 바꾸기에 실패하였습니다. 옮기거나 지운 후 다시 시도하세요. + + + Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable %s. + 수수료 추정 실패. Fallbackfee가 비활성화되었습니다. 몇 블록을 기다리거나 %s를 활성화하십시오. + + + File %s already exists. If you are sure this is what you want, move it out of the way first. + 파일 %s 가 이미 존재합니다. 정말 이대로 실행하고자 하신다면, 먼저 다른 곳으로 옮겨주세요. + + + Incompatible options: -dnsseed=1 was explicitly specified, but -onlynet forbids connections to IPv4/IPv6 + 호환할 수 없는 옵션: -dnsseed=1 이 명시적으로 지정되었으나, -onlynet은 IPv4/IPv6 와의 연결을 금지합니다 + Incorrect or no devnet genesis block found. Wrong datadir for devnet specified? 올바르지 않거나 개발 네트워크 생성 블록을 찾을 수 없습니다. 개발 네트워크에 지정된 데이터 디렉토리가 잘못된 것일 수 있습니다. + + Invalid amount for %s=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions) + %s=<amount>에 대한 금액이 유효하지 않음: '%s' (거래가 막히는 것을 방지하려면 최소 %s의 최소 릴레이 수수료여야 함) + + + 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. + 유효하지 않거나 손상된 peers.dat (%s). 이것이 버그라고 생각하신다면, %s에 보고해주십시오. 해결하기 위해서는, 이 파일 (%s) 을 다른 곳으로 이동해서 (이름 바꾸기, 옮기기 혹은 삭제) 다음 시작에 새 파일을 만들 수 있습니다. + + + No dump file provided. To use createfromdump, -dumpfile=<filename> must be provided. + 덤프 파일이 제공되지 않습니다. createfromdump를 사용하기 위해서는, -dumpfile=<filename> 이 제공되어야 합니다. + + + No dump file provided. To use dump, -dumpfile=<filename> must be provided. + 덤프 파일이 제공되지 않습니다. dump를 사용하기 위해서는, -dumpfile=<filename> 이 제공되어야 합니다. + + + No wallet file format provided. To use createfromdump, -format=<format> must be provided. + 지갑 파일 포맷이 제공되지 않습니다. createfromdump를 사용하기 위해서는, -format=<format> 이 제공되어야 합니다. + + + Outbound connections restricted to CJDNS (-onlynet=cjdns) but -cjdnsreachable is not provided + 아웃바운드 연결이 CJDNS (-onlynet=cjdns)로 제한되어 있으나 -cjdnsreachable이 제공되지 않음 + + + Outbound connections restricted to Tor (-onlynet=onion) but the proxy for reaching the Tor network is explicitly forbidden: -onion=0 + 아웃바운드 연결이 토르 (-onlynet=onion) 로 제한되어 있으나 토르 네트워크에 도달하기 위한 프록시가 명시적으로 금지되어 있습니다: -onion=0 + + + 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 + 아웃바운드 연결이 토르 (-onlynet=onion) 로 제한되어 있으나 토르 네트워크에 도달하기 위한 프록시가 제공되지 않았습니다: -proxy 혹은 -listenonion이 주어지지 않음 + + + Outbound connections restricted to i2p (-onlynet=i2p) but -i2psam is not provided + 아웃바운드 연결이 i2p (-onlynet=i2p)로 제한되어 있으나 -i2psam이 제공되지 않음 + Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly. 컴퓨터의 날짜와 시간이 올바른지 확인하십시오! 시간이 잘못되면 %s은 제대로 동작하지 않습니다. @@ -4449,6 +5870,14 @@ Please contribute if you find %s useful. Visit %s for further information about the software. %s이/가 유용하다고 생각한다면 프로젝트에 공헌해주세요. 이 소프트웨어에 대한 보다 자세한 정보는 %s를 방문해주십시오. + + Prune mode is incompatible with -reindex-chainstate. Use full -reindex instead. + 블록 축소 모드가 -reindex-chainstate와 호환되지 않습니다. 대신 완전한 -reindex를 사용하십시오. + + + This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection. + 이는 일반 코인 선택보다 부분 지출 회피를 우선하기 위해 (일반 거래 수수료에 더해) 지불하는 최대 거래 수수료입니다. + This is the transaction fee you may discard if change is smaller than dust at this level 잔돈이 이 수준의 더스트보다 적은 경우 당신이 버려야 할 수도 있는 거래 수수료입니다 @@ -4457,14 +5886,38 @@ This is the transaction fee you may pay when fee estimates are not available. 이것은 수수료 견적을 이용할 수 없는 경우 당신이 지불 하게 될 것으로 예상되는 거래 수수료입니다. + + Transaction requires one destination of non-0 value, a non-0 feerate, or a pre-selected input + 거래는 0이 아닌 값의 대상, 0이 아닌 수수료율 또는 사전 선택된 입력이 필요합니다 + Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate. 블록을 재실행 할 수 없습니다. -reindex-chainstate를 이용해 데이터베이스를 재구성해야 합니다. + + Unknown wallet file format "%s" provided. Please provide one of "bdb" or "sqlite". + 알 수 없는 지갑 파일 포맷 "%s" 이 입력되었습니다. "bdb" 혹은 "splite" 중 하나를 입력하세요. + + + Unsupported chainstate database format found. Please restart with -reindex-chainstate. This will rebuild the chainstate database. + 지원되지 않는 체인상태 데이터베이스 형식이 발견되었습니다. -reindex-chainstate로 재시작하십시오. 이렇게 하면 체인상태 데이터베이스가 재구성됩니다. + + + Warning: Dumpfile wallet format "%s" does not match command line specified format "%s". + 경고: 덤프파일 지갑 포맷 "%s" 이 명령줄에 지정된 포맷인 "%s" 과 일치하지 않습니다. + Warning: Private keys detected in wallet {%s} with disabled private keys 경고: 비활성화된 개인 키가 있는 지갑 {%s}에서 개인 키가 감지되었습니다. + + You need to rebuild the database using -reindex to enable -timestampindex + -timestampindex를 활성화하기 위해서는 -reindex를 이용하여 데이터베이스를 재구성해야 합니다. + + + %s -- Incorrect seed, it should be a hex string + %s -- 올바르지 않은 시드, 16진수 문자열이어야 합니다 + %s is not a valid backup folder! %s는 올바른 백업 폴더가 아닙니다! @@ -4489,10 +5942,30 @@ -rpcport must be specified when -devnet and -server are specified -devnet과 -server가 지정될 때에는 -rpcport도 지정되어야 합니다. + + -statsbatchsize cannot be configured with a negative value. + -statsbatchsize는 음수 값으로 구성할 수 없습니다. + + + -statsduration cannot be configured with a negative value. + -statsduration은 음수 값으로 구성할 수 없습니다. + A fatal internal error occurred, see debug.log for details 치명적인 내부 오류가 발생했습니다. 자세한 내용은 debug.log 에서 확인하십시오. + + Cannot create socket (socket() returned error %s) + 소켓을 생성할 수 없습니다 (socket()이 오류 %s를 반환함) + + + Cannot get socket address for %s + %s에 대한 소켓 주소를 가져올 수 없습니다 + + + Cannot init Statsd client + Statsd 클라이언트를 초기화할 수 없습니다 + Cannot resolve -%s address: '%s' %s주소: '%s'를 확인할 수 없습니다. @@ -4501,10 +5974,6 @@ Cannot write to data directory '%s'; check permissions. '%s' 데이터 디렉토리를 생성할 수 없습니다: 허용 내역을 확인하십시오. - - Change index out of range - 범위 밖의 인덱스 변경 - Copyright (C) Copyright (C) @@ -4513,6 +5982,14 @@ Disk space is too low! 디스크 공간이 부족합니다! + + Dump file %s does not exist. + 덤프파일 %s 가 존재하지 않습니다. + + + Error creating %s + %s 생성 오류 + Error loading %s %s 불러오기 오류 @@ -4530,8 +6007,8 @@ %s 로딩 에러: 이미 존재하는 HD 지갑에서 HD를 비활성화 할 수 없습니다. - Error upgrading chainstate database - 체인 상태 데이터베이스 업그레이드 중 오류가 발생했습니다. + Error reading next record from wallet database + 지갑 데이터베이스에서 다음 기록을 읽는데 오류 발생 Loading P2P addresses… @@ -4601,6 +6078,14 @@ Inputs vs outputs size mismatch. 입력값 vs 출력값 사이즈가 일치하지 않습니다. + + Invalid '%s'. Allowed values: 128, 160, 192, 224, 256. + 유효하지 않은 '%s'. 허용된 값: 128, 160, 192, 224, 256. + + + Invalid -i2psam address or hostname: '%s' + 유효하지 않은 -i2psam 주소 혹은 호스트이름: '%s' + Invalid -onion address or hostname: '%s' 올바르지 않은 -onion 주소 또는 호스트 이름: '%s' @@ -4645,14 +6130,78 @@ %s corrupt. Try using the wallet tool dash-wallet to salvage or restoring a backup. %s이(가) 손상되었습니다. 지갑 도구 dash-wallet을 사용하여 백업을 복구하거나 복원하십시오. + + %s is set very high! Fees this large could be paid on a single transaction. + %s가 매우 높게 설정되었습니다! 이렇게 큰 수수료는 단일 거래에서 지불될 수 있습니다. + + + %s request to listen on port %u. This port is considered "bad" and thus it is unlikely that any Dash Core peers connect to it. See doc/p2p-bad-ports.md for details and a full list. + %s가 포트 %u에서 수신 대기를 요청했습니다. 이 포트는 "나쁜" 것으로 간주되며, 따라서 어떤 Dash Core 피어도 연결하지 않을 가능성이 높습니다. 자세한 내용 및 전체 목록은 doc/p2p-bad-ports.md를 참고하세요. + + + Cannot provide specific connections and have addrman find outgoing connections at the same time. + 특정 연결을 제공하면서 addrman이 외부로 향하는 연결을 찾도록 동시에 설정할 수 없습니다. + + + Failed to upgrade Evo database + Evo 데이터베이스 업그레이드 실패 + + + Fee needed > fee paid + 필요한 수수료 > 지불한 수수료 + + + Host %s on unsupported network + 지원되지 않는 네트워크의 호스트 %s + + + Invalid amount for %s=<amount>: '%s' (must be at least %s) + %s=<amount>에 대한 금액이 유효하지 않음: '%s' (최소 %s여야 함) + + + Invalid amount for %s=<amount>: '%s' + %s=<amount>에 대한 금액이 유효하지 않음: '%s' + + + Invalid port specified in %s: '%s' + %s에 지정된 포트가 유효하지 않음: '%s' + Last successful action was too recent. 지난 성공적 액션이 너무 최신입니다. + + Missing solving data for estimating transaction size + 거래 크기를 추정하기 위한 해결 데이터 누락 + + + No host specified + 호스트가 지정되지 않음 + + + No host specified, malformed URL + 호스트가 지정되지 않음, 잘못된 형식의 URL + + + No text before the scheme delimiter, malformed URL + 스킴 구분 기호 앞에 텍스트 없음, 잘못된 형식의 URL + + + Port must be between %d and %d, supplied %d + 포트는 %d와 %d 사이여야 하며, %d가 제공됨 + + + Socket not initialized, cannot send message + 소켓이 초기화되지 않음, 메시지를 보낼 수 없습니다 + The source code is available from %s. 소스 코드는 %s 에서 확인하실 수 있습니다. + + The specified config file %s does not exist + 선택된 설정 파일 %s가 존재하지 않습니다 + The transaction amount is too small to pay the fee 수수료를 지불하기에 거래 금액이 너무 작습니다. @@ -4673,6 +6222,10 @@ Transaction fees are too high. 거래 수수료가 너무 높습니다. + + Transaction needs a change address, but we can't generate it. + 거래에 잔액 주소가 필요하지만 생성할 수 없습니다. + Transaction not valid. 거래가 유효하지 않습니다. @@ -4693,6 +6246,18 @@ Unable to locate enough non-denominated funds for this transaction. 이 거래에 필요한 비 분할단위 자금을 찾을 수 없습니다. + + Unable to lookup host %s + 호스트 %s를 조회할 수 없습니다 + + + Unable to parse -maxuploadtarget: '%s' + -maxuploadtarget을 파싱할 수 없습니다: '%s' + + + Unable to send message to %s (::sendto() returned error %s) + %s로 메시지를 보낼 수 없습니다 (::sendto()가 오류 %s를 반환함) + Unable to sign spork message, wrong key? 스포크 메시지에 사인할 수 없습니다. 키가 잘못된 것일 수 있습니다. @@ -4706,12 +6271,12 @@ 알 수 없는 상태: id = %u - Unsupported logging category %s=%s. - 지원되지 않는 로깅 카테고리 %s=%s. + Unsupported URL scheme, must begin with udp:// + 지원되지 않는 URL 스킴, udp://로 시작해야 함 - Upgrading txindex database - txindex 데이터베이스 업그레이드 + Unsupported logging category %s=%s. + 지원되지 않는 로깅 카테고리 %s=%s. Very low number of keys left: %d @@ -4741,9 +6306,25 @@ You can not disable governance validation on a masternode. 마스터노드에서 거버넌스 유효성 검사를 해제할 수 없습니다. + + You need to rebuild the database using -reindex to enable -addressindex + -addressindex를 활성화하기 위해서는 -reindex를 사용하여 데이터를 재구성해야 합니다 + + + You need to rebuild the database using -reindex to enable -spentindex + -spentindex를 활성화하기 위해서는 -reindex를 사용하여 데이터를 재구성해야 합니다 + Your entries added successfully. 당신의 입력이 성공적으로 추가되었습니다. + + Settings file could not be read + 설정 파일을 읽을 수 없습니다 + + + Settings file could not be written + 설정 파일을 작성할 수 없습니다 + \ No newline at end of file diff --git a/src/qt/locale/dash_nl.ts b/src/qt/locale/dash_nl.ts index 6f8f58daec6c..ec5ad79ee741 100644 --- a/src/qt/locale/dash_nl.ts +++ b/src/qt/locale/dash_nl.ts @@ -65,14 +65,6 @@ C&hoose K&iezen - - Sending addresses - Verzendadressen - - - Receiving addresses - Ontvangstadressen - These are your Dash addresses for sending payments. Always check the amount and the receiving address before sending coins. Dit zijn uw Dash adressen om betalingen mee uit te voeren. Controleer altijd het bedrag en ontvangstadres voordat u uw Dash verzendt. @@ -94,8 +86,8 @@ &Bewerken - &Show address QR code - Toon adres QR-code + Show address &QR code + Toon adres in &QR-code QR code @@ -105,6 +97,24 @@ Export Address List Exporteer adressenlijst + + Comma separated file + Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values. + Komma-gescheiden bestand + + + There was an error trying to save the address list to %1. Please try again. + An error message. %1 is a stand-in argument for the name of the file we attempted to save to. + Er is een fout is opgetreden tijdens het opslaan van deze adreslijst naar %1. Probeer het opnieuw. + + + Sending addresses - %1 + Verzendadressen - %1 + + + Receiving addresses - %1 + Ontvangstadressen - %1 + Exporting Failed Exporteren mislukt @@ -274,10 +284,22 @@ The passphrase entered for the wallet decryption was incorrect. Het ingevoerde wachtwoord om de portemonnee te ontsleutelen was incorrect. + + 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 23.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. + De ingevoerde wachtwoordzin voor de portemonnee-ontsleuteling is onjuist. Het bevat een null-teken (d.w.z. een nul-byte). Als de wachtwoordzin is ingesteld met een versie van deze software vóór 23.0, probeer het dan opnieuw met alleen de tekens tot — maar niet inclusief — het eerste null-teken. Als dit lukt, stel dan een nieuwe wachtwoordzin in om dit probleem in de toekomst te voorkomen. + Wallet passphrase was successfully changed. Het wachtwoord van de portemonnee is succesvol gewijzigd. + + Passphrase change failed + Wachtwoordzin wijzigen mislukt + + + 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 23.0, please try again with only the characters up to — but not including — the first null character. + De oude wachtwoordzin die is ingevoerd voor de portemonnee-ontsleuteling is onjuist. Het bevat een null-teken (d.w.z. een nul-byte). Als de wachtwoordzin is ingesteld met een versie van deze software vóór 23.0, probeer het dan opnieuw met alleen de tekens tot — maar niet inclusief — het eerste null-teken. + Warning: The Caps Lock key is on! Waarschuwing: Caps-lock staat aan! @@ -303,7 +325,23 @@ BitcoinApplication - + + Runaway exception + Runaway exception + + + A fatal error occurred. %1 can no longer continue safely and will quit. + Er is een fatale fout opgetreden. %1 kan niet langer veilig doorgaan en zal stoppen. + + + Internal error + Interne fout + + + An internal error occurred. %1 will attempt to continue safely. This is an unexpected bug which can be reported as described below. + Er is een interne fout opgetreden. %1 zal proberen veilig door te gaan. Dit is een onverwachte fout die gemeld kan worden zoals hieronder beschreven. + + BitcoinGUI @@ -330,6 +368,10 @@ Request payments (generates QR codes and dash: URIs) Vraag betaling aan (genereert QR-codes en Dash: URI's) + + Ctrl+Q + Ctrl+Q + &Options… &Opties… @@ -358,6 +400,10 @@ &Verify message… &Verifieer handtekening + + &Load PSBT from file… + &Laad PSBT van bestand… + &Sending addresses &Verzendadressen @@ -390,10 +436,6 @@ &Window &Scherm - - Minimize - Minimaliseer - Zoom Zoom @@ -446,14 +488,6 @@ Modify configuration options for %1 Wijzig configuratieopties voor %1 - - &Show / Hide - &Toon / Verberg - - - Show or hide the main Window - Toon of verberg het hoofdscherm - Encrypt the private keys that belong to your wallet Versleutel de geheime sleutels die behoren tot uw portemonnee @@ -518,10 +552,6 @@ Show wallet repair options Toon reparatie opties voor de portemonnee - - Open Wallet &Configuration File - Open portemonnee &configuratie bestand - Open configuration file Open configuratie bestand @@ -576,10 +606,40 @@ Show information about %1 Toon informatie over %1 + + Load PSBT from &clipboard… + Laad PSBT van &klembord… + + + Open debugging and diagnostic console + Open console voor foutopsporing en diagnose + + + Open &wallet configuration file + Open &portemonnee configuratiebestand + + + Open a dash: URI + Open een dash: URI + Create a new wallet Maak een nieuwe portemonnee aan + + Restore Wallet… + Name of the menu item that restores wallet from a backup file. + Portemonnee herstellen… + + + Restore a wallet from a backup file + Status tip for Restore Wallet menu item + Herstel een portemonnee van een back-upbestand + + + Close all wallets + Sluit alle portemonnees + %1 &information %1 &Informatie @@ -588,10 +648,42 @@ Show the %1 basic information Toon de %1 basis informatie + + &Discreet mode + &Discreet modus + + + Mask the values in the Overview tab + Verberg waarden op het Overzicht tabblad + + + Wallet Data + Name of the wallet data file format. + Portemonneegegevens + + + Load Wallet Backup + The title for Restore Wallet File Windows + Laad portemonnee-back-up + + + Restore Wallet + Title of pop-up window shown when the user is attempting to restore a wallet. + Portemonnee herstellen + + + Wallet Name + Label of the input field where the name of the wallet is entered. + Portemonnee naam + &Settings &Instellingen + + &Minimize + &Minimaliseren + &Help &Help @@ -608,8 +700,17 @@ View Governance Proposals Governance voorstellen bekijken + + &Hide + &Verbergen + + + S&how + T&onen + %n active connection(s) to Dash network + A substring of the tooltip. %n actieve verbinding met het Dash netwerk%n actieve verbindingen met het Dash netwerk @@ -628,10 +729,50 @@ Close Wallet… Portemonnee sluiten… + + Load Partially Signed Blockchain Transaction + Laad Gedeeltelijk Ondertekende Blockchain Transactie + + + Load Partially Signed Blockchain Transaction from clipboard + Laad Gedeeltelijk Ondertekende Blockchain Transactie van klembord + Create Wallet… Portemonnee aanmaken… + + Close All Wallets… + Sluit alle portemonnees… + + + Ctrl+Shift+D + Ctrl+Shift+D + + + Ctrl+M + Ctrl+M + + + Click for more actions. + A substring of the tooltip. "More actions" are available via the context menu. + Klik voor meer acties. + + + Show Peers tab + A context menu item. The "Peers tab" is an element of the "Node window". + Toon Peers tabblad + + + Disable network activity + A context menu item. + Zet netwerkactiviteit uit + + + Enable network activity + A context menu item. The network activity was disabled previously. + Zet netwerkactiviteit aan + Syncing Headers (%1%)… Kopteksten synchroniseren (%1%)… @@ -648,10 +789,6 @@ Processing blocks on disk… Bezig met verwerken van blocks op harde schijf… - - Reindexing blocks on disk… - Bezig met herindexeren van blocks op harde schijf… - Connecting to peers… Verbinden met peers… @@ -805,10 +942,6 @@ Coin Selection Munt selectie - - Dust: - Stof - After Fee: Na vergoeding: @@ -866,28 +999,32 @@ Bevestigd - Copy address - Kopieer adres + Copy amount + Kopieer bedrag + + + &Copy address + &Kopieer adres - Copy label - Kopieer Label + Copy &label + Kopieer &label - Copy amount - Kopieer bedrag + Copy &amount + Kopieer &bedrag - Copy transaction ID - Kopieer transactie-ID + Copy transaction &ID and output index + Kopieer transactie &ID en output index - Lock unspent - Blokeer ongebruikte + L&ock unspent + &Vergrendel onuitgegeven - Unlock unspent - Deblokkeer ongebruikte + &Unlock unspent + &Ontgrendel onuitgegeven Copy quantity @@ -905,10 +1042,6 @@ Copy bytes Kopieer bytes - - Copy dust - Kopieer stof - Copy change Kopieer wisselgeld @@ -921,18 +1054,6 @@ (%1 locked) (%1 geblokeerd) - - yes - ja - - - no - nee - - - This label turns red if any recipient receives an amount smaller than the current dust threshold. - Deze label wordt rood als een ontvanger een hoeveelheid kleiner dan de huidige dust-drempel krijgt. - Can vary +/- %1 duff(s) per input. Kan +/- %1 duff(s) per invoer variëren. @@ -976,8 +1097,14 @@ CreateWalletActivity + + Create Wallet + Title of window indicating the progress of creation of a new wallet. + Maak Portemonnee + Creating Wallet <b>%1</b>… + Descriptive text of the create wallet progress window which indicates to the user which wallet is currently being created. Portemonnee <b>%1</b> wordt aangemaakt… @@ -999,6 +1126,10 @@ Wallet Name Portemonnee naam + + Wallet + Portemonnee + Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice. Versleutel de portemonnee. De portemonnee wordt versleuteld met een wachtwoordzin naar keuze. @@ -1007,6 +1138,10 @@ Encrypt Wallet Portemonnee versleutelen + + Advanced Options + Geavanceerde Opties + 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. Schakel privésleutels voor deze portemonnee uit. Portemonnees met uitgeschakelde privésleutels hebben geen privésleutels en kunnen geen HD-seed of geïmporteerde privésleutels hebben. Dit is ideaal voor watch-only portemonnees. @@ -1023,11 +1158,23 @@ Make Blank Wallet Maak lege portemonnee + + Use descriptors for scriptPubKey management. This feature is well-tested but still considered experimental and not recommended for use yet. + Gebruik descriptors voor scriptPubKey beheer. Deze functie is goed getest, maar wordt nog steeds als experimenteel beschouwd en wordt voorlopig niet aanbevolen voor gebruik. + + + Descriptor Wallet (EXPERIMENTAL) + Descriptor Portemonnee (EXPERIMENTEEL) + Create Aanmaken - + + Compiled without sqlite support (required for descriptor wallets) + Gecompileerd zonder sqlite ondersteuning (vereist voor descriptor portemonnees) + + EditAddressDialog @@ -1116,18 +1263,106 @@ Filter List: Filter Lijst: + + Filter proposal list + Filter proposal lijst + + + Masternode Count: + Masternode aantal: + + + Number of masternodes this wallet can vote with (masternodes for which this wallet holds the voting key) + Aantal masternodes waarmee deze portemonnee kan stemmen (masternodes waarvoor deze portemonnee de stemsleutel heeft) + Proposal Count: Proposal aantal: + + Create Proposal + Voorstel maken + Filter by Title Filter op titel + + Unavailable + Niet beschikbaar + + + A synced node and an unlocked wallet are required. + Een gesynchroniseerde node en een ontgrendelde portemonnee zijn vereist. + + + Vote Yes + Stem Ja + + + Vote No + Stem Nee + + + Vote Abstain + Onthouding + Proposal Info: %1 Proposal Info: %1 + + Voting Failed + Stemmen mislukt + + + No wallet available. + Geen portemonnee beschikbaar. + + + No masternode voting keys found in wallet. + Geen masternode stemsleutels gevonden in portemonnee. + + + Please select a proposal to vote on. + Selecteer een voorstel om op te stemmen. + + + Unable to unlock wallet. + Kan portemonnee niet ontgrendelen. + + + Unable to get masternode list. Please try again later. + Kan masternode lijst niet ophalen. Probeer het later opnieuw. + + + Masternode %1 not found + Masternode %1 niet gevonden + + + Failed to sign vote for masternode %1 + Kan stem voor masternode %1 niet ondertekenen + + + Masternode %1: %2 + Masternode %1: %2 + + + Voted successfully %n time(s) + Succesvol gestemd %n keerSuccesvol gestemd %n keer + + + Failed to vote %n time(s) + Stemmen mislukt %n keerStemmen mislukt %n keer + + + Errors: + Fouten: + + + Voting Results + Stemresultaten + HelpMessageDialog @@ -1166,10 +1401,26 @@ As this is the first time the program is launched, you can choose where %1 will store its data. Omdat dit de eerste keer is dat het programma gestart is, kunt u nu kiezen waar %1 de data moet opslaan. + + Limit block chain storage to + Beperk blockchain opslag tot + + + 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. + Het terugzetten van deze instelling vereist het opnieuw downloaden van de gehele blockchain. Het is sneller om eerst de volledige keten te downloaden en later te prunen. Schakelt sommige geavanceerde functies uit. + + + GB + GB + 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. Deze initiële synchronisatie is heel veeleisend, en kan hardware problemen met uw computer blootleggen die voorheen onopgemerkt bleven. Elke keer dat %1 gebruikt word, zal verdergegaan worden waar gebleven is. + + 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. + Zodra je op OK drukt, zal %1 beginnen met het downloaden en verwerken van de volledige %4 blockchain (%2 GB), beginnend met de vroegste transacties in %3 %4 initieel werd gelanceerd. + 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. Als u gekozen heeft om de blokketenopslag te beperken (pruning), dan moet de historische data nog steeds gedownload en verwerkt worden, maar zal verwijderd worden naderhand om schijf gebruik zo laag mogelijk te houden. @@ -1182,6 +1433,18 @@ Use a custom data directory: Gebruik een persoonlijke gegevensmap: + + %n GB of space available + %n GB aan vrije ruimte beschikbaar%n GB aan vrije ruimte beschikbaar + + + (of %n GB needed) + (van %n GB benodigd)(van %n GB benodigd) + + + (%n GB needed for full chain) + (%n GB benodigd voor volledige keten)(%n GB benodigd voor volledige keten) + At least %1 GB of data will be stored in this directory, and it will grow over time. Tenminste %1 GB aan data zal worden opgeslagen in deze map, en dit zal naarmate de tijd voortschrijdt groeien. @@ -1190,6 +1453,11 @@ Approximately %1 GB of data will be stored in this directory. Gemiddeld %1 GB aan data zal worden opgeslagen in deze map. + + (sufficient to restore backups %n day(s) old) + Explanatory text on the capability of the current prune target. + (voldoende om back-ups van %n dag oud te herstellen)(voldoende om back-ups van %n dagen oud te herstellen) + %1 will download and store a copy of the Dash block chain. %1 zal een kopie van de blokketen van Dash downloaden en opslaan. @@ -1207,6 +1475,13 @@ Fout + + LoadWalletsActivity + + Loading wallets… + Portemonnees laden… + + MasternodeList @@ -1241,6 +1516,10 @@ Service Service + + Type + Type + PoSe Score PoSe Score @@ -1376,6 +1655,10 @@ Hide Verbergen + + %1 is currently syncing. It will download headers and blocks from peers and validate them until reaching the tip of the block chain. + %1 is momenteel aan het synchroniseren. Het zal kopteksten en blocks van peers downloaden en deze valideren totdat het het einde van de blockchain heeft bereikt. + Unknown. Syncing Headers (%1, %2%)… Onbekend. Kopteksten synchroniseren (%1, %2%)… @@ -1391,6 +1674,11 @@ URI: URI: + + Paste address from clipboard + Tooltip text for button that allows you to paste an address that is in your clipboard. + Plak adres van klembord + OpenWalletActivity @@ -1406,8 +1694,14 @@ default wallet standaard portemonnee + + Open Wallet + Title of window indicating the progress of opening of a wallet. + portemonnee openen + Opening Wallet <b>%1</b>… + Descriptive text of the open wallet progress window which indicates to the user which wallet is currently being opened. Portemonnee <b>%1</b> wordt geopend… @@ -1441,6 +1735,14 @@ &Appearance &Uiterlijk + + Show the icon in the system tray. + Toon het pictogram in het systeemvak. + + + &Show tray icon + &Toon systeemvakpictogram + Prune &block storage to Prune &blokopslag naar @@ -1453,10 +1755,58 @@ Reverting this setting requires re-downloading the entire blockchain. Deze instelling terugdraaien vereist het opnieuw downloaden van de complete blokketen. + + 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. + Tooltip text for Options window setting that sets the size of the database cache. Explains the corresponding effects of increasing/decreasing this value. + Maximale grootte van de database cache. Een grotere cache kan bijdragen aan snellere synchronisatie, waarna het voordeel voor de meeste toepassingen minder merkbaar is. Het verlagen van de cachegrootte vermindert het geheugengebruik. Ongebruikt mempool geheugen wordt gedeeld voor deze cache. + MiB MiB + + Set the number of script verification threads. Negative values correspond to the number of cores you want to leave free to the system. + 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. + Stel het aantal scriptverificatie threads in. Negatieve waarden komen overeen met het aantal cores dat je vrij wilt laten voor het systeem. + + + This allows you or a third party tool to communicate with the node through command-line and JSON-RPC commands. + Tooltip text for Options window setting that enables the RPC server. + Dit stelt jou of een tool van een derde partij in staat om via commandoregels en JSON-RPC opdrachten te communiceren met de node. + + + Enable R&PC server + An Options window setting to enable the RPC server. + Schakel R&PC server in + + + Whether to set subtract fee from amount as default or not. + Tooltip text for Options window setting that sets subtracting the fee from a sending amount as default. + Of het de standaardinstelling moet zijn om de kosten van het bedrag af te trekken of niet. + + + Subtract &fee from amount by default + An Options window setting to set subtracting the fee from a sending amount as default. + Trek &vergoeding standaard af van het bedrag + + + Enable &PSBT controls + An options window setting to enable PSBT controls. + &PSBT-besturing inschakelen + + + Whether to show PSBT controls. + Tooltip text for options window setting that enables PSBT controls. + Of PSBT-besturing getoond moet worden. + + + Whether to keep the specified custom change address or not. + Of het opgegeven aangepaste wisselgeld adres behouden moet blijven of niet. + + + Keep custom change &address + Houd aangepast wisselgeld&adres + Show additional tab listing all your masternodes in first sub-tab<br/>and all masternodes on the network in second sub-tab. Toon extra tabblad waarin je al jouw masternodes toont in de eerste sub-tab<br/> en alle masternodes op het netwerk in het tweede sub-tabblad. @@ -1513,6 +1863,14 @@ Enable &multi-session Schakel &multi-sessie in + + Use this many separate masternodes in parallel to mix funds.<br/>Note: You must use this feature carefully.<br/>Make sure you always have recent wallet (auto)backup in a safe place! + Gebruik dit aantal masternodes parallel om saldo te mixen.<br/> Opmerking: Gebruik deze functie voorzichtig. <br/>Zorg ervoor dat je altijd een recente portemonnee (auto)back-up op een veilige plek hebt! + + + Parallel sessions + Parallelle sessies + Mixing rounds Mixrondes @@ -1525,6 +1883,30 @@ Target balance Target Saldo + + How many inputs of each denominated amount are created.<br/>Lower these numbers if you want fewer smaller denominations. + Hoeveel inputs van elk gedenomineerd bedrag worden aangemaakt. <br/>Verlaag deze nummers als je minder kleinere denominaties wilt. + + + Inputs per denomination + Invoeren per denominatie + + + Try to create at least this many inputs for each denominated amount.<br/>Lower this number if you want fewer smaller denominations. + Probeer minimaal dit aantal invoeren te creëren voor elk gedenomineerd bedrag. <br/> Verlaag dit nummer als je minder kleinere denominaties wilt. + + + Target + Doel + + + Create up to this many inputs for each denominated amount.<br/>Lower this number if you want fewer smaller denominations. + Creëer tot dit aantal inputs voor elk gedenomineerd bedrag. <br/> Verlaag dit nummer als je minder kleinere denominaties wilt. + + + Maximum + Maximum + Automatically open the Dash Core client port on the router. This only works when your router supports UPnP and it is enabled. Open automatisch de Dash client poort op de router. Dit werkt alleen als uw router UPnP ondersteunt en dit is ingeschakeld. @@ -1554,20 +1936,26 @@ Toont of de opgegeven standaard SOCK5 proxy gebruikt is om peers via dit netwerk type te bereiken. - Options set in this dialog are overridden by the command line or in the configuration file: - Opties die in dit dialoogvenster worden ingesteld, worden overschreven door de opdrachtregel(CLI) of in het configuratiebestand: + Language missing or translation incomplete? Help contributing translations here: +https://explore.transifex.com/dash/dash/ + Taal ontbreekt of vertaling incompleet? Help mee met het bijdragen van vertalingen hier: +https://explore.transifex.com/dash/dash/ - 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. - 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. + Third-party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items.<br/>%s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |. + URL's van derden (bijvoorbeeld een block explorer) die verschijnen in het transactietabblad als contextmenu-items.<br/>%s in de URL wordt vervangen door transactiehash. Meerdere URL's worden gescheiden door verticale streep |. - Third party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items.<br/>%s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |. - Derde partij URL's (bijvoorbeeld block explorer) dat in de transacties tab verschijnen als contextmenu elementen. %s in de URL is vervangen door transactie hash. Verscheidene URL's zijn gescheiden met een verticale streep |. + &Third-party transaction URLs + &Transactie-URL's van derden - &Third party transaction URLs - &Transactie-URL's van derden + Options set in this dialog are overridden by the command line or in the configuration file: + Opties die in dit dialoogvenster worden ingesteld, worden overschreven door de opdrachtregel(CLI) of in het configuratiebestand: + + + 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. + 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. Whether to show coin control features or not. @@ -1605,6 +1993,10 @@ Map port using &UPnP Portmapping via &UPnP + + Automatically open the Dash Core client port on the router. This only works when your router supports NAT-PMP and it is enabled. The external port could be random. + Open automatisch de Dash Core poort op de router. Dit werkt alleen wanneer je router NAT-PMP ondersteunt en ingeschakeld is. De externe poort kan willekeurig zijn. + Proxy &IP: Proxy &IP: @@ -1654,8 +2046,16 @@ &Interface - User Interface &language: - Taal &Gebruikersinterface: + Connect to the Dash network through a separate SOCKS5 proxy for Tor onion services. + Verbind met het Dash netwerk via een aparte SOCKS5 proxy voor Tor Onion diensten. + + + Use separate SOCKS&5 proxy to reach peers via Tor onion services: + Gebruik een afzonderlijke SOCKS&5 proxy om peers te bereiken via Tor Onion services: + + + User Interface &language: + Taal &Gebruikersinterface: The user interface language can be set here. This setting will take effect after restarting %1. @@ -1699,14 +2099,22 @@ Confirm options reset + Window title text of pop-up window shown when the user has chosen to reset options. Bevestig reset van alle instellingen Client restart required to activate changes. + Text explaining that the settings changed will not come into effect until the client is restarted. Herstart van de client is vereist om aanpassingen door te voeren. + + Current settings will be backed up at "%1". + 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. + Huidige instellingen worden opgeslagen in "%1". + Client will be shut down. Do you want to proceed? + Text asking the user to confirm if they would like to proceed with a client shutdown. De client zal worden afgesloten, wilt u doorgaan? @@ -1845,6 +2253,10 @@ Om te mixen moeten andere gebruikers exact dezelfde denominaties inbrengen.%1 Balance %1 Saldo + + Discreet mode activated for the Overview tab. To unmask the values, uncheck Settings->Discreet mode. + Discrete modus geactiveerd voor het Overzicht-tabblad. Om de waarden zichtbaar te maken, maak optie Instellingen->Discrete modus ongedaan. + %n Rounds %n Ronde%n Rondes @@ -1944,7 +2356,140 @@ Om te mixen moeten andere gebruikers exact dezelfde denominaties inbrengen. PSBTOperationsDialog - + + Dialog + Dialoog + + + Sign Tx + Sign Tx + + + Broadcast Tx + Broadcast Tx + + + Copy to Clipboard + Kopieer naar klembord + + + Save… + Opslaan... + + + Close + Sluiten + + + Failed to load transaction: %1 + Fout bij het laden van de transactie: %1 + + + Failed to sign transaction: %1 + Fout bij het ondertekenen van de transactie: %1 + + + Cannot sign inputs while wallet is locked. + Kan de input niet ondertekenen terwijl de portemonnee vergrendeld is. + + + Could not sign any more inputs. + Kon geen extra inputs ondertekenen. + + + Signed %1 inputs, but more signatures are still required. + %1 inputs ondertekend, maar er zijn nog steeds meer handtekeningen vereist. + + + Signed transaction successfully. Transaction is ready to broadcast. + Transactie succesvol ondertekend. Transactie is klaar om uit te zenden. + + + Unknown error processing transaction. + Onbekende fout bij het verwerken van de transactie. + + + Transaction broadcast successfully! Transaction ID: %1 + Transactie succesvol vergezonden! Transactie ID: %1 + + + Transaction broadcast failed: %1 + Transactie verzending mislukt: %1 + + + PSBT copied to clipboard. + PSBT gekopieerd naar klembord. + + + Save Transaction Data + Transactiegegevens opslaan + + + Partially Signed Transaction (Binary) + Expanded name of the binary PSBT file format. See: BIP 174. + Deels ondertekende transactie (Binair) + + + PSBT saved to disk. + PSBT opgeslagen op schijf. + + + * Sends %1 to %2 + * Stuurt %1 naar %2 + + + own address + eigen adres + + + Unable to calculate transaction fee or total transaction amount. + Kan de transactie fee of het totale transactiebedrag niet berekenen. + + + Pays transaction fee: + Betaalt transactie fee: + + + Total Amount + Totaalbedrag + + + or + of + + + Transaction has %1 unsigned inputs. + Transactie heeft %1 niet-ondertekende inputs. + + + Transaction is missing some information about inputs. + Transactie mist wat informatie over inputs. + + + Transaction still needs signature(s). + Transactie heeft nog handtekening(en) nodig. + + + (But no wallet is loaded.) + (Maar er is geen portemonnee geladen.) + + + (But this wallet cannot sign transactions.) + (Maar deze portemonnee kan geen transacties ondertekenen.) + + + (But this wallet does not have the right keys.) + (Maar deze portemonnee heeft de juiste sleutels niet.) + + + Transaction is fully signed and ready for broadcast. + Transactie is volledig ondertekend en klaar voor verzending. + + + Transaction status is unknown. + Transactiestatus is onbekend. + + PaymentServer @@ -1963,6 +2508,11 @@ Om te mixen moeten andere gebruikers exact dezelfde denominaties inbrengen.'dash://' is not a valid URI. Use 'dash:' instead. 'dash://' is geen geldige URI. Gebruik in plaats daarvan 'dash:'. + + Cannot process payment request as BIP70 is no longer supported. +Due to discontinued support, you should request the merchant to provide you with a BIP21 compatible URI or use a wallet that does continue to support BIP70. + Kan de betalingsverzoek niet verwerken omdat BIP70 niet langer wordt ondersteund. Door het stopzetten van de ondersteuning, moet je de verkoper vragen om je een BIP21-compatibele URI te verstrekken of een portemonnee te gebruiken die BIP70 nog steeds ondersteunt. + URI cannot be parsed! This can be caused by an invalid Dash address or malformed URI parameters. URI kan niet verwerkt worden! Dit kan het gevolg zijn van een ongeldig Dash adres of misvormde URI parameters. @@ -1984,6 +2534,26 @@ Om te mixen moeten andere gebruikers exact dezelfde denominaties inbrengen.Title of Peers Table column which indicates the current latency of the connection with the peer. Ping + + Peer + Title of Peers Table column which contains a unique number used to identify a connection. + Peer + + + Age + Title of Peers Table column which indicates the duration (length of time) since the peer connection started. + Leeftijd + + + Direction + Title of Peers Table column which indicates the direction the peer connection was initiated from. + Richting + + + Type + Title of Peers Table column which describes the type of peer connection. The "type" describes why the connection exists. + Type + Sent Title of Peers Table column which indicates the total amount of network information we have sent to the peer. @@ -1994,7 +2564,27 @@ Om te mixen moeten andere gebruikers exact dezelfde denominaties inbrengen.Title of Peers Table column which indicates the total amount of network information we have received from the peer. Ontvangen - + + Address + Title of Peers Table column which contains the IP/Onion/I2P address of the connected peer. + Adres + + + Network + Title of Peers Table column which states the network the peer connected through. + Netwerk + + + Inbound + An Inbound Connection from a Peer. + Inkomend + + + Outbound + An Outbound Connection to a Peer. + Uitgaand + + Proposal @@ -2045,8 +2635,193 @@ Om te mixen moeten andere gebruikers exact dezelfde denominaties inbrengen.Status + + ProposalWizard + + Create Governance Proposal + Governance-voorstel maken + + + Enter proposal details + Voer voorsteldetails in + + + A fee will be burned when you prepare the proposal. + Er wordt een vergoeding verbrand wanneer u het voorstel voorbereidt. + + + Proposal &name + Voorstel&naam + + + &Description URL + &Beschrijvings-URL + + + Payment &address + Betalings&adres + + + Payment &amount + Betalings&bedrag + + + The amount to request in a single payment + Het bedrag om aan te vragen in een enkele betaling + + + &First payment + &Eerste betaling + + + Pa&yments + Bet&alingen + + + To&tal amount + To&taal bedrag + + + Proposal &fee + Voorstel&vergoeding + + + Next + Volgende + + + Review proposal JSON and validate. + Bekijk voorstel-JSON en valideer. + + + Hex-encoded JSON + Hex-gecodeerde JSON + + + Back + Terug + + + Validate + Valideren + + + Prepare (burn fee) and wait for confirmations. + Voorbereiden (vergoeding verbranden) en wachten op bevestigingen. + + + Copy + Kopiëren + + + At 1/6 confirmations: can be relayed and queued. At 6/6: accepted and processed. + Bij 1/6 bevestigingen: kan worden doorgestuurd en in de wachtrij geplaatst. Bij 6/6: geaccepteerd en verwerkt. + + + Confirmations progress + Bevestigingsvoortgang + + + Shows progress toward the required number of confirmations for the proposal fee transaction. + Toont de voortgang naar het vereiste aantal bevestigingen voor de voorstelvergoedingstransactie. + + + Estimated time remaining: - + Geschatte resterende tijd: - + + + Prepare Proposal + Voorstel voorbereiden + + + You can submit after 1 confirmation. At 6 confirmations it is accepted and processed. + U kunt indienen na 1 bevestiging. Bij 6 bevestigingen wordt het geaccepteerd en verwerkt. + + + Proposal ID: + Voorstel-ID: + + + Submit Proposal + Voorstel indienen + + + Close + Sluiten + + + Valid + Geldig + + + Invalid: %1 + Ongeldig: %1 + + + Burn %1 + Verbranden %1 + + + Burn %1 to create the fee transaction? + %1 verbranden om de vergoedingstransactie aan te maken? + + + Prepare failed + Voorbereiden mislukt + + + Confirmations: %1 / %2 required + Bevestigingen: %1 / %2 vereist + + + Estimated time remaining: Ready + Geschatte resterende tijd: Gereed + + + Estimated time remaining: %n minute(s) + Geschatte resterende tijd: %n minuutGeschatte resterende tijd: %n minuten + + + Your proposal was submitted successfully. + Uw voorstel is succesvol ingediend. + + + Already submitted + Reeds ingediend + + + This proposal has already been submitted. + Dit voorstel is al ingediend. + + + Submission failed + Indienen mislukt + + + Proposal submitted + Voorstel ingediend + + + A fee of %1 will be burned when you prepare the proposal. + Een vergoeding van %1 wordt verbrand wanneer u het voorstel voorbereidt. + + + Prepare (burn %1) and wait for %2 confirmations. + Voorbereiden (verbranden %1) en wachten op %2 bevestigingen. + + QObject + + Do you want to reset settings to default values, or to abort without making changes? + Explanatory text shown on startup when the settings file cannot be read. Prompts user to make a choice between resetting or aborting. + Wil je de instellingen terugzetten naar de standaardwaarden, of annuleren zonder wijzigingen aan te brengen? + + + A fatal error occurred. Check that settings file is writable, or try running with -nosettings. + 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. + Er is een fatale fout opgetreden. Controleer of het instellingenbestand beschrijfbaar is, of probeer het uit te voeren met -nosettings. + Choose data directory on startup (default: %u) Kies data map bij opstarten (standaard: %u) @@ -2147,6 +2922,53 @@ Om te mixen moeten andere gebruikers exact dezelfde denominaties inbrengen.This can also be adjusted later in the "Appearance" tab of the preferences. Dit kan later ook worden aangepast in het tabblad "Uiterlijk" van de voorkeuren. + + Ctrl+W + Ctrl+W + + + Unroutable + Onbereikbaar + + + Internal + Intern + + + Inbound + An inbound connection from a peer. An inbound connection is a connection initiated by a peer. + Inkomend + + + Outbound + An outbound connection to a peer. An outbound connection is a connection initiated by us. + Uitgaand + + + Full Relay + Peer connection type that relays all network information. + Volledige Relay + + + Block Relay + Peer connection type that relays network information about blocks and not transactions or addresses. + Block Relay + + + Manual + Peer connection type established manually through one of several methods. + Handmatig + + + Feeler + Short-lived peer connection type that tests the aliveness of known addresses. + Feeler + + + Address Fetch + Short-lived peer connection type that solicits known addresses from a peer. + Adres Ophalen + %1 d %1 d @@ -2208,8 +3030,8 @@ Om te mixen moeten andere gebruikers exact dezelfde denominaties inbrengen.%1 B - %1 KB - %1 KB + %1 kB + %1 kB %1 MB @@ -2265,7 +3087,12 @@ Om te mixen moeten andere gebruikers exact dezelfde denominaties inbrengen.Save QR Code Sla QR-code op - + + PNG Image + Expanded name of the PNG file format. See: https://en.wikipedia.org/wiki/Portable_Network_Graphics. + PNG Afbeelding + + RPCConsole @@ -2372,6 +3199,14 @@ Om te mixen moeten andere gebruikers exact dezelfde denominaties inbrengen.Version Versie + + High bandwidth BIP152 compact block relay: %1 + Hoge Bandbreedte BIP152 compact block relay: %1 + + + High Bandwidth + Hoge Bandbreedte + Starting Block Start Blok @@ -2384,6 +3219,51 @@ Om te mixen moeten andere gebruikers exact dezelfde denominaties inbrengen.Synced Blocks Gesynchroniseerde blocks + + Elapsed time since a novel block passing initial validity checks was received from this peer. + Verstreken tijd sinds een nieuw block dat de initiële geldigheidscontroles doorstond, werd ontvangen van deze peer. + + + Last Block + Laatste Block + + + Elapsed time since a novel transaction accepted into our mempool was received from this peer. + Tooltip text for the Last Transaction field in the peer details area. + Verstreken tijd sinds een nieuwe transactie die werd geaccepteerd in onze mempool, werd ontvangen van deze peer. + + + Last Transaction + Laatste Transactie + + + The mapped Autonomous System used for diversifying peer selection. + Het gemapte Autonomous System dat wordt gebruikt voor het diversifiëren van peerselectie. + + + Mapped AS + Gemapte AS + + + Whether we relay addresses to this peer. + Tooltip text for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No). + Of we adressen doorsturen naar deze peer. + + + Address Relay + Text title for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No). + Adres Relay + + + Addresses Processed + 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). + Verwerkte Adressen + + + Addresses Rate-Limited + 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. + Rate-Limited Adressen + Rescan blockchain files 1 Herscan blokketenbestanden 1 @@ -2424,6 +3304,22 @@ Om te mixen moeten andere gebruikers exact dezelfde denominaties inbrengen.To specify a non-default location of the blocks directory use the '%1' option. Om een niet-standaardlocatie van de blocks map op te geven, gebruik de optie '%1'. + + Local Addresses + Lokale adressen + + + Network addresses that your Dash node is currently using to communicate with other nodes. + Netwerkadressen die uw Dash-node momenteel gebruikt om met andere nodes te communiceren. + + + Number of regular Masternodes + Aantal reguliere Masternodes + + + Number of EvoNodes + Aantal EvoNodes + Current block height Huidige block hoogte @@ -2472,10 +3368,50 @@ Om te mixen moeten andere gebruikers exact dezelfde denominaties inbrengen.PoSe Score PoSe Score + + The transport layer version: %1 + De versie van de transportlaag: %1 + + + Transport + Transport + + + The BIP324 session ID string in hex. + De BIP324 sessie ID in hex. + + + Session ID + Sessie ID + + + The network protocol this peer is connected through: IPv4, IPv6, Onion, I2P, or CJDNS. + Het netwerkprotocol waarmee deze peer verbonden is: IPv4, IPv6, Onion, I2P of CJDNS. + + + Permissions + Machtigingen + + + The direction and type of peer connection: %1 + De richting en het type verbinding van peer: %1 + + + Direction/Type + Richting/Type + Services Services + + Whether we relay transactions to this peer. + Of we transacties doorgeven aan deze peer. + + + Transaction Relay + Transactiedoorgifte + Connection Time Verbindingstijd @@ -2512,6 +3448,16 @@ Om te mixen moeten andere gebruikers exact dezelfde denominaties inbrengen.&Wallet Repair &Portemonnee Herstel + + The total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting). + 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). + Het totale aantal verwerkte adressen ontvangen van deze peer (exclusief verworpen adressen vanwege snelheidsbeperkingen). + + + The total number of addresses received from this peer that were dropped (not processed) due to rate-limiting. + 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. + Het totale aantal ontvangen adressen van deze peer die zijn verworpen (niet verwerkt) vanwege snelheidsbeperkingen. + Wallet repair options. Portemonneeherstelopties @@ -2525,52 +3471,82 @@ Om te mixen moeten andere gebruikers exact dezelfde denominaties inbrengen.-herbouw index: Herbouw de blokketen index vanuit de huidige blk000???.dat bestanden. - &Disconnect - &Verbreek verbinding + Inbound: initiated by peer + Explanatory text for an inbound peer connection. + Inkomend: geïnitieerd door peer - Ban for - Ban Node voor + Outbound Full Relay: default + Explanatory text for an outbound peer connection that relays all network information. This is the default behavior for outbound connections. + Uitgaande Volledige Relay: standaard - 1 &hour - 1 &uur + Outbound Block Relay: does not relay transactions or addresses + Explanatory text for an outbound peer connection that relays network information about blocks and not transactions or addresses. + Uitgaande Block Relay: stuurt geen transacties of adressen door - 1 &day - 1 &dag + Outbound Manual: added using RPC %1 or %2/%3 configuration options + 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. + Uitgaand Handmatig: toegevoegd met RPC %1 of %2/%3 configuratieopties - 1 &week - 1 &week + Outbound Feeler: short-lived, for testing addresses + Explanatory text for a short-lived outbound peer connection that is used to test the aliveness of known addresses. + Uitgaande Feeler: kortdurend, voor het testen van adressen - 1 &year - 1 &jaar + Outbound Address Fetch: short-lived, for soliciting addresses + Explanatory text for a short-lived outbound peer connection that is used to request addresses from a peer. + Uitgaand Adres Ophalen: kortdurend, voor het opvragen van adressen - &Unban - &Maak ban voor Node ongedaan + To + Naar + + + we selected the peer for high bandwidth relay + Wij selecteerden de peer vanwege hoge bandbreedte van de relay. - Welcome to the %1 RPC console. - Welkom bij de %1 RPC-console. + From + Van - Use up and down arrows to navigate history, and %1 to clear screen. - Gebruik de pijl toetsen om door de geschiedenis te navigeren, en %1 om het scherm te wissen. + the peer selected us for high bandwidth relay + De peer geselecteerde ons vanwege hoge bandbreedte van de relay - Type %1 for an overview of available commands. - Typ %1 voor een overzicht van beschikbare opdrachten. + No + Nee + + + no high bandwidth relay selected + Geen hoge bandbreedte relay geselecteerd. + + + &Disconnect + &Verbreek verbinding - For more information on using this console type %1. - Typ %1 voor meer informatie over het gebruik van deze console. + Ban for + Ban Node voor + + + 1 &hour + 1 &uur + + + 1 &week + 1 &week + + + 1 &year + 1 &jaar - WARNING: Scammers have been active, telling users to type commands here, stealing their wallet contents. Do not use this console without fully understanding the ramifications of a command. - PAS OP: Oplichters zijn actief, die proberen om gebruikers hier opdrachten te typen, waardoor de inhoud van de portemonnee gestolen kan worden. Gebruik deze console niet zonder de consequenties van een opdracht volledig te begrijpen. + &Unban + &Maak ban voor Node ongedaan In: @@ -2584,6 +3560,10 @@ Om te mixen moeten andere gebruikers exact dezelfde denominaties inbrengen.Network activity disabled Netwerkactiviteit is uitgeschakeld + + None + Geen + Total: %1 (Enabled: %2) Totaal: %1 (Ingeschakeld: %2) @@ -2592,10 +3572,105 @@ Om te mixen moeten andere gebruikers exact dezelfde denominaties inbrengen.Executing command without any wallet Opdracht uitvoeren zonder portemonnee + + Ctrl++ + Main shortcut to increase the RPC console font size. + Ctrl++ + + + Ctrl+= + Secondary shortcut to increase the RPC console font size. + Ctrl+= + + + Ctrl+- + Main shortcut to decrease the RPC console font size. + Ctrl+- + + + Ctrl+_ + Secondary shortcut to decrease the RPC console font size. + Ctrl+_ + + + Ctrl+Shift+I + Ctrl+Shift+I + + + Ctrl+Shift+C + Ctrl+Shift+C + + + Ctrl+Shift+G + Ctrl+Shift+G + + + Ctrl+Shift+P + Ctrl+Shift+P + + + Ctrl+Shift+R + Ctrl+Shift+R + Executing command using "%1" wallet Opdracht uitvoeren met portemonnee "%1" + + detecting: peer could be v1 or v2 + Explanatory text for "detecting" transport type. + Detecteren: peer zou v1 of v2 kunnen zijn + + + v1: unencrypted, plaintext transport protocol + Explanatory text for v1 transport type. + v1: onversleuteld, platte tekst transportprotocol + + + v2: BIP324 encrypted transport protocol + Explanatory text for v2 transport type. + v2: BIP324 versleuteld transportprotocol + + + &Copy address + Context menu action to copy the address of a peer + &Kopieer adres + + + 1 d&ay + 1 d&ag + + + &Copy IP/Netmask + 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 + &Kopieer IP/Netmask + + + 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 + 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. + Welkom bij de %1 RPC console. +Gebruik de omhoog en omlaag pijltjestoetsen om door de geschiedenis te navigeren, en %2 om het scherm te wissen. +Gebruik %3 en %4 om de lettergrootte te vergroten of te verkleinen. +%5 voor een overzicht van de beschikbare commando's. +Voor meer informatie over het gebruik van deze console, typ %6. + +%7WAARSCHUWING: Oplichters zijn actief en vertellen gebruikers om hier commando's in te voeren, waardoor ze de inhoud van de portemonnee stelen. Gebruik deze console niet zonder volledig te begrijpen wat de gevolgen zijn van een commando.%8 + + + Executing… + A console message indicating an entered command is currently being executed. + Uitvoeren… + + + (peer: %1) + (peer: %1) + via %1 via %1 @@ -2612,11 +3687,19 @@ Om te mixen moeten andere gebruikers exact dezelfde denominaties inbrengen.Verified Masternode geverifieerde Masternode + + Yes + Ja + Unknown onbekend - + + Never + Nooit + + ReceiveCoinsDialog @@ -2636,6 +3719,10 @@ Om te mixen moeten andere gebruikers exact dezelfde denominaties inbrengen.Een optioneel bericht om aan het betalingsverzoek toe te voegen, die zal worden getoond wanneer het verzoek wordt geopend. <br> Nota: Het bericht zal niet verzonden worden met de betaling over het Dash netwerk. + + 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. + Een optioneel label om toe te voegen aan het nieuwe ontvangstadres (bv. voor een factuur). Het wordt ook toegevoegd aan het betalingsverzoek. + Use this form to request payments. All fields are <b>optional</b>. Gebruik dit formulier om te verzoeken tot betaling. Alle velden zijn <b>optioneel</b>. @@ -2693,28 +3780,60 @@ Nota: Het bericht zal niet verzonden worden met de betaling over het Dash netwer Voeg een bericht toe om bij het betalingsverzoek te voegen - Copy URI - Kopieer URI + Copy &URI + Kopieer &URI - Copy address - Kopiëer adres + &Copy address + &Kopieer adres - Copy label - Kopieer label + Copy &label + Kopieer &label - Copy message - Kopieer bericht + Copy &message + Kopieer &bericht - Copy amount - Kopieer bedrag + Copy &amount + Kopieer &bedrag + + + Could not unlock wallet. + Kon de portemonnee niet ontgrendelen. - + + Could not generate new address + Kon geen nieuw adres genereren. + + ReceiveRequestDialog + + Request payment to … + Vraag betaling aan voor … + + + Address: + Adres: + + + Amount: + Bedrag: + + + Label: + Label: + + + Message: + Bericht: + + + Wallet: + Portemonnee: + Copy &URI Kopieer &URI @@ -2767,6 +3886,34 @@ Nota: Het bericht zal niet verzonden worden met de betaling over het Dash netwer Verzoek ingediend + + RestoreWalletActivity + + Restore Wallet + Title of progress window which is displayed when wallets are being restored. + Portemonnee herstellen + + + Restoring Wallet <b>%1</b>… + Descriptive text of the restore wallets progress window which indicates to the user that wallets are currently being restored. + Portemonnee <b>%1</b> herstellen… + + + Restore wallet failed + Title of message box which is displayed when the wallet could not be restored. + Portemonnee herstellen mislukt + + + Restore wallet warning + Title of message box which is displayed when the wallet is restored with some warning. + Waarschuwing bij herstellen portemonnee + + + Restore wallet message + Title of message box which is displayed when the wallet is successfully restored. + Bericht bij herstellen portemonnee + + SendCoinsDialog @@ -2801,10 +3948,6 @@ Nota: Het bericht zal niet verzonden worden met de betaling over het Dash netwer Fee: Vergoeding: - - Dust: - Stof: - Inputs… Inputs… @@ -2829,6 +3972,14 @@ Nota: Het bericht zal niet verzonden worden met de betaling over het Dash netwer Transaction Fee: Transactiekosten + + 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 dash transactions than the network can process. + Wanneer er minder transactievolume is dan ruimte in de blocks, kunnen miners en relay nodes een minimumvergoeding afdwingen. Alleen deze minimumvergoeding betalen is prima, maar wees ervan bewust dat dit kan leiden tot een transactie die nooit wordt bevestigd zodra er meer vraag is naar transacties dan het netwerk kan verwerken. + + + A too low fee might result in a never confirming transaction (read the tooltip) + Een te lage vergoeding kan leiden tot een transactie die nooit wordt bevestigd (lees de tooltip) + (Smart fee not initialized yet. This usually takes a few blocks…) (Slimme kosten zijn nog niet geïnitialiseerd Dit duurt meestal een paar blocks …) @@ -2921,10 +4072,6 @@ Nota: Het bericht zal niet verzonden worden met de betaling over het Dash netwer Copy bytes Kopieer bytes - - Copy dust - Kopieer stof - Copy change Kopieer wijziging @@ -2941,10 +4088,6 @@ Nota: Het bericht zal niet verzonden worden met de betaling over het Dash netwer %1 to %2 %1 tot %2 - - Are you sure you want to send? - Weet u zeker dat u wilt verzenden? - <b>(%1 of %2 entries displayed)</b> <b>(%1 van de %2 items weergegeven)</b> @@ -2957,6 +4100,18 @@ Nota: Het bericht zal niet verzonden worden met de betaling over het Dash netwer Confirm the %1 send action Bevestig de %1 verstuuractie + + Cr&eate Unsigned + Maak &ongetekend aan + + + from wallet '%1' + van portemonnee '%1' + + + %1 to '%2' + %1 naar '%2' + %1 funds only alleen %1 saldo @@ -3005,6 +4160,51 @@ Nota: Het bericht zal niet verzonden worden met de betaling over het Dash netwer Confirm send coins Bevestig versturen munten + + Save Transaction Data + Sla transactiegegevens op + + + PSBT saved + PSBT opgeslagen + + + Watch-only balance: + Watch-only saldo: + + + Creates a Partially Signed Blockchain Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet. + Maakt een Partially Signed Blockchain Transaction (PSBT) aan voor gebruik met bijvoorbeeld een offline %1 portemonnee of een PSBT compatibele hardware portemonnee . + + + Do you want to create this transaction? + 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. + Wilt u deze transactie aanmaken? + + + Please, review your transaction proposal. This will produce a Partially Signed Blockchain Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet. + 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. + Controleer uw transactievoorstel. Dit zal een Partially Signed Blockchain Transaction (PSBT) produceren die u kunt opslaan of kopiëren en vervolgens ondertekenen met bijvoorbeeld een offline %1-portemonnee of een PSBT-compatibele hardware-portemonnee. + + + Please, review your transaction. You can create and send this transaction or create a Partially Signed Blockchain Transaction (PSBT), which you can save or copy and then sign with, e.g., an offline %1 wallet, or a PSBT-compatible hardware wallet. + 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. + Controleer uw transactie. U kunt deze transactie aanmaken en verzenden of een Partially Signed Blockchain Transaction (PSBT) aanmaken, die u kunt opslaan of kopiëren en vervolgens ondertekenen met bijvoorbeeld een offline %1-portemonnee of een PSBT-compatibele hardware-portemonnee. + + + Please, review your transaction. + Text to prompt a user to review the details of the transaction they are attempting to send. + Controleer uw transactie. + + + To review recipient list click "Show Details…" + Klik op "Toon Details..." om de ontvangerslijst te bekijken + + + Partially Signed Transaction (Binary) + Expanded name of the binary PSBT file format. See: BIP 174. + Deels ondertekende transactie (Binair) + The recipient address is not valid. Please recheck. Het adres van de ontvanger is niet geldig. Gelieve opnieuw te controleren. @@ -3124,21 +4324,16 @@ Nota: Het bericht zal niet verzonden worden met de betaling over het Dash netwer A message that was attached to the dash: URI which will be stored with the transaction for your reference. Note: This message will not be sent over the Dash network. Een boodschap die was bijgevoegd aan de dash: URI die met de transactie voor uw referentie wordt opgeslagen. Opmerking: Dit bericht zal niet over het Dash netwerk worden verzonden. + + + SendConfirmationDialog - This is an unauthenticated payment request. - Dit is een niet-geverifieerd betalingsverzoek. - - - This is an authenticated payment request. - Dit is een geverifieerd betalingsverzoek. - - - Pay To: - Betaal Aan: + Send + Verzenden - Memo: - Memo: + Create Unsigned + Ongetekende aanmaken @@ -3278,6 +4473,10 @@ Nota: Het bericht zal niet verzonden worden met de betaling over het Dash netwer Wallet unlock was cancelled. Portemonnee-ontsleuteling is geannuleerd. + + No error + Geen fout + Private key for the entered address is not available. Geheime sleutel voor het ingevoerde adres is niet beschikbaar. @@ -3303,19 +4502,30 @@ Nota: Het bericht zal niet verzonden worden met de betaling over het Dash netwer De handtekening hoort niet bij het bericht. - Message verification failed. - Berichtverificatie mislukt. + Message verification failed. + Berichtverificatie mislukt. + + + Message verified. + Bericht geverifiëerd. + + + + SplashScreen + + (press q to shutdown and continue later) + (druk op q om af te sluiten en later verder te gaan) - Message verified. - Bericht geverifiëerd. + press q to shutdown + druk op q om af te sluiten TrafficGraphWidget - KB/s - KB/s + kB/s + kB/s Total @@ -3332,20 +4542,9 @@ Nota: Het bericht zal niet verzonden worden met de betaling over het Dash netwer TransactionDesc - - Open for %n more block(s) - Open voor nog %n blokOpen voor nog %n blocks - - - Open until %1 - Open tot %1 - - - conflicted - Conflicterend - 0/unconfirmed, %1 + 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. 0/onbevestigd, %1 @@ -3358,22 +4557,32 @@ Nota: Het bericht zal niet verzonden worden met de betaling over het Dash netwer abandoned + 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. Opgegeven + + conflicted with a transaction with %1 confirmations + 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. + conflicteert met een transactie met %1 bevestigingen + %1/unconfirmed + 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, and still not locked via ChainLocks. %1/onbevestigd %1 confirmations + 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 or locked via ChainLocks. %1 bevestigingen locked via ChainLocks + 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 and has been locked by ChainLocks. op slot via ChainLocks verified via InstantSend + 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 has been locked by InstantSend. geverifieerd via InstantSend @@ -3392,6 +4601,10 @@ Nota: Het bericht zal niet verzonden worden met de betaling over het Dash netwer Generated Gegenereerd + + Platform Transfer + Platform overdracht + From Van @@ -3522,14 +4735,6 @@ Nota: Het bericht zal niet verzonden worden met de betaling over het Dash netwer Address / Label Adres / Label - - Open for %n more block(s) - Open voor nog %n blokOpen voor nog %n blocks - - - Open until %1 - Open tot %1 - Unconfirmed Onbevestigd @@ -3590,6 +4795,10 @@ Nota: Het bericht zal niet verzonden worden met de betaling over het Dash netwer Mined Gedolven + + Platform Transfer + Platform overdracht + %1 Mixing %1 Mixen @@ -3717,6 +4926,10 @@ Nota: Het bericht zal niet verzonden worden met de betaling over het Dash netwer Mined Gedolven + + Platform Transfer + Platform overdracht + Other Anders @@ -3730,49 +4943,63 @@ Nota: Het bericht zal niet verzonden worden met de betaling over het Dash netwer Min. bedrag - Abandon transaction - Doe afstand van transactie + &Copy address + &Kopieer adres - Copy address - Kopieer adres + Copy &label + Kopieer &label - Copy label - Kopieer label + Copy &amount + Kopieer &bedrag - Copy amount - Kopieer bedrag + Copy transaction &ID + Kopieer transactie &ID + + + Copy &raw transaction + Kopieer &ruwe transactie - Copy transaction ID - Kopieer transactie-ID + Copy full transaction &details + Kopieer volledige transactie &details - Copy raw transaction - Kopieer ruwe transactie + &Show transaction details + &Toon transactiedetails - Copy full transaction details - Kopieer volledige transactiedetials + A&bandon transaction + &Annuleer transactie - Edit address label - Bewerk adres label + Rese&nd transaction + Transactie &opnieuw versturen - Show transaction details - Toon transactiedetails + &Edit address label + &Bewerk adres label - Show address QR code - Toon adres QR-code + Show address &QR code + Toon adres in &QR-code + + + Show in %1 + 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. + Toon in %1 Export Transaction History Exporteer transactiegeschiedenis + + Comma separated file + Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values. + Komma gescheiden bestand + Confirmed Bevestigd @@ -3851,10 +5078,54 @@ Nota: Het bericht zal niet verzonden worden met de betaling over het Dash netwer Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled. Als u de portemonnee te afgesloten laat met terugsnoeien ingeschakeld, kan dit ertoe leiden dat de hele blockchain opnieuw moet worden gesynchroniseerd. - + + Close all wallets + Sluit alle portemonnees + + + Are you sure you wish to close all wallets? + Weet je zeker dat je alles portemonnees wilt sluiten? + + WalletFrame - + + No wallet has been loaded. +Go to File > Open Wallet to load a wallet. +- OR - + Er is geen portemonnee geladen. +Ga naar Bestand > Open portemonnee om een wallet te openen. +- OF - + + + Create a new wallet + Maak een nieuwe portemonnee aan + + + Error + Fout + + + Unable to decode PSBT from clipboard (invalid base64) + Kan PSBT van het klembord niet decoderen (ongeldige base64) + + + Load Transaction Data + Laad transactiegegevens + + + Partially Signed Transaction (*.psbt) + Partially Signed Blockchain Transaction (*.psbt) + + + PSBT file must be smaller than 100 MiB + PSBT-bestand moet kleiner zijn dan 100 MiB + + + Unable to decode PSBT + Kan PSBT niet decoderen + + WalletModel @@ -3880,6 +5151,11 @@ Nota: Het bericht zal niet verzonden worden met de betaling over het Dash netwer Selected amount: Gekozen bedrag: + + Wallet Data + Name of the wallet data file format. + Portemonnee gegevens + Backup Wallet Portemonnee backuppen @@ -3907,14 +5183,6 @@ Nota: Het bericht zal niet verzonden worden met de betaling over het Dash netwer dash-core - - Error: Listening for incoming connections failed (listen returned error %s) - Fout: luisteren naar binnenkomende verbindingen mislukt (luisteren gaf foutmelding %s) - - - Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee. - Vergoedingskosten raming mislukt. Fallbackfee is uitgeschakeld. Wacht een paar blocks of schakel -fallbackfee in. - 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 Deze fout kan optreden als deze portemonnee niet correct is afgesloten of voor het laatst is geladen met een nieuwere buildversie van Berkeley DB. Als dit het geval is, gebruik dan de software waarmee deze portemonnee voor het laatst is geladen @@ -3972,16 +5240,20 @@ Nota: Het bericht zal niet verzonden worden met de betaling over het Dash netwer Fout bij het lezen van de database, programma wordt beëindigd. - Failed to listen on any port. Use -listen=0 if you want this. - Het is mislukt om naar gelijk welke poort te luisteren. Gebruik -listen=0 als je dit wil + Error: Missing checksum + Fout: Checksum ontbreekt + + + Error: Unable to parse version %u as a uint32_t + Fout: Kan versie %u niet parsen als een uint32_t - -maxtxfee is set very high! Fees this large could be paid on a single transaction. - -maxtxfee staat zeer hoog! Transactiekosten van deze grootte kunnen worden gebruikt in een enkele transactie. + Error: Unable to write record to new wallet + Fout: Kan record niet naar nieuwe portemonnee schrijven - Cannot provide specific connections and have addrman find outgoing connections at the same. - Kan geen verbindingen bieden en addrman tegelijkertijd uitgaande verbindingen laten zoeken. + Failed to listen on any port. Use -listen=0 if you want this. + Het is mislukt om naar gelijk welke poort te luisteren. Gebruik -listen=0 als je dit wil Found unconfirmed denominated outputs, will wait till they confirm to continue. @@ -3992,13 +5264,17 @@ Nota: Het bericht zal niet verzonden worden met de betaling over het Dash netwer Ongeldige -socketevents ('%s') opgegeven. Alleen deze modi worden ondersteund: %s - Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions) - ongeldig bedrag voor -maxtxfee=<bedrag>: '%s' (moet ten minste de minimale doorgeefvergoeding van %s zijn om vastgelopen transacties te voorkomen) + SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is supported + SQLiteDatabase: Onbekend sqlite wallet schema versie %d. Alleen versie %d wordt ondersteund Transaction index can't be disabled with governance validation enabled. Either start with -disablegovernance command line switch or enable transaction index. Transactieindex kan niet worden uitgeschakeld als validatie van governance is ingeschakeld. Begin met -disablegovernance command line switch of schakel transactieindex in. + + Unsupported category-specific logging level -loglevel=%s. Expected -loglevel=<category>:<loglevel>. Valid categories: %s. Valid loglevels: %s. + Niet ondersteunde categorie specifieke logniveau -loglevel=%s. Verwacht -loglevel=<category>:<loglevel> . Geldige categorieën: %s. Geldige logniveaus: %s. + Can't mix: no compatible inputs found! Kan niet mixen: geen compatibele inputs gevonden! @@ -4007,6 +5283,14 @@ Nota: Het bericht zal niet verzonden worden met de betaling over het Dash netwer Entry exceeds maximum size. Invoer overschrijdt de maximale grootte. + + Error upgrading evo database for EHF + Fout bij het upgraden van de Evo database voor EHF + + + Failed to commit Evo database + Het is niet gelukt om de Evo database vast te leggen + Found enough users, signing ( waiting %s ) Voldoende gebruikers gevonden, aan het ondertekenen ( wacht %s ) @@ -4031,18 +5315,14 @@ Nota: Het bericht zal niet verzonden worden met de betaling over het Dash netwer Insufficient funds. Ontoereikend saldo. - - Invalid amount for -discardfee=<amount>: '%s' - Ongeldig bedrag voor -discardfee = <amount>: '%s' - - - Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s) - Ongeldig bedrag voor -paytxfee=<bedrag>: '%s' (Minimum %s) - Invalid minimum number of spork signers specified with -minsporkkeys Ongeldig minumum aantal spork ondertekenaars zoals ingesteld met -minsporkkeys + + Listening for incoming connections failed (listen returned error %s) + Luisteren naar inkomende verbindingen is mislukt (fout %s) + Lock is already in place. Vergrendeling is al op zijn plaats. @@ -4099,6 +5379,10 @@ Nota: Het bericht zal niet verzonden worden met de betaling over het Dash netwer Synchronizing governance objects… Synchroniseren governance objecten… + + Transaction change output index out of range + Transactie wisselgeld output index buiten bereik + Unable to start HTTP server. See debug log for details. Niet mogelijk ok HTTP-server te starten. Zie debuglogboek voor details. @@ -4107,6 +5391,10 @@ Nota: Het bericht zal niet verzonden worden met de betaling over het Dash netwer Unknown response. Onbekend reactie. + + Unsupported global logging level -loglevel=%s. Valid values: %s. + Niet ondersteund globaal logniveau -loglevel=%s. Geldige waarden: %s. + User Agent comment (%s) contains unsafe characters. User Agentcommentaar (%s) bevat onveilige karakters. @@ -4147,6 +5435,10 @@ Nota: Het bericht zal niet verzonden worden met de betaling over het Dash netwer Make sure to encrypt your wallet and delete all non-encrypted backups after you have verified that the wallet works! Zorg ervoor dat u uw portefeuille codeert en alle niet-gecodeerde back-ups verwijdert nadat u hebt geverifieerd dat de portefeuille werkt! + + More than one onion bind address is provided. Using %s for the automatically created Tor onion service. + Meer dan één onion bind-adres opgegeven. Gebruik %s voor de automatisch aangemaakte Tor onion service. + Prune configured below the minimum of %d MiB. Please use a higher number. Prune is ingesteld op minder dan het minimum van %d MiB. Gebruik a.u.b. een hoger aantal. @@ -4175,10 +5467,6 @@ Nota: Het bericht zal niet verzonden worden met de betaling over het Dash netwer Wallet is locked, can't replenish keypool! Automatic backups and mixing are disabled, please unlock your wallet to replenish keypool. Wallet is vergrendeld, niet instaat om keypool aan te vullen! Automatische backups en mixen zijn uitgeschakeld, ontgrendel alstublieft uw wallet om de keypool aan te vullen. - - You need to rebuild the database using -reindex to change -timestampindex - U moet de database opnieuw opbouwen met behulp van -reindex om -timestampindex te wijzigen - You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain U moet de database herbouwen met -reindex om terug te gaan naar de niet-prune modus. Dit zal de gehele blockchain opnieuw downloaden. @@ -4220,20 +5508,32 @@ Nota: Het bericht zal niet verzonden worden met de betaling over het Dash netwer Fout bij laden %s: privésleutels kunnen alleen worden uitgeschakeld tijdens aanmaken - Error upgrading evo database - Fout bij het upgraden van de evo database + Error: Couldn't create cursor into database + Fout: Kon geen cursor in de database aanmaken Error: Disk space is low for %s Fout: Schijfruimte is laag voor %s - Exceeded max tries. - Maximum aantal pogingen overschreden. + Error: Dumpfile checksum does not match. Computed %s, expected %s + Fout: Dumpbestand checksum komt niet overeen. Gecalculeerd %s, verwacht %s + + + Error: Got key that was not hex: %s + Fout: Ontvangen sleutel is niet in hex: %s + + + Error: Got value that was not hex: %s + Fout: Ontvangen waarde is geen hex: %s + + + Error: Keypool ran out, please call keypoolrefill first + Fout: Keypool is leeg, voer eerst keypoolrefill uit - Failed to commit EvoDB - EvoDB kan niet worden vastgelegd + Error: No addresses available. + Fout: Geen adressen beschikbaar. Failed to create backup %s! @@ -4251,17 +5551,29 @@ Nota: Het bericht zal niet verzonden worden met de betaling over het Dash netwer Failed to rescan the wallet during initialization Het herscannen van de portemonnee is mislukt tijdens het initialiseren + + Failed to verify database + Verifiëren van database mislukt + + + Fee rate (%s) is lower than the minimum fee rate setting (%s) + Transactiefee (%s) is lager dan de minimuminstelling voor transactiefees (%s) + Found enough users, signing… Voldoende gebruikers gevonden, aan het ondertekenen… - Invalid P2P permission: '%s' - Ongeldige P2P machtiging: '%s' + Ignoring duplicate -wallet %s. + Dubbele -wallet %s wordt genegeerd. + + + Input not found or already spent + Input niet gevonden of al besteed - Invalid amount for -fallbackfee=<amount>: '%s' - Ongeldig bedrag voor -fallbackfee=<bedrag>: '%s' + Invalid P2P permission: '%s' + Ongeldige P2P machtiging: '%s' Invalid masternodeblsprivkey. Please see documentation. @@ -4283,6 +5595,10 @@ Nota: Het bericht zal niet verzonden worden met de betaling over het Dash netwer Mixing in progress… Bezig met mixen… + + No addresses available + Geen adressen beschikbaar + No errors detected. Geen fouten gevonden @@ -4311,6 +5627,22 @@ Nota: Het bericht zal niet verzonden worden met de betaling over het Dash netwer Prune mode is incompatible with -txindex. Terugsnoeimodus is niet compatibel met -txindex. + + SQLiteDatabase: Failed to execute statement to verify database: %s + SQLiteDatabase: Fout bij het uitvoeren van de statement om de database te verifiëren: %s + + + SQLiteDatabase: Failed to prepare statement to verify database: %s + SQLiteDatabase: Fout bij het voorbereiden van de statement om de database te verifiëren: %s + + + SQLiteDatabase: Failed to read database verification error: %s + SQLiteDatabase: Fout bij het lezen van de database verificatiefout: %s + + + SQLiteDatabase: Unexpected application id. Expected %u, got %u + SQLiteDatabase: Onverwachte applicatie ID. Verwacht %u, ontvangen %u + Section [%s] is not recognized. Sectie [%s] wordt niet herkend. @@ -4343,6 +5675,10 @@ Nota: Het bericht zal niet verzonden worden met de betaling over het Dash netwer This is the transaction fee you will pay if you send a transaction. Dit is de transactievergoeding dat je betaalt wanneer je een transactie verstuurt. + + Topping up keypool… + Bijvullen van de keypool… + Transaction amounts must not be negative Transactiebedragen moeten positief zijn @@ -4371,13 +5707,17 @@ Nota: Het bericht zal niet verzonden worden met de betaling over het Dash netwer Unable to generate initial keys Kan eerste sleutels niet genereren + + Unable to open %s for writing + Kan %s niet openen om te schrijven + Unknown -blockfilterindex value %s. Onbekende -blockfilterindex waarde %s. - Upgrading UTXO database - Upgraden UTXO-database + Unknown new rules activated (versionbit %i) + Onbekende nieuwe regels geactiveerd (versionbit %i) Verifying blocks… @@ -4396,16 +5736,12 @@ Nota: Het bericht zal niet verzonden worden met de betaling over het Dash netwer Was niet in staat om de back-up folder aan te maken %s! - You can not start a masternode with wallet enabled. - U kunt geen masternode starten met portemennee ingeschakeld. - - - You need to rebuild the database using -reindex to change -addressindex - U moet de database opnieuw opbouwen met behulp van -reindex om -addressindex te wijzigen + Wiping wallet transactions… + Portemonnee transacties wissen… - You need to rebuild the database using -reindex to change -spentindex - U moet de database opnieuw opbouwen met behulp van -reindex om -spentindex te wijzigen + You can not start a masternode with wallet enabled. + U kunt geen masternode starten met portemennee ingeschakeld. no mixing available. @@ -4423,6 +5759,22 @@ Nota: Het bericht zal niet verzonden worden met de betaling over het Dash netwer %s uses exact denominated amounts to send funds, you might simply need to mix some more coins. %s gebruikt exact genoemde bedragen om geld te verzenden. Wellicht moet u gewoon wat meer munten mixen. + + -reindex-chainstate option is not compatible with -blockfilterindex. Please temporarily disable blockfilterindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes. + -reindex-chainstate optie is niet compatibel met -blockfilterindex. Schakel tijdelijk blockfilterindex uit tijdens het gebruik van -reindex-chainstate, of vervang -reindex-chainstate door -reindex om alle indexen volledig opnieuw op te bouwen. + + + -reindex-chainstate option is not compatible with -coinstatsindex. Please temporarily disable coinstatsindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes. + -reindex-chainstate optie is niet compatibel met -coinstatsindex. Schakel tijdelijk coinstatsindex uit tijdens het gebruik van -reindex-chainstate, of vervang -reindex-chainstate door -reindex om alle indexen volledig opnieuw op te bouwen. + + + -reindex-chainstate option is not compatible with -txindex. Please temporarily disable txindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes. + -reindex-chainstate optie is niet compatibel met -txindex. Schakel tijdelijk txindex uit tijdens het gebruik van -reindex-chainstate, of vervang -reindex-chainstate door -reindex om alle indexen volledig opnieuw op te bouwen. + + + Cannot downgrade wallet from version %i to version %i. Wallet version unchanged. + Kan portemonnee niet downgraden van versie %i naar versie %i. portemonnee versie is niet gewijzigd. + Cannot obtain a lock on data directory %s. %s is probably already running. Kan geen lock verkrijgen op gegevensmap %s. %s draait waarschijnlijk al. @@ -4435,14 +5787,82 @@ Nota: Het bericht zal niet verzonden worden met de betaling over het Dash netwer Error loading %s: You can't enable HD on an already existing non-HD wallet Fout bij laden %s: HD kan niet worden geactiveerd bij een bestaande non-HD portemonnee. + + 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 + Fout bij het laden van portemonnee. Portemonnee vereist dat blocks worden gedownload, en de software ondersteunt momenteel het laden van portefeuilles niet terwijl blocks niet op volgorde worden gedownload wanneer gebruik wordt gemaakt van assumeutxo snapshots. De portemonnee zou succesvol moeten kunnen laden nadat de node synchronisatie de hoogte %s heeft bereikt. + Error reading %s! All keys read correctly, but transaction data or address book entries might be missing or incorrect. Waarschuwing: Fout bij het lezen van %s! Alle sleutels zijn in goede orde uitgelezen, maar transactiedata of adresboeklemma's zouden kunnen ontbreken of fouten bevatten. + + Error: Dumpfile format record is incorrect. Got "%s", expected "format". + Fout: Dumpfile record formaat is onjuist. Ontvangen "%s", verwacht "format". + + + Error: Dumpfile identifier record is incorrect. Got "%s", expected "%s". + Fout: Dumpfile identificaterecord is onjuist. Ontvangen "%s", verwacht "%s". + + + Error: Dumpfile version is not supported. This version of bitcoin-wallet only supports version 1 dumpfiles. Got dumpfile with version %s + Fout: Dumpfile versie wordt niet ondersteund. Deze versie van bitcoin wallet ondersteunt alleen versie 1 dumpfiles. Ontvangen dumpfile is versie %s. + + + Failed to rename invalid peers.dat file. Please move or delete it and try again. + Fout bij het hernoemen van ongeldig peers.dat bestand. Verplaats of verwijder het en probeer het opnieuw. + + + Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable %s. + Vergoedingsschatting mislukt. Fallbackfee is uitgeschakeld. Wacht een paar blokken of schakel %s in. + + + File %s already exists. If you are sure this is what you want, move it out of the way first. + Bestand %s bestaat al. Als je zeker weet dat dit is wat je wilt, verplaats het dan eerst. + + + Incompatible options: -dnsseed=1 was explicitly specified, but -onlynet forbids connections to IPv4/IPv6 + Incompatibele opties: -dnsseed=1 was expliciet opgegeven, maar -onlynet staat verbindingen met IPv4/IPv6 niet toe. + Incorrect or no devnet genesis block found. Wrong datadir for devnet specified? Onjuiste of geen devnet genesisblok gevonden. Verkeerde devnet gegevensmap opgegeven? + + Invalid amount for %s=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions) + Ongeldig bedrag voor %s=<amount>: '%s' (moet minimaal de minrelay-vergoeding van %s zijn om vastgelopen transacties te voorkomen) + + + 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. + Ongeldig of beschadigd peers.dat (%s). Als je denkt dat dit een bug is, meld dit dan bij %s. Als tijdelijke oplossing kan je het bestand (%s) hernoemen, verplaatsen of verwijderen, zodat er een nieuw bestand wordt aangemaakt bij de volgende start. + + + No dump file provided. To use createfromdump, -dumpfile=<filename> must be provided. + Geen dump bestand opgegeven. Om createfromdump te gebruiken, moet -dumpfile=<filename> worden opgegeven. + + + No dump file provided. To use dump, -dumpfile=<filename> must be provided. + Geen dump bestand opgegeven. Om dump te gebruiken, moet -dumpfile=<filename> worden opgegeven. + + + No wallet file format provided. To use createfromdump, -format=<format> must be provided. + Geen portemonnee bestandsformaat opgegeven. Om createfromdump te gebruiken, moet -format=<format> worden opgegeven. + + + Outbound connections restricted to CJDNS (-onlynet=cjdns) but -cjdnsreachable is not provided + Uitgaande verbindingen beperkt tot CJDNS (-onlynet=cjdns) maar -cjdnsreachable is niet opgegeven + + + Outbound connections restricted to Tor (-onlynet=onion) but the proxy for reaching the Tor network is explicitly forbidden: -onion=0 + Uitgaande verbindingen zijn beperkt tot Tor (-onlynet=onion), maar de proxy om verbinding te maken met het Tor netwerk is expliciet verboden: -onion=0 + + + 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 + Uitgaande verbindingen zijn beperkt tot Tor (-onlynet=onion), maar de proxy om verbinding te maken met het Tor netwerk is niet opgegeven: geen enkele -proxy, -onion of -listenonion is opgegeven. + + + Outbound connections restricted to i2p (-onlynet=i2p) but -i2psam is not provided + Uitgaande verbindingen beperkt tot i2p (-onlynet=i2p) maar -i2psam is niet opgegeven + Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly. Waarschuwing: Controleer dat de datum en tijd van uw computer correct zijn ingesteld! Bij een onjuist ingestelde klok zal %s niet goed werken. @@ -4451,6 +5871,14 @@ Nota: Het bericht zal niet verzonden worden met de betaling over het Dash netwer Please contribute if you find %s useful. Visit %s for further information about the software. Gelieve bij te dragen als je %s nuttig vindt. Bezoek %s voor meer informatie over de software. + + Prune mode is incompatible with -reindex-chainstate. Use full -reindex instead. + Prune modus is incompatibel met -reindex-chainstate. Gebruik in plaats daarvan een volledige -reindex. + + + This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection. + Dit is de maximale transactie fee die je betaalt (naast de normale fee) om het vermijden van gedeeltelijke besteding te prioriteren boven de reguliere muntenselectie. + This is the transaction fee you may discard if change is smaller than dust at this level Dit is de transactievergoeding die u kunt negeren als het wisselgeld kleiner is dan het restantbedrag @@ -4459,14 +5887,38 @@ Nota: Het bericht zal niet verzonden worden met de betaling over het Dash netwer This is the transaction fee you may pay when fee estimates are not available. Dit is de transactievergoeding die je mogelijk betaalt indien geschatte tarief niet beschikbaar is + + Transaction requires one destination of non-0 value, a non-0 feerate, or a pre-selected input + Transactie vereist één bestemming met niet-0 waarde, een niet-0 vergoedingspercentage, of een vooraf geselecteerde invoer + Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate. Kan blokken niet nalopen. U moet de database opnieuw opbouwen met behulp van -reindex-chainstate. + + Unknown wallet file format "%s" provided. Please provide one of "bdb" or "sqlite". + Onbekend portemonnee bestandsformaat "%s" opgegeven. Geef een van de formaten "bdb" of "sqlite" op. + + + Unsupported chainstate database format found. Please restart with -reindex-chainstate. This will rebuild the chainstate database. + Niet-ondersteund chainstate-databaseformaat gevonden. Herstart met -reindex-chainstate. Dit zal de chainstate-database opnieuw opbouwen. + + + Warning: Dumpfile wallet format "%s" does not match command line specified format "%s". + Waarschuwing: Dump bestand portemonnee formaat "%s" komt niet overeen met het opgegeven formaat op de opdrachtregel "%s". + Warning: Private keys detected in wallet {%s} with disabled private keys Waarschuwing: privésleutels gedetecteerd in portemonnee {%s} terwijl privésleutels zijn uitgeschakeld + + You need to rebuild the database using -reindex to enable -timestampindex + Je moet de database opnieuw opbouwen met -reindex om -timestampindex in te schakelen. + + + %s -- Incorrect seed, it should be a hex string + %s -- Onjuiste seed, het zou een hex-string moeten zijn. + %s is not a valid backup folder! %s is geen geldige back-up map! @@ -4491,10 +5943,30 @@ Nota: Het bericht zal niet verzonden worden met de betaling over het Dash netwer -rpcport must be specified when -devnet and -server are specified -rpcport moet worden opgegeven wanneer -devnet en -server worden gebruikt + + -statsbatchsize cannot be configured with a negative value. + -statsbatchsize kan niet worden geconfigureerd met een negatieve waarde. + + + -statsduration cannot be configured with a negative value. + -statsduration kan niet worden geconfigureerd met een negatieve waarde. + A fatal internal error occurred, see debug.log for details Er is een fatale interne fout opgetreden, zie debug.log voor details + + Cannot create socket (socket() returned error %s) + Kan socket niet aanmaken (socket() gaf fout %s) + + + Cannot get socket address for %s + Kan socket-adres voor %s niet verkrijgen + + + Cannot init Statsd client + Kan Statsd-client niet initialiseren + Cannot resolve -%s address: '%s' Kan -%s adres niet herleiden: '%s' @@ -4503,10 +5975,6 @@ Nota: Het bericht zal niet verzonden worden met de betaling over het Dash netwer Cannot write to data directory '%s'; check permissions. Kan niet schrijven naar data map '%s'; controleer rechten. - - Change index out of range - Wijzigingsindex buiten bereik - Copyright (C) Copyright (C) @@ -4515,6 +5983,14 @@ Nota: Het bericht zal niet verzonden worden met de betaling over het Dash netwer Disk space is too low! Schijfruimte is te laag! + + Dump file %s does not exist. + Dump bestand %s bestaat niet. + + + Error creating %s + Fout bij het maken van %s + Error loading %s Fout bij het laden van %s @@ -4532,8 +6008,8 @@ Nota: Het bericht zal niet verzonden worden met de betaling over het Dash netwer Fout bij laden %s. HD kan niet worden uitgeschakeld bij een HD portemonnee. - Error upgrading chainstate database - Fout bij het upgraden van de ketenstaat database + Error reading next record from wallet database + Fout bij het lezen van het volgende record uit de portemonnee database Loading P2P addresses… @@ -4603,6 +6079,14 @@ Nota: Het bericht zal niet verzonden worden met de betaling over het Dash netwer Inputs vs outputs size mismatch. Invoer versus uitvoer komt niet overeen. + + Invalid '%s'. Allowed values: 128, 160, 192, 224, 256. + Ongeldige '%s'. Toegestane waarden: 128, 160, 192, 224, 256. + + + Invalid -i2psam address or hostname: '%s' + Ongeldig -i2psam adres of hostnaam: '%s' + Invalid -onion address or hostname: '%s' Ongeldig -onion adress of hostnaam: '%s' @@ -4647,14 +6131,78 @@ Nota: Het bericht zal niet verzonden worden met de betaling over het Dash netwer %s corrupt. Try using the wallet tool dash-wallet to salvage or restoring a backup. %s corrupt. Probeer de portemonnee tool te gebruiken om een back-up te redden of te herstellen. + + %s is set very high! Fees this large could be paid on a single transaction. + %s is zeer hoog ingesteld! Vergoedingen van deze grootte kunnen betaald worden op een enkele transactie. + + + %s request to listen on port %u. This port is considered "bad" and thus it is unlikely that any Dash Core peers connect to it. See doc/p2p-bad-ports.md for details and a full list. + %s verzoek om te luisteren op poort %u. Deze poort wordt als "slecht" beschouwd, waardoor het onwaarschijnlijk is dat Dash Core peers er mee verbinden. Zie doc/p2p-bad-ports.md voor details en een volledige lijst. + + + Cannot provide specific connections and have addrman find outgoing connections at the same time. + Het is niet mogelijk om specifieke verbindingen te bieden en tegelijkertijd addrman te laten zoeken naar uitgaande verbindingen. + + + Failed to upgrade Evo database + Upgraden van Evo-database mislukt + + + Fee needed > fee paid + Benodigde vergoeding > betaalde vergoeding + + + Host %s on unsupported network + Host %s op niet-ondersteund netwerk + + + Invalid amount for %s=<amount>: '%s' (must be at least %s) + Ongeldig bedrag voor %s=<amount>: '%s' (moet minimaal %s zijn) + + + Invalid amount for %s=<amount>: '%s' + Ongeldig bedrag voor %s=<amount>: '%s' + + + Invalid port specified in %s: '%s' + Ongeldige poort opgegeven in %s: '%s' + Last successful action was too recent. Vorige succesvolle actie is te recent. + + Missing solving data for estimating transaction size + Ontbrekende oplosgegevens voor het schatten van transactiegrootte + + + No host specified + Geen host opgegeven + + + No host specified, malformed URL + Geen host opgegeven, ongeldige URL + + + No text before the scheme delimiter, malformed URL + Geen tekst voor het schema-scheidingsteken, ongeldige URL + + + Port must be between %d and %d, supplied %d + Poort moet tussen %d en %d liggen, opgegeven %d + + + Socket not initialized, cannot send message + Socket niet geïnitialiseerd, kan bericht niet verzenden + The source code is available from %s. De broncode is beschikbaar van %s. + + The specified config file %s does not exist + Het opgegeven configuratiebestand %s bestaat niet + The transaction amount is too small to pay the fee Het transactiebedrag is te klein om transactiekosten in rekening te brengen @@ -4675,6 +6223,10 @@ Nota: Het bericht zal niet verzonden worden met de betaling over het Dash netwer Transaction fees are too high. Transactiekosten zijn te hoog. + + Transaction needs a change address, but we can't generate it. + Transactie heeft een wisselgeldadres nodig, maar we kunnen het niet genereren. + Transaction not valid. Transactie is niet geldig. @@ -4695,6 +6247,18 @@ Nota: Het bericht zal niet verzonden worden met de betaling over het Dash netwer Unable to locate enough non-denominated funds for this transaction. Kan onvoldoende met niet-gedenomineerd geld vinden voor deze transactie. + + Unable to lookup host %s + Kan host %s niet opzoeken + + + Unable to parse -maxuploadtarget: '%s' + Kan -maxuploadtarget niet ontleden: '%s' + + + Unable to send message to %s (::sendto() returned error %s) + Kan bericht niet verzenden naar %s (::sendto() gaf fout %s) + Unable to sign spork message, wrong key? Niet in staat om het sporkbericht te ondertekenen, verkeerde sleutel? @@ -4708,12 +6272,12 @@ Nota: Het bericht zal niet verzonden worden met de betaling over het Dash netwer Onbekende staat: id = %u - Unsupported logging category %s=%s. - Niet-ondersteunde logboekcategorie %s=%s. + Unsupported URL scheme, must begin with udp:// + Niet-ondersteund URL-schema, moet beginnen met udp:// - Upgrading txindex database - Upgraden txindex database + Unsupported logging category %s=%s. + Niet-ondersteunde logboekcategorie %s=%s. Very low number of keys left: %d @@ -4743,9 +6307,25 @@ Nota: Het bericht zal niet verzonden worden met de betaling over het Dash netwer You can not disable governance validation on a masternode. U kunt governance-validatie op een masternode niet uitschakelen. + + You need to rebuild the database using -reindex to enable -addressindex + Je moet de database opnieuw opbouwen met -reindex om -addressindex in te schakelen + + + You need to rebuild the database using -reindex to enable -spentindex + Je moet de database opnieuw opbouwen met -reindex om -spentindex in te schakelen + Your entries added successfully. Uw gegevens zijn succesvol toegevoegd. + + Settings file could not be read + Instellingen bestand kon niet worden gelezen + + + Settings file could not be written + Instellingen bestand kon niet worden geschreven + \ No newline at end of file diff --git a/src/qt/locale/dash_pl.ts b/src/qt/locale/dash_pl.ts index fff84bb7ba7e..4e8777d0623a 100644 --- a/src/qt/locale/dash_pl.ts +++ b/src/qt/locale/dash_pl.ts @@ -65,14 +65,6 @@ C&hoose W&ybierz - - Sending addresses - Adres do wysyłania - - - Receiving addresses - Adres odbiorczy - These are your Dash addresses for sending payments. Always check the amount and the receiving address before sending coins. To są twoje adresy Dash, na które wysyłasz płatności. Zanim wyślesz środki, zawsze upewnij się, że kwota i adres są prawidłowe. @@ -115,6 +107,14 @@ An error message. %1 is a stand-in argument for the name of the file we attempted to save to. Wystąpił błąd podczas próby zapisania listy adresów do %1. Spróbuj ponownie. + + Sending addresses - %1 + Adresy wysyłania - %1 + + + Receiving addresses - %1 + Adresy odbioru - %1 + Exporting Failed Próba eksportu nie powiodła się @@ -284,10 +284,22 @@ The passphrase entered for the wallet decryption was incorrect. Wprowadzone hasło do odszyfrowania portfela jest niepoprawne. + + 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 23.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. + Wprowadzone hasło do odszyfrowania portfela jest nieprawidłowe. Zawiera znak null (tj. bajt zerowy). Jeśli hasło zostało ustawione w wersji tego oprogramowania wcześniejszej niż 23.0, spróbuj ponownie używając tylko znaków do — ale nie włączając — pierwszego znaku null. Jeśli to się powiedzie, ustaw nowe hasło, aby uniknąć tego problemu w przyszłości. + Wallet passphrase was successfully changed. Hasło portfela zostało pomyślnie zmienione. + + Passphrase change failed + Zmiana hasła nie powiodła się + + + 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 23.0, please try again with only the characters up to — but not including — the first null character. + Stare hasło wprowadzone do odszyfrowania portfela jest nieprawidłowe. Zawiera znak null (tj. bajt zerowy). Jeśli hasło zostało ustawione w wersji tego oprogramowania wcześniejszej niż 23.0, spróbuj ponownie używając tylko znaków do — ale nie włączając — pierwszego znaku null. + Warning: The Caps Lock key is on! Uwaga: Klawisz Caps Lock jest włączony! @@ -392,10 +404,6 @@ &Load PSBT from file… &Załaduj PSBT z pliku… - - Load PSBT from clipboard… - &Załaduj PSBT ze schowka… - &Sending addresses &Adresy wysyłające @@ -428,10 +436,6 @@ &Window &Okno - - Minimize - Zminimalizuj - Zoom Powiększenie @@ -484,14 +488,6 @@ Modify configuration options for %1 Zmień opcje konfiguracji dla %1 - - &Show / Hide - &Pokaż / Ukryj - - - Show or hide the main Window - Pokazuje lub ukrywa główne okno - Encrypt the private keys that belong to your wallet Szyfruj klucze prywatne, dla twojego portfela @@ -556,10 +552,6 @@ Show wallet repair options Pokaż opcje naprawy portfela - - Open Wallet &Configuration File - Otwórz Plik &Konfiguracyjny Portfela - Open configuration file Otworz plik konfiguracji @@ -614,10 +606,18 @@ Show information about %1 Pokaż informacje o %1 + + Load PSBT from &clipboard… + Załaduj PSBT ze &schowka… + Open debugging and diagnostic console Otwórz debugowanie i konsolę diagnostyczną + + Open &wallet configuration file + Otwórz plik &konfiguracyjny portfela + Open a dash: URI Otwórz dash: URI @@ -626,6 +626,16 @@ Create a new wallet Stwórz nowy portfel + + Restore Wallet… + Name of the menu item that restores wallet from a backup file. + Przywróć portfel… + + + Restore a wallet from a backup file + Status tip for Restore Wallet menu item + Przywróć portfel z pliku kopii zapasowej + Close all wallets Zamknij wszystkie portfele @@ -646,10 +656,34 @@ Mask the values in the Overview tab Zamaskuj wartości na karcie Przegląd + + Wallet Data + Name of the wallet data file format. + Dane portfela + + + Load Wallet Backup + The title for Restore Wallet File Windows + Załaduj kopię zapasową portfela + + + Restore Wallet + Title of pop-up window shown when the user is attempting to restore a wallet. + Przywróć portfel + + + Wallet Name + Label of the input field where the name of the wallet is entered. + Nazwa portfela + &Settings P&referencje + + &Minimize + &Minimalizuj + &Help Pomo&c @@ -666,6 +700,14 @@ View Governance Proposals Zobacz wnioski dla nad którymi masternody mogą głosować + + &Hide + &Ukryj + + + S&how + &Pokaż + %n active connection(s) to Dash network A substring of the tooltip. @@ -687,6 +729,14 @@ Close Wallet… Zamknij Portfel… + + Load Partially Signed Blockchain Transaction + Ładuj Częściowo Podpisaną Transakcję Łańcucha Bloków + + + Load Partially Signed Blockchain Transaction from clipboard + Ładuj częściowo podpisaną transakcję łańcucha bloków z schowka + Create Wallet… Stwórz Portfel… @@ -739,10 +789,6 @@ Processing blocks on disk… Przetwarzanie bloków na dysku… - - Reindexing blocks on disk… - Ponowne indeksowanie bloków na dysku… - Connecting to peers… Łączenie z peerami @@ -896,10 +942,6 @@ Coin Selection Wybór Monet - - Dust: - Pył: - After Fee: Po opłacie: @@ -1000,10 +1042,6 @@ Copy bytes Skopiuj ilość bajtów - - Copy dust - Kopiuj pył (kwota poniżej 5460 duffów) - Copy change Skopiuj resztę @@ -1016,18 +1054,6 @@ (%1 locked) (%1 zablokowane) - - yes - tak - - - no - nie - - - This label turns red if any recipient receives an amount smaller than the current dust threshold. - Etykieta staje się czerwona, jeżeli któryś z odbiorców otrzymuje kwotę mniejszą niż obecna granica pyłu. - Can vary +/- %1 duff(s) per input. Może się różnić około +/- %1 duff(ów) na transację. @@ -1241,18 +1267,102 @@ Filter proposal list Filtruj listę wniosków + + Masternode Count: + Liczba masternodów: + + + Number of masternodes this wallet can vote with (masternodes for which this wallet holds the voting key) + Liczba masternodów, za pomocą których ten portfel może głosować (masternody, dla których ten portfel przechowuje klucz głosowania) + Proposal Count: Liczba Wniosków: + + Create Proposal + Utwórz wniosek + Filter by Title Filtruj Według Tytułu + + Unavailable + Niedostępne + + + A synced node and an unlocked wallet are required. + Wymagany jest zsynchronizowany węzeł i odblokowany portfel. + + + Vote Yes + Głosuj Za + + + Vote No + Głosuj Przeciw + + + Vote Abstain + Wstrzymaj się od głosu + Proposal Info: %1 Informacje dotyczące wniosku: %1 + + Voting Failed + Głosowanie nie powiodło się + + + No wallet available. + Brak dostępnego portfela. + + + No masternode voting keys found in wallet. + Nie znaleziono kluczy głosowania masternoda w portfelu. + + + Please select a proposal to vote on. + Wybierz wniosek do głosowania. + + + Unable to unlock wallet. + Nie można odblokować portfela. + + + Unable to get masternode list. Please try again later. + Nie można pobrać listy masternodów. Spróbuj ponownie później. + + + Masternode %1 not found + Nie znaleziono masternoda %1 + + + Failed to sign vote for masternode %1 + Nie udało się podpisać głosu dla masternoda %1 + + + Masternode %1: %2 + Masternode %1: %2 + + + Voted successfully %n time(s) + Pomyślnie zagłosowano %n razPomyślnie zagłosowano %n razyPomyślnie zagłosowano %n razyPomyślnie zagłosowano %n razy + + + Failed to vote %n time(s) + Nie udało się zagłosować %n razNie udało się zagłosować %n razyNie udało się zagłosować %n razyNie udało się zagłosować %n razy + + + Errors: + Błędy: + + + Voting Results + Wyniki głosowania + HelpMessageDialog @@ -1323,13 +1433,17 @@ Use a custom data directory: Użyj wybranego folderu dla danych - - (of %1 GB needed) - (z %1 GB potrzebnych) + + %n GB of space available + %n GB dostępnego miejsca%n GB dostępnego miejsca%n GB dostępnego miejsca%n GB dostępnego miejsca - - (%1 GB needed for full chain) - (%1 GB potrzebne do pełnego łańcucha) + + (of %n GB needed) + (z %n GB potrzebnego)(z %n GB potrzebnych)(z %n GB potrzebnych)(z %n GB potrzebnych) + + + (%n GB needed for full chain) + (%n GB potrzebny dla pełnego łańcucha)(%n GB potrzebne dla pełnego łańcucha)(%n GB potrzebnych dla pełnego łańcucha)(%n GB potrzebnych dla pełnego łańcucha) At least %1 GB of data will be stored in this directory, and it will grow over time. @@ -1361,6 +1475,13 @@ Błąd + + LoadWalletsActivity + + Loading wallets… + Ładowanie portfeli… + + MasternodeList @@ -1553,6 +1674,11 @@ URI: URI: + + Paste address from clipboard + Tooltip text for button that allows you to paste an address that is in your clipboard. + Wklej adres ze schowka + OpenWalletActivity @@ -1663,6 +1789,16 @@ An Options window setting to set subtracting the fee from a sending amount as default. Domyślnie odejmij &opłatę od kwoty + + Enable &PSBT controls + An options window setting to enable PSBT controls. + Włącz kontrole &PSBT + + + Whether to show PSBT controls. + Tooltip text for options window setting that enables PSBT controls. + Czy pokazywać kontrole PSBT. + Whether to keep the specified custom change address or not. Czy zachować określony niestandardowy adres zmiany, czy nie. @@ -1806,20 +1942,20 @@ https://explore.transifex.com/dash/dash/ https://explore.transifex.com/dash/dash/ - Options set in this dialog are overridden by the command line or in the configuration file: - Opcje ustawione w tym oknie są zastępowane przez wiersz poleceń lub w pliku konfiguracyjnym: + Third-party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items.<br/>%s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |. + Adresy URL stron trzecich (np. eksplorator bloków), które pojawiają się w zakładce transakcji jako elementy menu kontekstowego.<br/>%s w adresie URL jest zastępowane skrótem transakcji. Wiele adresów URL jest oddzielonych pionową kreską |. - 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. - Minimalizuje zamiast zakończyć działanie programu przy zamknięciu okna. Kiedy ta opcja jest włączona, program zakończy działanie po wybraniu Zamknij w menu. + &Third-party transaction URLs + Adresy URL transakcji &stron trzecich - Third party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items.<br/>%s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |. - URL do zewnętrznych seriwsó(np. eksplorator bloków), które pojawiają się w zakładce transakcji jako pozycje w menu kontekstowym.<br/> %s w URL jest zastąpione przez hash transakcji. Wielokrotne URL są oddzielane przez pionową poprzeczkę |. + Options set in this dialog are overridden by the command line or in the configuration file: + Opcje ustawione w tym oknie są zastępowane przez wiersz poleceń lub w pliku konfiguracyjnym: - &Third party transaction URLs - URL transakcji osób trzecich + 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. + Minimalizuje zamiast zakończyć działanie programu przy zamknięciu okna. Kiedy ta opcja jest włączona, program zakończy działanie po wybraniu Zamknij w menu. Whether to show coin control features or not. @@ -1963,14 +2099,22 @@ https://explore.transifex.com/dash/dash/ Confirm options reset + Window title text of pop-up window shown when the user has chosen to reset options. Potwierdź reset ustawień Client restart required to activate changes. + Text explaining that the settings changed will not come into effect until the client is restarted. Wymagany restart programu, aby uaktywnić zmiany. + + Current settings will be backed up at "%1". + 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. + Bieżące ustawienia zostaną utworzone jako kopia zapasowa w "%1". + Client will be shut down. Do you want to proceed? + Text asking the user to confirm if they would like to proceed with a client shutdown. Klient zostanie zamknięty. Kontynuować? @@ -2243,6 +2387,10 @@ https://explore.transifex.com/dash/dash/ Failed to sign transaction: %1 Nie udało się podpisać transakcji: %1 + + Cannot sign inputs while wallet is locked. + Nie można podpisać wejść, gdy portfel jest zablokowany. + Could not sign any more inputs. Nie można podpisać kolejnych wejść. @@ -2487,6 +2635,181 @@ Z powodu zaniechania obsługi należy poprosić sprzedawcę o dostarczenie adres Status + + ProposalWizard + + Create Governance Proposal + Utwórz wniosek governance + + + Enter proposal details + Wprowadź szczegóły wniosku + + + A fee will be burned when you prepare the proposal. + Opłata zostanie spalona podczas przygotowywania wniosku. + + + Proposal &name + &Nazwa wniosku + + + &Description URL + URL &opisu + + + Payment &address + &Adres płatności + + + Payment &amount + &Kwota płatności + + + The amount to request in a single payment + Kwota do zażądania w pojedynczej płatności + + + &First payment + &Pierwsza płatność + + + Pa&yments + P&łatności + + + To&tal amount + Łączna &kwota + + + Proposal &fee + &Opłata za wniosek + + + Next + Dalej + + + Review proposal JSON and validate. + Przejrzyj JSON wniosku i zwaliduj. + + + Hex-encoded JSON + JSON zakodowany w hex + + + Back + Wstecz + + + Validate + Zwaliduj + + + Prepare (burn fee) and wait for confirmations. + Przygotuj (spal opłatę) i poczekaj na potwierdzenia. + + + Copy + Kopiuj + + + At 1/6 confirmations: can be relayed and queued. At 6/6: accepted and processed. + Przy 1/6 potwierdzeniach: może być przekazany i umieszczony w kolejce. Przy 6/6: zaakceptowany i przetworzony. + + + Confirmations progress + Postęp potwierdzeń + + + Shows progress toward the required number of confirmations for the proposal fee transaction. + Pokazuje postęp w kierunku wymaganej liczby potwierdzeń dla transakcji opłaty wniosku. + + + Estimated time remaining: - + Szacowany pozostały czas: - + + + Prepare Proposal + Przygotuj wniosek + + + You can submit after 1 confirmation. At 6 confirmations it is accepted and processed. + Możesz przesłać po 1 potwierdzeniu. Przy 6 potwierdzeniach jest zaakceptowany i przetworzony. + + + Proposal ID: + ID wniosku: + + + Submit Proposal + Prześlij wniosek + + + Close + Zamknij + + + Valid + Ważny + + + Invalid: %1 + Nieprawidłowy: %1 + + + Burn %1 + Spal %1 + + + Burn %1 to create the fee transaction? + Spalić %1, aby utworzyć transakcję opłaty? + + + Prepare failed + Przygotowanie nie powiodło się + + + Confirmations: %1 / %2 required + Potwierdzenia: %1 / %2 wymagane + + + Estimated time remaining: Ready + Szacowany pozostały czas: Gotowe + + + Estimated time remaining: %n minute(s) + Szacowany pozostały czas: %n minutaSzacowany pozostały czas: %n minutySzacowany pozostały czas: %n minutSzacowany pozostały czas: %n minut + + + Your proposal was submitted successfully. + Twój wniosek został pomyślnie przesłany. + + + Already submitted + Już przesłano + + + This proposal has already been submitted. + Ten wniosek został już przesłany. + + + Submission failed + Przesłanie nie powiodło się + + + Proposal submitted + Wniosek przesłany + + + A fee of %1 will be burned when you prepare the proposal. + Opłata w wysokości %1 zostanie spalona podczas przygotowywania wniosku. + + + Prepare (burn %1) and wait for %2 confirmations. + Przygotuj (spal %1) i poczekaj na %2 potwierdzeń. + + QObject @@ -2877,8 +3200,12 @@ Z powodu zaniechania obsługi należy poprosić sprzedawcę o dostarczenie adres Wersja - Whether the peer requested us to relay transactions. - Czy peer zażądał przekazywania transakcji + High bandwidth BIP152 compact block relay: %1 + Kompaktowy przekaźnik blokowy BIP152 o dużej przepustowości: %1 + + + High Bandwidth + Duża Przepustowość Starting Block @@ -2900,10 +3227,23 @@ Z powodu zaniechania obsługi należy poprosić sprzedawcę o dostarczenie adres Last Block Ostatni Blok + + Elapsed time since a novel transaction accepted into our mempool was received from this peer. + Tooltip text for the Last Transaction field in the peer details area. + Czas, który upłynął od momentu odebrania od tego partnera nowej transakcji zaakceptowanej do naszej puli pamięci. + Last Transaction Ostatnia Transakcja + + The mapped Autonomous System used for diversifying peer selection. + Zmapowany Autonomiczny System służący do zróżnicowania doboru peerów. + + + Mapped AS + Zmapowane AS + Whether we relay addresses to this peer. Tooltip text for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No). @@ -2964,6 +3304,14 @@ Z powodu zaniechania obsługi należy poprosić sprzedawcę o dostarczenie adres To specify a non-default location of the blocks directory use the '%1' option. Aby określić inną niż domyślną lokalizację katalogu bloków, użyj opcji "%1". + + Local Addresses + Adresy lokalne + + + Network addresses that your Dash node is currently using to communicate with other nodes. + Adresy sieciowe, których węzeł Dash aktualnie używa do komunikacji z innymi węzłami. + Number of regular Masternodes Liczba zwykłych Masternodów @@ -3036,14 +3384,34 @@ Z powodu zaniechania obsługi należy poprosić sprzedawcę o dostarczenie adres Session ID Sesja ID + + The network protocol this peer is connected through: IPv4, IPv6, Onion, I2P, or CJDNS. + Protokół sieciowy, przez który ten węzeł jest połączony: IPv4, IPv6, Onion, I2P lub CJDNS. + Permissions Pozwolenia + + The direction and type of peer connection: %1 + Kierunek i typ połączenia z węzłem: %1 + + + Direction/Type + Kierunek/Rodzaj + Services Usługi + + Whether we relay transactions to this peer. + Czy przekazujemy transakcje do tego peera. + + + Transaction Relay + Przekazywanie transakcji + Connection Time Czas Połączenia @@ -3080,6 +3448,16 @@ Z powodu zaniechania obsługi należy poprosić sprzedawcę o dostarczenie adres &Wallet Repair &Naprawa portfela + + The total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting). + 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). + Łączna liczba adresów otrzymanych od tego węzła, które zostały przetworzone (wyklucza adresy, które zostały odrzucone z powodu ograniczania). + + + The total number of addresses received from this peer that were dropped (not processed) due to rate-limiting. + 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. + Łączna liczba adresów otrzymanych od tego węzła, które zostały odrzucone (nieprzetworzone) z powodu ograniczania. + Wallet repair options. Opcje naprawy portfela. @@ -3093,17 +3471,59 @@ Z powodu zaniechania obsługi należy poprosić sprzedawcę o dostarczenie adres reindex: Odtwórz index łańcucha bloków z najnowszego pliku blk000??.dat - To - Do + Inbound: initiated by peer + Explanatory text for an inbound peer connection. + Przychodzące: zainicjowane przez węzeł - From - Z + Outbound Full Relay: default + Explanatory text for an outbound peer connection that relays all network information. This is the default behavior for outbound connections. + Pełne przekazywanie wychodzące: domyślne - No + Outbound Block Relay: does not relay transactions or addresses + Explanatory text for an outbound peer connection that relays network information about blocks and not transactions or addresses. + Wysyłanie bloków wychodzących: nie przekazuje transakcji ani adresów + + + Outbound Manual: added using RPC %1 or %2/%3 configuration options + 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. + Ręczne wysyłanie wychodzące: dodane za pomocą RPC %1 lub opcji konfiguracyjnych %2/%3 + + + Outbound Feeler: short-lived, for testing addresses + Explanatory text for a short-lived outbound peer connection that is used to test the aliveness of known addresses. + Testowanie połączenia wychodzącego: krótkotrwałe, do testowania adresów + + + Outbound Address Fetch: short-lived, for soliciting addresses + Explanatory text for a short-lived outbound peer connection that is used to request addresses from a peer. + Pobieranie adresów wychodzących: krótkotrwałe, do pobierania adresów + + + To + Do + + + we selected the peer for high bandwidth relay + wybraliśmy peer'a dla przekazu o dużej przepustowości + + + From + Z + + + the peer selected us for high bandwidth relay + peer wybrał nas do przekazu o dużej przepustowości + + + No Nie + + no high bandwidth relay selected + nie wybrano przekazu o dużej przepustowości + &Disconnect &Rozłącz @@ -3140,6 +3560,10 @@ Z powodu zaniechania obsługi należy poprosić sprzedawcę o dostarczenie adres Network activity disabled Aktywność sieci jest wyłączona + + None + Brak + Total: %1 (Enabled: %2) Wszystkich: %1 (Włączonych: %2) @@ -3192,6 +3616,21 @@ Z powodu zaniechania obsługi należy poprosić sprzedawcę o dostarczenie adres Executing command using "%1" wallet Wykonywanie polecenia używając portfel "%1" + + detecting: peer could be v1 or v2 + Explanatory text for "detecting" transport type. + wykrywanie: peer może być w wersji v1 lub v2 + + + v1: unencrypted, plaintext transport protocol + Explanatory text for v1 transport type. + v1: niezaszyfrowany, protokół transportu w postaci tekstu + + + v2: BIP324 encrypted transport protocol + Explanatory text for v2 transport type. + v2: zaszyfrowany protokół transportu zgodny z BIP324 + &Copy address Context menu action to copy the address of a peer @@ -3201,11 +3640,36 @@ Z powodu zaniechania obsługi należy poprosić sprzedawcę o dostarczenie adres 1 d&ay 1 d&zień + + &Copy IP/Netmask + 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 + &Skopiuj IP/Maskę sieci + + + 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 + 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. + Witaj w konsoli RPC %1. +Użyj strzałek w górę i w dół, aby nawigować po historii, oraz %2, aby wyczyścić ekran. +Użyj %3 i %4, aby zwiększyć lub zmniejszyć rozmiar czcionki. +Wpisz %5, aby uzyskać przegląd dostępnych poleceń. +Aby uzyskać więcej informacji na temat korzystania z tej konsoli, wpisz %6. +%7OSTRZEŻENIE: Oszuści byli aktywni, mówiąc użytkownikom, aby wpisywali polecenia tutaj, kradnąc zawartość ich portfeli. Nie używaj tej konsoli, bez pełnego zrozumienia konsekwencji polecenia.%8 + Executing… A console message indicating an entered command is currently being executed. Wykonuje... + + (peer: %1) + (peer: %1) + via %1 przez %1 @@ -3344,6 +3808,10 @@ Z powodu zaniechania obsługi należy poprosić sprzedawcę o dostarczenie adres ReceiveRequestDialog + + Request payment to … + Żądanie płatności do … + Address: Adres: @@ -3416,6 +3884,34 @@ Z powodu zaniechania obsługi należy poprosić sprzedawcę o dostarczenie adres Zażądano + + RestoreWalletActivity + + Restore Wallet + Title of progress window which is displayed when wallets are being restored. + Przywróć portfel + + + Restoring Wallet <b>%1</b>… + Descriptive text of the restore wallets progress window which indicates to the user that wallets are currently being restored. + Przywracanie portfela <b>%1</b>… + + + Restore wallet failed + Title of message box which is displayed when the wallet could not be restored. + Przywracanie portfela nie powiodło się + + + Restore wallet warning + Title of message box which is displayed when the wallet is restored with some warning. + Ostrzeżenie przywracania portfela + + + Restore wallet message + Title of message box which is displayed when the wallet is successfully restored. + Komunikat przywracania portfela + + SendCoinsDialog @@ -3450,10 +3946,6 @@ Z powodu zaniechania obsługi należy poprosić sprzedawcę o dostarczenie adres Fee: Opłata: - - Dust: - Pył - Inputs… Wejścia… @@ -3578,10 +4070,6 @@ Z powodu zaniechania obsługi należy poprosić sprzedawcę o dostarczenie adres Copy bytes Skopiuj ilość bajtów - - Copy dust - skopiuj drobne (poniżej 5460 duffów) - Copy change Skopiuj resztę @@ -3598,10 +4086,6 @@ Z powodu zaniechania obsługi należy poprosić sprzedawcę o dostarczenie adres %1 to %2 %1 do %2 - - Are you sure you want to send? - Czy na pewno chcesz wysłać? - <b>(%1 of %2 entries displayed)</b> <b>(%1 z %2 wyświetlonych wpisów)</b> @@ -3626,10 +4110,6 @@ Z powodu zaniechania obsługi należy poprosić sprzedawcę o dostarczenie adres %1 to '%2' %1 do '%2' - - Do you want to draft this transaction? - Czy chcesz sporządzić projekt tej transakcji? - %1 funds only Tylko fundusze %1 @@ -3679,25 +4159,50 @@ Z powodu zaniechania obsługi należy poprosić sprzedawcę o dostarczenie adres Potwierdź wysyłanie monet - Confirm transaction proposal - Potwierdź propozycję transakcji + Save Transaction Data + Zapisz Dane Transakcji - Create Unsigned - Stwórz Niepodpisany + PSBT saved + PSBT zapisany - Save Transaction Data - Zapisz Dane Transakcji + Watch-only balance: + Saldo tylko do odczytu: - Send - Wyślij + Creates a Partially Signed Blockchain Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet. + Tworzy Częściowo Podpisaną Transakcję Blockchain (PSBT) do użycia z np. portfelem offline %1 lub zgodnym z PSBT portfelem sprzętowym. + + + Do you want to create this transaction? + 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. + Czy chcesz utworzyć tę transakcję? + + + Please, review your transaction proposal. This will produce a Partially Signed Blockchain Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet. + 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. + Proszę przejrzeć propozycję transakcji. Spowoduje to utworzenie Częściowo Podpisanej Transakcji Blockchain (PSBT), którą możesz zapisać lub skopiować, a następnie podpisać np. za pomocą portfela offline %1 lub portfela sprzętowego zgodnego z PSBT. + + + Please, review your transaction. You can create and send this transaction or create a Partially Signed Blockchain Transaction (PSBT), which you can save or copy and then sign with, e.g., an offline %1 wallet, or a PSBT-compatible hardware wallet. + 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. + Proszę przejrzeć transakcję. Możesz utworzyć i wysłać tę transakcję lub utworzyć Częściowo Podpisaną Transakcję Blockchain (PSBT), którą możesz zapisać lub skopiować, a następnie podpisać np. za pomocą portfela offline %1 lub portfela sprzętowego zgodnego z PSBT. + + + Please, review your transaction. + Text to prompt a user to review the details of the transaction they are attempting to send. + Proszę przejrzeć transakcję. To review recipient list click "Show Details…" Aby przejrzeć listę odbiorców, kliknij „Pokaż szczegóły…” + + Partially Signed Transaction (Binary) + Expanded name of the binary PSBT file format. See: BIP 174. + Częściowo Podpisana Transakcja (Binarna) + The recipient address is not valid. Please recheck. Adres odbiorcy jest nieprawidłowy, proszę poprawić. @@ -3817,21 +4322,16 @@ Z powodu zaniechania obsługi należy poprosić sprzedawcę o dostarczenie adres A message that was attached to the dash: URI which will be stored with the transaction for your reference. Note: This message will not be sent over the Dash network. Wiadomość, która została dołączona do dash: Link, który zostanie zapisany wraz z transakcją do wglądu w przyszłości. Zauważ, że sama wiadomość nie zostanie wysłana przez sieć Dash. + + + SendConfirmationDialog - This is an unauthenticated payment request. - To żądane zapłaty nie zostało uwierzytelnione. - - - This is an authenticated payment request. - To żądanie zapłaty jest uwierzytelnione. - - - Pay To: - Wpłać do: + Send + Wyślij - Memo: - Notatka: + Create Unsigned + Utwórz niepodpisaną @@ -4010,6 +4510,10 @@ Z powodu zaniechania obsługi należy poprosić sprzedawcę o dostarczenie adres SplashScreen + + (press q to shutdown and continue later) + (wciśnij q aby zamknąć i kontynuować później) + press q to shutdown Wciśnij q aby zamknąć @@ -4036,20 +4540,9 @@ Z powodu zaniechania obsługi należy poprosić sprzedawcę o dostarczenie adres TransactionDesc - - Open for %n more block(s) - Otwórz na %n dodatkowy blokOtwórz na %n dodatkowe blokiOtwórz na %n dodatkowych blokówOtwórz na %n dodatkowych bloków - - - Open until %1 - Otwórz do %1 - - - conflicted - konflikt - 0/unconfirmed, %1 + 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. 0/niepotwierdzone, %1 @@ -4062,22 +4555,32 @@ Z powodu zaniechania obsługi należy poprosić sprzedawcę o dostarczenie adres abandoned + 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. porzucony + + conflicted with a transaction with %1 confirmations + 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. + konflikt z transakcją z %1 potwierdzeniami + %1/unconfirmed + 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, and still not locked via ChainLocks. %1/niezatwierdzone %1 confirmations + 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 or locked via ChainLocks. %1 potwierdzeń locked via ChainLocks - zablokowane przez ChainLocs + 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 and has been locked by ChainLocks. + zablokowane przez ChainLocks verified via InstantSend + 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 has been locked by InstantSend. zweryfikowane przez InstantSend @@ -4230,14 +4733,6 @@ Z powodu zaniechania obsługi należy poprosić sprzedawcę o dostarczenie adres Address / Label Adres / Etykieta - - Open for %n more block(s) - Otwórz na %n dodatkowy blokOtwórz na %n dodatkowe blokiOtwórz na %n dodatkowych blokówOtwórz na %n dodatkowych bloków - - - Open until %1 - Otwórz do %1 - Unconfirmed Niepotwierdzone: @@ -4272,7 +4767,7 @@ Z powodu zaniechania obsługi należy poprosić sprzedawcę o dostarczenie adres locked via ChainLocks - zablokowane przez ChainLocs + zablokowane przez ChainLocks Received with @@ -4489,10 +4984,20 @@ Z powodu zaniechania obsługi należy poprosić sprzedawcę o dostarczenie adres Show address &QR code Pokaż &QR kod adresu + + Show in %1 + 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. + Pokaż w %1 + Export Transaction History Eksport historii transakcji + + Comma separated file + Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values. + Plik rozdzielony przecinkami + Confirmed Potwierdzony @@ -4598,6 +5103,10 @@ Przejdź do Plik > Otwórz portfel, aby załadować portfel. Error Błąd + + Unable to decode PSBT from clipboard (invalid base64) + Nie można odkodować PSBT ze schowka (nieprawidłowy base64) + Load Transaction Data Załaduj Dane Transakcji @@ -4606,7 +5115,15 @@ Przejdź do Plik > Otwórz portfel, aby załadować portfel. Partially Signed Transaction (*.psbt) Częściowo Podpisana Transakcja (.psbt) - + + PSBT file must be smaller than 100 MiB + Plik PSBT musi być mniejszy niż 100 MiB + + + Unable to decode PSBT + Nie można odkodować PSBT + + WalletModel @@ -4632,6 +5149,11 @@ Przejdź do Plik > Otwórz portfel, aby załadować portfel. Selected amount: Zaznaczona ilość: + + Wallet Data + Name of the wallet data file format. + Dane portfela + Backup Wallet Kopia Zapasowa Portfela @@ -4659,10 +5181,6 @@ Przejdź do Plik > Otwórz portfel, aby załadować portfel. dash-core - - Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee. - Oszacowanie opłaty nie powiodło się. Opłata domyślna jest wyłączona. Poczekaj kilka bloków lub włącz -fallbackfee. - 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 Ten błąd mógł wystąpić, jeśli portfel nie został poprawnie zamknięty i został ostatnio załadowany przy użyciu kompilacji z nowszą wersją Berkeley DB. Jeśli tak, użyj oprogramowania, które ostatnio załadowało ten portfel @@ -4720,12 +5238,20 @@ Przejdź do Plik > Otwórz portfel, aby załadować portfel. Błąd odczytu bazy danych, następuje zamknięcie. - Failed to listen on any port. Use -listen=0 if you want this. - Nie powiódł się nasłuch żadnego z portów. Użyj -listen=0 jeśli chcesz. + Error: Missing checksum + Błąd: Brak sumy kontrolnej + + + Error: Unable to parse version %u as a uint32_t + Błąd: Nie można przeanalizować wersji %u jako uint32_t + + + Error: Unable to write record to new wallet + Błąd: Nie można zapisać rekordu do nowego portfela - -maxtxfee is set very high! Fees this large could be paid on a single transaction. - -maxtxfee jest bardzo wysoka! Tak duże opłaty mogą być uiszczone przy wysłaniu jednej transakcji. + Failed to listen on any port. Use -listen=0 if you want this. + Nie powiódł się nasłuch żadnego z portów. Użyj -listen=0 jeśli chcesz. Found unconfirmed denominated outputs, will wait till they confirm to continue. @@ -4735,10 +5261,6 @@ Przejdź do Plik > Otwórz portfel, aby załadować portfel. Invalid -socketevents ('%s') specified. Only these modes are supported: %s Niewłaściwe wybrane -socetevents ('%s'). Tylko te tryby są wspierane: %s - - Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions) - Nieprawidłowa kwota za -maxtxfee=<amount>: '%s' (musi ona wynosić co najmniej tyle co minimalna opłata za retransmisje %s aby zapobiec utknięciu transakcji) - SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is supported SQLiteDatabase: Nieznana wersja schematu portfela sqlite %d. Obsługiwana jest tylko wersja %d @@ -4747,6 +5269,10 @@ Przejdź do Plik > Otwórz portfel, aby załadować portfel. Transaction index can't be disabled with governance validation enabled. Either start with -disablegovernance command line switch or enable transaction index. Indeks transakcji nie może zostać wyłączony jeśli walidacja zarządzania jest włączona. Albo uruchom z komendą -dsiablegovernance lub włącz indeks transakcji. + + Unsupported category-specific logging level -loglevel=%s. Expected -loglevel=<category>:<loglevel>. Valid categories: %s. Valid loglevels: %s. + Niewspierany kategoryzowany poziom logowania -loglevel=%s. Oczekiwane -loglevel=<category>:<loglevel>. Poprawne kategorie: %s. Poprawne poziomy logowania: %s. + Can't mix: no compatible inputs found! Mieszanie jest niemożliwe: nie znaleziono odpowiednich wartości wejściowych. @@ -4755,6 +5281,14 @@ Przejdź do Plik > Otwórz portfel, aby załadować portfel. Entry exceeds maximum size. Przekracza maksymalny rozmiar. + + Error upgrading evo database for EHF + Błąd podczas uaktualniania bazy danych evo dla EHF + + + Failed to commit Evo database + Niepowodzenie podczas zatwierdzania bazy danych Evo + Found enough users, signing ( waiting %s ) Znaleziono wystarczającą ilość użytkowników, trwa podoposywanie ( poczekaj %s ) @@ -4779,18 +5313,14 @@ Przejdź do Plik > Otwórz portfel, aby załadować portfel. Insufficient funds. Niewystarczające środki - - Invalid amount for -discardfee=<amount>: '%s' - Nieprawidłowa kwota dla -discardfee=<amount>: '%s' - - - Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s) - Nieprawidłowa kwota dla -paytxfee=<amount>: '%s' (musi wynosić co najmniej %s) - Invalid minimum number of spork signers specified with -minsporkkeys Nieważna minimalna liczba osób podpisujących sporka ustawiona z -minsporkkeys + + Listening for incoming connections failed (listen returned error %s) + Nasłuchiwanie połączeń przychodzących nie powiodło się (funkcja listen zwróciła błąd %s) + Lock is already in place. Transakcja została już zamknięta. @@ -4847,6 +5377,10 @@ Przejdź do Plik > Otwórz portfel, aby załadować portfel. Synchronizing governance objects… Synchronizuję obiekty zarządzania… + + Transaction change output index out of range + Indeks wyjścia transakcji spoza zakresu + Unable to start HTTP server. See debug log for details. Uruchomienie serwera HTTP nieudane. Szczegóły znajdziesz w dzienniku debugowania. @@ -4855,6 +5389,10 @@ Przejdź do Plik > Otwórz portfel, aby załadować portfel. Unknown response. Nieznana odpowiedź. + + Unsupported global logging level -loglevel=%s. Valid values: %s. + Niewspierany globalny poziom logowania -loglevel=%s. Poprawne wartości: %s. + User Agent comment (%s) contains unsafe characters. Komentarz agenta użytkownika (%s) zawiera znaki które nie są bezpieczne. @@ -4895,6 +5433,10 @@ Przejdź do Plik > Otwórz portfel, aby załadować portfel. Make sure to encrypt your wallet and delete all non-encrypted backups after you have verified that the wallet works! Jeśli już zweryfikowałeś że porfel działa jak należy, to nie zapomnij zaszyfrować porfel oraz usunąć wszystkie niezaszyfrowane kopie zapasowe. + + More than one onion bind address is provided. Using %s for the automatically created Tor onion service. + Podano więcej niż jeden adres wiązania onion. Używany jest %s dla automatycznie utworzonej usługi Tor onion. + Prune configured below the minimum of %d MiB. Please use a higher number. Czyszczenie starych danych ustawiono poniżej minimum %d MiB. Ustaw wyższą wartość. @@ -4915,10 +5457,6 @@ Przejdź do Plik > Otwórz portfel, aby załadować portfel. Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments. Całkowita długość sieciowej wersji struny (%i) przekracza maksymalną długość (%i). Zredukuj liczbę lub rozmiar uacomments. - - Transaction needs a change address, but we can't generate it. Please call keypoolrefill first. - Transakcja wymaga adresu zmiany, ale nie możemy go wygenerować. Najpierw wywołaj funkcję keypoolrefill. - WARNING! Failed to replenish keypool, please unlock your wallet to do so. OSTRZEŻENIE! Nie udało się uzupełnić puli kluczy. W tym celu musisz odblokować portfel. @@ -4967,10 +5505,22 @@ Przejdź do Plik > Otwórz portfel, aby załadować portfel. Error loading %s: Private keys can only be disabled during creation Błąd podczas ładowania %s: Klucze prywatne można wyłączyć tylko podczas tworzenia nowego portfela + + Error: Couldn't create cursor into database + Błąd: Nie można utworzyć kursora do bazy danych + Error: Disk space is low for %s Błąd: Nie ma wystarczająco miejsca na dysku dla %s + + Error: Dumpfile checksum does not match. Computed %s, expected %s + Błąd: Suma kontrolna pliku wyjściowego nie zgadza się. Obliczono %s, oczekiwano %s + + + Error: Got key that was not hex: %s + Błąd: Otrzymano klucz, który nie jest w formacie szesnastkowym: %s + Error: Got value that was not hex: %s Błąd: Otrzymano wartość, która nie jest wartością hex: %s @@ -4983,10 +5533,6 @@ Przejdź do Plik > Otwórz portfel, aby załadować portfel. Error: No addresses available. Błąd: Brak dostępnych adresów. - - Exceeded max tries. - Przekroczona została maksymalna liczba prób - Failed to create backup %s! Nie powiodło się tworzenie kopii zapasowej %s! @@ -5007,6 +5553,10 @@ Przejdź do Plik > Otwórz portfel, aby załadować portfel. Failed to verify database Nie udało się zweryfikować bazy danych + + Fee rate (%s) is lower than the minimum fee rate setting (%s) + Stawka opłaty (%s) jest niższa niż minimalna ustawiona stawka opłaty (%s) + Found enough users, signing… Znaleziono wystarczającą ilość użytkowników, zapisuje… @@ -5023,10 +5573,6 @@ Przejdź do Plik > Otwórz portfel, aby załadować portfel. Invalid P2P permission: '%s' Nieprawidłowe uprawnienie P2P: '%s' - - Invalid amount for -fallbackfee=<amount>: '%s' - Błędna ilość -fallbackfee=<amount>: '%s' - Invalid masternodeblsprivkey. Please see documentation. Niewłaściwy masternodeblsprivkey. Sprawdź dokumentacje. @@ -5163,10 +5709,6 @@ Przejdź do Plik > Otwórz portfel, aby załadować portfel. Unable to open %s for writing Nie można otworzyć %s do zapisu - - Unable to parse -maxuploadtarget: '%s' (possible integer overflow?) - Nie można przeanalizować -maxuploadtarget: '%s' (możliwe przepełnienie liczby całkowitej?) - Unknown -blockfilterindex value %s. Nieznana wartość -blockfilterindex %s. @@ -5175,10 +5717,6 @@ Przejdź do Plik > Otwórz portfel, aby załadować portfel. Unknown new rules activated (versionbit %i) Aktywowano nieznane nowe reguły (wersja bit %i) - - Upgrading UTXO database - Aktualizowanie bazy danych UTXO - Verifying blocks… Weryfikacja bloków… @@ -5219,6 +5757,22 @@ Przejdź do Plik > Otwórz portfel, aby załadować portfel. %s uses exact denominated amounts to send funds, you might simply need to mix some more coins. %s używa dokładnie zdenominowanych kwot, możliwe że musisz zmiksować więcej monet. + + -reindex-chainstate option is not compatible with -blockfilterindex. Please temporarily disable blockfilterindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes. + Opcja -reindex-chainstate nie jest kompatybilna z -blockfilterindex. Wyłącz tymczasowo -blockfilterindex podczas korzystania z -reindex-chainstate lub zastąp -reindex-chainstate opcją -reindex aby odbudować wszystkie indeksy. + + + -reindex-chainstate option is not compatible with -coinstatsindex. Please temporarily disable coinstatsindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes. + Opcja -reindex-chainstate nie jest kompatybilna z -coinstatsindex. Proszę tymczasowo wyłączyć coinstatsindex podczas korzystania z -reindex-chainstate lub zastąpić -reindex-chainstate opcją -reindex, aby odbudować wszystkie indeksy. + + + -reindex-chainstate option is not compatible with -txindex. Please temporarily disable txindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes. + Opcja -reindex-chainstate nie jest kompatybilna z -txindex. Proszę tymczasowo wyłączyć txindex podczas korzystania z -reindex-chainstate lub zastąpić -reindex-chainstate opcją -reindex, aby odbudować wszystkie indeksy. + + + Cannot downgrade wallet from version %i to version %i. Wallet version unchanged. + Nie można zaktualizować portfela z wersji %i do wersji %i. Wersja portfela pozostaje niezmieniona. + Cannot obtain a lock on data directory %s. %s is probably already running. Nie można uzyskać blokady na katalogu z danymi %s. %s najprawdopodobniej jest już uruchomiony. @@ -5231,14 +5785,82 @@ Przejdź do Plik > Otwórz portfel, aby załadować portfel. Error loading %s: You can't enable HD on an already existing non-HD wallet Błąd ładowania %s: Nie możesz włączyć HD na już istniejącym portfelu innym niż HD + + 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 + Błąd podczas ładowania portfela. Portfel wymaga pobrania bloków, a oprogramowanie nie obsługuje wgrania portfela podczas pobierania bloków w nieprawidłowej kolejności przy użyciu migawek assumeutxo. Portfel powinien być w stanie załadować się pomyślnie po synchronizacji węzła do poziomu %s. + Error reading %s! All keys read correctly, but transaction data or address book entries might be missing or incorrect. Błąd odczytu %s! Wszystkie klucze zostały odczytane poprawnie, ale może brakować danych transakcji lub wpisów w książce adresowej, lub mogą one być nieprawidłowe. + + Error: Dumpfile format record is incorrect. Got "%s", expected "format". + Błąd: Nagłówek formatu pliku dump jest nieprawidłowy. Otrzymano "%s", oczekiwano "format". + + + Error: Dumpfile identifier record is incorrect. Got "%s", expected "%s". + Błąd: Nagłówek identyfikatora pliku dump jest nieprawidłowy. Otrzymano "%s", oczekiwano "%s". + + + Error: Dumpfile version is not supported. This version of bitcoin-wallet only supports version 1 dumpfiles. Got dumpfile with version %s + Błąd: Wersja pliku dump nie jest obsługiwana. Ta wersja bitcoin-wallet obsługuje tylko wersję 1 plików dump. Otrzymano plik dump z wersją %s. + + + Failed to rename invalid peers.dat file. Please move or delete it and try again. + Niepowodzenie podczas próby przemianowania nieprawidłowego pliku peers.dat. Przenieś lub usuń plik i spróbuj ponownie. + + + Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable %s. + Szacowanie opłaty nie powiodło się. Fallbackfee jest wyłączona. Poczekaj kilka bloków lub włącz %s. + + + File %s already exists. If you are sure this is what you want, move it out of the way first. + Plik %s już istnieje. Jeśli jesteś pewien, że chcesz to zrobić, przenieś najpierw plik. + + + Incompatible options: -dnsseed=1 was explicitly specified, but -onlynet forbids connections to IPv4/IPv6 + Niezgodne opcje: -dnsseed=1 zostało jawnie określone, ale -onlynet zabrania połączeń z IPv4/IPv6. + Incorrect or no devnet genesis block found. Wrong datadir for devnet specified? Znaleziono błędny lub nie istniejący pierwszy blog devnet. Wybrano zły datadir dla devnet? + + Invalid amount for %s=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions) + Nieprawidłowa kwota dla %s=<amount>: '%s' (musi wynosić co najmniej opłatę minrelay %s, aby zapobiec utknięciu transakcji) + + + 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. + Nieprawidłowy lub uszkodzony plik peers.dat (%s). Jeśli uważasz, że jest to błąd, proszę zgłoś to do %s. Jako rozwiązanie tymczasowe, możesz przenieść plik (%s) i (zamień, przenieś lub usuń), aby utworzyć nowy plik podczas następnego uruchomienia. + + + No dump file provided. To use createfromdump, -dumpfile=<filename> must be provided. + Nie podano pliku dump. Aby użyć createfromdump, należy podać -dumpfile=<filename>. + + + No dump file provided. To use dump, -dumpfile=<filename> must be provided. + Nie podano pliku dump. Aby użyć dump, należy podać -dumpfile=<filename>. + + + No wallet file format provided. To use createfromdump, -format=<format> must be provided. + Nie podano formatu pliku portfela. Aby użyć createfromdump, należy podać -format=<format>. + + + Outbound connections restricted to CJDNS (-onlynet=cjdns) but -cjdnsreachable is not provided + Połączenia wychodzące ograniczone do CJDNS (-onlynet=cjdns), ale -cjdnsreachable nie jest podany + + + Outbound connections restricted to Tor (-onlynet=onion) but the proxy for reaching the Tor network is explicitly forbidden: -onion=0 + Połączenia wychodzące są ograniczone do Tor (-onlynet=onion), ale serwer proxy do sieci Tor jest jawnie zabroniony: -onion=0. + + + 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 + Połączenia wychodzące ograniczone do Tor (-onlynet=onion), ale serwer proxy do sieci Tor nie jest podany: żaden z -proxy, -onion lub -listenonion nie jest podany. + + + Outbound connections restricted to i2p (-onlynet=i2p) but -i2psam is not provided + Połączenia wychodzące ograniczone do i2p (-onlynet=i2p), ale -i2psam nie jest podany + Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly. 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. @@ -5247,6 +5869,14 @@ Przejdź do Plik > Otwórz portfel, aby załadować portfel. Please contribute if you find %s useful. Visit %s for further information about the software. Jeśli %s przydatne dla ciebie, wesprzyj nas. Odwiedź %s po więcej informacj na temat tego programu. + + Prune mode is incompatible with -reindex-chainstate. Use full -reindex instead. + Tryb prune nie jest zgodny z -reindex-chainstate. Zamias tego użyj pełnego -reindex. + + + This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection. + Jest to maksymalna opłata transakcyjna, którą płacisz (oprócz normalnej opłaty) w celu priorytetowego uniknięcia częściowego wydatku ponad regularny wybór monety. + This is the transaction fee you may discard if change is smaller than dust at this level Jest to opłata transakcyjna, którą możesz odrzucić, jeśli reszta jest mniejsza niż pył na tym poziomie @@ -5255,6 +5885,10 @@ Przejdź do Plik > Otwórz portfel, aby załadować portfel. This is the transaction fee you may pay when fee estimates are not available. To jest prawdopodobny koszt transakcj jeśli szacunki opłat są niedostępne. + + Transaction requires one destination of non-0 value, a non-0 feerate, or a pre-selected input + Transakcja wymaga jednego celu o wartości niezerowej, niezerowej stawki opłaty lub wstępnie wybranego wejścia + Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate. Nie można odtworzyć bloków. Będziesz musiał odbudować bazę danych przy użyciu -reindex-chainstate. @@ -5263,6 +5897,10 @@ Przejdź do Plik > Otwórz portfel, aby załadować portfel. Unknown wallet file format "%s" provided. Please provide one of "bdb" or "sqlite". Podano nieznany format pliku portfela „%s”. Podaj jeden z „bdb” lub „sqlite”. + + Unsupported chainstate database format found. Please restart with -reindex-chainstate. This will rebuild the chainstate database. + Znaleziono nieobsługiwany format bazy danych chainstate. Uruchom ponownie z -reindex-chainstate. Spowoduje to przebudowanie bazy danych chainstate. + Warning: Dumpfile wallet format "%s" does not match command line specified format "%s". Ostrzeżenie: Format portfela Dumpfile "%s" nie pasuje do formatu "%s" określonego w wierszu poleceń. @@ -5303,10 +5941,30 @@ Przejdź do Plik > Otwórz portfel, aby załadować portfel. -rpcport must be specified when -devnet and -server are specified kiedy -devnet oraz -server są ustawione -rpcport też musi być ustawiony + + -statsbatchsize cannot be configured with a negative value. + -statsbatchsize nie może być skonfigurowany z wartością ujemną. + + + -statsduration cannot be configured with a negative value. + -statsduration nie może być skonfigurowany z wartością ujemną. + A fatal internal error occurred, see debug.log for details Błąd: Wystąpił wewnętrzny błąd krytyczny, szczegóły znajdziesz w pliku debug.log + + Cannot create socket (socket() returned error %s) + Nie można utworzyć gniazda (socket() zwrócił błąd %s) + + + Cannot get socket address for %s + Nie można uzyskać adresu gniazda dla %s + + + Cannot init Statsd client + Nie można zainicjować klienta Statsd + Cannot resolve -%s address: '%s' Nie można rozpoznać -%s adresu: '%s' @@ -5351,10 +6009,6 @@ Przejdź do Plik > Otwórz portfel, aby załadować portfel. Error reading next record from wallet database Błąd podczas odczytu następnego rekordu z bazy danych portfela - - Error upgrading chainstate database - Błąd ładowania bazy bloków - Loading P2P addresses… Wczytywanie adresów P2P… @@ -5475,10 +6129,70 @@ Przejdź do Plik > Otwórz portfel, aby załadować portfel. %s corrupt. Try using the wallet tool dash-wallet to salvage or restoring a backup. %s uszkodzony. Spróbuj użyć narzędzia dash-wallet aby odzyskać lub odbudować portfel z kopi zapasowej. + + %s is set very high! Fees this large could be paid on a single transaction. + %s jest ustawiony bardzo wysoko! Opłaty tej wielkości mogą zostać zapłacone w jednej transakcji. + + + %s request to listen on port %u. This port is considered "bad" and thus it is unlikely that any Dash Core peers connect to it. See doc/p2p-bad-ports.md for details and a full list. + %s żądanie nasłuchiwania na porcie %u. Port ten jest uważany za "zły" i dlatego jest mało prawdopodobne, że dowolny węzeł Dash Core połączy się z nim. Zobacz doc/p2p-bad-ports.md, aby uzyskać więcej informacji i pełną listę. + + + Cannot provide specific connections and have addrman find outgoing connections at the same time. + Nie można zapewnić określonych połączeń i jednocześnie obsługiwać połączenia wychodzące za pomocą addrman. + + + Failed to upgrade Evo database + Nie udało się zaktualizować bazy danych Evo + + + Fee needed > fee paid + Potrzebna opłata > zapłacona opłata + + + Host %s on unsupported network + Host %s w nieobsługiwanej sieci + + + Invalid amount for %s=<amount>: '%s' (must be at least %s) + Nieprawidłowa kwota dla %s=<amount>: '%s' (musi wynosić co najmniej %s) + + + Invalid amount for %s=<amount>: '%s' + Nieprawidłowa kwota dla %s=<amount>: '%s' + + + Invalid port specified in %s: '%s' + Nieprawidłowy port określony w %s: '%s' + Last successful action was too recent. Za mało czasu upłynęło od ostatniej udanej transakcji. + + Missing solving data for estimating transaction size + Brak danych do oszacowania rozmiaru transakcji + + + No host specified + Nie określono hosta + + + No host specified, malformed URL + Nie określono hosta, nieprawidłowy URL + + + No text before the scheme delimiter, malformed URL + Brak tekstu przed ogranicznikiem schematu, nieprawidłowy URL + + + Port must be between %d and %d, supplied %d + Port musi być pomiędzy %d a %d, podano %d + + + Socket not initialized, cannot send message + Gniazdo nie zainicjowane, nie można wysłać wiadomości + The source code is available from %s. Kod źródłowy dostępny jest z %s. @@ -5507,6 +6221,10 @@ Przejdź do Plik > Otwórz portfel, aby załadować portfel. Transaction fees are too high. Opłaty za transakcję są zbyt wysokie. + + Transaction needs a change address, but we can't generate it. + Transakcja wymaga adresu reszty, ale nie można go wygenerować. + Transaction not valid. Transakcja niewłaściwa. @@ -5527,6 +6245,18 @@ Przejdź do Plik > Otwórz portfel, aby załadować portfel. Unable to locate enough non-denominated funds for this transaction. Nie znaleziono wystarczającej ilości zdenominowanych środków dla tej transakcji. + + Unable to lookup host %s + Nie można wyszukać hosta %s + + + Unable to parse -maxuploadtarget: '%s' + Nie można przetworzyć -maxuploadtarget: '%s' + + + Unable to send message to %s (::sendto() returned error %s) + Nie można wysłać wiadomości do %s (::sendto() zwrócił błąd %s) + Unable to sign spork message, wrong key? Niemożliwe podpisanie wiadomości spork, nieprawidłowy klucz? @@ -5539,6 +6269,10 @@ Przejdź do Plik > Otwórz portfel, aby załadować portfel. Unknown state: id = %u Status nieznany: id = %u + + Unsupported URL scheme, must begin with udp:// + Nieobsługiwany schemat URL, musi zaczynać się od udp:// + Unsupported logging category %s=%s. Nieobsługiwana kategoria rejestrowania %s=%s. diff --git a/src/qt/locale/dash_pt.ts b/src/qt/locale/dash_pt.ts index f412e616b47a..a016b3e21bdf 100644 --- a/src/qt/locale/dash_pt.ts +++ b/src/qt/locale/dash_pt.ts @@ -65,14 +65,6 @@ C&hoose E&scolha - - Sending addresses - Endereços de envio - - - Receiving addresses - Endereços de recebimento - These are your Dash addresses for sending payments. Always check the amount and the receiving address before sending coins. Esses são os seus endereços para enviar pagamentos. Sempre cheque a quantia e o endereço de recebimento antes de enviar moedas, @@ -94,8 +86,8 @@ &Editar - &Show address QR code - &Mostrar endereço QR code + Show address &QR code + Mostrar endereço &QR code QR code @@ -105,6 +97,24 @@ Export Address List Exportar lista de endereço + + Comma separated file + Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values. + Arquivo separado por vírgulas + + + There was an error trying to save the address list to %1. Please try again. + An error message. %1 is a stand-in argument for the name of the file we attempted to save to. + Houve um erro ao tentar salvar a lista de endereços em %1. Por favor, tente novamente. + + + Sending addresses - %1 + Endereços de envio - %1 + + + Receiving addresses - %1 + Endereços de recebimento - %1 + Exporting Failed Falha ao exportar @@ -274,10 +284,22 @@ The passphrase entered for the wallet decryption was incorrect. A senha inserida para descriptografar a carteira está incorreta. + + 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 23.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. + A senha inserida para descriptografar a carteira está incorreta. Ela contém um caractere nulo (ou seja - um byte zero). Se a senha foi definida com uma versão deste software anterior à 23.0, tente novamente usando apenas os caracteres até — mas não incluindo — o primeiro caractere nulo. Se isso funcionar, defina uma nova senha para evitar este problema no futuro. + Wallet passphrase was successfully changed. A frase de segurança da carteira foi alterada com êxito. + + Passphrase change failed + Falha ao alterar a senha + + + 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 23.0, please try again with only the characters up to — but not including — the first null character. + A senha antiga inserida para descriptografar a carteira está incorreta. Ela contém um caractere nulo (ou seja - um byte zero). Se a senha foi definida com uma versão deste software anterior à 23.0, tente novamente usando apenas os caracteres até — mas não incluindo — o primeiro caractere nulo. + Warning: The Caps Lock key is on! Atenção: A tecla Caps Lock está ligada! @@ -298,12 +320,28 @@ BitcoinAmountField Amount in %1 - Quantidade em %1 + Valor em %1 BitcoinApplication - + + Runaway exception + Erro de execução + + + A fatal error occurred. %1 can no longer continue safely and will quit. + Ocorreu um erro fatal. %1 não pode continuar com segurança e será encerrado. + + + Internal error + Erro interno + + + An internal error occurred. %1 will attempt to continue safely. This is an unexpected bug which can be reported as described below. + Ocorreu um erro interno. %1 tentará continuar com segurança. Este é um erro inesperado que pode ser reportado conforme descrito abaixo. + + BitcoinGUI @@ -330,6 +368,10 @@ Request payments (generates QR codes and dash: URIs) Solicitações de pagamentos (gera códigos QR e Dash: URIs) + + Ctrl+Q + Ctrl+Q + &Options… &Opções… @@ -358,6 +400,10 @@ &Verify message… &Verificar mensagem… + + &Load PSBT from file… + &Carregar PSBT do arquivo… + &Sending addresses &Endereços de envio @@ -390,10 +436,6 @@ &Window &Janela - - Minimize - Minimizar - Zoom Zoom @@ -446,14 +488,6 @@ Modify configuration options for %1 Modificar opções de configuração para o %1 - - &Show / Hide - &Exibir/Ocultar - - - Show or hide the main Window - Mostrar ou esconder a Janela Principal. - Encrypt the private keys that belong to your wallet Criptografar as chaves privadas que pertencem à sua carteira @@ -518,10 +552,6 @@ Show wallet repair options Mostrar opções de reparação da carteira - - Open Wallet &Configuration File - Abrir arquivo de &Configuração da carteira - Open configuration file Abrir arquivo de configuração @@ -576,10 +606,40 @@ Show information about %1 Mostrar informação sobre %1 + + Load PSBT from &clipboard… + Carregar PSBT da área de trans&ferência… + + + Open debugging and diagnostic console + Abrir painel de depuração e diagnóstico + + + Open &wallet configuration file + Abrir arquivo de configuração da c&arteira + + + Open a dash: URI + Abrir dash: URI + Create a new wallet Criar uma nova carteira + + Restore Wallet… + Name of the menu item that restores wallet from a backup file. + Restaurar carteira… + + + Restore a wallet from a backup file + Status tip for Restore Wallet menu item + Restaurar uma carteira de um arquivo de backup + + + Close all wallets + Fechar todas as carteiras + %1 &information %1 &Informação @@ -588,10 +648,42 @@ Show the %1 basic information Mostrar as informações básicas %1 + + &Discreet mode + Modo &Discreto + + + Mask the values in the Overview tab + Mascarar os valores na aba Visão Geral + + + Wallet Data + Name of the wallet data file format. + Dados da carteira + + + Load Wallet Backup + The title for Restore Wallet File Windows + Carregar backup da carteira + + + Restore Wallet + Title of pop-up window shown when the user is attempting to restore a wallet. + Restaurar carteira + + + Wallet Name + Label of the input field where the name of the wallet is entered. + Nome da carteira + &Settings &Configurações + + &Minimize + &Minimizar + &Help &Ajuda @@ -608,8 +700,17 @@ View Governance Proposals Ver Propostas de Governança + + &Hide + &Ocultar + + + S&how + E&xibir + %n active connection(s) to Dash network + A substring of the tooltip. %n conexões ativas com a rede Dash%n conexões ativas com a rede Dash%n conexões ativas com a rede Dash @@ -628,10 +729,50 @@ Close Wallet… Fechar Carteira… + + Load Partially Signed Blockchain Transaction + Carregar Transação de Blockchain Parcialmente Assinada + + + Load Partially Signed Blockchain Transaction from clipboard + Carregar Transação de Blockchain Parcialmente Assinada da área de transferência + Create Wallet… Criar Carteira… + + Close All Wallets… + Fechar todas as carteiras... + + + Ctrl+Shift+D + Ctrl+Shift+D + + + Ctrl+M + Ctrl+M + + + Click for more actions. + A substring of the tooltip. "More actions" are available via the context menu. + Clique para mais ações. + + + Show Peers tab + A context menu item. The "Peers tab" is an element of the "Node window". + Mostrar aba de Pares + + + Disable network activity + A context menu item. + Desabilitar atividade de rede + + + Enable network activity + A context menu item. The network activity was disabled previously. + Habilitar atividade de rede + Syncing Headers (%1%)… Sincronizando cabeçahos (%1%)… @@ -648,10 +789,6 @@ Processing blocks on disk… Processando blocos no disco… - - Reindexing blocks on disk… - Reindexando blocos no disco… - Connecting to peers… Conectando… @@ -729,7 +866,7 @@ Amount: %1 - Quantia: %1 + Valor: %1 @@ -795,7 +932,7 @@ Amount: - Quantia: + Valor: Fee: @@ -805,10 +942,6 @@ Coin Selection Seleção da Moeda - - Dust: - Poeira: - After Fee: Depois da taxa: @@ -839,7 +972,7 @@ Amount - Quantidade + Valor Received with label @@ -866,28 +999,32 @@ Confirmado - Copy address - Copie endereço + Copy amount + Copie quantia + + + &Copy address + &Copiar endereço - Copy label - Copiar rótulo + Copy &label + Copiar &identificador - Copy amount - Copie quantia + Copy &amount + Copiar &valor - Copy transaction ID - Copie ID da transação + Copy transaction &ID and output index + Copiar &ID da transação e índice de saída - Lock unspent - Bloquear não gasto + L&ock unspent + &Bloquear fundos não gastos - Unlock unspent - Desbloquear não gasto + &Unlock unspent + &Desbloquear fundos não gastos Copy quantity @@ -905,10 +1042,6 @@ Copy bytes Copiar bytes - - Copy dust - Copiar poeira - Copy change Copiar troco @@ -921,18 +1054,6 @@ (%1 locked) (%1 bloqueado) - - yes - sim - - - no - não - - - This label turns red if any recipient receives an amount smaller than the current dust threshold. - Este texto fica vermelho se qualquer destinatário receber uma quantidade menor que que o dust. - Can vary +/- %1 duff(s) per input. Pode variar +/- %1 duff(s) por entrada. @@ -976,8 +1097,14 @@ CreateWalletActivity + + Create Wallet + Title of window indicating the progress of creation of a new wallet. + Criar carteira + Creating Wallet <b>%1</b>… + Descriptive text of the create wallet progress window which indicates to the user which wallet is currently being created. Criando Carteira <b>%1</b>… @@ -999,6 +1126,10 @@ Wallet Name Nome da Carteira + + Wallet + Carteira + Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice. Criptografar a carteira. A carteira será criptografada com uma frase de segurança de sua escolha. @@ -1007,6 +1138,10 @@ Encrypt Wallet Criptografar Carteira + + Advanced Options + Opções avançadas + 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. Desativar as chaves privadas para esta carteira. Carteiras com chaves privadas desabilitadas não terão chaves privadas e não podem ter uma "HD seed" ou chaves privadas importadas. Isso é ideal para carteiras apenas para relógios. @@ -1023,11 +1158,23 @@ Make Blank Wallet Fazer Carteira em Branco + + Use descriptors for scriptPubKey management. This feature is well-tested but still considered experimental and not recommended for use yet. + Use descritores para o gerenciamento de scriptPubKey. Essa funcionalidade é bem testada, mas ainda é considerada experimental e não recomendada para uso. + + + Descriptor Wallet (EXPERIMENTAL) + Carteira de Descritores (EXPERIMENTAL) + Create Criar - + + Compiled without sqlite support (required for descriptor wallets) + Compilado sem suporte a sqlite (necessário para carteiras com descritores) + + EditAddressDialog @@ -1116,18 +1263,106 @@ Filter List: Filtrar Lista: + + Filter proposal list + Filtrar a lista de propostas + + + Masternode Count: + Contagem de masternodes: + + + Number of masternodes this wallet can vote with (masternodes for which this wallet holds the voting key) + Número de masternodes com os quais esta carteira pode votar (masternodes para os quais esta carteira possui a chave de votação) + Proposal Count: Contagem de Propostas: + + Create Proposal + Criar proposta + Filter by Title Filtrar por Título + + Unavailable + Indisponível + + + A synced node and an unlocked wallet are required. + Um nó sincronizado e uma carteira desbloqueada são necessários. + + + Vote Yes + Votar a favor + + + Vote No + Votar contra + + + Vote Abstain + Votar abstenção + Proposal Info: %1 Informações da proposta: %1 + + Voting Failed + Falha na votação + + + No wallet available. + Nenhuma carteira disponível. + + + No masternode voting keys found in wallet. + Nenhuma chave de votação de masternode encontrada na carteira. + + + Please select a proposal to vote on. + Por favor, selecione uma proposta para votar. + + + Unable to unlock wallet. + Não foi possível desbloquear a carteira. + + + Unable to get masternode list. Please try again later. + Não foi possível obter a lista de masternodes. Por favor, tente novamente mais tarde. + + + Masternode %1 not found + Masternode %1 não encontrado + + + Failed to sign vote for masternode %1 + Falha ao assinar voto para masternode %1 + + + Masternode %1: %2 + Masternode %1: %2 + + + Voted successfully %n time(s) + Votado com sucesso %n vezVotado com sucesso %n vezesVotado com sucesso %n vezes + + + Failed to vote %n time(s) + Falha ao votar %n vezFalha ao votar %n vezesFalha ao votar %n vezes + + + Errors: + Erros: + + + Voting Results + Resultados da votação + HelpMessageDialog @@ -1166,10 +1401,26 @@ As this is the first time the program is launched, you can choose where %1 will store its data. Como essa é a primeira vez que o programa é executado, você pode escolher onde %1 armazenará seus dados. + + Limit block chain storage to + Limitar o armazenamento da blockchain a + + + 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. + Reverter essa configuração requer o re-download de toda a blockchain. É mais rápido baixar a cadeia completa primeiro e podá-la depois. Desativa alguns recursos avançados. + + + GB + GB + 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. 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. + + 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. + Quando você clicar em OK, %1 começará a baixar e processar a blockchain completa de %4 (%2 GB), começando pelas transações mais antigas em %3, quando %4 foi lançado inicialmente. + 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. Se escolheu limitar o armazenamento da cadeia de blocos (modo pruning), 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. @@ -1182,6 +1433,18 @@ Use a custom data directory: Use um diretório de dados personalizado: + + %n GB of space available + %n GB de espaço disponível%n GB de espaço disponível%n GB de espaço disponível + + + (of %n GB needed) + (de %n GB necessário)(de %n GB necessários)(de %n GB necessários) + + + (%n GB needed for full chain) + (%n GB necessário para cadeia completa)(%n GB necessários para cadeia completa)(%n GB necessários para cadeia completa) + At least %1 GB of data will be stored in this directory, and it will grow over time. No mínimo %1 GB de dados irão ser armazenados nesta pasta. @@ -1190,6 +1453,11 @@ Approximately %1 GB of data will be stored in this directory. Aproximadamente %1 GB de dados irão ser guardados nesta pasta. + + (sufficient to restore backups %n day(s) old) + Explanatory text on the capability of the current prune target. + (suficiente para restaurar backups de %n dia atrás)(suficiente para restaurar backups de %n dias atrás)(suficiente para restaurar backups de %n dias atrás) + %1 will download and store a copy of the Dash block chain. %1 irá descarregar e armazenar uma cópia da cadeia de blocos da Dash. @@ -1207,6 +1475,13 @@ Erro + + LoadWalletsActivity + + Loading wallets… + Carregando carteiras… + + MasternodeList @@ -1241,6 +1516,10 @@ Service Serviço + + Type + Tipo + PoSe Score Contagem PoSe @@ -1376,6 +1655,10 @@ Hide Esconder + + %1 is currently syncing. It will download headers and blocks from peers and validate them until reaching the tip of the block chain. + %1 está atualmente sincronizando. Ele fará o download de cabeçalhos e blocos dos pares e os validará até alcançar o topo da blockchain. + Unknown. Syncing Headers (%1, %2%)… Desconhecido. Sincronizando cabeçalhos (%1, %2%)… @@ -1391,6 +1674,11 @@ URI: URI: + + Paste address from clipboard + Tooltip text for button that allows you to paste an address that is in your clipboard. + Colar endereço da área de transferência + OpenWalletActivity @@ -1406,8 +1694,14 @@ default wallet carteira padrão + + Open Wallet + Title of window indicating the progress of opening of a wallet. + Abrir Carteira + Opening Wallet <b>%1</b>… + Descriptive text of the open wallet progress window which indicates to the user which wallet is currently being opened. Abrindo Carteira<b>%1</b>… @@ -1441,6 +1735,14 @@ &Appearance &Aparência + + Show the icon in the system tray. + Exibir o ícone na bandeja do sistema. + + + &Show tray icon + &Exibir ícone na bandeja + Prune &block storage to Podar e bloquear o armazenamento para @@ -1453,10 +1755,58 @@ Reverting this setting requires re-downloading the entire blockchain. Reverter essa configuração requer realizar o download novamente de todo o blockchain. + + 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. + Tooltip text for Options window setting that sets the size of the database cache. Explains the corresponding effects of increasing/decreasing this value. + Tamanho máximo do cache do banco de dados. Um cache maior pode contribuir para uma sincronização mais rápida, embora o benefício se torne menos perceptível após a conclusão. Reduzir o tamanho do cache diminuirá o uso de memória. A memória não utilizada do mempool é compartilhada com esse cache. + MiB MiB + + Set the number of script verification threads. Negative values correspond to the number of cores you want to leave free to the system. + 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. + Defina o número de threads de verificação de scripts. Valores negativos correspondem ao número de núcleos que você deseja deixar livres para o sistema. + + + This allows you or a third party tool to communicate with the node through command-line and JSON-RPC commands. + Tooltip text for Options window setting that enables the RPC server. + Isso permite que você ou uma ferramenta de terceiros se comuniquem com o nó por meio de comandos de linha de comando e JSON-RPC. + + + Enable R&PC server + An Options window setting to enable the RPC server. + Habilitar servidor R&PC + + + Whether to set subtract fee from amount as default or not. + Tooltip text for Options window setting that sets subtracting the fee from a sending amount as default. + Definir se a taxa deve ser subtraída ou não do valor por padrão. + + + Subtract &fee from amount by default + An Options window setting to set subtracting the fee from a sending amount as default. + Subtrair &taxa do valor por padrão + + + Enable &PSBT controls + An options window setting to enable PSBT controls. + Ativar controles &PSBT + + + Whether to show PSBT controls. + Tooltip text for options window setting that enables PSBT controls. + Se deve mostrar controles PSBT. + + + Whether to keep the specified custom change address or not. + Definir se o endereço de troco personalizado especificado será mantido. + + + Keep custom change &address + Manter &endereço de troco personalizado + Show additional tab listing all your masternodes in first sub-tab<br/>and all masternodes on the network in second sub-tab. Mostre uma guia adicional listando todos os seus masternodes na primeira subposição <br/> e todos os masternodes na rede na segunda sub-guia. @@ -1513,6 +1863,14 @@ Enable &multi-session Ativar &multi-sessão + + Use this many separate masternodes in parallel to mix funds.<br/>Note: You must use this feature carefully.<br/>Make sure you always have recent wallet (auto)backup in a safe place! + Usar esta quantidade de masternodes separados em paralelo para misturar fundos. <br/>Nota: Use este recurso com cuidado. <br/>Certifique-se de sempre ter um backup (automático) recente da carteira em um local seguro! + + + Parallel sessions + Sessões paralelas + Mixing rounds Rodadas de Anonimização @@ -1525,6 +1883,30 @@ Target balance Escolher saldo + + How many inputs of each denominated amount are created.<br/>Lower these numbers if you want fewer smaller denominations. + Quantas entradas de cada valor denominado são criadas. <br/>Diminua esses números se quiser menos denominações de valor reduzido. + + + Inputs per denomination + Entradas por denominação + + + Try to create at least this many inputs for each denominated amount.<br/>Lower this number if you want fewer smaller denominations. + Tente criar pelo menos esta quantidade de entradas para cada denominação. <br/>Diminua esses números se quiser menos denominações de valor reduzido. + + + Target + Alvo + + + Create up to this many inputs for each denominated amount.<br/>Lower this number if you want fewer smaller denominations. + Crie até esta quantidade de entradas para cada denominação. <br/>Diminua esses números se quiser menos denominações de valor reduzido. + + + Maximum + Máximo + Automatically open the Dash Core client port on the router. This only works when your router supports UPnP and it is enabled. Abre automaticamente a porta para o cliente Dash Core no roteador. Essa função apenas funciona se o seu roteador oferece suporte a UPnP e a opção estiver habilitada. @@ -1554,20 +1936,26 @@ Mostra se o proxy SOCKS5 padrão fornecido for usado para alcançar pares através deste tipo de rede. - Options set in this dialog are overridden by the command line or in the configuration file: - As opções definidas nesta caixa de diálogo são substituídas pela linha de comando ou no arquivo de configuração: + Language missing or translation incomplete? Help contributing translations here: +https://explore.transifex.com/dash/dash/ + Idioma ausente ou tradução incompleta? Ajude a contribuir com traduções aqui: +https://explore.transifex.com/dash/dash/ - 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. - Minimizar em vez de sair do aplicativo quando a janela for fechada. Quando esta opção está ativada, o aplicativo só será fechado selecionando Sair no menu. + Third-party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items.<br/>%s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |. + URLs de terceiros (por exemplo, um explorador de blocos) que aparecem na aba de transações como itens do menu de contexto.<br/>%s na URL é substituído pelo hash da transação. Múltiplas URLs são separadas por barra vertical |. + + + &Third-party transaction URLs + URLs de transação de &terceiros - Third party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items.<br/>%s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |. - As URLs de terceiros (por exemplo, um explorador de blocos) que aparecem na guia de transações como itens de menu de contexto. <br/>%s na URL são substituídos por hash de transação. Vários URLs são separados pela barra vertical |. + Options set in this dialog are overridden by the command line or in the configuration file: + As opções definidas nesta caixa de diálogo são substituídas pela linha de comando ou no arquivo de configuração: - &Third party transaction URLs - &URLs de transações de terceiros + 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. + Minimizar em vez de sair do aplicativo quando a janela for fechada. Quando esta opção está ativada, o aplicativo só será fechado selecionando Sair no menu. Whether to show coin control features or not. @@ -1605,6 +1993,10 @@ Map port using &UPnP Mapear porta usando &UPnP + + Automatically open the Dash Core client port on the router. This only works when your router supports NAT-PMP and it is enabled. The external port could be random. + Abrir automaticamente a porta do cliente Dash Core no roteador. Isso só funciona se o seu roteador for compatível com NAT-PMP e essa opção estiver ativada. A porta externa pode ser aleatória. + Proxy &IP: &IP do proxy: @@ -1654,8 +2046,16 @@ &Mostrar - User Interface &language: - &Língua da interface com usuário: + Connect to the Dash network through a separate SOCKS5 proxy for Tor onion services. + Conectar à rede Dash por meio de um proxy SOCKS5 separado para serviços Tor onion. + + + Use separate SOCKS&5 proxy to reach peers via Tor onion services: + Use um SOCKS&5 separado para alcançar pares através de serviços Tor onion: + + + User Interface &language: + &Língua da interface com usuário: The user interface language can be set here. This setting will take effect after restarting %1. @@ -1699,14 +2099,22 @@ Confirm options reset + Window title text of pop-up window shown when the user has chosen to reset options. Confirmar redefinição de opções Client restart required to activate changes. + Text explaining that the settings changed will not come into effect until the client is restarted. Reinicialização do aplicativo necessária para efetivar alterações. + + Current settings will be backed up at "%1". + 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. + As configurações atuais serão copiadas em "%1". + Client will be shut down. Do you want to proceed? + Text asking the user to confirm if they would like to proceed with a client shutdown. O programa será encerrado. Deseja continuar? @@ -1844,6 +2252,10 @@ %1 Balance %1 Saldo + + Discreet mode activated for the Overview tab. To unmask the values, uncheck Settings->Discreet mode. + O modo discreto foi ativado para a aba Visão Geral. Para desmascarar os valores, desmarque Configurações->Modo discreto. + %n Rounds %n Rodadas%n Rodadas%n Rodadas @@ -1943,7 +2355,140 @@ PSBTOperationsDialog - + + Dialog + Diálogo + + + Sign Tx + Assinar transação + + + Broadcast Tx + Transmitir transação + + + Copy to Clipboard + Copiar para a área de transferência + + + Save… + Salvar... + + + Close + Fechar + + + Failed to load transaction: %1 + Falha ao carregar a transação: %1 + + + Failed to sign transaction: %1 + Falha ao assinar transação: %1 + + + Cannot sign inputs while wallet is locked. + Não é possível assinar as entradas enquanto a carteira estiver bloqueada. + + + Could not sign any more inputs. + Não foi possível assinar mais entradas. + + + Signed %1 inputs, but more signatures are still required. + Assinadas %1 entradas, mas ainda são necessárias mais assinaturas. + + + Signed transaction successfully. Transaction is ready to broadcast. + Transação assinada com sucesso. A transação está pronta para ser transmitida. + + + Unknown error processing transaction. + Erro desconhecido ao processar transação + + + Transaction broadcast successfully! Transaction ID: %1 + Transação transmitida com sucesso! ID da transação: %1 + + + Transaction broadcast failed: %1 + A transmissão da transação falhou: %1 + + + PSBT copied to clipboard. + PSBT copiado para área de transferência + + + Save Transaction Data + Salvar Dados da Transação + + + Partially Signed Transaction (Binary) + Expanded name of the binary PSBT file format. See: BIP 174. + Transação assinada parcialmente (binário) + + + PSBT saved to disk. + PSBT salvo no disco. + + + * Sends %1 to %2 + * Envia %1 de %2 + + + own address + endereço próprio + + + Unable to calculate transaction fee or total transaction amount. + Não foi possível calcular a taxa de transação ou o valor total da transação. + + + Pays transaction fee: + Paga a taxa de transação: + + + Total Amount + Valor total + + + or + ou + + + Transaction has %1 unsigned inputs. + A transação possui %1 entradas não assinadas. + + + Transaction is missing some information about inputs. + Está faltando na transação algumas informações sobre as entradas. + + + Transaction still needs signature(s). + A transação ainda precisa de assinatura(s). + + + (But no wallet is loaded.) + (Mas nenhuma carteira está carregada.) + + + (But this wallet cannot sign transactions.) + (Mas esta carteira não pode assinar transações.) + + + (But this wallet does not have the right keys.) + (Mas esta carteira não possui as chaves corretas.) + + + Transaction is fully signed and ready for broadcast. + A transação está completamente assinada e está pronta para transmissão + + + Transaction status is unknown. + O estado da transação é desconhecido. + + PaymentServer @@ -1962,6 +2507,12 @@ 'dash://' is not a valid URI. Use 'dash:' instead. 'dash://' não é uma URL válida. Use 'dash:' como alternativa. + + Cannot process payment request as BIP70 is no longer supported. +Due to discontinued support, you should request the merchant to provide you with a BIP21 compatible URI or use a wallet that does continue to support BIP70. + Não é possível processar o pedido de pagamento, pois o BIP70 não é mais suportado. +Devido ao suporte descontinuado, você deve solicitar ao comerciante que forneça um URI compatível com BIP21 ou usar uma carteira que continue a suportar o BIP70. + URI cannot be parsed! This can be caused by an invalid Dash address or malformed URI parameters. A URI não pode ser analisada! Isto pode ser causado por um endereço inválido ou um parâmetro URI malformado. @@ -1983,6 +2534,26 @@ Title of Peers Table column which indicates the current latency of the connection with the peer. Ping + + Peer + Title of Peers Table column which contains a unique number used to identify a connection. + Par + + + Age + Title of Peers Table column which indicates the duration (length of time) since the peer connection started. + Duração + + + Direction + Title of Peers Table column which indicates the direction the peer connection was initiated from. + Direção + + + Type + Title of Peers Table column which describes the type of peer connection. The "type" describes why the connection exists. + Tipo + Sent Title of Peers Table column which indicates the total amount of network information we have sent to the peer. @@ -1993,7 +2564,27 @@ Title of Peers Table column which indicates the total amount of network information we have received from the peer. Recebido - + + Address + Title of Peers Table column which contains the IP/Onion/I2P address of the connected peer. + Endereço + + + Network + Title of Peers Table column which states the network the peer connected through. + Rede + + + Inbound + An Inbound Connection from a Peer. + Entrada + + + Outbound + An Outbound Connection to a Peer. + Saída + + Proposal @@ -2033,7 +2624,7 @@ Amount - Quantidade + Valor Active @@ -2044,8 +2635,193 @@ Status + + ProposalWizard + + Create Governance Proposal + Criar proposta de governança + + + Enter proposal details + Digite os detalhes da proposta + + + A fee will be burned when you prepare the proposal. + Uma taxa será queimada quando você preparar a proposta. + + + Proposal &name + &Nome da proposta + + + &Description URL + URL da &descrição + + + Payment &address + &Endereço de pagamento + + + Payment &amount + V&alor do pagamento + + + The amount to request in a single payment + O valor a solicitar em um único pagamento + + + &First payment + &Primeiro pagamento + + + Pa&yments + Pa&gamentos + + + To&tal amount + Valor to&tal + + + Proposal &fee + &Taxa da proposta + + + Next + Próximo + + + Review proposal JSON and validate. + Revisar JSON da proposta e validar. + + + Hex-encoded JSON + JSON codificado em Hex + + + Back + Voltar + + + Validate + Validar + + + Prepare (burn fee) and wait for confirmations. + Preparar (queimar taxa) e aguardar confirmações. + + + Copy + Copiar + + + At 1/6 confirmations: can be relayed and queued. At 6/6: accepted and processed. + Em 1/6 confirmações: pode ser retransmitida e enfileirada. Em 6/6: aceita e processada. + + + Confirmations progress + Progresso das confirmações + + + Shows progress toward the required number of confirmations for the proposal fee transaction. + Mostra o progresso em direção ao número necessário de confirmações para a transação de taxa da proposta. + + + Estimated time remaining: - + Tempo estimado restante: - + + + Prepare Proposal + Preparar proposta + + + You can submit after 1 confirmation. At 6 confirmations it is accepted and processed. + Você pode enviar após 1 confirmação. Em 6 confirmações é aceita e processada. + + + Proposal ID: + ID da proposta: + + + Submit Proposal + Enviar proposta + + + Close + Fechar + + + Valid + Válido + + + Invalid: %1 + Inválido: %1 + + + Burn %1 + Queimar %1 + + + Burn %1 to create the fee transaction? + Queimar %1 para criar a transação de taxa? + + + Prepare failed + Falha ao preparar + + + Confirmations: %1 / %2 required + Confirmações: %1 / %2 necessárias + + + Estimated time remaining: Ready + Tempo estimado restante: Pronto + + + Estimated time remaining: %n minute(s) + Tempo estimado restante: %n minutoTempo estimado restante: %n minutosTempo estimado restante: %n minutos + + + Your proposal was submitted successfully. + Sua proposta foi enviada com sucesso. + + + Already submitted + Já enviada + + + This proposal has already been submitted. + Esta proposta já foi enviada. + + + Submission failed + Falha no envio + + + Proposal submitted + Proposta enviada + + + A fee of %1 will be burned when you prepare the proposal. + Uma taxa de %1 será queimada quando você preparar a proposta. + + + Prepare (burn %1) and wait for %2 confirmations. + Preparar (queimar %1) e aguardar %2 confirmações. + + QObject + + Do you want to reset settings to default values, or to abort without making changes? + Explanatory text shown on startup when the settings file cannot be read. Prompts user to make a choice between resetting or aborting. + Você deseja redefinir as configurações para os valores padrão ou abortar sem fazer alterações?  + + + A fatal error occurred. Check that settings file is writable, or try running with -nosettings. + 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. + Ocorreu um erro fatal. Verifique se o arquivo de configurações é gravável ou tente executar com a opção com -nosettings + Choose data directory on startup (default: %u) Escolher diretório de dados na inicialização (padrão: %u) @@ -2128,7 +2904,7 @@ Amount - Quantia + Valor Enter a Dash address (e.g. %1) @@ -2146,6 +2922,53 @@ This can also be adjusted later in the "Appearance" tab of the preferences. Isso também pode ser ajustado posteriormente na aba "Aparência" nas preferências. + + Ctrl+W + Ctrl+W + + + Unroutable + Não roteável + + + Internal + Interno + + + Inbound + An inbound connection from a peer. An inbound connection is a connection initiated by a peer. + Entrada + + + Outbound + An outbound connection to a peer. An outbound connection is a connection initiated by us. + Saída + + + Full Relay + Peer connection type that relays all network information. + Retransmissão Completa + + + Block Relay + Peer connection type that relays network information about blocks and not transactions or addresses. + Retransmissão de Blocos + + + Manual + Peer connection type established manually through one of several methods. + Manual + + + Feeler + Short-lived peer connection type that tests the aliveness of known addresses. + Sondagem + + + Address Fetch + Short-lived peer connection type that solicits known addresses from a peer. + Busca de endereço + %1 d %1 d @@ -2207,8 +3030,8 @@ %1 B - %1 KB - %1 KB + %1 kB + %1 kB %1 MB @@ -2264,7 +3087,12 @@ Save QR Code Salvar código QR - + + PNG Image + Expanded name of the PNG file format. See: https://en.wikipedia.org/wiki/Portable_Network_Graphics. + Imagem PNG + + RPCConsole @@ -2371,6 +3199,14 @@ Version Versão + + High bandwidth BIP152 compact block relay: %1 + Retransmissão de blocos compactos BIP152 de alta largura de banda: %1 + + + High Bandwidth + Alta largura de banda + Starting Block Bloco inicial @@ -2383,6 +3219,51 @@ Synced Blocks Blocos Sincronizados + + Elapsed time since a novel block passing initial validity checks was received from this peer. + Tempo decorrido desde que um novo bloco, passando nas verificações iniciais de validade, foi recebido deste par. + + + Last Block + Último bloqueio + + + Elapsed time since a novel transaction accepted into our mempool was received from this peer. + Tooltip text for the Last Transaction field in the peer details area. + Tempo decorrido desde que uma nova transação aceita em nosso mempool foi recebida deste par. + + + Last Transaction + Última transação + + + The mapped Autonomous System used for diversifying peer selection. + Sistema Autônomo mapeado usado para diversificar a seleção de pares. + + + Mapped AS + Sistema Autônomo Mapeado + + + Whether we relay addresses to this peer. + Tooltip text for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No). + Se retransmitimos endereços para este par. + + + Address Relay + Text title for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No). + Retransmissão de endereço + + + Addresses Processed + 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). + Endereço Processado + + + Addresses Rate-Limited + 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. + Endereços com Limite de Taxa + Rescan blockchain files 1 Reescanear o blockchain 1 @@ -2423,6 +3304,22 @@ To specify a non-default location of the blocks directory use the '%1' option. Para especificar um local fora do padrão do diretório de blocos, use a opção '%1'. + + Local Addresses + Endereços locais + + + Network addresses that your Dash node is currently using to communicate with other nodes. + Endereços de rede que seu nó Dash está usando atualmente para se comunicar com outros nós. + + + Number of regular Masternodes + Número de Masternodes regulares + + + Number of EvoNodes + Número de EvoNodes + Current block height Altura do bloco atual @@ -2471,10 +3368,50 @@ PoSe Score Contagem PoSe + + The transport layer version: %1 + A versão da camada de transporte: %1 + + + Transport + Transporte + + + The BIP324 session ID string in hex. + A string ID da sessão BIP324 em hexadecimal. + + + Session ID + ID da sessão + + + The network protocol this peer is connected through: IPv4, IPv6, Onion, I2P, or CJDNS. + O protocolo de rede através do qual este par está conectado: IPv4, IPv6, Onion, I2P ou CJDNS. + + + Permissions + Permissões + + + The direction and type of peer connection: %1 + A direção e o tipo de conexão do par: %1 + + + Direction/Type + Direção/Tipo + Services Serviços + + Whether we relay transactions to this peer. + Se retransmitimos transações para este par. + + + Transaction Relay + Retransmissão de transação + Connection Time Tempo de conexão @@ -2511,6 +3448,16 @@ &Wallet Repair &Reparar carteira + + The total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting). + 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). + O número total de endereços recebidos deste par que foram processados (exclui endereços que foram descartados devido à limitação de taxa). + + + The total number of addresses received from this peer that were dropped (not processed) due to rate-limiting. + 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. + O número total de endereços recebidos deste par que foram descartados (não processados) devido à limitação de taxa. + Wallet repair options. Opções de reparação da carteira. @@ -2524,52 +3471,82 @@ -reindex: Reconstrói o índice de cadeia de blocos a partir dos arquivos atuais de dados blk000??.dat . - &Disconnect - &Desconectar + Inbound: initiated by peer + Explanatory text for an inbound peer connection. + Entrada: iniciada pelo par - Ban for - Banir por + Outbound Full Relay: default + Explanatory text for an outbound peer connection that relays all network information. This is the default behavior for outbound connections. + Saída Retransmissão Completa: padrão - 1 &hour - 1 &hora + Outbound Block Relay: does not relay transactions or addresses + Explanatory text for an outbound peer connection that relays network information about blocks and not transactions or addresses. + Saída Retransmissão de Blocos: não retransmite transações ou endereços - 1 &day - 1 &dia + Outbound Manual: added using RPC %1 or %2/%3 configuration options + 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. + Saída Manual: adicionada usando as opções de configuração RPC %1 ou %2/%3 - 1 &week - 1 &semana + Outbound Feeler: short-lived, for testing addresses + Explanatory text for a short-lived outbound peer connection that is used to test the aliveness of known addresses. + Saída de sondagem: de curta duração, para testar endereços - 1 &year - 1 &ano + Outbound Address Fetch: short-lived, for soliciting addresses + Explanatory text for a short-lived outbound peer connection that is used to request addresses from a peer. + Saída para busca de endereços: de curta duração, para solicitar endereços - &Unban - &Desbanir + To + Para + + + we selected the peer for high bandwidth relay + nós selecionamos o par para retransmissão de alta largura de banda - Welcome to the %1 RPC console. - Bem-vindo ao console RPC do %1. + From + De - Use up and down arrows to navigate history, and %1 to clear screen. - Use as setas para cima e para baixo para navegar pelo histórico, e %1 para limpar a tela. + the peer selected us for high bandwidth relay + o par nos selecionou para retransmissão de alta largura de banda - Type %1 for an overview of available commands. - Digite %1 para obter uma visão geral dos comandos disponíveis. + No + Não + + + no high bandwidth relay selected + nenhuma retransmissão de alta largura de banda selecionada + + + &Disconnect + &Desconectar - For more information on using this console type %1. - Para mais informações sobre como usar este painel, digite %1. + Ban for + Banir por + + + 1 &hour + 1 &hora + + + 1 &week + 1 &semana + + + 1 &year + 1 &ano - WARNING: Scammers have been active, telling users to type commands here, stealing their wallet contents. Do not use this console without fully understanding the ramifications of a command. - AVISO: Os golpistas estão ativos, dizendo aos usuários para digitar comandos aqui, roubando o conteúdo da carteira. Não use este console sem compreender totalmente o contexto de um comando. + &Unban + &Desbanir In: @@ -2583,6 +3560,10 @@ Network activity disabled Atividade da rede disativada + + None + Nenhum + Total: %1 (Enabled: %2) Total: %1 (Habilitado: %2) @@ -2591,10 +3572,105 @@ Executing command without any wallet Execução de comando sem nenhuma carteira + + Ctrl++ + Main shortcut to increase the RPC console font size. + Ctrl++ + + + Ctrl+= + Secondary shortcut to increase the RPC console font size. + Ctrl+= + + + Ctrl+- + Main shortcut to decrease the RPC console font size. + Ctrl+- + + + Ctrl+_ + Secondary shortcut to decrease the RPC console font size. + Ctrl+_ + + + Ctrl+Shift+I + Ctrl+Shift+I + + + Ctrl+Shift+C + Ctrl+Shift+C + + + Ctrl+Shift+G + Ctrl+Shift+G + + + Ctrl+Shift+P + Ctrl+Shift+P + + + Ctrl+Shift+R + Ctrl+Shift+R + Executing command using "%1" wallet Execução de comando usando a carteira "%1" + + detecting: peer could be v1 or v2 + Explanatory text for "detecting" transport type. + detectando: o par pode ser v1 ou v2 + + + v1: unencrypted, plaintext transport protocol + Explanatory text for v1 transport type. + v1: não criptografado, protocolo de transporte de texto simples + + + v2: BIP324 encrypted transport protocol + Explanatory text for v2 transport type. + v2: protocolo de transporte criptografado BIP324 + + + &Copy address + Context menu action to copy the address of a peer + &Copiar endereço + + + 1 d&ay + 1 &dia + + + &Copy IP/Netmask + 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 + &Copiar IP/Netmask + + + 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 + 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. + Bem-vindo ao painel RPC %1. +Use as setas para cima e para baixo para navegar pelo histórico e %2 para limpar a tela. +Use %3 e %4 para aumentar ou diminuir o tamanho da fonte. +Digite %5 para uma visão geral dos comandos disponíveis. +Para obter mais informações sobre como usar este console, digite %6. + +%7AVISO: Golpistas estão ativos, dizendo aos usuários para digitarem comandos aqui, roubando o conteúdo de suas carteiras. Não use este painel sem entender completamente as ramificações de um comando.%8 + + + Executing… + A console message indicating an entered command is currently being executed. + Executando... + + + (peer: %1) + (par: %1) + via %1 por %1 @@ -2611,11 +3687,19 @@ Verified Masternode Masternode verificado + + Yes + Sim + Unknown Desconhecido - + + Never + Nunca + + ReceiveCoinsDialog @@ -2634,6 +3718,10 @@ An optional message to attach to the payment request, which will be displayed when the request is opened.<br>Note: The message will not be sent with the payment over the Dash network. Uma mensagem opcional para anexar à solicitação de pagamento, que será exibida quando a solicitação for aberta. <br>Observação: a mensagem não será enviada com o pagamento pela rede do Dash. + + 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. + Um rótulo opcional para associar ao novo endereço de recebimento (usado por você para identificar uma fatura). Também é anexado à solicitação de pagamento. + Use this form to request payments. All fields are <b>optional</b>. Use esse formulário para fazer cobranças. Todos os campos são <b>opcionais</b>. @@ -2691,28 +3779,60 @@ Insira uma mensagem para anexar à solicitação de pagamento - Copy URI - Copiar URI + Copy &URI + Copiar &URI - Copy address - Copiar endereço + &Copy address + &Copiar endereço - Copy label - Copiar rótulo + Copy &label + Copiar &Identificador - Copy message - Copiar mensagem + Copy &message + Copiar &mensagem - Copy amount - Copiar quantia + Copy &amount + Copiar &valor + + + Could not unlock wallet. + Não foi possível desbloquear carteira. + + + Could not generate new address + Não foi possível gerar novo endereço - + ReceiveRequestDialog + + Request payment to … + Solicitar pagamento para ... + + + Address: + Endereço: + + + Amount: + Valor: + + + Label: + Identificador: + + + Message: + Mensagem: + + + Wallet: + Carteira: + Copy &URI Copiar &URI @@ -2765,6 +3885,34 @@ Solicitado + + RestoreWalletActivity + + Restore Wallet + Title of progress window which is displayed when wallets are being restored. + Restaurar carteira + + + Restoring Wallet <b>%1</b>… + Descriptive text of the restore wallets progress window which indicates to the user that wallets are currently being restored. + Restaurando carteira <b>%1</b>… + + + Restore wallet failed + Title of message box which is displayed when the wallet could not be restored. + Falha ao restaurar carteira + + + Restore wallet warning + Title of message box which is displayed when the wallet is restored with some warning. + Aviso de restauração de carteira + + + Restore wallet message + Title of message box which is displayed when the wallet is successfully restored. + Mensagem de restauração de carteira + + SendCoinsDialog @@ -2799,10 +3947,6 @@ Fee: Taxa: - - Dust: - Poeira: - Inputs… Entradas… @@ -2827,9 +3971,17 @@ Transaction Fee: Taxa de transação + + 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 dash transactions than the network can process. + Quando o volume de transações é menor do que o espaço nos blocos, mineradores e nós de retransmissão podem impor uma taxa mínima. Pagar apenas essa taxa mínima é perfeitamente aceitável, mas esteja ciente de que isso pode resultar em uma transação que nunca será confirmada, uma vez que houver mais demanda por transações Dash do que a rede pode processar. + + + A too low fee might result in a never confirming transaction (read the tooltip) + Uma taxa muito baixa pode resultar em uma transação que nunca será confirmada (leia a dica de ferramenta) + (Smart fee not initialized yet. This usually takes a few blocks…) - (Smart fee não iniciado. Isso requer alguns blocos…) + (Taxa inteligente ainda não inicializada. Isso normalmente requer alguns blocos…) Confirmation time target: @@ -2919,10 +4071,6 @@ Copy bytes Copiar bytes - - Copy dust - Copiar poeira - Copy change Copiar troco @@ -2939,10 +4087,6 @@ %1 to %2 %1 a %2 - - Are you sure you want to send? - Você tem certeza que deseja enviar? - <b>(%1 of %2 entries displayed)</b> <b>(%1 de %2 entradas exibidas)</b> @@ -2955,6 +4099,18 @@ Confirm the %1 send action Confirmar o envio %1 + + Cr&eate Unsigned + &Criar não assinado + + + from wallet '%1' + da carteira '%1' + + + %1 to '%2' + %1 para '%2' + %1 funds only Apenas saldo %1 @@ -2993,7 +4149,7 @@ Total Amount - Quantidade Total + Valor Total or @@ -3003,6 +4159,51 @@ Confirm send coins Confirme o envio de moedas + + Save Transaction Data + Salvar Dados da Transação + + + PSBT saved + PSBT salvo + + + Watch-only balance: + Saldo somente para visualização: + + + Creates a Partially Signed Blockchain Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet. + Cria uma Transação Parcialmente Assinada em Blockchain (PSBT) para uso com, por exemplo, uma carteira %1 offline ou uma carteira de hardware compatível com PSBT. + + + Do you want to create this transaction? + 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. + Você deseja criar esta transação? + + + Please, review your transaction proposal. This will produce a Partially Signed Blockchain Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet. + 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. + Por favor, revise sua proposta de transação. Isto produzirá uma Transação Parcialmente Assinada em Blockchain (PSBT) que você pode salvar ou copiar e então assinar com, por exemplo, uma carteira %1 offline ou uma carteira de hardware compatível com PSBT. + + + Please, review your transaction. You can create and send this transaction or create a Partially Signed Blockchain Transaction (PSBT), which you can save or copy and then sign with, e.g., an offline %1 wallet, or a PSBT-compatible hardware wallet. + 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. + Por favor, revise sua transação. Você pode criar e enviar esta transação ou criar uma Transação Parcialmente Assinada em Blockchain (PSBT), que você pode salvar ou copiar e então assinar com, por exemplo, uma carteira %1 offline ou uma carteira de hardware compatível com PSBT. + + + Please, review your transaction. + Text to prompt a user to review the details of the transaction they are attempting to send. + Por favor, revise sua transação. + + + To review recipient list click "Show Details…" + Para analisar a lista de destinatários, clique em "Mostrar Detalhes..." + + + Partially Signed Transaction (Binary) + Expanded name of the binary PSBT file format. See: BIP 174. + Transação assinada parcialmente (binário) + The recipient address is not valid. Please recheck. Endereço de envio inváido. Favor checar. @@ -3122,21 +4323,16 @@ A message that was attached to the dash: URI which will be stored with the transaction for your reference. Note: This message will not be sent over the Dash network. A mensagem que foi anexada ao Dash: URI na qual será gravada na transação para sua referência. Nota: Essa mensagem não será gravada publicamente na rede Dash. + + + SendConfirmationDialog - This is an unauthenticated payment request. - Esta é uma cobrança não autenticada. - - - This is an authenticated payment request. - Esta é uma cobrança autenticada. - - - Pay To: - Pague Para: + Send + Enviar - Memo: - Memorizar: + Create Unsigned + Criar não assinada @@ -3276,6 +4472,10 @@ Wallet unlock was cancelled. O desbloqueio da carteira foi cancelado + + No error + Sem erro + Private key for the entered address is not available. A chave privada para o endereço disponibilizado não está disponível. @@ -3301,19 +4501,30 @@ A assinatura não corresponde a mensagem - Message verification failed. - Falha na verificação da mensagem + Message verification failed. + Falha na verificação da mensagem + + + Message verified. + Mensagem verificada + + + + SplashScreen + + (press q to shutdown and continue later) + (pressione q para desligar e continuar depois) - Message verified. - Mensagem verificada + press q to shutdown + pressione q para desligar TrafficGraphWidget - KB/s - KB/s + kB/s + kB/s Total @@ -3330,20 +4541,9 @@ TransactionDesc - - Open for %n more block(s) - Aberto para %n mais blocosAberto para %n mais blocosAberto para %n mais blocos - - - Open until %1 - Aberto até %1 - - - conflicted - Conflitado - 0/unconfirmed, %1 + 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. 0/não confirmado, %1 @@ -3356,22 +4556,32 @@ abandoned + 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. abandonado + + conflicted with a transaction with %1 confirmations + 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. + conflitou com uma transação com %1 confirmações + %1/unconfirmed + 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, and still not locked via ChainLocks. %1/não confirmado %1 confirmations + 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 or locked via ChainLocks. %1 confirmações locked via ChainLocks + 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 and has been locked by ChainLocks. bloqueado via ChainLocks verified via InstantSend + 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 has been locked by InstantSend. verificado via EnvioInstantâneo @@ -3390,6 +4600,10 @@ Generated Gerado + + Platform Transfer + Transferência de Plataforma + From De @@ -3520,14 +4734,6 @@ Address / Label Endereço / Etiqueta - - Open for %n more block(s) - Aberto para %n mais blocosAberto para %n mais blocosAberto para %n mais blocos - - - Open until %1 - Aberto até %1 - Unconfirmed Não confirmado @@ -3588,6 +4794,10 @@ Mined Minerado + + Platform Transfer + Transferência de Plataforma + %1 Mixing %1 o Mixing @@ -3715,6 +4925,10 @@ Mined Minerado + + Platform Transfer + Transferência de Plataforma + Other Outro @@ -3728,49 +4942,63 @@ Quantia mínima - Abandon transaction - Abandonar transação + &Copy address + &Copiar endereço - Copy address - Copiar endereço + Copy &label + Copiar &identificador - Copy label - Copiar rótulo + Copy &amount + Copiar &valor - Copy amount - Copias quantia + Copy transaction &ID + Copiar &ID da transação - Copy transaction ID - Copiar ID da transação + Copy &raw transaction + Copiar transação &original - Copy raw transaction - Copiar o raw da transação + Copy full transaction &details + Copiar &detalhes completos da transação - Copy full transaction details - Copiar dados completos da transação + &Show transaction details + &Mostrar detalhes da transação - Edit address label - Editar etiqueta de endereço + A&bandon transaction + &Abandonar transação - Show transaction details - Mostrar detalhes da transação + Rese&nd transaction + &Reenviar transação - Show address QR code - Mostrar endereço QR code + &Edit address label + &Editar rótulo de endereço + + + Show address &QR code + Mostrar endereço &QR code + + + Show in %1 + 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. + Mostrar em %1 Export Transaction History Exportar histórico de transações + + Comma separated file + Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values. + Arquivo separado por vírgulas + Confirmed Confirmado @@ -3849,10 +5077,54 @@ Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled. Fechar a carteira por muito tempo pode resultar em ter que sincronizar novamente toda a cadeia se o modo pruning estiver habilitado. - + + Close all wallets + Fechar todas as carteiras + + + Are you sure you wish to close all wallets? + Tem certeza de que deseja fechar todas as carteiras? + + WalletFrame - + + No wallet has been loaded. +Go to File > Open Wallet to load a wallet. +- OR - + Nenhuma carteira for carregada. +Acesse: Arquivo > Abrir Carteira para carregar a carteira. +- OU - + + + Create a new wallet + Criar uma nova carteira + + + Error + Erro + + + Unable to decode PSBT from clipboard (invalid base64) + Não foi possível decodificar o PSBT da área de transferência (base64 inválido) + + + Load Transaction Data + Carregar Dados da Transação + + + Partially Signed Transaction (*.psbt) + Transação Parcialmente Assinada (*.psbt) + + + PSBT file must be smaller than 100 MiB + Arquivo PSBT deve ser menor que 100 MiB + + + Unable to decode PSBT + Não foi possível decodificar o PSBT + + WalletModel @@ -3878,6 +5150,11 @@ Selected amount: Quantidade selecionada: + + Wallet Data + Name of the wallet data file format. + Dados da Carteira + Backup Wallet Backup da carteira @@ -3905,14 +5182,6 @@ dash-core - - Error: Listening for incoming connections failed (listen returned error %s) - Erro: Aceitar conexões de entrada falhou (retornou erro %s) - - - Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee. - Falha na estimativa de taxa. A taxa de retorno está desabilitada. Aguarde alguns blocos ou habilite -fallbackfee. - 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 Este erro pode ocorrer se esta carteira não foi encerrada corretamente e foi carregada pela última vez usando uma compilação com uma versão mais recente do Berkeley DB. Em caso afirmativo, por favor, use o software que carregou esta carteira pela última vez @@ -3970,16 +5239,20 @@ Erro ao ler o banco de dados. Finalizando. - Failed to listen on any port. Use -listen=0 if you want this. - Falha ao escutar em qualquer porta. Use -listen=0 se você quiser isso. + Error: Missing checksum + Erro: Checksum ausente - -maxtxfee is set very high! Fees this large could be paid on a single transaction. - -maxtxfee é muito alto! Essa quantia poderia ser paga em uma única transação. + Error: Unable to parse version %u as a uint32_t + Erro: Não foi possível analisar a versão %u como um uint32_t - Cannot provide specific connections and have addrman find outgoing connections at the same. - Não é possível fornecer conexões específicas e fazer com que o addrman encontre conexões de saída ao mesmo tempo. + Error: Unable to write record to new wallet + Erro: Não foi possível gravar o registro na nova carteira + + + Failed to listen on any port. Use -listen=0 if you want this. + Falha ao escutar em qualquer porta. Use -listen=0 se você quiser isso. Found unconfirmed denominated outputs, will wait till they confirm to continue. @@ -3990,13 +5263,17 @@ -socketevents ('%s') inválido. Apenas esses modos são suportados: %s - Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions) - Valor inválido para -maxtxfee=<valor>: '%s' (precisa ser pelo menos a taxa mínima de %s para prevenir que a transação nunca seja confirmada) + SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is supported + SQLiteDatabase: Esquema de carteira sqlite desconhecido versão %d. Apenas a versão %d é suportada Transaction index can't be disabled with governance validation enabled. Either start with -disablegovernance command line switch or enable transaction index. O índice de transação não pode ser desabilitado com a validação de governança habilitada. Comece com o comando -disablegovernance ou ative o índice de transação. + + Unsupported category-specific logging level -loglevel=%s. Expected -loglevel=<category>:<loglevel>. Valid categories: %s. Valid loglevels: %s. + Nível de registro específico da categoria não suportado -loglevel=%s. Esperado -loglevel=<category>:<loglevel>. Categorias válidas: %s. Níveis de registro válidos: %s. + Can't mix: no compatible inputs found! Não é possível misturar: não foram encontradas entradas compatíveis! @@ -4005,6 +5282,14 @@ Entry exceeds maximum size. Entrada excede o tamanho máximo. + + Error upgrading evo database for EHF + Erro ao atualizar o banco de dados evo para EHF + + + Failed to commit Evo database + Falhou ao confirmar o banco de dados Evo + Found enough users, signing ( waiting %s ) Encontrou usuários suficientes, assinando ( esperando %s ) @@ -4029,18 +5314,14 @@ Insufficient funds. Saldo insuficiente. - - Invalid amount for -discardfee=<amount>: '%s' - Quantidade inválida para -discardfee=<amount>: '%s' - - - Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s) - Valor inválido para -paytxfee=<amount>: '%s' (precisa ser no mínimo %s) - Invalid minimum number of spork signers specified with -minsporkkeys Número mínimo inválido de assinantes do spork especificados com -minsporkkeys + + Listening for incoming connections failed (listen returned error %s) + Falha ao aguardar conexões de entrada (escuta retornou erro %s) + Lock is already in place. Bloqueio já está no lugar. @@ -4097,6 +5378,10 @@ Synchronizing governance objects… Sincronizando objetos de governança …. + + Transaction change output index out of range + Índice de saída de alteração de transação fora do alcance + Unable to start HTTP server. See debug log for details. Não foi possível iniciar o servidor HTTP. Veja o log de debug para detalhes. @@ -4105,6 +5390,10 @@ Unknown response. Resposta desconhecida. + + Unsupported global logging level -loglevel=%s. Valid values: %s. + Nível de registro global não suportado -loglevel=%s. Valores válidos: %s. + User Agent comment (%s) contains unsafe characters. Comentário User Agent (%s) contém caracteres inseguros. @@ -4145,6 +5434,10 @@ Make sure to encrypt your wallet and delete all non-encrypted backups after you have verified that the wallet works! Certifique-se de criptografar sua carteira e excluir todos os backups não criptografados depois de verificar se a carteira funciona! + + More than one onion bind address is provided. Using %s for the automatically created Tor onion service. + Mais de um endereço de vínculo onion foi fornecido. Usando %s para o serviço Tor onion criado automaticamente. + Prune configured below the minimum of %d MiB. Please use a higher number. Prune configurado abaixo do mínimo de %d MiB. Por favor use um número mais alto. @@ -4173,10 +5466,6 @@ Wallet is locked, can't replenish keypool! Automatic backups and mixing are disabled, please unlock your wallet to replenish keypool. Carteira travada, impossível reabastecer o keypool. Backups e misturas automáticas estão desabilitadas, por favor, destrave sua carteira para reabastecer o keypool. - - You need to rebuild the database using -reindex to change -timestampindex - Você precisa reconstruir o banco de dados usando -reindex para alterar -timestampindex - You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain Você precisa reconstruir o banco de dados usando -reindex para sair do modo prune. Isso irá rebaixar todo o blockchain. @@ -4218,20 +5507,32 @@ Erro ao carregar %s: As chaves privadas só podem ser desativadas durante a criação - Error upgrading evo database - Erro de upgrade na base de dados evo + Error: Couldn't create cursor into database + Erro: Não foi possível criar um cursor no banco de dados Error: Disk space is low for %s Erro: Espaço em disco está pequeno para %s - Exceeded max tries. - Tentativas máximas excedidas. + Error: Dumpfile checksum does not match. Computed %s, expected %s + Erro: A soma de verificação do arquivo de dump não corresponde. Calculado %s, esperado %s. + + + Error: Got key that was not hex: %s + Erro: Chave recebida não estava em hexadecimal: %s + + + Error: Got value that was not hex: %s + Erro: Valor recebido não estava em hexadecimal: %s + + + Error: Keypool ran out, please call keypoolrefill first + Erro: O pool de chaves acabou, por favor, chame keypoolrefill primeiro - Failed to commit EvoDB - Falha ao enviar dados para EvoDB + Error: No addresses available. + Erro: Nenhum endereço disponível. Failed to create backup %s! @@ -4249,17 +5550,29 @@ Failed to rescan the wallet during initialization Falha ao verificar novamente a carteira durante a inicialização + + Failed to verify database + Falha ao verificar base de dados + + + Fee rate (%s) is lower than the minimum fee rate setting (%s) + A taxa de comissão (%s) é inferior à configuração de taxa de comissão mínima (%s) + Found enough users, signing… Encontrou usuários suficientes, assinando… - Invalid P2P permission: '%s' - Permissão P2P inválida: '%s' + Ignoring duplicate -wallet %s. + Ignorando -carteira duplicada %s. + + + Input not found or already spent + Entrada não encontrada ou já gasta - Invalid amount for -fallbackfee=<amount>: '%s' - Valor inválido para -fallbackfee=<amount>: '%s' + Invalid P2P permission: '%s' + Permissão P2P inválida: '%s' Invalid masternodeblsprivkey. Please see documentation. @@ -4281,6 +5594,10 @@ Mixing in progress… Mixing em progresso… + + No addresses available + Nenhum endereço disponível + No errors detected. Nenhum erro detectado. @@ -4309,6 +5626,22 @@ Prune mode is incompatible with -txindex. O modo prune é incompatível com -txindex. + + SQLiteDatabase: Failed to execute statement to verify database: %s + SQLiteDatabase: Falhou ao executar a declaração para verificar o banco de dados: %s + + + SQLiteDatabase: Failed to prepare statement to verify database: %s + SQLiteDatabase: Falhou ao preparar a declaração para verificar o banco de dados: %s + + + SQLiteDatabase: Failed to read database verification error: %s + SQLiteDatabase: Falhou ao ler o erro de verificação do banco de dados: %s + + + SQLiteDatabase: Unexpected application id. Expected %u, got %u + SQLiteDatabase: ID de aplicativo inesperado. Esperado %u, obtido %u + Section [%s] is not recognized. A seção [%s] não é reconhecida. @@ -4341,6 +5674,10 @@ This is the transaction fee you will pay if you send a transaction. Esta é a taxa que você irá pagar se enviar uma transação. + + Topping up keypool… + Completando o pool de chaves... + Transaction amounts must not be negative As quantidades nas transações não podem ser negativas. @@ -4369,13 +5706,17 @@ Unable to generate initial keys Incapaz de gerar chaves iniciais + + Unable to open %s for writing + Não foi possível abrir %s para escrita + Unknown -blockfilterindex value %s. Valor desconhecido -blockfilterindex %s. - Upgrading UTXO database - Atualizando banco de dados UTXO + Unknown new rules activated (versionbit %i) + Novas regras desconhecidas ativadas (versionbit %i) Verifying blocks… @@ -4394,16 +5735,12 @@ Não foi possível criar a pasta para backup da carteira %s! - You can not start a masternode with wallet enabled. - Você não pode iniciar um masternode com a carteira habilitada. - - - You need to rebuild the database using -reindex to change -addressindex - Você precisa reconstruir o banco de dados usando -reindex para alterar -addressindex + Wiping wallet transactions… + Limpando as transações da carteira... - You need to rebuild the database using -reindex to change -spentindex - Você precisa reconstruir o banco de dados usando -reindex para alterar -spentindex + You can not start a masternode with wallet enabled. + Você não pode iniciar um masternode com a carteira habilitada. no mixing available. @@ -4421,6 +5758,22 @@ %s uses exact denominated amounts to send funds, you might simply need to mix some more coins. %s usa denominações exatas para enviar fundos; talvez seja necessário misturar mais algumas moedas. + + -reindex-chainstate option is not compatible with -blockfilterindex. Please temporarily disable blockfilterindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes. + A opção -reindex-chainstate não é compatível com -blockfilterindex. Por favor, desabilite temporariamente blockfilterindex enquanto usar -reindex-chainstate, ou substitua -reindex-chainstate por -reindex para reconstruir totalmente todos os índices. + + + -reindex-chainstate option is not compatible with -coinstatsindex. Please temporarily disable coinstatsindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes. + A opção -reindex-chainstate não é compatível com -coinstatsindex. Por favor, desabilite temporariamente coinstatsindex enquanto usar -reindex-chainstate, ou substitua -reindex-chainstate por -reindex para reconstruir totalmente todos os índices.  + + + -reindex-chainstate option is not compatible with -txindex. Please temporarily disable txindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes. + A opção -reindex-chainstate não é compatível com -txindex. Por favor, desabilite temporariamente txindex enquanto usar -reindex-chainstate, ou substitua -reindex-chainstate por -reindex para reconstruir totalmente todos os índices. + + + Cannot downgrade wallet from version %i to version %i. Wallet version unchanged. + Não é possível fazer downgrade da carteira da versão %i para a versão %i. Versão da carteira não alterada. + Cannot obtain a lock on data directory %s. %s is probably already running. Não foi possível obter exclusividade de escrita no endereço %s. O %s provavelmente já está sendo executado. @@ -4433,14 +5786,82 @@ Error loading %s: You can't enable HD on an already existing non-HD wallet Erro ao carregar %s: você não pode ativar o HD em uma carteira não HD já existente + + 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 + Erro ao carregar a carteira. A carteira requer que os blocos sejam baixados, e o software não oferece suporte ao carregamento de carteiras enquanto os blocos estão sendo baixados fora de ordem ao usar snapshots assumeutxo. A carteira deverá carregar com sucesso após a sincronização do nó atingir a altura %s. + Error reading %s! All keys read correctly, but transaction data or address book entries might be missing or incorrect. Erro ao ler arquivo %s! Todas as chaves privadas foram lidas corretamente, mas os dados de transação ou o livro de endereços podem estar faltando ou incorretos. + + Error: Dumpfile format record is incorrect. Got "%s", expected "format". + Erro: Registro de formato do arquivo de dump está incorreto. Recebido "%s", esperado "format". + + + Error: Dumpfile identifier record is incorrect. Got "%s", expected "%s". + Erro: Registro de identificador do arquivo de dump está incorreto. Recebido "%s", esperado "%s". + + + Error: Dumpfile version is not supported. This version of bitcoin-wallet only supports version 1 dumpfiles. Got dumpfile with version %s + Erro: Versão do arquivo de dump não suportada. Esta versão do bitcoin-wallet suporta apenas arquivos de dump versão 1. Arquivo de dump recebido com versão %s. + + + Failed to rename invalid peers.dat file. Please move or delete it and try again. + Falhou ao renomear o arquivo peers.dat. Por favor, mova ou exclua-o e tente novamente. + + + Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable %s. + Estimativa de taxa falhou. Fallbackfee está desabilitada. Aguarde alguns blocos ou habilite %s. + + + File %s already exists. If you are sure this is what you want, move it out of the way first. + O arquivo %s já existe. Se você tem certeza de que é isso que deseja, remova-o primeiro. + + + Incompatible options: -dnsseed=1 was explicitly specified, but -onlynet forbids connections to IPv4/IPv6 + Opções incompatíveis: -dnsseed=1 foi explicitamente especificado, mas -onlynet proíbe conexões com IPv4/IPv6. + Incorrect or no devnet genesis block found. Wrong datadir for devnet specified? Bloco gênese incorreto ou não encontrado. Datadir errado para a devnet rede? + + Invalid amount for %s=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions) + Valor inválido para %s=<amount>: '%s' (deve ser pelo menos a taxa minrelay de %s para prevenir transações travadas) + + + 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. + Peers.dat (%s) inválido ou corrompido. Se você acredita que isso é um bug, por favor, reporte-o para %s. Como solução alternativa, você pode remover o arquivo (%s) (renomear, mover ou excluir) para que um novo seja criado na próxima inicialização. + + + No dump file provided. To use createfromdump, -dumpfile=<filename> must be provided. + Nenhum arquivo de dump fornecido. Para usar createfromdump, -dumpfile=<filename> deve ser fornecido. + + + No dump file provided. To use dump, -dumpfile=<filename> must be provided. + Nenhum arquivo de dump fornecido. Para usar dump, -dumpfile=<filename> deve ser fornecido. + + + No wallet file format provided. To use createfromdump, -format=<format> must be provided. + Nenhum formato de arquivo de carteira fornecido. Para usar createfromdump, -format=<format> deve ser fornecido. + + + Outbound connections restricted to CJDNS (-onlynet=cjdns) but -cjdnsreachable is not provided + Conexões de saída restritas a CJDNS (-onlynet=cjdns), mas -cjdnsreachable não foi fornecido + + + Outbound connections restricted to Tor (-onlynet=onion) but the proxy for reaching the Tor network is explicitly forbidden: -onion=0 + Conexões de saída restritas ao Tor (-onlynet=onion), mas o proxy para alcançar a rede Tor está explicitamente proibido: -onion=0 + + + 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 + Conexões de saída restritas ao Tor (-onlynet=onion), mas o proxy para acessar a rede Tor não foi fornecido: nenhum de -proxy, -onion ou -listenonion foi dado. + + + Outbound connections restricted to i2p (-onlynet=i2p) but -i2psam is not provided + Conexões de saída restritas a i2p (-onlynet=i2p), mas -i2psam não foi fornecido + Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly. 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. @@ -4449,6 +5870,14 @@ Please contribute if you find %s useful. Visit %s for further information about the software. Por favor contribua se você entender que %s é útil. Visite %s para mais informações sobre o software. + + Prune mode is incompatible with -reindex-chainstate. Use full -reindex instead. + O modo prune é incompatível com -reindex-chainstate. Use -reindex completo em vez disso. + + + This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection. + Essa é a taxa máxima de transação que você paga (além da taxa normal) para priorizar a prevenção de gastos parciais em relação à seleção regular de moedas. + This is the transaction fee you may discard if change is smaller than dust at this level Essa é a taxa de transação que você pode descartar se a alteração for menor que o mínimo neste nível @@ -4457,14 +5886,38 @@ This is the transaction fee you may pay when fee estimates are not available. Esta é a taxa que você deve pagar quando a taxa estimada não está disponível. + + Transaction requires one destination of non-0 value, a non-0 feerate, or a pre-selected input + A transação requer um destino de valor diferente de zero, uma taxa diferente de zero ou uma entrada pré-selecionada + Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate. Não foi possível reproduzir os blocos. Você precisará reconstruir o banco de dados usando -reindex-chainstate. + + Unknown wallet file format "%s" provided. Please provide one of "bdb" or "sqlite". + Formato de arquivo de carteira desconhecido "%s" fornecido. Forneça um dos formatos "bdb" ou "sqlite". + + + Unsupported chainstate database format found. Please restart with -reindex-chainstate. This will rebuild the chainstate database. + Formato de banco de dados chainstate não suportado encontrado. Por favor, reinicie com -reindex-chainstate. Isto reconstruirá o banco de dados chainstate. + + + Warning: Dumpfile wallet format "%s" does not match command line specified format "%s". + Aviso: O formato de arquivo de dump da carteira "%s" não corresponde ao formato especificado na linha de comando "%s". + Warning: Private keys detected in wallet {%s} with disabled private keys Aviso: Chaves privadas detectadas na carteira {%s} com chaves privadas desativadas + + You need to rebuild the database using -reindex to enable -timestampindex + Você precisa reconstruir o banco de dados usando -reindex para habilitar -timestampindex + + + %s -- Incorrect seed, it should be a hex string + %s -- Semente incorreta, deve ser uma string hexadecimal + %s is not a valid backup folder! %s não é uma pasta de backup válida! @@ -4489,10 +5942,30 @@ -rpcport must be specified when -devnet and -server are specified -rpcport deve ser especificado quando -devnet e -server são especificados + + -statsbatchsize cannot be configured with a negative value. + -statsbatchsize não pode ser configurado com um valor negativo. + + + -statsduration cannot be configured with a negative value. + -statsduration não pode ser configurado com um valor negativo. + A fatal internal error occurred, see debug.log for details Ocorreu um erro interno fatal, veja o debug.log para mais detalhes + + Cannot create socket (socket() returned error %s) + Não é possível criar socket (socket() retornou erro %s) + + + Cannot get socket address for %s + Não é possível obter endereço de socket para %s + + + Cannot init Statsd client + Não é possível inicializar cliente Statsd + Cannot resolve -%s address: '%s' Não foi possível encontrar o endereço de -%s: '%s' @@ -4501,10 +5974,6 @@ Cannot write to data directory '%s'; check permissions. Não é possível escrever no diretório de dados '%s'; verifique as permissões. - - Change index out of range - Índice de mudança fora do intervalo - Copyright (C) Copyright @@ -4513,6 +5982,14 @@ Disk space is too low! O espaço em disco está muito pequeno! + + Dump file %s does not exist. + O arquivo de dump %s não existe. + + + Error creating %s + Erro ao criar %s + Error loading %s Erro ao carregar %s @@ -4530,8 +6007,8 @@ Erro ao carregar %s: você não pode desativar o HD em uma carteira HD já existente - Error upgrading chainstate database - Erro ao atualizar banco de dados do chainstate + Error reading next record from wallet database + Erro ao ler o próximo registro do banco de dados da carteira Loading P2P addresses… @@ -4601,6 +6078,14 @@ Inputs vs outputs size mismatch. Incompatibilidade de tamanho de entradas x saídas. + + Invalid '%s'. Allowed values: 128, 160, 192, 224, 256. + '%s' inválido. Os valores permitidos são: 128, 160, 192, 224, 256. + + + Invalid -i2psam address or hostname: '%s' + Endereço ou nome de host -i2psam inválido: '%s' + Invalid -onion address or hostname: '%s' Endereço -onion ou hostname inválido: '%s' @@ -4645,14 +6130,78 @@ %s corrupt. Try using the wallet tool dash-wallet to salvage or restoring a backup. %s corrompido. Tente usar a ferramenta da carteira dash-wallet para salvar ou restaurar um backup. + + %s is set very high! Fees this large could be paid on a single transaction. + %s está configurado muito alto! Taxas tão grandes podem ser pagas em uma única transação. + + + %s request to listen on port %u. This port is considered "bad" and thus it is unlikely that any Dash Core peers connect to it. See doc/p2p-bad-ports.md for details and a full list. + Solicitação %s para escutar na porta %u. Esta porta é considerada "ruim" e, portanto, é improvável que quaisquer pares do Dash Core se conectem a ela. Consulte doc/p2p-bad-ports.md para obter detalhes e uma lista completa. + + + Cannot provide specific connections and have addrman find outgoing connections at the same time. + Não é possível fornecer conexões específicas e fazer com que o addrman encontre conexões de saída ao mesmo tempo. + + + Failed to upgrade Evo database + Falha ao atualizar banco de dados Evo + + + Fee needed > fee paid + Taxa necessária > taxa paga + + + Host %s on unsupported network + Host %s em rede não suportada + + + Invalid amount for %s=<amount>: '%s' (must be at least %s) + Valor inválido para %s=<amount>: '%s' (deve ser pelo menos %s) + + + Invalid amount for %s=<amount>: '%s' + Valor inválido para %s=<amount>: '%s' + + + Invalid port specified in %s: '%s' + Porta inválida especificada em %s: '%s' + Last successful action was too recent. A última acção é muito recente. + + Missing solving data for estimating transaction size + Faltando dados de resolução para estimar o tamanho da transação + + + No host specified + Nenhum host especificado + + + No host specified, malformed URL + Nenhum host especificado, URL mal formada + + + No text before the scheme delimiter, malformed URL + Nenhum texto antes do delimitador de esquema, URL mal formada + + + Port must be between %d and %d, supplied %d + A porta deve estar entre %d e %d, fornecido %d + + + Socket not initialized, cannot send message + Socket não inicializado, não é possível enviar mensagem + The source code is available from %s. O código fonte está disponível pelo %s. + + The specified config file %s does not exist + O arquivo config especificado %s não existe + The transaction amount is too small to pay the fee O valor da transação é muito pequeno para pagar a taxa @@ -4673,6 +6222,10 @@ Transaction fees are too high. Taxa de transação muito alta. + + Transaction needs a change address, but we can't generate it. + A transação precisa de um endereço de troco, mas não podemos gerá-lo. + Transaction not valid. Transação inválida. @@ -4693,6 +6246,18 @@ Unable to locate enough non-denominated funds for this transaction. Não foi possível localizar fundos não denominados suficientes para esta transacção. + + Unable to lookup host %s + Não é possível pesquisar o host %s + + + Unable to parse -maxuploadtarget: '%s' + Não é possível analisar -maxuploadtarget: '%s' + + + Unable to send message to %s (::sendto() returned error %s) + Não é possível enviar mensagem para %s (::sendto() retornou erro %s) + Unable to sign spork message, wrong key? Impossível assinar mensagem spork, chave incorreta? @@ -4706,12 +6271,12 @@ Estado desconhecido: id = %u - Unsupported logging category %s=%s. - Categoria de log não suportada %s=%s. + Unsupported URL scheme, must begin with udp:// + Esquema de URL não suportado, deve começar com udp:// - Upgrading txindex database - Atualizando o banco de dados txindex + Unsupported logging category %s=%s. + Categoria de log não suportada %s=%s. Very low number of keys left: %d @@ -4741,9 +6306,25 @@ You can not disable governance validation on a masternode. Você não pode desabilitar a validação de governança em um masternode. + + You need to rebuild the database using -reindex to enable -addressindex + Você precisa reconstruir o banco de dados usando -reindex para habilitar -addressindex + + + You need to rebuild the database using -reindex to enable -spentindex + Você precisa reconstruir o banco de dados usando -reindex para habilitar -spentindex + Your entries added successfully. Suas entradas foram adicionadas com êxito. + + Settings file could not be read + Arquivo de configurações não pôde ser lido + + + Settings file could not be written + Arquivo de configurações não pôde ser gravado + \ No newline at end of file diff --git a/src/qt/locale/dash_ro.ts b/src/qt/locale/dash_ro.ts index a0ebf6d29d4b..817f4d55e6f5 100644 --- a/src/qt/locale/dash_ro.ts +++ b/src/qt/locale/dash_ro.ts @@ -1,6 +1,10 @@ AddressBookPage + + Enter address or label to search + Introduceți adresa sau eticheta pentru căutare + Right-click to edit address or label Click-dreapta pentru a edita adresa sau eticheta @@ -61,18 +65,14 @@ C&hoose A&lege - - Sending addresses - Adresa de trimitere - - - Receiving addresses - Adresa de primire - These are your Dash addresses for sending payments. Always check the amount and the receiving address before sending coins. Acestea sunt adresele tale Dash pentru efectuarea platilor. Intotdeauna verifica atent suma de plata si adresa beneficiarului inainte de a trimite monede. + + These are your Dash addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses. + Acestea sunt adresele dumneavoastră Dash pentru primirea plăților. Folosiți butonul 'Creează o nouă adresă de primire' în tab-ul de primire pentru a crea adrese noi. + &Copy Address &Copiază adresa @@ -86,8 +86,8 @@ &Editare - &Show address QR code - &Afișează codul QR al adresei + Show address &QR code + Arată codul &QR al adresei QR code @@ -97,11 +97,24 @@ Export Address List Exportă listă de adrese + + Comma separated file + Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values. + Fișier cu valori separate prin virgulă + There was an error trying to save the address list to %1. Please try again. An error message. %1 is a stand-in argument for the name of the file we attempted to save to. A apărut o eroare la salvarea listei de adrese la %1. Vă rugăm să încercaţi din nou. + + Sending addresses - %1 + Adrese de trimitere - %1 + + + Receiving addresses - %1 + Adrese de primire - %1 + Exporting Failed Export nereusit @@ -124,7 +137,43 @@ AppearanceWidget - + + Lighter + Mai deschis + + + Bolder + Mai îngroșat + + + Font Weight Normal: + Grosime font normal: + + + Smaller + Mai mic + + + Bigger + Mai mare + + + Font Scale: + Scală font: + + + Font Family: + Familie font: + + + Theme: + Temă: + + + Font Weight Bold: + Grosime font îngroșat: + + AskPassphraseDialog @@ -143,6 +192,10 @@ Repeat new passphrase Repetaţi noua frază de acces + + Show passphrase + Arată parola + Encrypt wallet Criptare portofel @@ -179,6 +232,30 @@ Wallet encrypted Portofel criptat + + 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>. + Introduceți noua parolă pentru portofel.<br/>Vă rugăm să folosiți o parolă de <b>zece sau mai multe caractere aleatorii</b>, sau <b>opt sau mai multe cuvinte</b>. + + + Enter the old passphrase and new passphrase for the wallet. + Introduceți vechea frază de acces și noua frază de acces pentru portofel. + + + Remember that encrypting your wallet cannot fully protect your funds from being stolen by malware infecting your computer. + Rețineți că criptarea portofelului nu poate proteja complet fondurile dumneavoastră de a fi furate de malware care infectează calculatorul. + + + Wallet to be encrypted + Portofel de criptat + + + Your wallet is about to be encrypted. + Portofelul tău este pe cale să fie criptat. + + + Your wallet is now encrypted. + Portofelul tău este acum criptat. + IMPORTANT: Any previous backups you have made of your wallet file should be replaced with the newly generated, encrypted wallet file. Previous backups of the unencrypted wallet file contain the same HD seed and still have full access to all your funds just like the new, encrypted wallet. IMPORTANT: Toate backup-urile anterioare pe care le-ai realizat pentru fișierul portofelului tău ar trebui înlocuite cu fișierul portofelului criptat nou generat. Backup-urile anterioare ale fișierului portofelului necriptat conțin aceleași semințe HD și încă mai au acces deplin la toate fondurile tale la fel ca noul portofel criptat. @@ -207,10 +284,22 @@ The passphrase entered for the wallet decryption was incorrect. Fraza de acces introdusă pentru decriptarea portofelului a fost incorectă. + + 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 23.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. + Fraza de acces introdusă pentru decriptarea portofelului este incorectă. Aceasta conține un caracter nul (adică - un octet zero). Dacă fraza de acces a fost setată cu o versiune a acestui software anterioară 23.0, vă rugăm să încercați din nou doar cu caracterele până la - dar fără a include - primul caracter nul. Dacă aceasta are succes, vă rugăm să setați o nouă frază de acces pentru a evita această problemă în viitor. + Wallet passphrase was successfully changed. Parola portofelului a fost schimbata. + + Passphrase change failed + Schimbarea parolei a eșuat + + + 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 23.0, please try again with only the characters up to — but not including — the first null character. + Vechea frază de acces introdusă pentru decriptarea portofelului este incorectă. Aceasta conține un caracter nul (adică - un octet zero). Dacă fraza de acces a fost setată cu o versiune a acestui software anterioară 23.0, vă rugăm să încercați din nou doar cu caracterele până la - dar fără a include - primul caracter nul. + Warning: The Caps Lock key is on! Atentie! Caps Lock este pornit @@ -229,10 +318,30 @@ BitcoinAmountField - + + Amount in %1 + Sumă în %1 + + BitcoinApplication - + + Runaway exception + Excepție scăpată de sub control + + + A fatal error occurred. %1 can no longer continue safely and will quit. + A apărut o eroare fatală. %1 nu mai poate continua în siguranță și se va închide. + + + Internal error + Eroare internă + + + An internal error occurred. %1 will attempt to continue safely. This is an unexpected bug which can be reported as described below. + A apărut o eroare internă. %1 va încerca să continue în siguranță. Acesta este un bug neașteptat care poate fi raportat așa cum este descris mai jos. + + BitcoinGUI @@ -259,6 +368,10 @@ Request payments (generates QR codes and dash: URIs) Cereţi plăţi (generează coduri QR şi Dash-uri: URls) + + Ctrl+Q + Ctrl+Q + &Options… &Opţiuni… @@ -287,10 +400,50 @@ &Verify message… &Verifică mesaj… + + &Load PSBT from file… + &Încarcă PSBT din fișier… + + + &Sending addresses + Adrese de &trimitere + + + &Receiving addresses + Adrese de &primire + Open &URI… Deschide &URI… + + Open Wallet + Deschide portofel + + + Open a wallet + Deschide un portofel + + + Close wallet + Închide portofel + + + No wallets available + Niciun portofel disponibil + + + &Window + &Fereastră + + + Zoom + Zoom + + + Main Window + Fereastra principală + &Transactions &Tranzacţii @@ -328,16 +481,12 @@ &Despre %1 - Modify configuration options for %1 - Modifică opţiunile de configurare pentru %1 - - - &Show / Hide - Arata/Ascunde + Send %1 funds to a Dash address + Trimite fonduri %1 către o adresă Dash - Show or hide the main Window - Arată sau ascunde fereastra principală + Modify configuration options for %1 + Modifică opţiunile de configurare pentru %1 Encrypt the private keys that belong to your wallet @@ -397,23 +546,19 @@ Wallet &Repair - Portofel & Reparare + Portofel &Reparare Show wallet repair options Afișează opțiunile de reparare a portofelului - - Open Wallet &Configuration File - Deschide Fișierul Portofel & Configurare - Open configuration file Deschide fisierul de configurare. Show Automatic &Backups - Afișează Automat & Backup-uri + Afișează Automat &Backup-uri Show automatically created wallet backups @@ -435,18 +580,110 @@ Show the %1 help message to get a list with possible Dash command-line options Arată mesajul de ajutor %1 pentru a obţine o listă cu opţiunile posibile de linii de comandă Dash + + default wallet + portofel implicit + %1 client Client %1 + + Wallet: %1 + + Portofel: %1 + + + + Wallet is <b>unencrypted</b> + Portofelul este <b>necriptat</b> + &File &Fişier + + Show information about %1 + Arată informații despre %1 + + + Load PSBT from &clipboard… + Încarcă PSBT din &clipboard… + + + Open debugging and diagnostic console + Deschide consola de debugging și diagnostic + + + Open &wallet configuration file + Deschide fișierul de configurare al &portofelului + + + Open a dash: URI + Deschide un URI dash: + + + Create a new wallet + Creează un portofel nou + + + Restore Wallet… + Name of the menu item that restores wallet from a backup file. + Restaurează portofel… + + + Restore a wallet from a backup file + Status tip for Restore Wallet menu item + Restaurează un portofel dintr-un fișier de backup + + + Close all wallets + Închide toate portofelele + + + %1 &information + %1 &informații + + + Show the %1 basic information + Arată informațiile de bază despre %1 + + + &Discreet mode + Mod &discret + + + Mask the values in the Overview tab + Ascunde valorile în tab-ul Prezentare generală + + + Wallet Data + Name of the wallet data file format. + Date portofel + + + Load Wallet Backup + The title for Restore Wallet File Windows + Încarcă backup portofel + + + Restore Wallet + Title of pop-up window shown when the user is attempting to restore a wallet. + Restaurează portofel + + + Wallet Name + Label of the input field where the name of the wallet is entered. + Nume portofel + &Settings &Setări + + &Minimize + &Minimizează + &Help A&jutor @@ -455,8 +692,25 @@ Tabs toolbar Bara de file + + &Governance + &Guvernare + + + View Governance Proposals + Vizualizează propunerile de guvernare + + + &Hide + &Ascunde + + + S&how + A&rată + %n active connection(s) to Dash network + A substring of the tooltip. %n conexiune activă la rețeaua Dash%n conexiuni active la rețeaua Dash%n conexiuni active la rețeaua Dash @@ -471,6 +725,54 @@ %1 behind %1 în urmă + + Close Wallet… + Închide portofel… + + + Load Partially Signed Blockchain Transaction + Încarcă tranzacție blockchain parțial semnată + + + Load Partially Signed Blockchain Transaction from clipboard + Încarcă tranzacție blockchain parțial semnată din clipboard + + + Create Wallet… + Creează portofel… + + + Close All Wallets… + Închide toate portofelele… + + + Ctrl+Shift+D + Ctrl+Shift+D + + + Ctrl+M + Ctrl+M + + + Click for more actions. + A substring of the tooltip. "More actions" are available via the context menu. + Click pentru mai multe acțiuni. + + + Show Peers tab + A context menu item. The "Peers tab" is an element of the "Node window". + Arată tab-ul Peers + + + Disable network activity + A context menu item. + Dezactivează activitatea rețelei + + + Enable network activity + A context menu item. The network activity was disabled previously. + Activează activitatea rețelei + Syncing Headers (%1%)… Se sincronizeaza Header-ele (%1%)… @@ -487,10 +789,6 @@ Processing blocks on disk… Se proceseaza blocurile pe disc… - - Reindexing blocks on disk… - Se reindexează blocurile pe disc… - Connecting to peers… Se conecteaza cu alte noduri… @@ -519,10 +817,18 @@ Error Eroare + + Error: %1 + Eroare: %1 + Warning Avertisment + + Warning: %1 + Avertisment: %1 + Information Informaţie @@ -605,7 +911,15 @@ Wallet is <b>encrypted</b> and currently <b>locked</b> Portofelul este <b>criptat</b> iar în momentul de faţă este <b>blocat</b> - + + Proxy is <b>enabled</b>: %1 + Proxy este <b>activat</b>: %1 + + + Original message: + Mesaj original: + + CoinControlDialog @@ -628,10 +942,6 @@ Coin Selection Selectarea monedei - - Dust: - Praf: - After Fee: După taxe: @@ -672,6 +982,10 @@ Received with address Primite cu adresa + + Mixing Rounds + Runde de amestecare + Date Data @@ -685,28 +999,32 @@ Confirmat - Copy address - Copiază adresa + Copy amount + Copiază suma - Copy label - Copiază eticheta + &Copy address + &Copiază adresa - Copy amount - Copiază suma + Copy &label + Copiază &eticheta + + + Copy &amount + Copiază &suma - Copy transaction ID - Copiază ID tranzacţie + Copy transaction &ID and output index + Copiază &ID-ul tranzacției și indexul ieșirii - Lock unspent - Blocare necheltuiţi + L&ock unspent + B&lochează necheltuite - Unlock unspent - Deblocare necheltuiţi + &Unlock unspent + &Deblochează necheltuite Copy quantity @@ -724,10 +1042,6 @@ Copy bytes Copiază bytes - - Copy dust - Copiază praf - Copy change Copiază rest @@ -741,20 +1055,28 @@ (%1 blocat) - yes - Da + Can vary +/- %1 duff(s) per input. + Poate varia +/- %1 duff(i) per intrare. - no - Nu + Some coins were unselected because they were spent. + Unele monede au fost deselectate deoarece au fost cheltuite. - This label turns red if any recipient receives an amount smaller than the current dust threshold. - Această etichetă devine roşie, dacă orice beneficiar primeşte o sumă mai mică decât pragul curent pentru praf. + Show all coins + Arată toate monedele - Can vary +/- %1 duff(s) per input. - Poate varia +/- %1 duff(i) per intrare. + Hide %1 coins + Ascunde monedele %1 + + + Show all %1 coins + Arată toate monedele %1 + + + Show spendable coins only + Arată doar monedele cheltuibile (no label) @@ -775,10 +1097,84 @@ CreateWalletActivity - + + Create Wallet + Title of window indicating the progress of creation of a new wallet. + Creează portofel + + + Creating Wallet <b>%1</b>… + Descriptive text of the create wallet progress window which indicates to the user which wallet is currently being created. + Creare portofel <b>%1</b>… + + + Create wallet failed + Crearea portofelului a eșuat + + + Create wallet warning + Avertisment creare portofel + + CreateWalletDialog - + + Create Wallet + Creează portofel + + + Wallet Name + Nume portofel + + + Wallet + Portofel + + + Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice. + Criptează portofelul. Portofelul va fi criptat cu o parolă la alegerea ta. + + + Encrypt Wallet + Criptează portofel + + + Advanced Options + Opțiuni avansate + + + 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. + Dezactivează cheile private pentru acest portofel. Portofelele cu chei private dezactivate nu vor avea chei private și nu pot avea o sămânță HD sau chei private importate. Acest lucru este ideal pentru portofelele doar-vizualizare. + + + Disable Private Keys + Dezactivează cheile private + + + 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. + Creează un portofel gol. Portofelele goale nu au inițial chei private sau scripturi. Cheile private și adresele pot fi importate, sau o sămânță HD poate fi setată, ulterior. + + + Make Blank Wallet + Creează portofel gol + + + Use descriptors for scriptPubKey management. This feature is well-tested but still considered experimental and not recommended for use yet. + Folosește descriptori pentru gestionarea scriptPubKey. Această funcție este bine testată, dar este încă considerată experimentală și nu este recomandată pentru utilizare încă. + + + Descriptor Wallet (EXPERIMENTAL) + Portofel cu descriptori (EXPERIMENTAL) + + + Create + Creează + + + Compiled without sqlite support (required for descriptor wallets) + Compilat fără suport sqlite (necesar pentru portofelele cu descriptori) + + EditAddressDialog @@ -817,6 +1213,14 @@ The entered address "%1" is not a valid Dash address. Adresa introdusă "%1" nu este o adresă Dash validă + + Address "%1" already exists as a receiving address with label "%2" and so cannot be added as a sending address. + Adresa "%1" există deja ca adresă de primire cu eticheta "%2" și prin urmare nu poate fi adăugată ca adresă de trimitere. + + + The entered address "%1" is already in the address book with label "%2". + Adresa introdusă "%1" este deja în agenda de adrese cu eticheta "%2". + Could not unlock wallet. Portofelul nu a putut fi deblocat. @@ -851,22 +1255,138 @@ GovernanceList - - - HelpMessageDialog - version - versiune + Form + Formular - About %1 - Despre %1 + Filter List: + Listă filtrare: - Command-line options - Optiuni linie de comanda + Filter proposal list + Filtrează lista de propuneri - + + Masternode Count: + Număr Masternode: + + + Number of masternodes this wallet can vote with (masternodes for which this wallet holds the voting key) + Numărul de masternoduri cu care acest portofel poate vota (masternoduri pentru care acest portofel deține cheia de vot) + + + Proposal Count: + Număr propuneri: + + + Create Proposal + Creează propunere + + + Filter by Title + Filtrează după titlu + + + Unavailable + Indisponibil + + + A synced node and an unlocked wallet are required. + Este necesar un nod sincronizat și un portofel deblocat. + + + Vote Yes + Votează Da + + + Vote No + Votează Nu + + + Vote Abstain + Votează Abținere + + + Proposal Info: %1 + Informații propunere: %1 + + + Voting Failed + Votul a eșuat + + + No wallet available. + Niciun portofel disponibil. + + + No masternode voting keys found in wallet. + Nu s-au găsit chei de vot masternode în portofel. + + + Please select a proposal to vote on. + Vă rugăm să selectați o propunere pentru a vota. + + + Unable to unlock wallet. + Imposibil de deblocat portofelul. + + + Unable to get masternode list. Please try again later. + Imposibil de obținut lista masternode. Vă rugăm să încercați din nou mai târziu. + + + Masternode %1 not found + Masternode-ul %1 nu a fost găsit + + + Failed to sign vote for masternode %1 + Eșec la semnarea votului pentru masternode-ul %1 + + + Masternode %1: %2 + Masternode %1: %2 + + + Voted successfully %n time(s) + A votat cu succes de %n oriA votat cu succes de %n oriA votat cu succes de %n ori + + + Failed to vote %n time(s) + Eșec la vot de %n oriEșec la vot de %n oriEșec la vot de %n ori + + + Errors: + Erori: + + + Voting Results + Rezultate vot + + + + HelpMessageDialog + + version + versiune + + + About %1 + Despre %1 + + + Command-line options + Optiuni linie de comanda + + + %1 information + Informații %1 + + + <h3>%1 Basics</h3> %1 gives you true financial privacy by obscuring the origins of your funds. All the Dash in your wallet is comprised of different "inputs" which you can think of as separate, discrete coins.<br> %1 uses an innovative process to mix your inputs with the inputs of two or more other people, without having your coins ever leave your wallet. You retain control of your money at all times.<hr> <b>The %1 process works like this:</b><ol type="1"> <li>%1 begins by breaking your transaction inputs down into standard denominations. These denominations are 0.001 DASH, 0.01 DASH, 0.1 DASH, 1 DASH and 10 DASH -- sort of like the paper money you use every day.</li> <li>Your wallet then sends requests to specially configured software nodes on the network, called "masternodes." These masternodes are informed then that you are interested in mixing a certain denomination. No identifiable information is sent to the masternodes, so they never know "who" you are.</li> <li>When two or more other people send similar messages, indicating that they wish to mix the same denomination, a mixing session begins. The masternode mixes up the inputs and instructs all three users' wallets to pay the now-transformed input back to themselves. Your wallet pays that denomination directly to itself, but in a different address (called a change address).</li> <li>In order to fully obscure your funds, your wallet must repeat this process a number of times with each denomination. Each time the process is completed, it's called a "round." Each round of %1 makes it exponentially more difficult to determine where your funds originated.</li> <li>This mixing process happens in the background without any intervention on your part. When you wish to make a transaction, your funds will already be mixed. No additional waiting is required.</li> </ol> <hr><b>IMPORTANT:</b> Your wallet only contains 1000 of these "change addresses." Every time a mixing event happens, up to 9 of your addresses are used up. This means those 1000 addresses last for about 100 mixing events. When 900 of them are used, your wallet must create more addresses. It can only do this, however, if you have automatic backups enabled.<br> Consequently, users who have backups disabled will also have %1 disabled. <hr>For more information, see the <a style="%2" href="%3">%1 documentation</a>. + <h3>Noțiuni de bază %1</h3> %1 vă oferă adevărată confidențialitate financiară prin ascunderea originii fondurilor dumneavoastră. Toate monedele Dash din portofelul dumneavoastră sunt compuse din diferite "intrări" pe care le puteți considera ca monede separate, discrete.<br> %1 folosește un proces inovator pentru a amesteca intrările dumneavoastră cu intrările a două sau mai multe alte persoane, fără ca monedele dumneavoastră să părăsească vreodată portofelul. Rețineți controlul banilor dumneavoastră în orice moment.<hr> <b>Procesul %1 funcționează astfel:</b><ol type="1"> <li>%1 începe prin defalcarea intrărilor de tranzacție în denominații standard. Aceste denominații sunt 0.001 DASH, 0.01 DASH, 0.1 DASH, 1 DASH și 10 DASH -- similar cu bancnotele pe care le folosiți în fiecare zi.</li> <li>Portofelul dumneavoastră trimite apoi cereri către noduri software special configurate în rețea, numite "masternode-uri." Aceste masternode-uri sunt informate că sunteți interesat să amestecați o anumită denominație. Nicio informație identificabilă nu este trimisă către masternode-uri, astfel încât acestea nu știu niciodată "cine" sunteți.</li> <li>Când două sau mai multe persoane trimit mesaje similare, indicând că doresc să amestece aceeași denominație, începe o sesiune de amestecare. Masternode-ul amestecă intrările și instruiește portofelele tuturor celor trei utilizatori să plătească intrarea acum transformată înapoi către ei înșiși. Portofelul dumneavoastră plătește acea denominație direct către sine, dar la o adresă diferită (numită adresă de rest).</li> <li>Pentru a ascunde complet fondurile dumneavoastră, portofelul trebuie să repete acest proces de mai multe ori cu fiecare denominație. De fiecare dată când procesul este finalizat, se numește o "rundă." Fiecare rundă de %1 face exponențial mai dificil de determinat de unde au provenit fondurile dumneavoastră.</li> <li>Acest proces de amestecare se întâmplă în fundal fără nicio intervenție din partea dumneavoastră. Când doriți să faceți o tranzacție, fondurile dumneavoastră vor fi deja amestecate. Nu este necesară nicio așteptare suplimentară.</li> </ol> <hr><b>IMPORTANT:</b> Portofelul dumneavoastră conține doar 1000 dintre aceste "adrese de rest." De fiecare dată când are loc un eveniment de amestecare, până la 9 dintre adresele dumneavoastră sunt folosite. Aceasta înseamnă că cele 1000 de adrese durează pentru aproximativ 100 de evenimente de amestecare. Când 900 dintre ele sunt folosite, portofelul trebuie să creeze mai multe adrese. Cu toate acestea, poate face acest lucru doar dacă aveți activat backup-urile automate.<br> În consecință, utilizatorii care au backup-urile dezactivate vor avea și %1 dezactivat. <hr>Pentru mai multe informații, consultați <a style="%2" href="%3">documentația %1</a>. + + Intro @@ -881,10 +1401,26 @@ As this is the first time the program is launched, you can choose where %1 will store its data. Deoarece este prima lansare a programului poți alege unde %1 va stoca datele sale. + + Limit block chain storage to + Limitează stocarea blockchain la + + + 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. + Revenirea la această setare necesită re-descărcarea întregului blockchain. Este mai rapid să descărcați mai întâi lanțul complet și să îl reduceți ulterior. Dezactivează unele funcții avansate. + + + GB + GB + 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. Sincronizarea initiala necesita foarte multe resurse, si poate releva probleme de hardware ale computerului care anterior au trecut neobservate. De fiecare data cand rulati %1, descarcarea va continua de unde a fost intrerupta. + + 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. + Când dați click pe OK, %1 va începe să descarce și să proceseze întregul blockchain %4 (%2 GB) începând cu cele mai vechi tranzacții din %3 când %4 a fost lansat inițial. + 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. Daca ati ales o limita pentru capacitatea de stocare a blockchainului (pruning), datele mai vechi tot trebuie sa fie descarcate si procesate, insa vor fi sterse ulterior pentru a reduce utilizarea harddiskului. @@ -897,13 +1433,17 @@ Use a custom data directory: Foloseşte un dosar de date personalizat: - - %1 GB of free space available - %1 GB de spațiu liber disponibil + + %n GB of space available + %n GB de spațiu disponibil%n GB de spațiu disponibil%n GB de spațiu disponibil - - (of %1 GB needed) - (din %1 GB necesar) + + (of %n GB needed) + (din %n GB necesari)(din %n GB necesari)(din %n GB necesari) + + + (%n GB needed for full chain) + (%n GB necesari pentru lanțul complet)(%n GB necesari pentru lanțul complet)(%n GB necesari pentru lanțul complet) At least %1 GB of data will be stored in this directory, and it will grow over time. @@ -913,6 +1453,11 @@ Approximately %1 GB of data will be stored in this directory. Aproximativ %1 GB de date vor fi stocate in acest director. + + (sufficient to restore backups %n day(s) old) + Explanatory text on the capability of the current prune target. + (suficient pentru a restaura backup-uri vechi de %n zile)(suficient pentru a restaura backup-uri vechi de %n zile)(suficient pentru a restaura backup-uri vechi de %n zile) + %1 will download and store a copy of the Dash block chain. %1 va descarca si stoca o copie a blockchainului Dash @@ -930,6 +1475,13 @@ Eroare + + LoadWalletsActivity + + Loading wallets… + Se încarcă portofele… + + MasternodeList @@ -964,6 +1516,10 @@ Service Serviciu + + Type + Tip + PoSe Score Scorul PoSe @@ -1008,6 +1564,14 @@ Copy Collateral Outpoint Copiază Collateral Outpoint + + Please wait… + Vă rugăm așteptați… + + + Updating… + Actualizare… + ENABLED ACTIVAT @@ -1036,6 +1600,10 @@ NONE Niciuna + + Filter by any property (e.g. address or protx hash) + Filtrează după orice proprietate (de ex. adresă sau hash protx) + Additional information for DIP3 Masternode %1 Informații suplimentare pentru Masternode DIP3 %1 @@ -1087,7 +1655,15 @@ Hide Ascunde - + + %1 is currently syncing. It will download headers and blocks from peers and validate them until reaching the tip of the block chain. + %1 se sincronizează în prezent. Va descărca header-ele și blocurile de la peers și le va valida până la atingerea vârfului blockchain-ului. + + + Unknown. Syncing Headers (%1, %2%)… + Necunoscut. Sincronizare anteturi (%1, %2%)… + + OpenURIDialog @@ -1098,10 +1674,37 @@ URI: URI: + + Paste address from clipboard + Tooltip text for button that allows you to paste an address that is in your clipboard. + Lipește adresa din clipboard + OpenWalletActivity - + + Open wallet failed + Deschiderea portofelului a eșuat + + + Open wallet warning + Avertisment deschidere portofel + + + default wallet + portofel implicit + + + Open Wallet + Title of window indicating the progress of opening of a wallet. + Deschide portofel + + + Opening Wallet <b>%1</b>… + Descriptive text of the open wallet progress window which indicates to the user which wallet is currently being opened. + Deschidere portofel <b>%1</b>… + + OptionsDialog @@ -1128,6 +1731,82 @@ W&allet Portofel + + &Appearance + &Aspect + + + Show the icon in the system tray. + Arată iconița în bara de sistem. + + + &Show tray icon + &Arată iconița în tray + + + Prune &block storage to + Reduce &stocarea blocurilor la + + + GB + GB + + + Reverting this setting requires re-downloading the entire blockchain. + Revenirea la această setare necesită re-descărcarea întregului blockchain. + + + 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. + Tooltip text for Options window setting that sets the size of the database cache. Explains the corresponding effects of increasing/decreasing this value. + Dimensiunea maximă a cache-ului bazei de date. Un cache mai mare poate contribui la o sincronizare mai rapidă, după care beneficiul este mai puțin pronunțat pentru majoritatea cazurilor de utilizare. Reducerea dimensiunii cache-ului va reduce utilizarea memoriei. Memoria mempool nefolosită este partajată pentru acest cache. + + + MiB + MiB + + + Set the number of script verification threads. Negative values correspond to the number of cores you want to leave free to the system. + 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. + Setează numărul de thread-uri de verificare a scripturilor. Valorile negative corespund numărului de nuclee pe care doriți să le lăsați libere pentru sistem. + + + This allows you or a third party tool to communicate with the node through command-line and JSON-RPC commands. + Tooltip text for Options window setting that enables the RPC server. + Acest lucru vă permite dumneavoastră sau unui instrument terț să comunicați cu nodul prin comenzi command-line și JSON-RPC. + + + Enable R&PC server + An Options window setting to enable the RPC server. + Activează serverul R&PC + + + Whether to set subtract fee from amount as default or not. + Tooltip text for Options window setting that sets subtracting the fee from a sending amount as default. + Dacă să setați sau nu scăderea taxei din sumă ca implicit. + + + Subtract &fee from amount by default + An Options window setting to set subtracting the fee from a sending amount as default. + Scade &taxa din sumă implicit + + + Enable &PSBT controls + An options window setting to enable PSBT controls. + Activează controalele &PSBT + + + Whether to show PSBT controls. + Tooltip text for options window setting that enables PSBT controls. + Dacă să afișeze controalele PSBT. + + + Whether to keep the specified custom change address or not. + Dacă să păstrați sau nu adresa de rest personalizată specificată. + + + Keep custom change &address + Păstrează &adresa de rest personalizată + Show additional tab listing all your masternodes in first sub-tab<br/>and all masternodes on the network in second sub-tab. Afișează o pagină suplimentară care conține lista tuturor masternode-urilor în prima sub-pagină<br/>și toate masternode-urile din rețea în a sub-pagină. @@ -1136,14 +1815,114 @@ Show Masternodes Tab Arată Pagina Masternode-urilor + + Show additional tab listing governance proposals. + Arată un tab suplimentar care listează propunerile de guvernare. + + + Show Governance Tab + Arată tab-ul guvernare + If you disable the spending of unconfirmed change, the change from a transaction<br/>cannot be used until that transaction has at least one confirmation.<br/>This also affects how your balance is computed. Dacă dezactivezi cheltuirea restului neconfirmat, restul dintr-o tranzacție<br/>nu poate fi utilizat până când tranzacția nu are cel puțin o confirmare.<br/>Acest lucru afectează de asemenea modul în care se calculează soldul tău. + + Show mixing interface on Overview screen and reveal an additional screen which allows to spend fully mixed coins only.<br/>A new tab with more settings will also appear in this dialog, please make sure to check them before mixing your coins. + Arată interfața de amestecare pe ecranul Overview și dezvăluie un ecran suplimentar care permite cheltuirea doar a monedelor complet amestecate.<br/>Un nou tab cu mai multe setări va apărea de asemenea în acest dialog, vă rugăm să vă asigurați că le verificați înainte de a vă amesteca monedele. + + + Show additional information and buttons on overview screen. + Arată informații suplimentare și butoane pe ecranul de prezentare generală. + + + Enable advanced interface + Activează interfața avansată + + + Show system popups for mixing transactions<br/>just like for all other transaction types. + Arată popup-uri de sistem pentru tranzacțiile de amestecare<br/>la fel ca pentru toate celelalte tipuri de tranzacții. + + + Show popups for mixing transactions + Arată popup-uri pentru tranzacțiile de amestecare + + + Show warning dialog when the wallet has very low number of keys left. + Arată dialogul de avertizare când portofelul are un număr foarte mic de chei rămase. + + + Warn if the wallet is running out of keys + Avertizează dacă portofelul rămâne fără chei + + + Whether to use experimental mode with multiple mixing sessions per block.<br/>Note: You must use this feature carefully.<br/>Make sure you always have recent wallet (auto)backup in a safe place! + Dacă să folosiți sau nu modul experimental cu mai multe sesiuni de amestecare pe bloc.<br/>Notă: Trebuie să folosiți această funcție cu atenție.<br/>Asigurați-vă că aveți întotdeauna un backup (auto) recent al portofelului într-un loc sigur! + + + Enable &multi-session + Activează &multi-sesiune + + + Use this many separate masternodes in parallel to mix funds.<br/>Note: You must use this feature carefully.<br/>Make sure you always have recent wallet (auto)backup in a safe place! + Folosiți atât de multe masternode-uri separate în paralel pentru a amesteca fonduri.<br/>Notă: Trebuie să folosiți această funcție cu atenție.<br/>Asigurați-vă că aveți întotdeauna un backup (auto) recent al portofelului într-un loc sigur! + + + Parallel sessions + Sesiuni paralele + + + Mixing rounds + Runde amestecare + + + This amount acts as a threshold to turn off mixing once it's reached. + Această sumă acționează ca un prag pentru a opri amestecarea odată ce este atinsă. + + + Target balance + Balanță țintă + + + How many inputs of each denominated amount are created.<br/>Lower these numbers if you want fewer smaller denominations. + Câte input-uri ale fiecărei sume denominate sunt create.<br/>Reduceți aceste numere dacă doriți mai puține denominații mai mici. + + + Inputs per denomination + Input-uri per denominație + + + Try to create at least this many inputs for each denominated amount.<br/>Lower this number if you want fewer smaller denominations. + Încercați să creați cel puțin atât de multe intrări pentru fiecare sumă denominată.<br/>Reduceți acest număr dacă doriți mai puține denominații mai mici. + + + Target + Țintă + + + Create up to this many inputs for each denominated amount.<br/>Lower this number if you want fewer smaller denominations. + Creați până la atât de multe input-uri pentru fiecare sumă denominată.<br/>Reduceți acest număr dacă doriți mai puține denominații mai mici. + + + Maximum + Maxim + Automatically open the Dash Core client port on the router. This only works when your router supports UPnP and it is enabled. Deschide automat portul client Dash Core de pe router. Asta funcționează numai atunci când routerul dvs. acceptă UPnP și este activat. + + Map port using NA&T-PMP + Mapează portul folosind NA&T-PMP + + + Accept connections from outside. + Acceptă conexiuni din exterior. + + + Allow incomin&g connections + Permite conexiuni de &intrare + Connect to the Dash network through a SOCKS5 proxy. Conectare la reţeaua Dash printr-un proxy SOCKS. @@ -1157,12 +1936,26 @@ Afișează dacă proxy-ul implicit SOCKS5 furnizat este utilizat pentru a ajunge la peers prin intermediul acestui tip de rețea. - 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. - Minimizează fereastra în locul părăsirii programului în momentul închiderii ferestrei. Cînd acestă opţiune e activă, aplicaţia se va opri doar în momentul selectării comenzii 'Închide aplicaţia' din menu. + Language missing or translation incomplete? Help contributing translations here: +https://explore.transifex.com/dash/dash/ + Limba lipsește sau traducerea este incompletă? Ajutați contribuind la traduceri aici: +https://explore.transifex.com/dash/dash/ + + + Third-party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items.<br/>%s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |. + URL-uri terțe (de ex. un explorator de blocuri) care apar în tab-ul de tranzacții ca elemente de meniu contextual.<br/>%s în URL este înlocuit cu hash-ul tranzacției. Mai multe URL-uri sunt separate prin bară verticală |. + + + &Third-party transaction URLs + URL-uri de tranzacții &terțe + + + Options set in this dialog are overridden by the command line or in the configuration file: + Opțiunile setate în acest dialog sunt suprascrise de linia de comandă sau în fișierul de configurare: - Third party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items.<br/>%s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |. - Adresele URL ale unor terțe părți (de exemplu, un explorator block) care apar în tab-ul de tranzacții ca elemente de meniu contextual.<br/>%s în URL este înlocuit de hash-ul tranzacției. Adresele URL multiple sunt separate prin bara verticală |. + 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. + Minimizează fereastra în locul părăsirii programului în momentul închiderii ferestrei. Cînd acestă opţiune e activă, aplicaţia se va opri doar în momentul selectării comenzii 'Închide aplicaţia' din menu. Whether to show coin control features or not. @@ -1192,10 +1985,18 @@ &Network &Retea + + 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. + Activarea tăierii (pruning) reduce semnificativ spațiul de disc necesar pentru stocarea tranzacțiilor. Toate blocurile sunt încă validate complet. Revenirea acestei setări necesită re-descărcarea întregului blockchain. + Map port using &UPnP Mapare port folosind &UPnP + + Automatically open the Dash Core client port on the router. This only works when your router supports NAT-PMP and it is enabled. The external port could be random. + Deschide automat portul clientului Dash Core pe router. Aceasta funcționează doar când routerul dvs. suportă NAT-PMP și este activat. Portul extern poate fi aleatoriu. + Proxy &IP: Proxy &IP: @@ -1244,6 +2045,14 @@ &Display &Afişare + + Connect to the Dash network through a separate SOCKS5 proxy for Tor onion services. + Conectați-vă la rețeaua Dash printr-un proxy SOCKS5 separat pentru serviciile Tor onion. + + + Use separate SOCKS&5 proxy to reach peers via Tor onion services: + Folosește proxy SOCKS&5 separat pentru a ajunge la peer-uri prin servicii Tor onion: + User Interface &language: Interfaţă utilizator &Limbă @@ -1258,7 +2067,7 @@ Choose the default subdivision unit to show in the interface and when sending coins. - Alege subdiviziunea folosită la afişarea interfeţei şi la trimiterea de bitcoin. + Alegeți unitatea de subdiviziune implicită de afișat în interfață și la trimiterea de monede. Decimal digits @@ -1274,11 +2083,15 @@ &OK - & OK + &OK &Cancel - & Renunta + &Renunta + + + Enable %1 features + Activează funcțiile %1 default @@ -1286,14 +2099,22 @@ Confirm options reset + Window title text of pop-up window shown when the user has chosen to reset options. Confirmă resetarea opţiunilor Client restart required to activate changes. + Text explaining that the settings changed will not come into effect until the client is restarted. Este necesară repornirea clientului pentru a activa schimbările. + + Current settings will be backed up at "%1". + 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. + Setările curente vor fi salvate la "%1". + Client will be shut down. Do you want to proceed? + Text asking the user to confirm if they would like to proceed with a client shutdown. Clientul va fi închis. Doriţi să continuaţi? @@ -1302,7 +2123,7 @@ The supplied proxy address is invalid. - Adresa bitcoin pe care a-ti specificat-o este invalida + Adresa proxy furnizată este invalidă. @@ -1427,10 +2248,26 @@ No inputs detected Nu au fost detectate intrări + + %1 Balance + Balanță %1 + + + Discreet mode activated for the Overview tab. To unmask the values, uncheck Settings->Discreet mode. + Mod discret activat pentru tab-ul Prezentare generală. Pentru a demasca valorile, debifați Setări->Mod discret. + %n Rounds %n Rundă%n Runde%n Runde + + Found enough compatible inputs to mix %1 + S-au găsit suficiente input-uri compatibile pentru a amesteca %1 + + + Not enough compatible inputs to mix <span style='%1'>%2</span>,<br>will mix <span style='%1'>%3</span> instead + Nu sunt suficiente input-uri compatibile pentru a amesteca <span style='%1'>%2</span>,<br>în schimb se va amesteca <span style='%1'>%3</span> + Overall progress Progres general @@ -1455,6 +2292,26 @@ keys left: %1 chei rămase: %1 + + Start %1 + Pornește %1 + + + If you don't want to see internal %1 fees/transactions select "Most Common" as Type on the "Transactions" tab. + Dacă nu doriți să vedeți taxele/tranzacțiile interne %1, selectați "Cele mai comune" ca Tip în tab-ul "Tranzacții". + + + %1 requires at least %2 to use. + %1 necesită cel puțin %2 pentru a fi folosit. + + + Wallet is locked and user declined to unlock. Disabling %1. + Portofelul este blocat și utilizatorul a refuzat să-l deblocheze. Se dezactivează %1. + + + Stop %1 + Oprește %1 + Disabled Dezactivat @@ -1498,62 +2355,619 @@ PSBTOperationsDialog - - - PaymentServer - Payment request error - Eroare la cererea de plată + Dialog + Dialog - Cannot start dash: click-to-pay handler - Dash nu poate porni: click-to-pay handler + Sign Tx + Semnează Tx - URI handling - Gestionare URI + Broadcast Tx + Difuzează Tx - URI cannot be parsed! This can be caused by an invalid Dash address or malformed URI parameters. - URI nu poate fi analizat! Acest lucru poate fi cauzat de o adresă Dash invalidă sau parametri URI deformaţi. + Copy to Clipboard + Copiază în clipboard - Payment request file handling - Manipulare fişier cerere de plată + Save… + Salvează… - - - PeerTableModel + + Close + Închide + + + Failed to load transaction: %1 + Nu s-a reușit încărcarea tranzacției: %1 + + + Failed to sign transaction: %1 + Nu s-a reușit semnarea tranzacției: %1 + + + Cannot sign inputs while wallet is locked. + Nu se pot semna intrări în timp ce portofelul este blocat. + + + Could not sign any more inputs. + Nu s-au putut semna mai multe intrări. + + + Signed %1 inputs, but more signatures are still required. + S-au semnat %1 intrări, dar mai sunt necesare semnături. + + + Signed transaction successfully. Transaction is ready to broadcast. + Tranzacție semnată cu succes. Tranzacția este pregătită pentru difuzare. + + + Unknown error processing transaction. + Eroare necunoscută la procesarea tranzacției. + + + Transaction broadcast successfully! Transaction ID: %1 + Tranzacție difuzată cu succes! ID tranzacție: %1 + + + Transaction broadcast failed: %1 + Difuzarea tranzacției a eșuat: %1 + + + PSBT copied to clipboard. + PSBT copiat în clipboard. + + + Save Transaction Data + Salvează datele tranzacției + + + Partially Signed Transaction (Binary) + Expanded name of the binary PSBT file format. See: BIP 174. + Tranzacție parțial semnată (binară) + + + PSBT saved to disk. + PSBT salvat pe disc. + + + * Sends %1 to %2 + * Trimite %1 către %2 + + + own address + propria adresă + + + Unable to calculate transaction fee or total transaction amount. + Imposibil de calculat taxa tranzacției sau suma totală a tranzacției. + + + Pays transaction fee: + Plătește taxa de tranzacție: + + + Total Amount + Suma totală + + + or + sau + + + Transaction has %1 unsigned inputs. + Tranzacția are %1 intrări nesemnate. + + + Transaction is missing some information about inputs. + Tranzacției îi lipsesc unele informații despre intrări. + + + Transaction still needs signature(s). + Tranzacția încă necesită semnătură(i). + + + (But no wallet is loaded.) + (Dar niciun portofel nu este încărcat.) + + + (But this wallet cannot sign transactions.) + (Dar acest portofel nu poate semna tranzacții.) + + + (But this wallet does not have the right keys.) + (Dar acest portofel nu are cheile potrivite.) + + + Transaction is fully signed and ready for broadcast. + Tranzacția este complet semnată și pregătită pentru difuzare. + + + Transaction status is unknown. + Starea tranzacției este necunoscută. + + + + PaymentServer + + Payment request error + Eroare la cererea de plată + + + Cannot start dash: click-to-pay handler + Dash nu poate porni: click-to-pay handler + + + URI handling + Gestionare URI + + + 'dash://' is not a valid URI. Use 'dash:' instead. + 'dash://' nu este un URI valid. Folosiți 'dash:' în schimb. + + + Cannot process payment request as BIP70 is no longer supported. +Due to discontinued support, you should request the merchant to provide you with a BIP21 compatible URI or use a wallet that does continue to support BIP70. + Nu se poate procesa cererea de plată deoarece BIP70 nu mai este suportat. +Din cauza încetării suportului, ar trebui să cereți comerciantului să vă furnizeze un URI compatibil BIP21 sau să folosiți un portofel care continuă să suporte BIP70. + + + URI cannot be parsed! This can be caused by an invalid Dash address or malformed URI parameters. + URI nu poate fi analizat! Acest lucru poate fi cauzat de o adresă Dash invalidă sau parametri URI deformaţi. + + + Payment request file handling + Manipulare fişier cerere de plată + + + + PeerTableModel User Agent Title of Peers Table column which contains the peer's User Agent string. Agent utilizator - Ping - Title of Peers Table column which indicates the current latency of the connection with the peer. - Ping + Ping + Title of Peers Table column which indicates the current latency of the connection with the peer. + Ping + + + Peer + Title of Peers Table column which contains a unique number used to identify a connection. + Peer + + + Age + Title of Peers Table column which indicates the duration (length of time) since the peer connection started. + Vârstă + + + Direction + Title of Peers Table column which indicates the direction the peer connection was initiated from. + Direcție + + + Type + Title of Peers Table column which describes the type of peer connection. The "type" describes why the connection exists. + Tip + + + Sent + Title of Peers Table column which indicates the total amount of network information we have sent to the peer. + Trimis + + + Received + Title of Peers Table column which indicates the total amount of network information we have received from the peer. + Primit + + + Address + Title of Peers Table column which contains the IP/Onion/I2P address of the connected peer. + Adresă + + + Network + Title of Peers Table column which states the network the peer connected through. + Rețea + + + Inbound + An Inbound Connection from a Peer. + Intrare + + + Outbound + An Outbound Connection to a Peer. + Ieșire + + + + Proposal + + Passing +%1 + Se trece +%1 + + + Needs additional %1 votes + Necesită %1 voturi suplimentare + + + + ProposalModel + + Yes + Da + + + No + Nu + + + Hash + Hash + + + Title + Titlu + + + Start + Start + + + End + Final + + + Amount + Sumă + + + Active + Activ + + + Status + Status + + + + ProposalWizard + + Create Governance Proposal + Creează propunere de guvernare + + + Enter proposal details + Introduceți detaliile propunerii + + + A fee will be burned when you prepare the proposal. + O taxă va fi arsă când pregătiți propunerea. + + + Proposal &name + &Nume propunere + + + &Description URL + URL &descriere + + + Payment &address + &Adresă de plată + + + Payment &amount + S&umă de plată + + + The amount to request in a single payment + Suma de solicitat într-o singură plată + + + &First payment + &Prima plată + + + Pa&yments + Pl&ăți + + + To&tal amount + Suma to&tală + + + Proposal &fee + &Taxă propunere + + + Next + Următorul + + + Review proposal JSON and validate. + Revizuiți JSON-ul propunerii și validați. + + + Hex-encoded JSON + JSON codificat în hex + + + Back + Înapoi + + + Validate + Validează + + + Prepare (burn fee) and wait for confirmations. + Pregătiți (ardeți taxa) și așteptați confirmări. + + + Copy + Copiază + + + At 1/6 confirmations: can be relayed and queued. At 6/6: accepted and processed. + La 1/6 confirmări: poate fi transmis și pus în coadă. La 6/6: acceptat și procesat. + + + Confirmations progress + Progres confirmări + + + Shows progress toward the required number of confirmations for the proposal fee transaction. + Arată progresul către numărul necesar de confirmări pentru tranzacția taxei de propunere. + + + Estimated time remaining: - + Timp estimat rămas: - + + + Prepare Proposal + Pregătește propunere + + + You can submit after 1 confirmation. At 6 confirmations it is accepted and processed. + Puteți trimite după 1 confirmare. La 6 confirmări este acceptată și procesată. + + + Proposal ID: + ID propunere: + + + Submit Proposal + Trimite propunerea + + + Close + Închide + + + Valid + Valid + + + Invalid: %1 + Invalid: %1 + + + Burn %1 + Arde %1 + + + Burn %1 to create the fee transaction? + Ardeți %1 pentru a crea tranzacția de taxă? + + + Prepare failed + Pregătirea a eșuat + + + Confirmations: %1 / %2 required + Confirmări: %1 / %2 necesare + + + Estimated time remaining: Ready + Timp estimat rămas: Gata + + + Estimated time remaining: %n minute(s) + Timp estimat rămas: %n minuteTimp estimat rămas: %n minuteTimp estimat rămas: %n minute + + + Your proposal was submitted successfully. + Propunerea dvs. a fost trimisă cu succes. + + + Already submitted + Deja trimis + + + This proposal has already been submitted. + Această propunere a fost deja trimisă. + + + Submission failed + Trimiterea a eșuat + + + Proposal submitted + Propunere trimisă + + + A fee of %1 will be burned when you prepare the proposal. + O taxă de %1 va fi arsă când pregătiți propunerea. + + + Prepare (burn %1) and wait for %2 confirmations. + Pregătiți (ardeți %1) și așteptați %2 confirmări. + + + + QObject + + Do you want to reset settings to default values, or to abort without making changes? + Explanatory text shown on startup when the settings file cannot be read. Prompts user to make a choice between resetting or aborting. + Doriți să resetați setările la valorile implicite sau să anulați fără a face modificări? + + + A fatal error occurred. Check that settings file is writable, or try running with -nosettings. + 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. + A apărut o eroare fatală. Verificați că fișierul de setări este inscriptibil sau încercați să rulați cu -nosettings. + + + Choose data directory on startup (default: %u) + Alegeți directorul de date la pornire (implicit: %u) + + + Set the font family. Possible values: %1. (default: %2) + Setați familia de font. Valori posibile: %1. (implicit: %2) + + + Set a scale factor which gets applied to the base font size. Possible range %1 (smallest fonts) to %2 (largest fonts). (default: %3) + Setați un factor de scalare care se aplică la dimensiunea de bază a fontului. Interval posibil %1 (cele mai mici fonturi) până la %2 (cele mai mari fonturi). (implicit: %3) + + + Set the font weight for bold texts. Possible range %1 to %2 (default: %3) + Setați grosimea fontului pentru textele îngroșate. Interval posibil %1 până la %2 (implicit: %3) + + + Set the font weight for normal texts. Possible range %1 to %2 (default: %3) + Setați grosimea fontului pentru textele normale. Interval posibil %1 până la %2 (implicit: %3) + + + Set language, for example "de_DE" (default: system locale) + Setați limba, de exemplu "de_DE" (implicit: limba sistemului) + + + Start minimized + Pornește minimizat + + + Reset all settings changed in the GUI + Resetează toate setările modificate în GUI + + + Show splash screen on startup (default: %u) + Arată ecranul de pornire la startup (implicit: %u) + + + Error: Specified data directory "%1" does not exist. + Eroare: Directorul de date specificat "%1" nu există. + + + Error: Cannot parse configuration file: %1. + Eroare: Nu se poate analiza fișierul de configurare: %1. + + + Error: %1 + Eroare: %1 + + + Error: Failed to load application fonts. + Eroare: Eșec la încărcarea fonturilor aplicației. + + + Error: Specified font-family invalid. Valid values: %1. + Eroare: Font-family specificat invalid. Valori valide: %1. + + + Error: Specified font-weight-normal invalid. Valid range %1 to %2. + Eroare: Font-weight-normal specificat invalid. Interval valid %1 până la %2. + + + Error: Specified font-weight-bold invalid. Valid range %1 to %2. + Eroare: Font-weight-bold specificat invalid. Interval valid %1 până la %2. + + + Error: Specified font-scale invalid. Valid range %1 to %2. + Eroare: Font-scale specificat invalid. Interval valid %1 până la %2. + + + Error: Invalid -custom-css-dir path. + Eroare: Cale -custom-css-dir invalidă. + + + Error: %1 CSS file(s) missing in -custom-css-dir path. + Eroare: %1 fișier(e) CSS lipsesc în calea -custom-css-dir. + + + %1 didn't yet exit safely… + %1 nu a fost inchis in siguranta… + + + Amount + Cantitate + + + Enter a Dash address (e.g. %1) + Introduceţi o adresă Dash (de exemplu %1) + + + Appearance Setup + Configurare aspect + + + Please choose your preferred settings for the appearance of %1 + Vă rugăm să alegeți setările preferate pentru aspectul %1 + + + This can also be adjusted later in the "Appearance" tab of the preferences. + Aceasta poate fi ajustată și mai târziu în tab-ul "Aspect" al preferințelor. + + + Ctrl+W + Ctrl+W + + + Unroutable + Nemarsrutabil + + + Internal + Intern + + + Inbound + An inbound connection from a peer. An inbound connection is a connection initiated by a peer. + Intrare + + + Outbound + An outbound connection to a peer. An outbound connection is a connection initiated by us. + Ieșire + + + Full Relay + Peer connection type that relays all network information. + Relay complet + + + Block Relay + Peer connection type that relays network information about blocks and not transactions or addresses. + Relay de blocuri - - - Proposal - - - ProposalModel - - - QObject - %1 didn't yet exit safely… - %1 nu a fost inchis in siguranta… + Manual + Peer connection type established manually through one of several methods. + Manual - Amount - Cantitate + Feeler + Short-lived peer connection type that tests the aliveness of known addresses. + Feeler - Enter a Dash address (e.g. %1) - Introduceţi o adresă Dash (de exemplu %1) + Address Fetch + Short-lived peer connection type that solicits known addresses from a peer. + Preluare adrese %1 d @@ -1611,6 +3025,22 @@ %1 and %2 %1 şi %2 + + %1 B + %1 B + + + %1 kB + %1 kB + + + %1 MB + %1 MB + + + %1 GB + %1 GB + unknown necunoscut @@ -1641,11 +3071,28 @@ &Copy Image &Copiaza Imaginea + + Resulting URI too long, try to reduce the text for label / message. + URI rezultat prea lung, încercați să reduceți textul pentru etichetă / mesaj. + + + Error encoding URI into QR Code. + Eroare la codificarea URI în cod QR. + + + QR code support not available. + Suport pentru cod QR indisponibil. + Save QR Code Salvează codul QR - + + PNG Image + Expanded name of the PNG file format. See: https://en.wikipedia.org/wiki/Portable_Network_Graphics. + Imagine PNG + + RPCConsole @@ -1736,6 +3183,10 @@ &Peers &Parteneri + + Wallet: + Portofel: + Banned peers Terti banati @@ -1748,6 +3199,14 @@ Version versiune + + High bandwidth BIP152 compact block relay: %1 + Releu bloc compact BIP152 cu lățime de bandă mare: %1 + + + High Bandwidth + Lățime de bandă mare + Starting Block Bloc de început @@ -1760,6 +3219,71 @@ Synced Blocks Blocuri Sincronizate + + Elapsed time since a novel block passing initial validity checks was received from this peer. + Timp scurs de când un bloc nou care a trecut verificările inițiale de validitate a fost primit de la acest peer. + + + Last Block + Ultimul bloc + + + Elapsed time since a novel transaction accepted into our mempool was received from this peer. + Tooltip text for the Last Transaction field in the peer details area. + Timp scurs de la primirea unei tranzacții noi acceptate în mempool-ul nostru de la acest peer. + + + Last Transaction + Ultima tranzacție + + + The mapped Autonomous System used for diversifying peer selection. + Sistemul autonom mapitat folosit pentru diversificarea selecției peer-urilor. + + + Mapped AS + AS mapitat + + + Whether we relay addresses to this peer. + Tooltip text for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No). + Dacă transmitem adrese către acest peer. + + + Address Relay + Text title for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No). + Releu adrese + + + Addresses Processed + 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). + Adrese procesate + + + Addresses Rate-Limited + 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. + Adrese limitate de rată + + + Rescan blockchain files 1 + Rescanează fișierele blockchain 1 + + + Rescan blockchain files 2 + Rescanează fișierele blockchain 2 + + + The buttons below will restart the wallet with command-line options to repair the wallet, fix issues with corrupt blockchain files or missing/obsolete transactions. + Butoanele de mai jos vor reporni portofelul cu opțiuni din linia de comandă pentru a repara portofelul, a remedia problemele cu fișierele blockchain corupte sau tranzacțiile lipsă/învechite. + + + -rescan=1: Rescan the block chain for missing wallet transactions starting from wallet creation time. + -rescan=1: Rescanează blockchain-ul pentru tranzacții lipsă din portofel începând de la momentul creării portofelului. + + + -rescan=2: Rescan the block chain for missing wallet transactions starting from genesis block. + -rescan=2: Rescanează blockchain-ul pentru tranzacții lipsă din portofel începând de la blocul geneză. + User Agent Agent utilizator @@ -1768,6 +3292,50 @@ Datadir Dirdate + + To specify a non-default location of the data directory use the '%1' option. + Pentru a specifica o locație ne-implicită a directorului de date folosiți opțiunea '%1'. + + + Blocksdir + Director blocuri + + + To specify a non-default location of the blocks directory use the '%1' option. + Pentru a specifica o locație ne-implicită a directorului de blocuri folosiți opțiunea '%1'. + + + Local Addresses + Adrese locale + + + Network addresses that your Dash node is currently using to communicate with other nodes. + Adresele de rețea pe care nodul dvs. Dash le folosește în prezent pentru a comunica cu alte noduri. + + + Number of regular Masternodes + Număr Masternode-uri obișnuite + + + Number of EvoNodes + Număr EvoNode-uri + + + Current block height + Înălțimea blocului curent + + + Last block hash + Hash-ul ultimului bloc + + + Latest ChainLocked block hash + Hash-ul ultimului bloc ChainLocked + + + Latest ChainLocked block height + Înălțimea ultimului bloc ChainLocked + Open the %1 debug log file from the current data directory. This can take a few seconds for large log files. Deschide fişierul jurnal depanare %1 din directorul curent. Aceasta poate dura cateva secunde pentru fişierele mai mari. @@ -1776,6 +3344,10 @@ InstantSend locks Chei TrimiteInstant + + (none) + (niciunul) + Decrease font size Micsoreaza fontul @@ -1788,10 +3360,58 @@ &Reset &Resetează + + Node Type + Tip nod + + + PoSe Score + Scor PoSe + + + The transport layer version: %1 + Versiunea stratului de transport: %1 + + + Transport + Transport + + + The BIP324 session ID string in hex. + String-ul ID de sesiune BIP324 în hex. + + + Session ID + ID sesiune + + + The network protocol this peer is connected through: IPv4, IPv6, Onion, I2P, or CJDNS. + Protocolul de rețea prin care acest peer este conectat: IPv4, IPv6, Onion, I2P sau CJDNS. + + + Permissions + Permisiuni + + + The direction and type of peer connection: %1 + Direcția și tipul conexiunii peer: %1 + + + Direction/Type + Direcție/Tip + Services Servicii + + Whether we relay transactions to this peer. + Dacă preprimăm tranzacții către acest peer. + + + Transaction Relay + Releu tranzacții + Connection Time Timp conexiune @@ -1828,6 +3448,16 @@ &Wallet Repair &Repararea Portofelului + + The total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting). + 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). + Numărul total de adrese primite de la acest peer care au fost procesate (exclude adresele care au fost eliminate din cauza limitării ratei). + + + The total number of addresses received from this peer that were dropped (not processed) due to rate-limiting. + 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. + Numărul total de adrese primite de la acest peer care au fost eliminate (neprocesate) din cauza limitării ratei. + Wallet repair options. Opțiuni de reparație a portofelului @@ -1840,10 +3470,60 @@ -reindex: Rebuild block chain index from current blk000??.dat files. -reindexează: Reconstruiește index-ul block chain din fișierele curente blk000??.dat. + + Inbound: initiated by peer + Explanatory text for an inbound peer connection. + Intrare: inițiat de peer + + + Outbound Full Relay: default + Explanatory text for an outbound peer connection that relays all network information. This is the default behavior for outbound connections. + Outbound Full Relay: implicit + + + Outbound Block Relay: does not relay transactions or addresses + Explanatory text for an outbound peer connection that relays network information about blocks and not transactions or addresses. + Outbound Block Relay: nu retransmite tranzacții sau adrese + + + Outbound Manual: added using RPC %1 or %2/%3 configuration options + 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. + Outbound Manual: adăugat folosind RPC %1 sau opțiunile de configurare %2/%3 + + + Outbound Feeler: short-lived, for testing addresses + Explanatory text for a short-lived outbound peer connection that is used to test the aliveness of known addresses. + Outbound Feeler: de scurtă durată, pentru testarea adreselor + + + Outbound Address Fetch: short-lived, for soliciting addresses + Explanatory text for a short-lived outbound peer connection that is used to request addresses from a peer. + Outbound Address Fetch: de scurtă durată, pentru solicitarea adreselor + + + To + Către + + + we selected the peer for high bandwidth relay + am selectat peer-ul pentru relay cu lățime de bandă mare + + + From + De la + + + the peer selected us for high bandwidth relay + peer-ul ne-a selectat pentru relay cu lățime de bandă mare + No Nu + + no high bandwidth relay selected + niciun relay cu lățime de bandă mare selectat + &Disconnect &Deconectare @@ -1856,10 +3536,6 @@ 1 &hour 1 &oră - - 1 &day - 1 &zi - 1 &week 1 &săptămână @@ -1872,18 +3548,6 @@ &Unban &Unban - - Welcome to the %1 RPC console. - Bun venit la consola %1 RPC. - - - Use up and down arrows to navigate history, and %1 to clear screen. - Foloseste sagetile sus si jos pentru a naviga in istoric si %1 pentru a curata. - - - WARNING: Scammers have been active, telling users to type commands here, stealing their wallet contents. Do not use this console without fully understanding the ramifications of a command. - AVERTIZARE: scamerii au fost si sunt activi, spunându-le utilizatorilor să tasteze aici comenzile, furându-le conținutul portofelului. Nu folosiți această consolă fără să înțelegeți complet ramificările unei comenzi. - In: Intrare: @@ -1896,19 +3560,146 @@ Network activity disabled Activitatea retelei a fost oprita. + + None + Niciunul + Total: %1 (Enabled: %2) Total: %1 (Activat: %2) + + Executing command without any wallet + Se execută comanda fără niciun portofel + + + Ctrl++ + Main shortcut to increase the RPC console font size. + Ctrl++ + + + Ctrl+= + Secondary shortcut to increase the RPC console font size. + Ctrl+= + + + Ctrl+- + Main shortcut to decrease the RPC console font size. + Ctrl+- + + + Ctrl+_ + Secondary shortcut to decrease the RPC console font size. + Ctrl+_ + + + Ctrl+Shift+I + Ctrl+Shift+I + + + Ctrl+Shift+C + Ctrl+Shift+C + + + Ctrl+Shift+G + Ctrl+Shift+G + + + Ctrl+Shift+P + Ctrl+Shift+P + + + Ctrl+Shift+R + Ctrl+Shift+R + + + Executing command using "%1" wallet + Execută comanda folosind portofelul "%1" + + + detecting: peer could be v1 or v2 + Explanatory text for "detecting" transport type. + detectare: peer-ul ar putea fi v1 sau v2 + + + v1: unencrypted, plaintext transport protocol + Explanatory text for v1 transport type. + v1: protocol de transport necriptat, text simplu + + + v2: BIP324 encrypted transport protocol + Explanatory text for v2 transport type. + v2: protocol de transport criptat BIP324 + + + &Copy address + Context menu action to copy the address of a peer + &Copiază adresa + + + 1 d&ay + 1 &zi + + + &Copy IP/Netmask + 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 + &Copiază IP/Mască rețea + + + 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 + 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. + Bun venit la consola RPC %1. +Folosiți săgețile sus și jos pentru a naviga în istoric și %2 pentru a curăța ecranul. +Folosiți %3 și %4 pentru a mări sau micșora dimensiunea fontului. +Tastați %5 pentru o prezentare generală a comenzilor disponibile. +Pentru mai multe informații despre utilizarea acestei console, tastați %6. + +%7AVERTISMENT: Escrocii au fost activi, spunând utilizatorilor să tasteze comenzi aici, furând conținutul portofelelor lor. Nu folosiți această consolă fără a înțelege pe deplin ramificațiile unei comenzi.%8 + + + Executing… + A console message indicating an entered command is currently being executed. + Se execută… + + + (peer: %1) + (peer: %1) + via %1 via %1 + + Regular + Regulat + + + Masternode + Masternode + + + Verified Masternode + Masternode verificat + + + Yes + Da + Unknown necunoscut - + + Never + Niciodată + + ReceiveCoinsDialog @@ -1927,6 +3718,10 @@ An optional message to attach to the payment request, which will be displayed when the request is opened.<br>Note: The message will not be sent with the payment over the Dash network. Un mesaj opțional pentru a atașa solicitării de plată, care va fi afișat la deschiderea cererii.<br>Notă: mesajul nu va fi trimis cu plata prin rețeaua Dash. + + 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. + O etichetă opțională de asociat cu noua adresă de primire (folosită de dvs. pentru a identifica o factură). Este de asemenea atașată la cererea de plată. + Use this form to request payments. All fields are <b>optional</b>. Foloseşte acest formular pentru a solicita plăţi. Toate cîmpurile sînt <b>opţionale</b>. @@ -1940,56 +3735,104 @@ O sumă opţională de cerut. Lăsaţi gol sau zero pentru a nu cere o sumă anume. - &Amount: - Sum&a: + &Amount: + Sum&a: + + + &Create new receiving address + &Creează o nouă adresă de primire + + + Clear all fields of the form. + Curăţă toate cîmpurile formularului. + + + Clear + Curăţă + + + Requested payments history + Istoricul plăţilor cerute + + + Show the selected request (does the same as double clicking an entry) + Arată cererea selectată (acelaşi lucru ca şi dublu-clic pe o înregistrare) + + + Show + Arată + + + Remove the selected entries from the list + Înlătură intrările selectate din listă + + + Remove + Înlătură + + + Enter a label to associate with the new receiving address + Introduceți o etichetă de asociat cu noua adresă de primire + + + Enter a message to attach to the payment request + Introduceți un mesaj de atașat la cererea de plată + + + Copy &URI + Copiază &URI + + + &Copy address + &Copiază adresa - Clear all fields of the form. - Curăţă toate cîmpurile formularului. + Copy &label + Copiază &eticheta - Clear - Curăţă + Copy &message + Copiază &mesajul - Requested payments history - Istoricul plăţilor cerute + Copy &amount + Copiază &suma - Show the selected request (does the same as double clicking an entry) - Arată cererea selectată (acelaşi lucru ca şi dublu-clic pe o înregistrare) + Could not unlock wallet. + Nu s-a putut debloca portofelul. - Show - Arată + Could not generate new address + Nu s-a putut genera o nouă adresă + + + ReceiveRequestDialog - Remove the selected entries from the list - Înlătură intrările selectate din listă + Request payment to … + Solicită plată către … - Remove - Înlătură + Address: + Adresă: - Copy URI - Copiază URl + Amount: + Sumă: - Copy label - Copiază eticheta + Label: + Etichetă: - Copy message - Copiază mesajul + Message: + Mesaj: - Copy amount - Copiază suma + Wallet: + Portofel: - - - ReceiveRequestDialog Copy &URI Copiază &URl @@ -2042,6 +3885,34 @@ Ceruta + + RestoreWalletActivity + + Restore Wallet + Title of progress window which is displayed when wallets are being restored. + Restaurează portofel + + + Restoring Wallet <b>%1</b>… + Descriptive text of the restore wallets progress window which indicates to the user that wallets are currently being restored. + Restaurare portofel <b>%1</b>… + + + Restore wallet failed + Title of message box which is displayed when the wallet could not be restored. + Restaurarea portofelului a eșuat + + + Restore wallet warning + Title of message box which is displayed when the wallet is restored with some warning. + Avertisment restaurare portofel + + + Restore wallet message + Title of message box which is displayed when the wallet is successfully restored. + Mesaj restaurare portofel + + SendCoinsDialog @@ -2076,10 +3947,6 @@ Fee: Comision: - - Dust: - Praf: - Inputs… Intrări @@ -2104,6 +3971,14 @@ Transaction Fee: Taxă tranzacţie: + + 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 dash transactions than the network can process. + Când există mai puțin volum de tranzacții decât spațiu în blocuri, minerii precum și nodurile de relay pot impune o taxă minimă. Plata doar a acestei taxe minime este perfect în regulă, dar fiți conștienți că acest lucru poate duce la o tranzacție care nu se va confirma niciodată odată ce există mai multă cerere de tranzacții dash decât poate procesa rețeaua. + + + A too low fee might result in a never confirming transaction (read the tooltip) + O taxă prea mică poate rezulta într-o tranzacție care nu se confirmă niciodată (citiți tooltip-ul) + (Smart fee not initialized yet. This usually takes a few blocks…) (Taxa smart nu este inca initializata. Aceasta poate dura cateva blocuri…) @@ -2132,6 +4007,10 @@ Note: Not enough data for fee estimation, using the fallback fee instead. Notă: Nu sunt suficiente date pentru estimarea comisionului, folosind în schimb taxa de recuperare. + + Hide transaction fee settings + Ascunde setările taxei de tranzacție + Hide Ascunde @@ -2192,10 +4071,6 @@ Copy bytes Copiază octeţi - - Copy dust - Copiază praf - Copy change Copiază rest @@ -2212,18 +4087,46 @@ %1 to %2 %1 la %2 - - Are you sure you want to send? - Sigur doriţi să trimiteţi? - <b>(%1 of %2 entries displayed)</b> <b>(%1 of %2 înregistrările afișate)</b> + + S&end mixed funds + Trimite fonduri a&mestecate + + + Confirm the %1 send action + Confirmă acțiunea de trimitere %1 + + + Cr&eate Unsigned + Cr&eează nesemnat + + + from wallet '%1' + din portofelul '%1' + + + %1 to '%2' + %1 către '%2' + + + %1 funds only + Doar fonduri %1 + any available funds orice fonduri disponibile + + Transaction fee + Taxă tranzacție + + + (%1 transactions have higher fees usually due to no change output being allowed) + (%1 tranzacții au taxe mai mari de obicei din cauza faptului că nu este permisă ieșirea de rest) + Transaction size: %1 Marimea tranzactiei: %1 @@ -2236,10 +4139,71 @@ This transaction will consume %n input(s) Aceasta tranzactie va consuma %n din intrariAceasta tranzactie va consuma %n din intrariAceasta tranzactie va consuma %n din intrari + + Warning: Using %1 with %2 or more inputs can harm your privacy and is not recommended + Avertisment: Folosirea %1 cu %2 sau mai multe input-uri poate dăuna confidențialității dvs. și nu este recomandat + + + Click to learn more + Clic pentru a afla mai multe + + + Total Amount + Suma totală + + + or + sau + Confirm send coins Confirmă trimiterea de monede + + Save Transaction Data + Salvează datele tranzacției + + + PSBT saved + PSBT salvat + + + Watch-only balance: + Sold doar-vizualizare: + + + Creates a Partially Signed Blockchain Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet. + Creează o tranzacție blockchain parțial semnată (PSBT) pentru utilizare cu de ex. un portofel %1 offline sau un portofel hardware compatibil PSBT. + + + Do you want to create this transaction? + 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. + Doriți să creați această tranzacție? + + + Please, review your transaction proposal. This will produce a Partially Signed Blockchain Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet. + 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. + Vă rugăm să revizuiți propunerea de tranzacție. Aceasta va produce o Tranzacție Blockchain Parțial Semnată (PSBT) pe care o puteți salva sau copia și apoi semna cu de exemplu un portofel %1 offline sau un portofel hardware compatibil PSBT. + + + Please, review your transaction. You can create and send this transaction or create a Partially Signed Blockchain Transaction (PSBT), which you can save or copy and then sign with, e.g., an offline %1 wallet, or a PSBT-compatible hardware wallet. + 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. + Vă rugăm să revizuiți tranzacția. Puteți crea și trimite această tranzacție sau puteți crea o Tranzacție Blockchain Parțial Semnată (PSBT), pe care o puteți salva sau copia și apoi semna cu, de exemplu, un portofel %1 offline sau un portofel hardware compatibil PSBT. + + + Please, review your transaction. + Text to prompt a user to review the details of the transaction they are attempting to send. + Vă rugăm să revizuiți tranzacția. + + + To review recipient list click "Show Details…" + Pentru a revizui lista destinatarilor faceți clic pe "Arată detalii…" + + + Partially Signed Transaction (Binary) + Expanded name of the binary PSBT file format. See: BIP 174. + Tranzacție parțial semnată (binară) + The recipient address is not valid. Please recheck. Adresa destinatarului nu este validă. Rugăm să reverificaţi. @@ -2335,6 +4299,10 @@ A&mount: Su&mă: + + The amount to send in the selected unit + Suma de trimis în unitatea selectată + The fee will be deducted from the amount being sent. The recipient will receive a lower amount of Dash than you enter in the amount field. If multiple recipients are selected, the fee is split equally. Taxa va fi dedusă din suma trimisă. Destinatarul va primi o sumă mai mică de Dash decât introduci în câmpul pentru suma. Dacă sunt selectați mai mulți destinatari, taxa este împărțită în mod egal. @@ -2343,6 +4311,10 @@ S&ubtract fee from amount S&cade taxa din suma + + Use available balance + Folosește balanța disponibilă + Message: Mesaj: @@ -2351,21 +4323,16 @@ A message that was attached to the dash: URI which will be stored with the transaction for your reference. Note: This message will not be sent over the Dash network. un mesaj a fost ataşat la Dash: URI care va fi stocat cu tranzacţia pentru referinţa dvs. Notă: Acest mesaj nu va fi trimis către reţeaua Dash. + + + SendConfirmationDialog - This is an unauthenticated payment request. - Aceasta este o cerere de plata neautentificata. - - - This is an authenticated payment request. - Aceasta este o cerere de plata autentificata. - - - Pay To: - Plăteşte către: + Send + Trimite - Memo: - Memo: + Create Unsigned + Creează nesemnat @@ -2453,6 +4420,14 @@ The Dash address the message was signed with Introduceţi o adresă Dash + + The signed message to verify + Mesajul semnat de verificat + + + The signature given when the message was signed + Semnătura furnizată când mesajul a fost semnat + Verify the message to ensure it was signed with the specified Dash address Verificaţi mesajul pentru a vă asigura că a fost semnat cu adresa Dash specificată @@ -2465,10 +4440,22 @@ Reset all verify message fields Reseteaza toate spatiile mesajelor semnate. + + Enter a message to be signed + Introduceți un mesaj de semnat + Click "Sign Message" to generate signature Click "Semneaza msajul" pentru a genera semnatura + + Enter a message to be verified + Introduceți un mesaj de verificat + + + Enter a signature for the message to be verified + Introduceți o semnătură pentru mesajul de verificat + The entered address is invalid. Adresa introdusa nu este valida @@ -2485,6 +4472,10 @@ Wallet unlock was cancelled. Blocarea portofelului a fost intrerupta + + No error + Nicio eroare + Private key for the entered address is not available. Cheia privata pentru adresa introdusa nu este valida. @@ -2519,28 +4510,40 @@ - TrafficGraphWidget + SplashScreen + + (press q to shutdown and continue later) + (apăsați q pentru a opri și a continua mai târziu) + - KB/s - KB/s + press q to shutdown + apăsați q pentru a opri - + - TransactionDesc - - Open for %n more block(s) - Deschis pentru %n block în plusDeschis pentru %n block-uri în plusDeschis pentru %n block-uri în plus + TrafficGraphWidget + + kB/s + kB/s - Open until %1 - Deschis până la %1 + Total + Total - conflicted - conflictual + Received + Primit + + + Sent + Trimis + + + TransactionDesc 0/unconfirmed, %1 + 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. 0/neconfirmat, %1 @@ -2553,16 +4556,34 @@ abandoned + 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. Abandonat + + conflicted with a transaction with %1 confirmations + 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. + în conflict cu o tranzacție cu %1 confirmări + %1/unconfirmed + 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, and still not locked via ChainLocks. %1/neconfirmat %1 confirmations + 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 or locked via ChainLocks. %1 confirmări + + locked via ChainLocks + 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 and has been locked by ChainLocks. + blocat prin ChainLocks + + + verified via InstantSend + 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 has been locked by InstantSend. + verificat prin InstantSend + Status Stare @@ -2579,6 +4600,10 @@ Generated Generat + + Platform Transfer + Transfer platformă + From De la @@ -2709,14 +4734,6 @@ Address / Label Adresă / Etichetă - - Open for %n more block(s) - Deschis pentru %n block în plus Deschis pentru %n block-uri în plus Deschis pentru %n block-uri în plus - - - Open until %1 - Deschis până la %1 - Unconfirmed Neconfirmat @@ -2745,6 +4762,14 @@ Generated but not accepted Generat dar neacceptat + + verified via InstantSend + verificat prin InstantSend + + + locked via ChainLocks + blocat prin ChainLocks + Received with Recepţionat cu @@ -2753,6 +4778,10 @@ Received from Primit de la + + Received via %1 + Primit prin %1 + Sent to Trimis către @@ -2765,6 +4794,30 @@ Mined Minat + + Platform Transfer + Transfer platformă + + + %1 Mixing + Amestecare %1 + + + %1 Collateral Payment + Plată colateral %1 + + + %1 Make Collateral Inputs + %1 Creează intrări colaterale + + + %1 Create Denominations + %1 Creează denominații + + + %1 Send + Trimitere %1 + watch-only doar-supraveghere @@ -2844,6 +4897,26 @@ Sent to Trimis către + + %1 Send + Trimitere %1 + + + %1 Make Collateral Inputs + %1 Creează intrări colaterale + + + %1 Create Denominations + %1 Creează denominații + + + %1 Mixing + Amestecare %1 + + + %1 Collateral Payment + Plată colateral %1 + To yourself Către dvs. @@ -2852,54 +4925,80 @@ Mined Minat + + Platform Transfer + Transfer platformă + Other Altele + + Enter address, transaction id, or label to search + Introduceți adresa, ID-ul tranzacției sau eticheta pentru căutare + Min amount Cantitatea minimă - Abandon transaction - Abandoneaza tranzacţia + &Copy address + &Copiază adresa - Copy address - Copiază adresa + Copy &label + Copiază &eticheta - Copy label - Copiază eticheta + Copy &amount + Copiază &suma - Copy amount - Copiază suma + Copy transaction &ID + Copiază &ID-ul tranzacției - Copy transaction ID - Copiază ID tranzacţie + Copy &raw transaction + Copiază tranzacția &brută - Copy raw transaction - Copiază tranzacţia bruta + Copy full transaction &details + Copiază &detaliile complete ale tranzacției - Copy full transaction details - Copiaza toate detaliile tranzacţiei + &Show transaction details + &Arată detaliile tranzacției - Show transaction details - Arată detaliile tranzacţiei + A&bandon transaction + A&bandonează tranzacția - Show address QR code - Afișează codul QR al adresei + Rese&nd transaction + Retri&mite tranzacția + + + &Edit address label + &Editează eticheta adresei + + + Show address &QR code + Arată codul &QR al adresei + + + Show in %1 + 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. + Arată în %1 Export Transaction History Export istoric tranzacţii + + Comma separated file + Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values. + Fișier cu valori separate prin virgulă + Confirmed Confirmat @@ -2966,17 +5065,77 @@ WalletController - + + Close wallet + Închide portofel + + + Are you sure you wish to close the wallet <i>%1</i>? + Sigur doriți să închideți portofelul <i>%1</i>? + + + Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled. + Închiderea portofelului pentru prea mult timp poate duce la necesitatea de a resincroniza întregul lanț dacă reducerea este activată. + + + Close all wallets + Închide toate portofelele + + + Are you sure you wish to close all wallets? + Sigur doriți să închideți toate portofele? + + WalletFrame - + + No wallet has been loaded. +Go to File > Open Wallet to load a wallet. +- OR - + Niciun portofel nu a fost încărcat. +Mergeți la Fișier > Deschide portofel pentru a încărca un portofel. +- SAU - + + + Create a new wallet + Creează un portofel nou + + + Error + Eroare + + + Unable to decode PSBT from clipboard (invalid base64) + Imposibil de decodat PSBT din clipboard (base64 invalid) + + + Load Transaction Data + Încarcă datele tranzacției + + + Partially Signed Transaction (*.psbt) + Tranzacție parțial semnată (*.psbt) + + + PSBT file must be smaller than 100 MiB + Fișierul PSBT trebuie să fie mai mic de 100 MiB + + + Unable to decode PSBT + Imposibil de decodat PSBT + + WalletModel Send Coins Trimite monede - + + default wallet + portofel implicit + + WalletView @@ -2991,6 +5150,11 @@ Selected amount: Suma selectată: + + Wallet Data + Name of the wallet data file format. + Date portofel + Backup Wallet Backup portofelul electronic @@ -3011,12 +5175,16 @@ The wallet data was successfully saved to %1. Datele portofelului s-au salvat cu succes la %1. - + + Cancel + Anulează + + dash-core - Error: Listening for incoming connections failed (listen returned error %s) - Eroare: Ascultarea conexiunilor de intrare nu a reuşit (ascultarea a reurnat eroarea %s) + 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 + Această eroare ar putea apărea dacă acest portofel nu a fost închis corect și a fost încărcat ultima dată folosind o versiune cu o versiune mai nouă de Berkeley DB. Dacă este așa, vă rugăm să folosiți software-ul care a încărcat ultima dată acest portofel This is a pre-release test build - use at your own risk - do not use for mining or merchant applications @@ -3071,20 +5239,40 @@ Eroare la citirea bazei de date. Oprire. - Failed to listen on any port. Use -listen=0 if you want this. - Am esuat ascultarea pe orice port. Folositi -listen=0 daca vreti asta. + Error: Missing checksum + Eroare: Checksum lipsește - -maxtxfee is set very high! Fees this large could be paid on a single transaction. - -maxtxfee este setata foarte sus! Se pot plati taxe de aceasta marime pe o singura tranzactie. + Error: Unable to parse version %u as a uint32_t + Eroare: Imposibil de analizat versiunea %u ca uint32_t + + + Error: Unable to write record to new wallet + Eroare: Imposibil de scris înregistrare în noul portofel + + + Failed to listen on any port. Use -listen=0 if you want this. + Am esuat ascultarea pe orice port. Folositi -listen=0 daca vreti asta. Found unconfirmed denominated outputs, will wait till they confirm to continue. S-au găsit rezultate denominate neconfirmate, vom aștepta până se confirmă continuarea. - Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions) - Sumă nevalidă pentru -maxtxfee=<amount>: '%s' (trebuie să fie cel puţin taxa minrelay de %s pentru a preveni blocarea tranzactiilor) + Invalid -socketevents ('%s') specified. Only these modes are supported: %s + Parametru -socketevents ('%s') invalid. Doar aceste moduri sunt suportate: %s + + + SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is supported + SQLiteDatabase: Versiune schemă portofel sqlite necunoscută %d. Doar versiunea %d este suportată + + + Transaction index can't be disabled with governance validation enabled. Either start with -disablegovernance command line switch or enable transaction index. + Indexul de tranzacții nu poate fi dezactivat cu validarea guvernării activată. Fie porniți cu parametrul -disablegovernance fie activați indexul de tranzacții. + + + Unsupported category-specific logging level -loglevel=%s. Expected -loglevel=<category>:<loglevel>. Valid categories: %s. Valid loglevels: %s. + Nivel de jurnalizare specific categoriei nesuportat -loglevel=%s. Așteptat -loglevel=<category>:<loglevel>. Categorii valide: %s. Loglevels valide: %s. Can't mix: no compatible inputs found! @@ -3094,6 +5282,14 @@ Entry exceeds maximum size. Intrarea depășește dimensiunea maximă. + + Error upgrading evo database for EHF + Eroare la actualizarea bazei de date evo pentru EHF + + + Failed to commit Evo database + Eșec la commit-ul bazei de date Evo + Found enough users, signing ( waiting %s ) S-au găsit suficienți utilizatori, semnând (așteptând %s ) @@ -3118,18 +5314,14 @@ Insufficient funds. Fonduri insuficiente. - - Invalid amount for -discardfee=<amount>: '%s' - Suma nevalidă pentru -discardfee=<amount>: '%s' - - - Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s) - Sumă nevalidă pentru -paytxfee=<suma>: '%s' (trebuie să fie cel puţin %s) - Invalid minimum number of spork signers specified with -minsporkkeys Număr minim de semnatari spork specificat cu -minsporkkeys nu este valabil. + + Listening for incoming connections failed (listen returned error %s) + Ascultarea conexiunilor de intrare a eșuat (listen a returnat eroarea %s) + Lock is already in place. Blocarea este deja în vigoare. @@ -3186,6 +5378,10 @@ Synchronizing governance objects… Sincronizarea obiectelor de guvernare… + + Transaction change output index out of range + Indexul de ieșire pentru rest al tranzacției este în afara intervalului + Unable to start HTTP server. See debug log for details. Imposibil de pornit serverul HTTP. Pentru detalii vezi logul de depanare. @@ -3194,6 +5390,10 @@ Unknown response. Răspuns necunoscut. + + Unsupported global logging level -loglevel=%s. Valid values: %s. + Nivel global de logging nesuportat -loglevel=%s. Valori valide: %s. + User Agent comment (%s) contains unsafe characters. Comentariul (%s) al Agentului Utilizator contine caractere nesigure. @@ -3202,6 +5402,14 @@ Can't find random Masternode. Nu se găseşte un Masternode aleatoariu. + + %s can't be lower than %s + %s nu poate fi mai mic decât %s + + + %s is idle. + %s este inactiv. + Can't mix while sync in progress. Nu se poate amesteca în timp ce sincronizarea este în desfășurare. @@ -3226,6 +5434,10 @@ Make sure to encrypt your wallet and delete all non-encrypted backups after you have verified that the wallet works! Fii sigur sa criptezi portofelul tau si sa stergi toate backup-urile non-criptate dupa ce ai verificat ca portofelul functioneaza! + + More than one onion bind address is provided. Using %s for the automatically created Tor onion service. + Mai mult de o adresă onion bind este furnizată. Se folosește %s pentru serviciul Tor onion creat automat. + Prune configured below the minimum of %d MiB. Please use a higher number. Reductia e configurata sub minimul de %d MiB. Rugam folositi un numar mai mare. @@ -3254,14 +5466,14 @@ Wallet is locked, can't replenish keypool! Automatic backups and mixing are disabled, please unlock your wallet to replenish keypool. Portofelul este blocat, nu poate fi completat keypool-ul! Backupurile automate și amestecarea sunt dezactivate, deblochează portofelul pentru a completa keypool-ul. - - You need to rebuild the database using -reindex to change -timestampindex - Trebuie să reconstruiești baza de date utilizând -reindex pentru a schimba -timestampindex - You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain Trebuie reconstruita intreaga baza de date folosind -reindex pentru a va intoarce la modul non-redus. Aceasta va determina descarcarea din nou a intregului blockchain + + %s failed + %s a eșuat + -maxmempool must be at least %d MB -maxmempool trebuie sa fie macar %d MB @@ -3270,10 +5482,58 @@ Automatic backups disabled Backup-urile automate sunt dezactivate + + Cannot set -peerblockfilters without -blockfilterindex. + Nu se poate seta -peerblockfilters fără -blockfilterindex. + + + Config setting for %s only applied on %s network when in [%s] section. + Setarea de configurare pentru %s este aplicată doar pe rețeaua %s când este în secțiunea [%s]. + + + Could not find asmap file %s + Nu s-a putut găsi fișierul asmap %s + + + Could not parse asmap file %s + Nu s-a putut analiza fișierul asmap %s + ERROR! Failed to create automatic backup EROARE! Backup-ul automat a eșuat + + Error loading %s: Private keys can only be disabled during creation + Eroare la încărcarea %s: Cheile private pot fi dezactivate doar în timpul creării + + + Error: Couldn't create cursor into database + Eroare: Nu s-a putut crea cursor în baza de date + + + Error: Disk space is low for %s + Eroare: Spațiu pe disc scăzut pentru %s + + + Error: Dumpfile checksum does not match. Computed %s, expected %s + Eroare: Checksum-ul fișierului de dump nu se potrivește. Calculat %s, așteptat %s + + + Error: Got key that was not hex: %s + Eroare: Am primit cheie care nu era hex: %s + + + Error: Got value that was not hex: %s + Eroare: S-a primit o valoare care nu este hex: %s + + + Error: Keypool ran out, please call keypoolrefill first + Eroare: Keypool epuizat, vă rugăm să apelați mai întâi keypoolrefill + + + Error: No addresses available. + Eroare: Nicio adresă disponibilă. + Failed to create backup %s! Crearea backup-ului a eșuat %s! @@ -3286,13 +5546,33 @@ Failed to delete backup, error: %s Ștergerea backup-ului a eșuat, eroare: %s + + Failed to rescan the wallet during initialization + Eșec la rescanarea portofelului în timpul inițializării + + + Failed to verify database + Eșec la verificarea bazei de date + + + Fee rate (%s) is lower than the minimum fee rate setting (%s) + Rata de taxă (%s) este mai mică decât setarea minimă de rată de taxă (%s) + Found enough users, signing… S-au găsit suficienți utilizatori, semnând… - Invalid amount for -fallbackfee=<amount>: '%s' - Suma nevalidă pentru -fallbackfee=<amount>: '%s' + Ignoring duplicate -wallet %s. + Se ignoră duplicatul -wallet %s. + + + Input not found or already spent + Input-ul nu a fost găsit sau a fost deja cheltuit + + + Invalid P2P permission: '%s' + Permisiune P2P invalidă: '%s' Invalid masternodeblsprivkey. Please see documentation. @@ -3314,6 +5594,10 @@ Mixing in progress… Amestecare în curs … + + No addresses available + Nicio adresă disponibilă + No errors detected. Nu au fost detectate erori. @@ -3334,14 +5618,54 @@ Prune cannot be configured with a negative value. Reductia nu poate fi configurata cu o valoare negativa. + + Prune mode is incompatible with -disablegovernance=false. + Modul prune este incompatibil cu -disablegovernance=false. + Prune mode is incompatible with -txindex. Modul redus este incompatibil cu -txindex. + + SQLiteDatabase: Failed to execute statement to verify database: %s + SQLiteDatabase: Eșec la executarea instrucțiunii de verificare a bazei de date: %s + + + SQLiteDatabase: Failed to prepare statement to verify database: %s + SQLiteDatabase: Eșec la pregătirea instrucțiunii de verificare a bazei de date: %s + + + SQLiteDatabase: Failed to read database verification error: %s + SQLiteDatabase: Eșec la citirea erorii de verificare a bazei de date: %s + + + SQLiteDatabase: Unexpected application id. Expected %u, got %u + SQLiteDatabase: ID de aplicație neașteptat. Se aștepta %u, s-a primit %u + + + Section [%s] is not recognized. + Secțiunea [%s] nu este recunoscută. + + + Specified -walletdir "%s" does not exist + Directorul -walletdir "%s" specificat nu există + + + Specified -walletdir "%s" is a relative path + Directorul -walletdir "%s" specificat este o cale relativă + + + Specified -walletdir "%s" is not a directory + Directorul -walletdir "%s" specificat nu este un director + The wallet will avoid paying less than the minimum relay fee. Portofelul va evita sa plateasca mai putin decat minimul taxei de retransmisie. + + This is expected because you are running a pruned node. + Acest lucru este așteptat deoarece rulați un nod tăiat (pruned). + This is the minimum transaction fee you pay on every transaction. Acesta este minimum de taxa de tranzactie care va fi platit la fiecare tranzactie. @@ -3350,6 +5674,10 @@ This is the transaction fee you will pay if you send a transaction. Aceasta este taxa de tranzactie pe care o platiti cand trimiteti o tranzactie. + + Topping up keypool… + Se completează keypool… + Transaction amounts must not be negative Sumele tranzactionate nu pot fi negative @@ -3371,8 +5699,24 @@ Nu se poate efectua legatura la %s pe acest computer. %s probabil ruleaza deja. - Upgrading UTXO database - Actualizarea bazei de date UTXO + Unable to create the PID file '%s': %s + Nu se poate crea fișierul PID '%s': %s + + + Unable to generate initial keys + Nu se pot genera cheile inițiale + + + Unable to open %s for writing + Imposibil de deschis %s pentru scriere + + + Unknown -blockfilterindex value %s. + Valoare -blockfilterindex necunoscută %s. + + + Unknown new rules activated (versionbit %i) + Reguli noi necunoscute activate (versionbit %i) Verifying blocks… @@ -3391,16 +5735,12 @@ Nu s-a putut creea un backup folder pentru portofel %s! - You can not start a masternode with wallet enabled. - Nu poți porni un masternode cu portofelul activat. - - - You need to rebuild the database using -reindex to change -addressindex - Trebuie să reconstruiești baza de date utilizând -reindex pentru a schimba -addressindex + Wiping wallet transactions… + Se șterg tranzacțiile portofelului… - You need to rebuild the database using -reindex to change -spentindex - Trebuie să reconstruiești baza de date utilizând -reindex pentru a schimba -spentindex + You can not start a masternode with wallet enabled. + Nu poți porni un masternode cu portofelul activat. no mixing available. @@ -3414,6 +5754,26 @@ The %s developers Dezvoltatorii %s + + %s uses exact denominated amounts to send funds, you might simply need to mix some more coins. + %s folosește sume exact denominate pentru a trimite fonduri, s-ar putea să fie nevoie pur și simplu să amestecați mai multe monede. + + + -reindex-chainstate option is not compatible with -blockfilterindex. Please temporarily disable blockfilterindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes. + Opțiunea -reindex-chainstate nu este compatibilă cu -blockfilterindex. Vă rugăm să dezactivați temporar blockfilterindex în timp ce folosiți -reindex-chainstate, sau înlocuiți -reindex-chainstate cu -reindex pentru a reconstrui complet toate indexurile. + + + -reindex-chainstate option is not compatible with -coinstatsindex. Please temporarily disable coinstatsindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes. + Opțiunea -reindex-chainstate nu este compatibilă cu -coinstatsindex. Vă rugăm să dezactivați temporar coinstatsindex în timp ce folosiți -reindex-chainstate, sau înlocuiți -reindex-chainstate cu -reindex pentru a reconstrui complet toate indexurile. + + + -reindex-chainstate option is not compatible with -txindex. Please temporarily disable txindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes. + Opțiunea -reindex-chainstate nu este compatibilă cu -txindex. Vă rugăm să dezactivați temporar txindex în timp ce folosiți -reindex-chainstate, sau înlocuiți -reindex-chainstate cu -reindex pentru a reconstrui complet toate indexurile. + + + Cannot downgrade wallet from version %i to version %i. Wallet version unchanged. + Nu se poate retrograda portofelul de la versiunea %i la versiunea %i. Versiunea portofelului nemodificată. + Cannot obtain a lock on data directory %s. %s is probably already running. Nu se poate obține o blocare a directorului de date %s. %s probabil rulează deja. @@ -3426,14 +5786,82 @@ Error loading %s: You can't enable HD on an already existing non-HD wallet Eroare la încărcare %s: Nu poți activa HD pe un portofel non-HD deja existent + + 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 + Eroare la încărcarea portofelului. Portofelul necesită descărcarea blocurilor, iar software-ul nu suportă în prezent încărcarea portofelelor în timp ce blocurile sunt descărcate în afara ordinii atunci când se folosesc snapshot-uri assumeutxo. Portofelul ar trebui să se poată încărca cu succes după ce sincronizarea nodului atinge înălțimea %s + Error reading %s! All keys read correctly, but transaction data or address book entries might be missing or incorrect. Eroare la citirea %s! Toate cheile sînt citite corect, dar datele tranzactiei sau anumite intrări din agenda sînt incorecte sau lipsesc. + + Error: Dumpfile format record is incorrect. Got "%s", expected "format". + Eroare: Înregistrarea formatului fișierului dump este incorectă. S-a primit "%s", se aștepta "format". + + + Error: Dumpfile identifier record is incorrect. Got "%s", expected "%s". + Eroare: Înregistrarea identificatorului fișierului dump este incorectă. S-a primit "%s", se aștepta "%s". + + + Error: Dumpfile version is not supported. This version of bitcoin-wallet only supports version 1 dumpfiles. Got dumpfile with version %s + Eroare: Versiunea fișierului dump nu este suportată. Această versiune de bitcoin-wallet suportă doar fișiere dump versiunea 1. S-a primit fișier dump cu versiunea %s + + + Failed to rename invalid peers.dat file. Please move or delete it and try again. + Nu s-a reușit redenumirea fișierului peers.dat invalid. Vă rugăm să îl mutați sau ștergeți și să încercați din nou. + + + Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable %s. + Estimarea taxei a eșuat. Fallbackfee este dezactivată. Așteptați câteva blocuri sau activați %s. + + + File %s already exists. If you are sure this is what you want, move it out of the way first. + Fișierul %s există deja. Dacă sunteți sigur că aceasta este ceea ce doriți, mutați-l mai întâi. + + + Incompatible options: -dnsseed=1 was explicitly specified, but -onlynet forbids connections to IPv4/IPv6 + Opțiuni incompatibile: -dnsseed=1 a fost specificat explicit, dar -onlynet interzice conexiunile către IPv4/IPv6 + Incorrect or no devnet genesis block found. Wrong datadir for devnet specified? Incorect sau nici un block de geneză devnet nu a fost găsit. Datadir greșit pentru specificarea devnet-ului? + + Invalid amount for %s=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions) + Sumă invalidă pentru %s=<amount>: '%s' (trebuie să fie cel puțin taxa minrelay de %s pentru a preveni tranzacții blocate) + + + 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. + Fișier peers.dat invalid sau corupt (%s). Dacă credeți că este un bug, vă rugăm să îl raportați la %s. Ca soluție de rezolvare, puteți muta fișierul (%s) din cale (redenumire, mutare sau ștergere) pentru a avea unul nou creat la următoarea pornire. + + + No dump file provided. To use createfromdump, -dumpfile=<filename> must be provided. + Niciun fișier dump furnizat. Pentru a folosi createfromdump, trebuie furnizat -dumpfile=<filename>. + + + No dump file provided. To use dump, -dumpfile=<filename> must be provided. + Niciun fișier dump furnizat. Pentru a folosi dump, trebuie furnizat -dumpfile=<filename>. + + + No wallet file format provided. To use createfromdump, -format=<format> must be provided. + Niciun format de fișier portofel furnizat. Pentru a folosi createfromdump, trebuie furnizat -format=<format>. + + + Outbound connections restricted to CJDNS (-onlynet=cjdns) but -cjdnsreachable is not provided + Conexiuni de ieșire restricționate la CJDNS (-onlynet=cjdns) dar -cjdnsreachable nu este furnizat + + + Outbound connections restricted to Tor (-onlynet=onion) but the proxy for reaching the Tor network is explicitly forbidden: -onion=0 + Conexiuni de ieșire restricționate la Tor (-onlynet=onion) dar proxy-ul pentru accesarea rețelei Tor este interzis explicit: -onion=0 + + + 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 + Conexiuni de ieșire restricționate la Tor (-onlynet=onion) dar proxy-ul pentru accesarea rețelei Tor nu este furnizat: niciuna dintre -proxy, -onion sau -listenonion nu este furnizată + + + Outbound connections restricted to i2p (-onlynet=i2p) but -i2psam is not provided + Conexiuni de ieșire restricționate la i2p (-onlynet=i2p) dar -i2psam nu este furnizat + Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly. Vă rugăm verificaţi dacă data/timpul calculatorului dvs. sînt corecte! Dacă ceasul calcultorului este gresit, %s nu va funcţiona corect. @@ -3442,6 +5870,14 @@ Please contribute if you find %s useful. Visit %s for further information about the software. Va rugam sa contribuiti daca apreciati ca %s va este util. Vizitati %s pentru mai multe informatii despre software. + + Prune mode is incompatible with -reindex-chainstate. Use full -reindex instead. + Modul prune este incompatibil cu -reindex-chainstate. Folosiți -reindex complet în schimb. + + + This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection. + Aceasta este taxa maximă de tranzacție pe care o plătiți (în plus față de taxa normală) pentru a prioritiza evitarea cheltuirii parțiale față de selecția obișnuită a monedelor. + This is the transaction fee you may discard if change is smaller than dust at this level Aceasta este taxa de tranzacție pe care o puteți elimina dacă schimbarea este mai mică decât dust la acest nivel @@ -3450,10 +5886,38 @@ This is the transaction fee you may pay when fee estimates are not available. Aceasta este taxa de tranzactie pe care este posibil sa o platiti daca estimarile de taxe nu sunt disponibile. + + Transaction requires one destination of non-0 value, a non-0 feerate, or a pre-selected input + Tranzacția necesită o destinație cu valoare diferită de 0, un feerate diferit de 0, sau un input pre-selectat + Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate. Imposibil de redat block-urile. Va trebui să reconstruiți baza de date folosind -reindex-chainstate. + + Unknown wallet file format "%s" provided. Please provide one of "bdb" or "sqlite". + Format de fișier portofel necunoscut "%s" furnizat. Vă rugăm să furnizați unul dintre "bdb" sau "sqlite". + + + Unsupported chainstate database format found. Please restart with -reindex-chainstate. This will rebuild the chainstate database. + Format de bază de date chainstate nesuportat găsit. Vă rugăm să reporniți cu -reindex-chainstate. Acest lucru va reconstrui baza de date chainstate. + + + Warning: Dumpfile wallet format "%s" does not match command line specified format "%s". + Avertisment: Formatul portofelului fișierului dump "%s" nu se potrivește cu formatul specificat în linia de comandă "%s". + + + Warning: Private keys detected in wallet {%s} with disabled private keys + Avertisment: Chei private detectate în portofelul {%s} cu chei private dezactivate + + + You need to rebuild the database using -reindex to enable -timestampindex + Trebuie să reconstruiți baza de date folosind -reindex pentru a activa -timestampindex + + + %s -- Incorrect seed, it should be a hex string + %s -- Sămânță incorectă, ar trebui să fie un string hex + %s is not a valid backup folder! %s nu este un folder de backup valid! @@ -3462,6 +5926,10 @@ %s is set very high! %s este setata foarte sus! + + %s request incomplete: + Cerere %s incompletă: + -devnet can only be specified once -devnet poate fi specificat o singură dată @@ -3474,18 +5942,54 @@ -rpcport must be specified when -devnet and -server are specified -rpcport trebuie specificat când -devnet și -server sunt specificate + + -statsbatchsize cannot be configured with a negative value. + -statsbatchsize nu poate fi configurat cu o valoare negativă. + + + -statsduration cannot be configured with a negative value. + -statsduration nu poate fi configurat cu o valoare negativă. + + + A fatal internal error occurred, see debug.log for details + A apărut o eroare internă fatală, vezi debug.log pentru detalii + + + Cannot create socket (socket() returned error %s) + Nu se poate crea socket (socket() a returnat eroarea %s) + + + Cannot get socket address for %s + Nu se poate obține adresa socket pentru %s + + + Cannot init Statsd client + Nu se poate inițializa clientul Statsd + Cannot resolve -%s address: '%s' Nu se poate rezolva adresa -%s: '%s' - Change index out of range - Indexul de schimbare este iesit din parametrii + Cannot write to data directory '%s'; check permissions. + Nu se poate scrie în directorul de date '%s'; verificați permisiunile. Copyright (C) Copyright (C) + + Disk space is too low! + Spațiul pe disc este prea mic! + + + Dump file %s does not exist. + Fișierul dump %s nu există. + + + Error creating %s + Eroare la crearea %s + Error loading %s Eroare la încărcarea %s @@ -3503,8 +6007,8 @@ Eroare la încărcare %s: Nu poți dezactiva HD pe un portofel HD deja existent - Error upgrading chainstate database - Eroare la actualizarea bazei de date chainstate + Error reading next record from wallet database + Eroare la citirea înregistrării următoare din baza de date a portofelului Loading P2P addresses… @@ -3522,10 +6026,38 @@ Loading wallet… Încarc portofel… + + Failed to clear fulfilled requests cache at %s + Eșec la ștergerea cache-ului de cereri îndeplinite la %s + + + Failed to clear governance cache at %s + Eșec la ștergerea cache-ului de guvernare la %s + + + Failed to clear masternode cache at %s + Eșec la ștergerea cache-ului de masternode la %s + Failed to find mixing queue to join Nu a reușit să găsească și să se alăture unui nou queue de amestecare + + Failed to load fulfilled requests cache from %s + Eșec la încărcarea cache-ului de cereri îndeplinite de la %s + + + Failed to load governance cache from %s + Eșec la încărcarea cache-ului de guvernare de la %s + + + Failed to load masternode cache from %s + Eșec la încărcarea cache-ului de masternode de la %s + + + Failed to load sporks cache from %s + Eșec la încărcarea cache-ului de sporks de la %s + Failed to start a new mixing queue Nu a reușit să pornească un nou queue de amestecare @@ -3534,6 +6066,10 @@ Importing… Import… + + Incorrect -rescan mode, falling back to default value + Mod -rescan incorect, se revine la valoarea implicită + Initialization sanity check failed. %s is shutting down. Nu s-a reuşit iniţierea verificării sănătăţii. %s se inchide. @@ -3542,6 +6078,14 @@ Inputs vs outputs size mismatch. Nepotriviri în mărime între intrări și ieșiri. + + Invalid '%s'. Allowed values: 128, 160, 192, 224, 256. + Invalid '%s'. Valori permise: 128, 160, 192, 224, 256. + + + Invalid -i2psam address or hostname: '%s' + Adresă -i2psam sau hostname invalid: '%s' + Invalid -onion address or hostname: '%s' Adresa sau hostname -onion invalide: '%s' @@ -3574,10 +6118,90 @@ Signing transaction failed Nu s-a reuşit semnarea tranzacţiei + + Specified blocks directory "%s" does not exist. + Directorul de blocuri specificat "%s" nu există. + + + Last queue was created too recently. + Ultima coadă a fost creată prea recent. + + + %s corrupt. Try using the wallet tool dash-wallet to salvage or restoring a backup. + %s corupt. Încercați să folosiți instrumentul portofel dash-wallet pentru a salva sau a restaura o copie de siguranță. + + + %s is set very high! Fees this large could be paid on a single transaction. + %s este setat foarte mare! Taxe atât de mari ar putea fi plătite pe o singură tranzacție. + + + %s request to listen on port %u. This port is considered "bad" and thus it is unlikely that any Dash Core peers connect to it. See doc/p2p-bad-ports.md for details and a full list. + %s cere ascultarea pe portul %u. Acest port este considerat "rău" și astfel este puțin probabil ca vreun peer Dash Core să se conecteze la el. Vezi doc/p2p-bad-ports.md pentru detalii și o listă completă. + + + Cannot provide specific connections and have addrman find outgoing connections at the same time. + Nu se pot furniza conexiuni specifice și să aibă addrman să găsească conexiuni de ieșire în același timp. + + + Failed to upgrade Evo database + Eșec la actualizarea bazei de date Evo + + + Fee needed > fee paid + Taxa necesară > taxa plătită + + + Host %s on unsupported network + Host %s pe rețea nesuportată + + + Invalid amount for %s=<amount>: '%s' (must be at least %s) + Sumă invalidă pentru %s=<amount>: '%s' (trebuie să fie cel puțin %s) + + + Invalid amount for %s=<amount>: '%s' + Sumă invalidă pentru %s=<amount>: '%s' + + + Invalid port specified in %s: '%s' + Port invalid specificat în %s: '%s' + + + Last successful action was too recent. + Ultima acțiune reușită a fost prea recentă. + + + Missing solving data for estimating transaction size + Date de rezolvare lipsă pentru estimarea dimensiunii tranzacției + + + No host specified + Niciun host specificat + + + No host specified, malformed URL + Niciun host specificat, URL malformat + + + No text before the scheme delimiter, malformed URL + Niciun text înainte de delimitatorul de schemă, URL malformat + + + Port must be between %d and %d, supplied %d + Portul trebuie să fie între %d și %d, furnizat %d + + + Socket not initialized, cannot send message + Socket-ul nu este inițializat, nu se poate trimite mesajul + The source code is available from %s. Codul sursa este disponibil la %s. + + The specified config file %s does not exist + Fișierul de configurare specificat %s nu există + The transaction amount is too small to pay the fee Suma tranzactiei este prea mica pentru plata taxei @@ -3598,6 +6222,10 @@ Transaction fees are too high. Taxele de tranzacție sunt prea mari. + + Transaction needs a change address, but we can't generate it. + Tranzacția necesită o adresă de rest, dar nu o putem genera. + Transaction not valid. Tranzacția nu este validă. @@ -3610,6 +6238,26 @@ Unable to bind to %s on this computer (bind returned error %s) Nu se poate lega la %s pe acest calculator. (Legarea a întors eroarea %s) + + Unable to locate enough mixed funds for this transaction. + Imposibil de localizat suficiente fonduri amestecate pentru această tranzacție. + + + Unable to locate enough non-denominated funds for this transaction. + Imposibil de localizat suficiente fonduri ne-denominate pentru această tranzacție. + + + Unable to lookup host %s + Imposibil de găsit host-ul %s + + + Unable to parse -maxuploadtarget: '%s' + Imposibil de analizat -maxuploadtarget: '%s' + + + Unable to send message to %s (::sendto() returned error %s) + Imposibil de trimis mesaj către %s (::sendto() a returnat eroarea %s) + Unable to sign spork message, wrong key? Imposibil de semnat mesajul spork, cheia greșită? @@ -3622,6 +6270,10 @@ Unknown state: id = %u Status necunoscut: id = %u + + Unsupported URL scheme, must begin with udp:// + Schemă URL nesuportată, trebuie să înceapă cu udp:// + Unsupported logging category %s=%s. Categorie de înregistrare neacceptată %s=%s. @@ -3634,13 +6286,45 @@ Wallet is locked. Portofel blocat. + + Warning: can't use %s and %s together, will prefer %s + Avertisment: nu se pot folosi %s și %s împreună, se va prefera %s + + + Warning: incorrect parameter %s, path must exist! Using default path. + Avertisment: parametru incorect %s, calea trebuie să existe! Se folosește calea implicită. + Will retry… Se va reîncerca… + + You are starting with governance validation disabled. + Porniți cu validarea guvernării dezactivată. + + + You can not disable governance validation on a masternode. + Nu puteți dezactiva validarea guvernării pe un masternode. + + + You need to rebuild the database using -reindex to enable -addressindex + Trebuie să reconstruiți baza de date folosind -reindex pentru a activa -addressindex + + + You need to rebuild the database using -reindex to enable -spentindex + Trebuie să reconstruiți baza de date folosind -reindex pentru a activa -spentindex + Your entries added successfully. Intrările tale au fost adăugate cu succes. + + Settings file could not be read + Fișierul de setări nu a putut fi citit + + + Settings file could not be written + Fișierul de setări nu a putut fi scris + \ No newline at end of file diff --git a/src/qt/locale/dash_ru.ts b/src/qt/locale/dash_ru.ts index 2fb7a706af2a..76dcb8119ce4 100644 --- a/src/qt/locale/dash_ru.ts +++ b/src/qt/locale/dash_ru.ts @@ -65,14 +65,6 @@ C&hoose &Выбрать - - Sending addresses - Адреса отправки - - - Receiving addresses - Адреса получения - These are your Dash addresses for sending payments. Always check the amount and the receiving address before sending coins. Это ваши адреса Dash для отправки платежей. Всегда проверяйте количество и адрес получателя перед отправкой перевода. @@ -115,6 +107,14 @@ An error message. %1 is a stand-in argument for the name of the file we attempted to save to. Произошла ошибка при сохранении адресной книги в %1. Пожалуйста, попробуйте еще раз. + + Sending addresses - %1 + Адреса отправки - %1 + + + Receiving addresses - %1 + Адреса получения - %1 + Exporting Failed Экспорт не удался @@ -282,12 +282,24 @@ The passphrase entered for the wallet decryption was incorrect. - Указанный пароль не подходит. + Введённая парольная фраза для расшифровки кошелька неверна. + + + 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 23.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. + Введённая парольная фраза для расшифровки кошелька неверна. Она содержит нулевой символ (т.е. нулевой байт). Если парольная фраза была установлена в версии этого программного обеспечения до 23.0, попробуйте еще раз, используя только символы до первого нулевого символа, не включая его. Если это сработает, установите новую парольную фразу, чтобы избежать этой проблемы в будущем. Wallet passphrase was successfully changed. Пароль кошелька успешно изменён. + + Passphrase change failed + Не удалось сменить пароль + + + 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 23.0, please try again with only the characters up to — but not including — the first null character. + Введённая старая парольная фраза для расшифровки кошелька неверна. Она содержит нулевой символ (т.е. нулевой байт). Если парольная фраза была установлена в версии этого программного обеспечения до 23.0, попробуйте еще раз, используя только символы до первого нулевого символа, не включая его. + Warning: The Caps Lock key is on! Внимание: включен Caps Lock! @@ -392,10 +404,6 @@ &Load PSBT from file… &Загрузить PSBT из файла… - - Load PSBT from clipboard… - Загрузить PSBT из буфера обмена… - &Sending addresses Адреса &отправки @@ -428,10 +436,6 @@ &Window &Окно - - Minimize - Свернуть - Zoom Увеличить @@ -484,14 +488,6 @@ Modify configuration options for %1 Изменить параметры конфигурации %1 - - &Show / Hide - &Показать / Скрыть - - - Show or hide the main Window - Показать или скрыть главное окно - Encrypt the private keys that belong to your wallet Зашифровать закрытые ключи, содержащиеся в вашем кошельке @@ -556,10 +552,6 @@ Show wallet repair options Показать варианты ремонта кошелька - - Open Wallet &Configuration File - Открыть файл &настроек кошелька - Open configuration file Открыть файл настроек @@ -614,10 +606,18 @@ Show information about %1 Показать информацию о %1 + + Load PSBT from &clipboard… + Загрузить PSBT из &буфера обмена… + Open debugging and diagnostic console Открыть консоль отладки и диагностики + + Open &wallet configuration file + Открыть файл &настроек кошелька + Open a dash: URI Открыть dash: URI @@ -626,6 +626,16 @@ Create a new wallet Создать новый кошелёк + + Restore Wallet… + Name of the menu item that restores wallet from a backup file. + Восстановить кошелёк… + + + Restore a wallet from a backup file + Status tip for Restore Wallet menu item + Восстановить кошелёк из резервной копии + Close all wallets Закрыть все кошельки @@ -646,10 +656,34 @@ Mask the values in the Overview tab Скрыть суммы на вкладке Обзор + + Wallet Data + Name of the wallet data file format. + Данные кошелька + + + Load Wallet Backup + The title for Restore Wallet File Windows + Загрузить кошелёк из резервной копии + + + Restore Wallet + Title of pop-up window shown when the user is attempting to restore a wallet. + Восстановить кошелёк + + + Wallet Name + Label of the input field where the name of the wallet is entered. + Имя кошелька + &Settings &Настройки + + &Minimize + &Свернуть + &Help &Помощь @@ -666,6 +700,14 @@ View Governance Proposals Посмотреть предложения по Управлению + + &Hide + С&крыть + + + S&how + &Показать + %n active connection(s) to Dash network A substring of the tooltip. @@ -747,10 +789,6 @@ Processing blocks on disk… Обработка блоков на диске… - - Reindexing blocks on disk… - Идёт переиндексация блоков на диске… - Connecting to peers… Подключение к пирам… @@ -904,10 +942,6 @@ Coin Selection Выбор монет - - Dust: - Пыль: - After Fee: После комиссии: @@ -1008,10 +1042,6 @@ Copy bytes Копировать байты - - Copy dust - Скопировать пыль - Copy change Копировать сдачу @@ -1024,18 +1054,6 @@ (%1 locked) (%1 заблокировано) - - yes - да - - - no - нет - - - This label turns red if any recipient receives an amount smaller than the current dust threshold. - Эта метка становится красной, если какой-либо из адресатов получает сумму меньше, чем "пыль". - Can vary +/- %1 duff(s) per input. Может отличаться на +/- %1 duff(ов) на каждый вход. @@ -1249,18 +1267,102 @@ Filter proposal list Фильтровать список предложений + + Masternode Count: + Количество мастернод: + + + Number of masternodes this wallet can vote with (masternodes for which this wallet holds the voting key) + Количество мастернод, с которыми этот кошелек может голосовать (мастерноды, для которых этот кошелек хранит ключ для голосования) + Proposal Count: Количество предложений: + + Create Proposal + Создать предложение + Filter by Title - Сортировать по названию + Фильтровать по названию + + + Unavailable + Недоступно + + + A synced node and an unlocked wallet are required. + Требуется синхронизированная нода и разблокированный кошелек. + + + Vote Yes + Голосовать За + + + Vote No + Голосовать Против + + + Vote Abstain + Голосовать Воздержался Proposal Info: %1 Информация о предложении: %1 + + Voting Failed + Голосование не удалось + + + No wallet available. + Нет доступного кошелька + + + No masternode voting keys found in wallet. + Ключи для голосования мастернод не найдены в кошельке. + + + Please select a proposal to vote on. + Пожалуйста, выберите предложение для голосования. + + + Unable to unlock wallet. + Не удается разблокировать кошелёк. + + + Unable to get masternode list. Please try again later. + Невозможно получить список мастернод. Пожалуйста, попробуйте позже. + + + Masternode %1 not found + Мастернода %1 не найдена + + + Failed to sign vote for masternode %1 + Ошибка подписи голоса за мастерноду %1 + + + Masternode %1: %2 + Мастернода %1: %2 + + + Voted successfully %n time(s) + Проголосовано успешно %n разПроголосовано успешно %n разаПроголосовано успешно %n разПроголосовано успешно %n раз + + + Failed to vote %n time(s) + Не удалось проголосовать %n разНе удалось проголосовать %n разаНе удалось проголосовать %n разНе удалось проголосовать %n раз + + + Errors: + Ошибки: + + + Voting Results + Результаты голосования + HelpMessageDialog @@ -1331,17 +1433,17 @@ Use a custom data directory: Использовать другой каталог данных: - - %1 GB of space available - доступно %1 ГБ + + %n GB of space available + Доступно %n ГБДоступно %n ГБДоступно %n ГБДоступно %n ГБ - - (of %1 GB needed) - (из требующихся %1 ГБ) + + (of %n GB needed) + (из требующихся %n ГБ)(из требующихся %n ГБ)(из требующихся %n ГБ)(из требующихся %n ГБ) - - (%1 GB needed for full chain) - (из %1 ГБ, требующихся для полной цепочки блоков) + + (%n GB needed for full chain) + (для полной цепочки блоков требуется %n ГБ)(для полной цепочки блоков требуется %n ГБ)(для полной цепочки блоков требуется %n ГБ)(для полной цепочки блоков требуется %n ГБ) At least %1 GB of data will be stored in this directory, and it will grow over time. @@ -1373,6 +1475,13 @@ Ошибка + + LoadWalletsActivity + + Loading wallets… + Загрузка кошельков… + + MasternodeList @@ -1565,6 +1674,11 @@ URI: URI: + + Paste address from clipboard + Tooltip text for button that allows you to paste an address that is in your clipboard. + Вставить адрес из буфера обмена + OpenWalletActivity @@ -1675,6 +1789,16 @@ An Options window setting to set subtracting the fee from a sending amount as default. Вычесть &комиссию из суммы по умолчанию + + Enable &PSBT controls + An options window setting to enable PSBT controls. + Включить функции работы с &PSBT + + + Whether to show PSBT controls. + Tooltip text for options window setting that enables PSBT controls. + Показывать ли кнопки для работы с PSBT или нет. + Whether to keep the specified custom change address or not. Сохранять указанный свой адрес для сдачи или нет. @@ -1818,20 +1942,20 @@ https://explore.transifex.com/dash/dash/ https://explore.transifex.com/dash/dash/ - Options set in this dialog are overridden by the command line or in the configuration file: - Настройки, указанные в этом диалоге, перекрываются командной строкой либо файлом настроек: + Third-party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items.<br/>%s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |. + Сторонние URL (например, block explorer), которые отображаются на вкладке транзакций как пункты контекстного меню.<br/>%s в URL заменяется хешем транзакции. URL отделяются друг от друга вертикальной чертой |. - 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. - Сворачивать вместо закрытия. Если данная настройка будет выбрана, то приложение закроется только после выбора пункта меню Завершить. + &Third-party transaction URLs + &Сторонние URL для транзакций - Third party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items.<br/>%s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |. - Сторонние URL (например, block explorer), которые отображаются на вкладке транзакций как пункты контекстного меню.<br/>%s в URL заменяется хешем транзакции. URL отделяются друг от друга вертикальной чертой |. + Options set in this dialog are overridden by the command line or in the configuration file: + Настройки, указанные в этом диалоге, перекрываются командной строкой либо файлом настроек: - &Third party transaction URLs - &Сторонние URL для транзакций + 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. + Сворачивать вместо закрытия. Если данная настройка будет выбрана, то приложение закроется только после выбора пункта меню Завершить. Whether to show coin control features or not. @@ -1975,14 +2099,22 @@ https://explore.transifex.com/dash/dash/ Confirm options reset + Window title text of pop-up window shown when the user has chosen to reset options. Подтвердите сброс настроек Client restart required to activate changes. + Text explaining that the settings changed will not come into effect until the client is restarted. Для применения изменений требуется перезапуск клиента. + + Current settings will be backed up at "%1". + 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. + Текущие настройки будут сохранены в "%1". + Client will be shut down. Do you want to proceed? + Text asking the user to confirm if they would like to proceed with a client shutdown. Клиент будет выключен. Продолжить? @@ -2503,6 +2635,181 @@ Due to discontinued support, you should request the merchant to provide you with Статус + + ProposalWizard + + Create Governance Proposal + Создать предложение по Управлению + + + Enter proposal details + Введите сведения о предложении + + + A fee will be burned when you prepare the proposal. + При подготовке предложения будет сожжена комиссия. + + + Proposal &name + &Название предложения + + + &Description URL + &Ссылка с описанием + + + Payment &address + &Адрес оплаты + + + Payment &amount + Сумма &оплаты + + + The amount to request in a single payment + Сумма для запроса в одном платеже + + + &First payment + &Первый платёж + + + Pa&yments + П&латежи + + + To&tal amount + По&лная сумма + + + Proposal &fee + Ко&миссия + + + Next + Дальше + + + Review proposal JSON and validate. + Просмотрите JSON предложения и проверьте. + + + Hex-encoded JSON + JSON в шестнадцатеричной кодировке + + + Back + Назад + + + Validate + Проверить + + + Prepare (burn fee) and wait for confirmations. + Подготовьте (сожгите комиссию) и ждите подтверждений. + + + Copy + &Копировать + + + At 1/6 confirmations: can be relayed and queued. At 6/6: accepted and processed. + При 1/6 подтверждениях: может быть передано и поставлено в очередь. При 6/6: принято и обработано. + + + Confirmations progress + Прогресс подтверждения: + + + Shows progress toward the required number of confirmations for the proposal fee transaction. + Показывает прогресс к необходимому количеству подтверждений для транзакции комиссии предложения. + + + Estimated time remaining: - + Оставшееся время, приблизительно: - + + + Prepare Proposal + Подготовить предложение + + + You can submit after 1 confirmation. At 6 confirmations it is accepted and processed. + Вы можете отправить после 1 подтверждения. При 6 подтверждениях оно принимается и обрабатывается. + + + Proposal ID: + ID предложения: + + + Submit Proposal + Отправить предложение + + + Close + Закрыть + + + Valid + Действительно + + + Invalid: %1 + Недействительно: %1 + + + Burn %1 + Сжечь %1 + + + Burn %1 to create the fee transaction? + Сжечь %1 для создания транзакции комиссии? + + + Prepare failed + Не удалось подготовить + + + Confirmations: %1 / %2 required + Подтверждения: %1 / %2 необходимых + + + Estimated time remaining: Ready + Оставшееся время, приблизительно: готово + + + Estimated time remaining: %n minute(s) + Оставшееся время, приблизительно: %n минутаОставшееся время, приблизительно: %n минутыОставшееся время, приблизительно: %n минутОставшееся время, приблизительно: %n минут + + + Your proposal was submitted successfully. + Ваше предложение успешно отправлено. + + + Already submitted + Уже отправлено + + + This proposal has already been submitted. + Это предложение уже отправлено. + + + Submission failed + Отправка предложения закончилась неудачно + + + Proposal submitted + Предложение отправлено + + + A fee of %1 will be burned when you prepare the proposal. + При подготовке предложения будет сожжена комиссия %1. + + + Prepare (burn %1) and wait for %2 confirmations. + Подготовьте (сожгите %1) и ждите %2 подтверждений. + + QObject @@ -2557,7 +2864,7 @@ Due to discontinued support, you should request the merchant to provide you with Error: Cannot parse configuration file: %1. - Ошибка: не могу прочитать файл настроек: %1. + Ошибка: не могу разобрать файл настроек: %1. Error: %1 @@ -2892,14 +3199,6 @@ Due to discontinued support, you should request the merchant to provide you with Version Версия - - Whether the peer requested us to relay transactions. - Запрашивал ли пир ретрансляцию транзакций. - - - Wants Tx Relay - Хочет ретрансляцию Tx - High bandwidth BIP152 compact block relay: %1 Компактное блочное реле BIP152 с высокой пропускной способностью: %1 @@ -3005,6 +3304,14 @@ Due to discontinued support, you should request the merchant to provide you with To specify a non-default location of the blocks directory use the '%1' option. Чтобы указать нестандартное расположение папки с блоками, используйте опцию '%1'. + + Local Addresses + Локальные адреса + + + Network addresses that your Dash node is currently using to communicate with other nodes. + Сетевые адреса, которые ваша нода Dash в настоящее время использует для связи с другими нодами. + Number of regular Masternodes Количество обычных Мастернод @@ -3097,6 +3404,14 @@ Due to discontinued support, you should request the merchant to provide you with Services Сервисы + + Whether we relay transactions to this peer. + Будем ли мы передавать транзакции этому пиру. + + + Transaction Relay + Пересылка транзакций + Connection Time Время соединения @@ -3245,6 +3560,10 @@ Due to discontinued support, you should request the merchant to provide you with Network activity disabled Сетевая активность отключена + + None + Нет + Total: %1 (Enabled: %2) Всего: %1 (Активных: %2) @@ -3566,6 +3885,34 @@ For more information on using this console, type %6. Запрошено + + RestoreWalletActivity + + Restore Wallet + Title of progress window which is displayed when wallets are being restored. + Восстановить кошелёк + + + Restoring Wallet <b>%1</b>… + Descriptive text of the restore wallets progress window which indicates to the user that wallets are currently being restored. + Восстанавливается кошелёк<b>%1</b>… + + + Restore wallet failed + Title of message box which is displayed when the wallet could not be restored. + Не удалось восстановить кошелёк + + + Restore wallet warning + Title of message box which is displayed when the wallet is restored with some warning. + Предупреждение при восстановлении кошелька + + + Restore wallet message + Title of message box which is displayed when the wallet is successfully restored. + Сообщение при восстановлении кошелька + + SendCoinsDialog @@ -3600,10 +3947,6 @@ For more information on using this console, type %6. Fee: Комиссия: - - Dust: - Пыль: - Inputs… Входы… @@ -3728,10 +4071,6 @@ For more information on using this console, type %6. Copy bytes Копировать байты - - Copy dust - Скопировать пыль - Copy change Копировать сдачу @@ -3740,10 +4079,6 @@ For more information on using this console, type %6. %1 (%2 blocks) %1 (блоков: %2) - - This will produce a Partially Signed Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet. - В результате будет создана частично подписанная транзакция (PSBT), которую можно сохранить или скопировать и затем подписать, например, на офлайн-кошельке %1 или на аппаратном кошельке, совместимом с PSBT. - using используя @@ -3752,10 +4087,6 @@ For more information on using this console, type %6. %1 to %2 %1 на %2 - - Are you sure you want to send? - Вы уверены, что хотите отправить? - <b>(%1 of %2 entries displayed)</b> <b>(показано записей: %1 из %2)</b> @@ -3780,10 +4111,6 @@ For more information on using this console, type %6. %1 to '%2' %1 на '%2' - - Do you want to draft this transaction? - Вы хотите создать шаблон данной транзакции? - %1 funds only только средства %1 @@ -3832,14 +4159,6 @@ For more information on using this console, type %6. Confirm send coins Подтвердите отправку монет - - Confirm transaction proposal - Подтвердить предложение по сделке - - - Create Unsigned - Создать неподписанную - Save Transaction Data Сохранить данные транзакции @@ -3852,14 +4171,30 @@ For more information on using this console, type %6. Watch-only balance: Баланс только для просмотра: - - Send - Отправить - Creates a Partially Signed Blockchain Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet. Создает частично подписанную блокчейн транзакцию (PSBT) для использования, например, с автономным кошельком %1 или аппаратным кошельком, совместимым с PSBT. + + Do you want to create this transaction? + 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. + Вы хотите создать данную транзакцию? + + + Please, review your transaction proposal. This will produce a Partially Signed Blockchain Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet. + 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. + Пожалуйста, проверьте ваше предложение транзакции. Это создаст частично подписанную блокчейн-транзакцию (PSBT), которую вы можете сохранить или скопировать, а затем подписать, например, с помощью оффлайн-кошелька %1 или аппаратного кошелька, совместимого с PSBT. + + + Please, review your transaction. You can create and send this transaction or create a Partially Signed Blockchain Transaction (PSBT), which you can save or copy and then sign with, e.g., an offline %1 wallet, or a PSBT-compatible hardware wallet. + 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. + Пожалуйста, проверьте вашу транзакцию. Вы можете создать и отправить эту транзакцию или создать частично подписанную блокчейн-транзакцию (PSBT), которую вы можете сохранить или скопировать, а затем подписать, например, с помощью оффлайн-кошелька %1 или аппаратного кошелька, совместимого с PSBT. + + + Please, review your transaction. + Text to prompt a user to review the details of the transaction they are attempting to send. + Пожалуйста, проверьте вашу транзакцию. + To review recipient list click "Show Details…" Для просмотра списка получателей нажмите кнопку "Show Details…". @@ -3988,21 +4323,16 @@ For more information on using this console, type %6. A message that was attached to the dash: URI which will be stored with the transaction for your reference. Note: This message will not be sent over the Dash network. К dash: URI было прикреплено сообщение, которое будет сохранено вместе с транзакцией для вашего сведения. Обратите внимание: сообщение не будет отправлено через сеть Dash. + + + SendConfirmationDialog - This is an unauthenticated payment request. - Этот запрос платежа неаутентифицирован. - - - This is an authenticated payment request. - Этот запрос платежа аутентифицирован. - - - Pay To: - Получатель: + Send + Отправить - Memo: - Примечание: + Create Unsigned + Создать неподписанную @@ -4211,20 +4541,9 @@ For more information on using this console, type %6. TransactionDesc - - Open for %n more block(s) - Будет открыто ещё %n блокБудет открыто ещё %n блокаБудет открыто ещё %n блоковБудет открыто ещё %n блоков - - - Open until %1 - Открыто до %1 - - - conflicted - в противоречии - 0/unconfirmed, %1 + 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. 0/не подтверждено, %1 @@ -4237,22 +4556,32 @@ For more information on using this console, type %6. abandoned + 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. сброшена + + conflicted with a transaction with %1 confirmations + 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. + конфликт с транзакцией с %1 подтверждениями + %1/unconfirmed + 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, and still not locked via ChainLocks. %1/не подтверждено %1 confirmations + 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 or locked via ChainLocks. %1 подтверждений locked via ChainLocks + 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 and has been locked by ChainLocks. зафиксировано с помощью ChainLocks verified via InstantSend + 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 has been locked by InstantSend. проверено с помощью InstantSend @@ -4405,14 +4734,6 @@ For more information on using this console, type %6. Address / Label Адрес / Метка - - Open for %n more block(s) - Будет открыто ещё %n блокБудет открыто ещё %n блокаБудет открыто ещё %n блоковБудет открыто ещё %n блоков - - - Open until %1 - Открыто до %1 - Unconfirmed Неподтверждено @@ -4664,6 +4985,11 @@ For more information on using this console, type %6. Show address &QR code Показать QR-&код адреса + + Show in %1 + 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. + Показать в %1 + Export Transaction History Экспортировать историю транзакций @@ -4856,10 +5182,6 @@ Go to File > Open Wallet to load a wallet. dash-core - - Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee. - Расчет комиссии невозможен. Комиссия по умолчанию не установлена. подождите пару блоков либо укажите -fallbackfee. - 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 Эта ошибка может появляться, если кошелёк был закрыт некорректно либо был ранее открыт через приложение с более новой версией Berkeley DB. Если так, то, пожалуйста, используйте то же приложение, которым вы открывали кошелёк в прошлый раз @@ -4922,7 +5244,7 @@ Go to File > Open Wallet to load a wallet. Error: Unable to parse version %u as a uint32_t - Ошибка: Не удалось проанализировать версию %u как uint32_t + Ошибка: Не удалось разобрать версию %u как uint32_t Error: Unable to write record to new wallet @@ -4932,10 +5254,6 @@ Go to File > Open Wallet to load a wallet. Failed to listen on any port. Use -listen=0 if you want this. Не удалось начать прослушивание на порту. Используйте -listen=0, если вас это устраивает. - - -maxtxfee is set very high! Fees this large could be paid on a single transaction. - установлено очень большое значение -maxtxfee! Комиссия такого размера может быть уплачена при проведении отдельной транзакции. - Found unconfirmed denominated outputs, will wait till they confirm to continue. Найдены неподтверждённые номиналы, процесс продолжится после их подтверждения. @@ -4944,22 +5262,18 @@ Go to File > Open Wallet to load a wallet. Invalid -socketevents ('%s') specified. Only these modes are supported: %s Указан некорректный параметр -socketevents ('%s'). Поддерживаются только следующие режимы: %s - - Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions) - Некорректная сумма для -maxtxfee=<amount>: '%s' (должна быть минимум как комиссия minrelay - %s, чтобы предотвратить застревание транзакций) - SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is supported SQLiteDatabase: Неизвестная версия %d схемы кошелька sqlite. Поддерживается только версия %d - - The -txindex upgrade started by a previous version cannot be completed. Restart with the previous version or run a full -reindex. - Обновление -txindex, начатое предыдущей версией, не может быть завершено. Перезапустите с предыдущей версией или выполните полный -reindex. - Transaction index can't be disabled with governance validation enabled. Either start with -disablegovernance command line switch or enable transaction index. Индексирование транзакций нельзя отключить в режиме проверки данных управления. Либо запустите кошелек с опцией -disablegovernance, либо включите индексирование транзакций. + + Unsupported category-specific logging level -loglevel=%s. Expected -loglevel=<category>:<loglevel>. Valid categories: %s. Valid loglevels: %s. + Неподдерживаемый уровень логирования для категории -loglevel=%s. Ожидается -loglevel=<category>:<loglevel>. Допустимые категории: %s. Допустимые уровни: %s. + Can't mix: no compatible inputs found! Перемешивание невозможно: подходящие монеты не найдены! @@ -4968,10 +5282,6 @@ Go to File > Open Wallet to load a wallet. Entry exceeds maximum size. Запись превышает максимально допустимый размер. - - Error upgrading Evo database - Ошибка обновления базы данных Evo - Error upgrading evo database for EHF Ошибка обновления базы данных Evo в части EHF @@ -5004,14 +5314,6 @@ Go to File > Open Wallet to load a wallet. Insufficient funds. Недостаточно средств. - - Invalid amount for -discardfee=<amount>: '%s' - Неверная сумма в параметре -discardfee=<amount>: '%s' - - - Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s) - Неверная сумма в параметре -paytxfee=<amount>: '%s' (должна быть минимум %s) - Invalid minimum number of spork signers specified with -minsporkkeys Некорректное минимальное количество подписантов спорков, указанное в -minsporkkeys @@ -5088,6 +5390,10 @@ Go to File > Open Wallet to load a wallet. Unknown response. Неизвестный ответ. + + Unsupported global logging level -loglevel=%s. Valid values: %s. + Неподдерживаемый глобальный уровень логирования -loglevel=%s. Допустимые значения: %s. + User Agent comment (%s) contains unsafe characters. Комментарий User Agent (%s) содержит небезопасные символы. @@ -5152,10 +5458,6 @@ Go to File > Open Wallet to load a wallet. Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments. Длина строки сетевой версии (%i) превышает максимально допустимую (%i). Уменьшите количество или размер строк uacomment. - - Transaction needs a change address, but we can't generate it. Please call keypoolrefill first. - Транзакции нужен адрес сдачи, но мы не можем его сгенерировать. Пожалуйста, сначала выполните команду keypoolrefill. - WARNING! Failed to replenish keypool, please unlock your wallet to do so. ВНИМАНИЕ! Ну удалось обновить пул ключей, пожалуйста, разблокируйте кошелек. @@ -5194,7 +5496,7 @@ Go to File > Open Wallet to load a wallet. Could not parse asmap file %s - Не удалось прочитать файл asmap %s + Не удалось разобрать файл asmap %s ERROR! Failed to create automatic backup @@ -5232,10 +5534,6 @@ Go to File > Open Wallet to load a wallet. Error: No addresses available. Ошибка: Нет доступных адресов. - - Exceeded max tries. - Превышено максимальное количество попыток. - Failed to create backup %s! Не удалось создать резервную копию %s! @@ -5276,10 +5574,6 @@ Go to File > Open Wallet to load a wallet. Invalid P2P permission: '%s' Некорректные разрешения P2P : '%s' - - Invalid amount for -fallbackfee=<amount>: '%s' - Неверная сумма в параметре -fallbackfee=<amount>: '%s' - Invalid masternodeblsprivkey. Please see documentation. Некорректный masternodeblsprivkey. Пожалуйста, ознакомьтесь с документацией. @@ -5416,10 +5710,6 @@ Go to File > Open Wallet to load a wallet. Unable to open %s for writing Невозможно открыть %s для записи - - Unable to parse -maxuploadtarget: '%s' (possible integer overflow?) - Невозможно пропарсить -maxuploadtarget: '%s' (возможно integer overflow?) - Unknown -blockfilterindex value %s. Неизвестное значение -blockfilterindex %s. @@ -5428,10 +5718,6 @@ Go to File > Open Wallet to load a wallet. Unknown new rules activated (versionbit %i) Вступили в силу неизвестные правила (versionbit %i) - - Upgrading UTXO database - Обновление базы UTXO - Verifying blocks… Проверка блоков… @@ -5492,10 +5778,6 @@ Go to File > Open Wallet to load a wallet. Cannot obtain a lock on data directory %s. %s is probably already running. Не удалось установить блокировку на каталог данных %s. Возможно, %s уже запущен. - - Cannot upgrade a non HD wallet from version %i to version %i which is non-HD wallet. Use upgradetohd RPC - Невозможно обновить не-HD кошелек с версии %i до версии %i, которая также является не-HD кошельком. Используйте команду upgradetohd RPC. - Distributed under the MIT software license, see the accompanying file %s or %s Распространяется под лицензией на программное обеспечение MIT, смотрите прилагаемый файл %s или %s. @@ -5528,6 +5810,10 @@ Go to File > Open Wallet to load a wallet. Failed to rename invalid peers.dat file. Please move or delete it and try again. Не удалось переименовать некорректный файл peers.dat. Пожалуйста, переместите или удалите его и повторите попытку. + + Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable %s. + Расчет комиссии невозможен. Комиссия по умолчанию не установлена. Подождите пару блоков либо включите %s. + File %s already exists. If you are sure this is what you want, move it out of the way first. Файл %s уже существует. Если вы уверены, что это необходимо, сначала переместите его в другое место. @@ -5540,6 +5826,10 @@ Go to File > Open Wallet to load a wallet. Incorrect or no devnet genesis block found. Wrong datadir for devnet specified? Неверный или отсутствующий начальный блок devnet. Неправильный каталог данных для devnet? + + Invalid amount for %s=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions) + Некорректная сумма для %s=<amount>: '%s' (должна быть минимум как комиссия minrelay - %s, чтобы предотвратить застревание транзакций) + 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. Некорректный или поврежденный файл peers.dat (%s). Если вы считаете, что это ошибка, пожалуйста, сообщите об этом на %s. В качестве временного решения вы можете переместить файл (%s) (переименовать, переместить или удалить), чтобы при следующем запуске был создан новый файл. @@ -5556,6 +5846,10 @@ Go to File > Open Wallet to load a wallet. No wallet file format provided. To use createfromdump, -format=<format> must be provided. Формат файла кошелька не указан. Для использования команды createfromdump необходимо задать параметр -format=<format>. + + Outbound connections restricted to CJDNS (-onlynet=cjdns) but -cjdnsreachable is not provided + Исходящие подключения ограничены сетью CJDNS (-onlynet=cjdns), но -cjdnsreachable не включен. + Outbound connections restricted to Tor (-onlynet=onion) but the proxy for reaching the Tor network is explicitly forbidden: -onion=0 Исходящие подключения ограничены сетью Tor (-onlynet=onion), но прокси для подключения к сети Tor явно запрещен: -onion=0. @@ -5564,6 +5858,10 @@ Go to File > Open Wallet to load a wallet. 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 Исходящие подключения ограничены сетью Tor (-onlynet=onion), но прокси для подключения к сети Tor не указан: отсутствуют параметры -proxy, -onion или -listenonion. + + Outbound connections restricted to i2p (-onlynet=i2p) but -i2psam is not provided + Исходящие подключения ограничены сетью i2p (-onlynet=i2p), но -i2psam не включен. + Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly. Пожалуйста, убедитесь что дата и время на Вашем компьютере выставлены правильно! %s не сможет работать корректно, если часы настроены неверно. @@ -5576,10 +5874,6 @@ Go to File > Open Wallet to load a wallet. Prune mode is incompatible with -reindex-chainstate. Use full -reindex instead. Режим prune несовместим с параметром -reindex-chainstate. Используйте полный параметр -reindex вместо этого. - - The block index db contains a legacy 'txindex'. To clear the occupied disk space, run a full -reindex, otherwise ignore this error. This error message will not be displayed again. - База данных индекса блоков содержит устаревший 'txindex'. Чтобы освободить занятое дисковое пространство, выполните полный -reindex, в противном случае игнорируйте эту ошибку. Это сообщение об ошибке больше не будет отображаться. - This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection. Это максимальная комиссия за транзакцию, которую вы платите (в дополнение к обычной комиссии), чтобы отдать приоритет частичному избеганию траты монет по сравнению с обычным выбором монет. @@ -5592,6 +5886,10 @@ Go to File > Open Wallet to load a wallet. This is the transaction fee you may pay when fee estimates are not available. Это комиссия, которую Вы заплатите при отправке транзакции, если расчет комиссии не доступен. + + Transaction requires one destination of non-0 value, a non-0 feerate, or a pre-selected input + Транзакция требует одного получателя с ненулевым значением, ненулевой ставки комиссии или предварительно выбранного входа + Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate. Невозможно повторить блоки. Необходимо перестроить базы даных с помощью -reindex-chainstate. @@ -5600,6 +5898,10 @@ Go to File > Open Wallet to load a wallet. Unknown wallet file format "%s" provided. Please provide one of "bdb" or "sqlite". Указан неизвестный формат файла кошелька "%s". Пожалуйста, укажите один из следующих: "bdb" или "sqlite". + + Unsupported chainstate database format found. Please restart with -reindex-chainstate. This will rebuild the chainstate database. + Обнаружен неподдерживаемый формат базы данных состояния цепи. Пожалуйста, перезапустите с -reindex-chainstate. Это перестроит базу данных состояния цепи. + Warning: Dumpfile wallet format "%s" does not match command line specified format "%s". Предупреждение: формат кошелька в файле дампа "%s" не соответствует указанному в командной строке формату "%s". @@ -5640,10 +5942,30 @@ Go to File > Open Wallet to load a wallet. -rpcport must be specified when -devnet and -server are specified Необходимо указать -rpcport, если указаны -devnet и -server + + -statsbatchsize cannot be configured with a negative value. + -statsbatchsize не может использовать отрицательное значение. + + + -statsduration cannot be configured with a negative value. + -statsduration не может использовать отрицательное значение. + A fatal internal error occurred, see debug.log for details Произошла критическая ошибка, подробности смотрите в файле debug.log + + Cannot create socket (socket() returned error %s) + Ошибка: не удалось создать сокет (socket() вернул ошибку %s) + + + Cannot get socket address for %s + Не удалось получить адрес сокета для %s + + + Cannot init Statsd client + Не удалось инициализировать клиент Statsd + Cannot resolve -%s address: '%s' Не удаётся разрешить адрес в параметре -%s: '%s' @@ -5688,10 +6010,6 @@ Go to File > Open Wallet to load a wallet. Error reading next record from wallet database Ошибка чтения следующей записи из базы данных кошелька. - - Error upgrading chainstate database - Ошибка обновления базы данных состояний цепочки - Loading P2P addresses… Загрузка P2P адресов… @@ -5812,14 +6130,70 @@ Go to File > Open Wallet to load a wallet. %s corrupt. Try using the wallet tool dash-wallet to salvage or restoring a backup. %s поврежден. Попробуете воспользоваться утилитой dash-wallet для восстановления. + + %s is set very high! Fees this large could be paid on a single transaction. + Установлено очень большое значение %s! Комиссия такого размера может быть уплачена при проведении отдельной транзакции. + + + %s request to listen on port %u. This port is considered "bad" and thus it is unlikely that any Dash Core peers connect to it. See doc/p2p-bad-ports.md for details and a full list. + %s запрашивает прослушивание на порту %u. Этот порт считается «плохим», поэтому маловероятно, что к нему подключатся какие-либо пиры Dash Core. Подробности и полный список смотрите в doc/p2p-bad-ports.md + Cannot provide specific connections and have addrman find outgoing connections at the same time. Одновременное указание конкретных соединений и использование addrman для поиска исходящих соединений не допускается. + + Failed to upgrade Evo database + Ошибка обновления базы данных Evo + + + Fee needed > fee paid + Требуемая комиссия > уплаченная комиссия + + + Host %s on unsupported network + Хост %s в неподдерживаемой сети + + + Invalid amount for %s=<amount>: '%s' (must be at least %s) + Неверная сумма в параметре %s=<amount>: '%s' (должна быть минимум %s) + + + Invalid amount for %s=<amount>: '%s' + Некорректное значение в параметре %s=<amount>: '%s' + + + Invalid port specified in %s: '%s' + Указан некорректный порт в %s: '%s' + Last successful action was too recent. Последнее успешное действие было слишком недавно. + + Missing solving data for estimating transaction size + Отсутствуют данные для оценки размера транзакции + + + No host specified + Хост не указан + + + No host specified, malformed URL + Хост не указан, неправильный формат URL + + + No text before the scheme delimiter, malformed URL + Нет текста перед разделителем схемы, неправильный формат URL + + + Port must be between %d and %d, supplied %d + Порт должен быть между %d и %d, указан %d + + + Socket not initialized, cannot send message + Сокет не инициализирован, невозможно отправить сообщение + The source code is available from %s. Исходный код доступен по адресу %s. @@ -5848,6 +6222,10 @@ Go to File > Open Wallet to load a wallet. Transaction fees are too high. Комиссия по транзакции слишком большая. + + Transaction needs a change address, but we can't generate it. + Транзакции нужен адрес сдачи, но мы не можем его сгенерировать. + Transaction not valid. Транзакция некорректна. @@ -5868,6 +6246,18 @@ Go to File > Open Wallet to load a wallet. Unable to locate enough non-denominated funds for this transaction. Не удалось обнаружить достаточных для выполнения этой транзакции неденоминированных средств. + + Unable to lookup host %s + Невозможно найти хост %s + + + Unable to parse -maxuploadtarget: '%s' + Невозможно разобрать -maxuploadtarget: '%s' + + + Unable to send message to %s (::sendto() returned error %s) + Невозможно отправить сообщение на %s (::sendto() вернула ошибку %s) + Unable to sign spork message, wrong key? Не удалось подписать spork-сообщение. Неправильный ключ? @@ -5880,6 +6270,10 @@ Go to File > Open Wallet to load a wallet. Unknown state: id = %u Неизвестное состояние: id = %u + + Unsupported URL scheme, must begin with udp:// + Неподдерживаемая схема URL, должна начинаться с udp:// + Unsupported logging category %s=%s. Неподдерживаемая категория отладочной информации %s=%s. diff --git a/src/qt/locale/dash_sk.ts b/src/qt/locale/dash_sk.ts index 62096499888f..c83a25f0aaba 100644 --- a/src/qt/locale/dash_sk.ts +++ b/src/qt/locale/dash_sk.ts @@ -65,14 +65,6 @@ C&hoose &Vybrať - - Sending addresses - Adresa odoslania - - - Receiving addresses - Adresa prijatia - These are your Dash addresses for sending payments. Always check the amount and the receiving address before sending coins. Toto sú vaše Dash adresy pre posielanie platieb. Pred poslaním mincí vždy overte sumu a doručovaciu adresu. @@ -94,8 +86,8 @@ &Upraviť - &Show address QR code - &Zobraziť adresový QR kód + Show address &QR code + Zobraziť &QR kód adresy QR code @@ -105,6 +97,24 @@ Export Address List Exportovať zoznam adries + + Comma separated file + Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values. + Súbor s čiarkou oddelenými hodnotami + + + There was an error trying to save the address list to %1. Please try again. + An error message. %1 is a stand-in argument for the name of the file we attempted to save to. + Nastala chyba pri pokuse uložiť zoznam adries do %1. Prosím, skúste znova. + + + Sending addresses - %1 + Odosielacie adresy - %1 + + + Receiving addresses - %1 + Prijímacie adresy - %1 + Exporting Failed Export zlyhal @@ -274,10 +284,22 @@ The passphrase entered for the wallet decryption was incorrect. Zadané heslo pre dešifrovanie peňaženky bolo nesprávne. + + 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 23.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. + Zadané heslo pre dešifrovanie peňaženky je nesprávne. Obsahuje nulový znak (t.j. nulový bajt). Ak bolo heslo nastavené verziou tohto softvéru pred 23.0, skúste to znova iba so znakmi až po — ale bez — prvý nulový znak. Ak je to úspešné, nastavte si nové heslo, aby ste sa tomuto problému v budúcnosti vyhli. + Wallet passphrase was successfully changed. Heslo k peňaženke bolo úspešne zmenené. + + Passphrase change failed + Zmena hesla zlyhala + + + 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 23.0, please try again with only the characters up to — but not including — the first null character. + Staré heslo zadané pre dešifrovanie peňaženky je nesprávne. Obsahuje nulový znak (t.j. nulový bajt). Ak bolo heslo nastavené verziou tohto softvéru pred 23.0, skúste to znova iba so znakmi až po — ale bez — prvý nulový znak. + Warning: The Caps Lock key is on! Upozornenie: Caps Lock je zapnutý @@ -303,7 +325,23 @@ BitcoinApplication - + + Runaway exception + Neodchytená výnimka + + + A fatal error occurred. %1 can no longer continue safely and will quit. + Vyskytla sa fatálna chyba. %1 nemôže bezpečne pokračovať a ukončí sa. + + + Internal error + Vnútorná chyba + + + An internal error occurred. %1 will attempt to continue safely. This is an unexpected bug which can be reported as described below. + Vyskytla sa vnútorná chyba. %1 sa pokúsi bezpečne pokračovať. Toto je neočakávaná chyba, ktorú je možné nahlásiť podľa popisu nižšie. + + BitcoinGUI @@ -330,6 +368,10 @@ Request payments (generates QR codes and dash: URIs) Vyžiadať platby (vygeneruje QR kódy a Dash: URI) + + Ctrl+Q + Ctrl+Q + &Options… &Možnosti… @@ -358,6 +400,10 @@ &Verify message… &Overiť správu… + + &Load PSBT from file… + &Načítať PSBT zo súboru… + &Sending addresses &Odosielacie adresy @@ -390,10 +436,6 @@ &Window &Okno - - Minimize - Minimalizovať - Zoom Priblížiť @@ -446,14 +488,6 @@ Modify configuration options for %1 Upraviť nastavenia pre %1 - - &Show / Hide - &Zobraziť / Skryť - - - Show or hide the main Window - Zobraziť alebo skryť hlavné okno - Encrypt the private keys that belong to your wallet Zašifruj súkromné kľúče ktoré patria do vašej peňaženky @@ -518,10 +552,6 @@ Show wallet repair options Zobraziť možnosti opravy peňaženky - - Open Wallet &Configuration File - Otvoriť &konfiguračný súbor peňaženky - Open configuration file Otvoriť konfiguračný súbor @@ -576,10 +606,40 @@ Show information about %1 Zobraziť informácie o %1 + + Load PSBT from &clipboard… + Načítať PSBT zo &schránky… + + + Open debugging and diagnostic console + Otvoriť ladiaca a diagnostická konzola + + + Open &wallet configuration file + Otvoriť konfiguračný súbor &peňaženky + + + Open a dash: URI + Otvoriť dash: URI + Create a new wallet Vytvoriť novú peňaženku + + Restore Wallet… + Name of the menu item that restores wallet from a backup file. + Obnoviť peňaženku… + + + Restore a wallet from a backup file + Status tip for Restore Wallet menu item + Obnoviť peňaženku zo záložného súboru + + + Close all wallets + Zavrieť všetky peňaženky + %1 &information %1 &Informácie @@ -588,10 +648,42 @@ Show the %1 basic information Ukázať základné Informácie o %1 + + &Discreet mode + &Diskrétny režim + + + Mask the values in the Overview tab + Skryť hodnoty na záložke Prehľad + + + Wallet Data + Name of the wallet data file format. + Dáta peňaženky + + + Load Wallet Backup + The title for Restore Wallet File Windows + Načítať zálohu peňaženky + + + Restore Wallet + Title of pop-up window shown when the user is attempting to restore a wallet. + Obnoviť peňaženku + + + Wallet Name + Label of the input field where the name of the wallet is entered. + Názov peňaženky + &Settings &Nastavenia + + &Minimize + &Minimalizovať + &Help &Pomoc @@ -608,8 +700,17 @@ View Governance Proposals Zobraziť návrhy dozoru + + &Hide + &Skryť + + + S&how + &Zobraziť + %n active connection(s) to Dash network + A substring of the tooltip. %n aktívne spojenie so sieťou Dash%n aktívne spojenia so sieťou Dash%n aktívnych spojení so sieťou Dash%n aktívnych spojení so sieťou Dash @@ -628,10 +729,50 @@ Close Wallet… Zatvoriť Peňaženku… + + Load Partially Signed Blockchain Transaction + Načítať čiastočne podpísanú blockchainovú transakciu + + + Load Partially Signed Blockchain Transaction from clipboard + Načítať čiastočne podpísanú blockchainovú transakciu zo schránky + Create Wallet… Vytvoriť peňaženku… + + Close All Wallets… + Zatvoriť všetky peňaženky… + + + Ctrl+Shift+D + Ctrl+Shift+D + + + Ctrl+M + Ctrl+M + + + Click for more actions. + A substring of the tooltip. "More actions" are available via the context menu. + Kliknite pre ďalšie akcie. + + + Show Peers tab + A context menu item. The "Peers tab" is an element of the "Node window". + Zobraziť kartu Peerov + + + Disable network activity + A context menu item. + Zakázať sieťovú aktivitu + + + Enable network activity + A context menu item. The network activity was disabled previously. + Povoliť sieťovú aktivitu + Syncing Headers (%1%)… Synchronizujú sa hlavičky (%1%)… @@ -648,10 +789,6 @@ Processing blocks on disk… Spracovávam bloky na disku… - - Reindexing blocks on disk… - Reindexujú sa bloky na disku… - Connecting to peers… Pripája sa k partnerom… @@ -805,10 +942,6 @@ Coin Selection Výber mince - - Dust: - Prach: - After Fee: Po poplatku: @@ -866,28 +999,32 @@ Potvrdené - Copy address - Kopírovať adresu + Copy amount + Kopírovať sumu + + + &Copy address + &Kopírovať adresu - Copy label - Kopírovať popis + Copy &label + Kopírovať &popis - Copy amount - Kopírovať sumu + Copy &amount + Kopírovať &sumu - Copy transaction ID - Kopírovať ID transakcie + Copy transaction &ID and output index + Kopírovať &ID transakcie a index výstupu - Lock unspent - Uzamknúť neminuté + L&ock unspent + &Uzamknúť neutratené - Unlock unspent - Odomknúť neminuté + &Unlock unspent + &Odomknúť neutratené Copy quantity @@ -905,10 +1042,6 @@ Copy bytes Kopírovať bajty - - Copy dust - Kopírovať prach - Copy change Kopírovať zmenu @@ -921,18 +1054,6 @@ (%1 locked) (%1 zamknutých) - - yes - áno - - - no - nie - - - This label turns red if any recipient receives an amount smaller than the current dust threshold. - Tento popis sčervenie ak ktorýkoľvek príjemca dostane sumu menšiu ako súčasný limit pre "prach". - Can vary +/- %1 duff(s) per input. Môže sa pohybovať +/- %1 duff(y) pre vstup. @@ -976,8 +1097,14 @@ CreateWalletActivity + + Create Wallet + Title of window indicating the progress of creation of a new wallet. + Vytvoriť peňaženku + Creating Wallet <b>%1</b>… + Descriptive text of the create wallet progress window which indicates to the user which wallet is currently being created. Vytvára sa peňaženka <b>%1</b>… @@ -999,6 +1126,10 @@ Wallet Name Názov peňaženky + + Wallet + Peňaženka + Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice. Zašifruje peňaženku. Peňaženka bude zašifrovaná pomocou prístupovej frázy podľa vášho výberu. @@ -1007,6 +1138,10 @@ Encrypt Wallet Zašifrovať peňaženku + + Advanced Options + Pokročilé možnosti + 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. Zakázať súkromné kľúče pre túto peňaženku. Peňaženky so zakázanými súkromnými kľúčmi nebudú mať žiadne súkromné kľúče a nemôžu mať HD pôvod ani importované súkromné kľúče. Toto je ideálne pre peňaženky, ktoré len sledujete. @@ -1023,11 +1158,23 @@ Make Blank Wallet Vytvoriť prázdnu peňaženku + + Use descriptors for scriptPubKey management. This feature is well-tested but still considered experimental and not recommended for use yet. + Použiť deskriptory pre správu scriptPubKey. Táto funkcia je dobre otestovaná, ale stále sa považuje za experimentálnu a zatiaľ sa neodporúča na použitie. + + + Descriptor Wallet (EXPERIMENTAL) + Deskriptorová peňaženka (EXPERIMENTÁLNE) + Create Vytvoriť - + + Compiled without sqlite support (required for descriptor wallets) + Skompilované bez podpory sqlite (vyžadované pre deskriptorové peňaženky) + + EditAddressDialog @@ -1116,18 +1263,106 @@ Filter List: Filtrovať zoznam: + + Filter proposal list + Filtrovať zoznam návrhov + + + Masternode Count: + Počet masternodov: + + + Number of masternodes this wallet can vote with (masternodes for which this wallet holds the voting key) + Počet masternodov, ktorými môže táto peňaženka hlasovať (masternody, pre ktoré táto peňaženka drží hlasovací kľúč) + Proposal Count: Počet návrhov: + + Create Proposal + Vytvoriť návrh + Filter by Title Filtrovať podľa názvu + + Unavailable + Nedostupné + + + A synced node and an unlocked wallet are required. + Vyžaduje sa synchronizovaný uzol a odomknutá peňaženka. + + + Vote Yes + Hlasovať áno + + + Vote No + Hlasovať nie + + + Vote Abstain + Zdržať sa hlasovania + Proposal Info: %1 Informácie o návrhu: %1 + + Voting Failed + Hlasovanie zlyhalo + + + No wallet available. + Žiadna peňaženka nie je k dispozícii. + + + No masternode voting keys found in wallet. + V peňaženke sa nenašli žiadne hlasovacie kľúče masternodov. + + + Please select a proposal to vote on. + Prosím, vyberte návrh na hlasovanie. + + + Unable to unlock wallet. + Nie je možné odomknúť peňaženku. + + + Unable to get masternode list. Please try again later. + Nie je možné získať zoznam masternodov. Prosím, skúste to neskôr. + + + Masternode %1 not found + Masternód %1 sa nenašiel + + + Failed to sign vote for masternode %1 + Nepodarilo sa podpísať hlasovanie pre masternód %1 + + + Masternode %1: %2 + Masternód %1: %2 + + + Voted successfully %n time(s) + Úspešne hlasované %n krátÚspešne hlasované %n krátÚspešne hlasované %n krátÚspešne hlasované %n krát + + + Failed to vote %n time(s) + Nepodarilo sa hlasovať %n krátNepodarilo sa hlasovať %n krátNepodarilo sa hlasovať %n krátNepodarilo sa hlasovať %n krát + + + Errors: + Chyby: + + + Voting Results + Výsledky hlasovania + HelpMessageDialog @@ -1166,10 +1401,26 @@ As this is the first time the program is launched, you can choose where %1 will store its data. Keďže toto je prvé spustenie programu, môžete si vybrať, kam %1 bude ukladať vaše údaje. + + Limit block chain storage to + Obmedziť úložisko blockchainu na + + + 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. + Vrátenie tohto nastavenia vyžaduje opätovné stiahnutie celého blockchainu. Je rýchlejšie najprv stiahnuť celý reťazec a neskôr ho orezať. Zakáže niektoré pokročilé funkcie. + + + GB + GB + 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. Počiatočná synchronizácia je veľmi náročná a môže odhaliť hardvérové problémy vo vašom počítači o ktorých ste do teraz nevedeli. Vždy keď zapnete %1 tak sa sťahovanie začne presne tam kde bolo pred vypnutím. + + 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. + Keď kliknete na OK, %1 začne sťahovať a spracovávať úplný %4 blockchain (%2 GB), počnúc najstaršími transakciami v %3, keď bol %4 pôvodne spustený. + 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. Keď ste si vybrali limit na uloženie blockchainu (zmenšenie) tak sa historické dáta budú musieť aj tak stiahnuť a spracovať, ale potom budú zmazané aby sa používanie disku znížilo. @@ -1182,6 +1433,18 @@ Use a custom data directory: Použiť vlastný dátový adresár: + + %n GB of space available + %n GB dostupného miesta%n GB dostupného miesta%n GB dostupného miesta%n GB dostupného miesta + + + (of %n GB needed) + (z %n GB potrebného)(z %n GB potrebných)(z %n GB potrebných)(z %n GB potrebných) + + + (%n GB needed for full chain) + (%n GB potrebný pre úplný reťazec)(%n GB potrebné pre úplný reťazec)(%n GB potrebných pre úplný reťazec)(%n GB potrebných pre úplný reťazec) + At least %1 GB of data will be stored in this directory, and it will grow over time. V tomto adresári bude uložené minimálne %1 GB dát, časom sa využité dáta zvýšia. @@ -1190,6 +1453,11 @@ Approximately %1 GB of data will be stored in this directory. V tomto adresári bude uložených približne %1 GB dát. + + (sufficient to restore backups %n day(s) old) + Explanatory text on the capability of the current prune target. + (dostačujúce na obnovenie %n deň starých záloh)(dostačujúce na obnovenie %n dni starých záloh)(dostačujúce na obnovenie %n dní starých záloh)(dostačujúce na obnovenie %n dní starých záloh) + %1 will download and store a copy of the Dash block chain. %1 stiahne a bude uchovávať kópiu Dash blockchainu. @@ -1207,6 +1475,13 @@ Chyba + + LoadWalletsActivity + + Loading wallets… + Načítavanie peňaženiek… + + MasternodeList @@ -1241,6 +1516,10 @@ Service Služba + + Type + Typ + PoSe Score PoSe skóre @@ -1376,6 +1655,10 @@ Hide Skryť + + %1 is currently syncing. It will download headers and blocks from peers and validate them until reaching the tip of the block chain. + %1 sa momentálne synchronizuje. Sťahuje hlavičky a bloky od peerov a overuje ich, kým nedosiahne koniec blockchainu. + Unknown. Syncing Headers (%1, %2%)… Neznáme. Synchronizujú sa hlavičky (%1, %2%)… @@ -1391,6 +1674,11 @@ URI: URI: + + Paste address from clipboard + Tooltip text for button that allows you to paste an address that is in your clipboard. + Vložiť adresu zo schránky + OpenWalletActivity @@ -1406,8 +1694,14 @@ default wallet predvolená peňaženka + + Open Wallet + Title of window indicating the progress of opening of a wallet. + Otvoriť peňaženku + Opening Wallet <b>%1</b>… + Descriptive text of the open wallet progress window which indicates to the user which wallet is currently being opened. Otvára sa peňaženka <b>%1</b>… @@ -1441,6 +1735,14 @@ &Appearance &Vzhľad + + Show the icon in the system tray. + Zobraziť ikonu v systémovej lište. + + + &Show tray icon + &Zobraziť ikonu v lište + Prune &block storage to Orezať blok úložiska na @@ -1453,10 +1755,58 @@ Reverting this setting requires re-downloading the entire blockchain. Vrátenie tohto nastavenia si vyžaduje opätovné stiahnutie celého blockchainu. + + 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. + Tooltip text for Options window setting that sets the size of the database cache. Explains the corresponding effects of increasing/decreasing this value. + Maximálna veľkosť cache databázy. Väčšia cache môže prispieť k rýchlejšej synchronizácii, po ktorej je prínos pre väčšinu prípadov použitia menej výrazný. Zníženie veľkosti cache zníži využitie pamäte. Nepoužitá pamäť mempoolu je zdieľaná pre túto cache. + MiB MiB + + Set the number of script verification threads. Negative values correspond to the number of cores you want to leave free to the system. + 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. + Nastavte počet vlákien na overovanie skriptov. Záporné hodnoty zodpovedajú počtu jadier, ktoré chcete ponechať voľné pre systém. + + + This allows you or a third party tool to communicate with the node through command-line and JSON-RPC commands. + Tooltip text for Options window setting that enables the RPC server. + Toto umožňuje vám alebo nástroju tretej strany komunikovať s uzlom prostredníctvom príkazového riadku a JSON-RPC príkazov. + + + Enable R&PC server + An Options window setting to enable the RPC server. + Povoliť R&PC server + + + Whether to set subtract fee from amount as default or not. + Tooltip text for Options window setting that sets subtracting the fee from a sending amount as default. + Či nastaviť odpočítanie poplatku zo sumy ako predvolené alebo nie. + + + Subtract &fee from amount by default + An Options window setting to set subtracting the fee from a sending amount as default. + Predvolene odpočítať &poplatok zo sumy + + + Enable &PSBT controls + An options window setting to enable PSBT controls. + Povoliť ovládacie prvky &PSBT + + + Whether to show PSBT controls. + Tooltip text for options window setting that enables PSBT controls. + Či zobraziť ovládacie prvky PSBT. + + + Whether to keep the specified custom change address or not. + Či ponechať zadanú vlastnú adresu pre výdavok alebo nie. + + + Keep custom change &address + Ponechať vlastnú &adresu pre výdavok + Show additional tab listing all your masternodes in first sub-tab<br/>and all masternodes on the network in second sub-tab. Zobraziť dodatočnú záložku, ktorá vypíše všetky vaše masternódy v prvej pod-zložke<br/>- a všetky masternódy v druhej pod-zložke. @@ -1513,6 +1863,14 @@ Enable &multi-session Zapnúť &multi-sekciové + + Use this many separate masternodes in parallel to mix funds.<br/>Note: You must use this feature carefully.<br/>Make sure you always have recent wallet (auto)backup in a safe place! + Použite toľko oddelených masternódov paralelne na miešanie prostriedkov.<br/>Poznámka: Túto funkciu musíte používať opatrne.<br/>Uistite sa, že máte vždy aktuálnu (automatickú) zálohu peňaženky na bezpečnom mieste! + + + Parallel sessions + Paralelné relácie + Mixing rounds Miešacie kolá @@ -1525,6 +1883,30 @@ Target balance Cieľový zostatok + + How many inputs of each denominated amount are created.<br/>Lower these numbers if you want fewer smaller denominations. + Koľko vstupov každej denominovanej čiastky sa vytvorí.<br/>Znížte tieto čísla, ak chcete menej menších denominácií. + + + Inputs per denomination + Vstupy na denomináciu + + + Try to create at least this many inputs for each denominated amount.<br/>Lower this number if you want fewer smaller denominations. + Pokúsiť sa vytvoriť aspoň toľko vstupov pre každú denominovanú čiastku.<br/>Znížte toto číslo, ak chcete menej menších denominácií. + + + Target + Cieľ + + + Create up to this many inputs for each denominated amount.<br/>Lower this number if you want fewer smaller denominations. + Vytvoriť až toľko vstupov pre každú denominovanú čiastku.<br/>Znížte toto číslo, ak chcete menej menších denominácií. + + + Maximum + Maximum + Automatically open the Dash Core client port on the router. This only works when your router supports UPnP and it is enabled. Automaticky otvoriť na smerovači port pre Dash Core klient. Toto funguje iba ak váš smerovač podporuje UPnP a je povolené @@ -1554,20 +1936,26 @@ Zobrazuje či je poskytované predvolené SOCKS5 proxy používané pre získavanie peerov cez tento typ siete. - Options set in this dialog are overridden by the command line or in the configuration file: - Možnosti nastavené v tomto dialógovom okne sú prepísané príkazovým riadkom alebo v konfiguračnom súbore: + Language missing or translation incomplete? Help contributing translations here: +https://explore.transifex.com/dash/dash/ + Chýba jazyk alebo je preklad neúplný? Pomôžte s prekladom tu: +https://explore.transifex.com/dash/dash/ - 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. - Minimalizovať namiesto ukončenia aplikácie keď sa okno zavrie. Keď je zvolená táto možnosť, aplikácia sa zavrie len po zvolení Ukončiť v menu. + Third-party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items.<br/>%s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |. + URL adresy tretích strán (napr. prehliadač blokov), ktoré sa zobrazujú na záložke transakcií ako položky kontextového menu.<br/>%s v URL sa nahrádza hašom transakcie. Viacero URL je oddelených zvislou čiarou |. - Third party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items.<br/>%s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |. - URL tretích strán (napr. prehliadač blockchain) ktoré sa zobrazujú v záložke transakcií ako položky kontextového menu.<br/> %s v URL je nahradené hash-om transakcie. Viaceré URL sú oddelené zvislou čiarou |. + &Third-party transaction URLs + &URL adresy transakcií tretích strán - &Third party transaction URLs - &URL transakcií s tretími stranami + Options set in this dialog are overridden by the command line or in the configuration file: + Možnosti nastavené v tomto dialógovom okne sú prepísané príkazovým riadkom alebo v konfiguračnom súbore: + + + 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. + Minimalizovať namiesto ukončenia aplikácie keď sa okno zavrie. Keď je zvolená táto možnosť, aplikácia sa zavrie len po zvolení Ukončiť v menu. Whether to show coin control features or not. @@ -1605,6 +1993,10 @@ Map port using &UPnP Mapovať port pomocou &UPnP + + Automatically open the Dash Core client port on the router. This only works when your router supports NAT-PMP and it is enabled. The external port could be random. + Automaticky otvoriť na smerovači port pre Dash Core klient. Toto funguje iba ak váš smerovač podporuje NAT-PMP a je povolené. Externý port môže byť náhodný. + Proxy &IP: Proxy &IP: @@ -1653,6 +2045,14 @@ &Display &Zobrazenie + + Connect to the Dash network through a separate SOCKS5 proxy for Tor onion services. + Pripojiť sa k sieti Dash cez samostatné SOCKS5 proxy pre Tor onion služby. + + + Use separate SOCKS&5 proxy to reach peers via Tor onion services: + Použiť samostatné SOCKS&5 proxy pre dosiahnutie peerov cez Tor onion služby: + User Interface &language: &Jazyk užívateľského rozhrania: @@ -1699,14 +2099,22 @@ Confirm options reset + Window title text of pop-up window shown when the user has chosen to reset options. Potvrdiť obnovenie možností Client restart required to activate changes. + Text explaining that the settings changed will not come into effect until the client is restarted. Reštart klienta potrebný pre aktivovanie zmien. + + Current settings will be backed up at "%1". + 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. + Aktuálne nastavenia budú zálohované v "%1". + Client will be shut down. Do you want to proceed? + Text asking the user to confirm if they would like to proceed with a client shutdown. Klient bude vypnutý, chcete pokračovať? @@ -1844,6 +2252,10 @@ %1 Balance %1 Zostatok + + Discreet mode activated for the Overview tab. To unmask the values, uncheck Settings->Discreet mode. + Diskrétny režim aktivovaný pre záložku Prehľad. Ak chcete zobraziť hodnoty, zrušte začiarknutie Nastavenia->Diskrétny režim. + %n Rounds %n kolo%n kolá%n kôl%n kôl @@ -1943,7 +2355,140 @@ PSBTOperationsDialog - + + Dialog + Dialóg + + + Sign Tx + Podpísať Tx + + + Broadcast Tx + Vysielať Tx + + + Copy to Clipboard + Kopírovať do schránky + + + Save… + Uložiť… + + + Close + Zavrieť + + + Failed to load transaction: %1 + Nepodarilo sa načítať transakciu: %1 + + + Failed to sign transaction: %1 + Nepodarilo sa podpísať transakciu: %1 + + + Cannot sign inputs while wallet is locked. + Nie je možné podpísať vstupy, kým je peňaženka zamknutá. + + + Could not sign any more inputs. + Nie je možné podpísať viac vstupov. + + + Signed %1 inputs, but more signatures are still required. + Podpísané %1 vstupy, ale stále sú potrebné ďalšie podpisy. + + + Signed transaction successfully. Transaction is ready to broadcast. + Transakcia úspešne podpísaná. Transakcia je pripravená na vysielanie. + + + Unknown error processing transaction. + Neznáma chyba pri spracovaní transakcie. + + + Transaction broadcast successfully! Transaction ID: %1 + Transakcia úspešne vysielaná! ID transakcie: %1 + + + Transaction broadcast failed: %1 + Vysielanie transakcie zlyhalo: %1 + + + PSBT copied to clipboard. + PSBT skopírované do schránky. + + + Save Transaction Data + Uložiť údaje transakcie + + + Partially Signed Transaction (Binary) + Expanded name of the binary PSBT file format. See: BIP 174. + Čiastočne podpísaná transakcia (binárna) + + + PSBT saved to disk. + PSBT uložené na disk. + + + * Sends %1 to %2 + * Posiela %1 na %2 + + + own address + vlastná adresa + + + Unable to calculate transaction fee or total transaction amount. + Nie je možné vypočítať transakčný poplatok alebo celkovú sumu transakcie. + + + Pays transaction fee: + Platí transakčný poplatok: + + + Total Amount + Celková suma + + + or + alebo + + + Transaction has %1 unsigned inputs. + Transakcia má %1 nepodpísaných vstupov. + + + Transaction is missing some information about inputs. + V transakcii chýbajú niektoré informácie o vstupoch. + + + Transaction still needs signature(s). + Transakcia stále potrebuje podpis(y). + + + (But no wallet is loaded.) + (Ale nie je načítaná žiadna peňaženka.) + + + (But this wallet cannot sign transactions.) + (Ale táto peňaženka nemôže podpisovať transakcie.) + + + (But this wallet does not have the right keys.) + (Ale táto peňaženka nemá správne kľúče.) + + + Transaction is fully signed and ready for broadcast. + Transakcia je úplne podpísaná a pripravená na vysielanie. + + + Transaction status is unknown. + Stav transakcie je neznámy. + + PaymentServer @@ -1962,6 +2507,12 @@ 'dash://' is not a valid URI. Use 'dash:' instead. „dash://“ nie je platný URI. Namiesto toho použite „dash:“. + + Cannot process payment request as BIP70 is no longer supported. +Due to discontinued support, you should request the merchant to provide you with a BIP21 compatible URI or use a wallet that does continue to support BIP70. + Nie je možné spracovať požiadavku na platbu, pretože BIP70 už nie je podporovaný. +Kvôli ukončeniu podpory by ste mali požiadať obchodníka, aby vám poskytol URI kompatibilné s BIP21, alebo použite peňaženku, ktorá naďalej podporuje BIP70. + URI cannot be parsed! This can be caused by an invalid Dash address or malformed URI parameters. URI sa nedá analyzovať! Toto môže byť spôsobené neplatnou Dash adresou, alebo nesprávnym tvarom URI parametrov. @@ -1983,6 +2534,26 @@ Title of Peers Table column which indicates the current latency of the connection with the peer. Odozva + + Peer + Title of Peers Table column which contains a unique number used to identify a connection. + Peer + + + Age + Title of Peers Table column which indicates the duration (length of time) since the peer connection started. + Vek + + + Direction + Title of Peers Table column which indicates the direction the peer connection was initiated from. + Smer + + + Type + Title of Peers Table column which describes the type of peer connection. The "type" describes why the connection exists. + Typ + Sent Title of Peers Table column which indicates the total amount of network information we have sent to the peer. @@ -1993,7 +2564,27 @@ Title of Peers Table column which indicates the total amount of network information we have received from the peer. Prijaté - + + Address + Title of Peers Table column which contains the IP/Onion/I2P address of the connected peer. + Adresa + + + Network + Title of Peers Table column which states the network the peer connected through. + Sieť + + + Inbound + An Inbound Connection from a Peer. + Prichádzajúce + + + Outbound + An Outbound Connection to a Peer. + Odchádzajúce + + Proposal @@ -2044,8 +2635,193 @@ Stav + + ProposalWizard + + Create Governance Proposal + Vytvoriť návrh správy + + + Enter proposal details + Zadajte podrobnosti návrhu + + + A fee will be burned when you prepare the proposal. + Pri príprave návrhu bude spálený poplatok. + + + Proposal &name + &Názov návrhu + + + &Description URL + &URL s popisom + + + Payment &address + Platobná &adresa + + + Payment &amount + &Suma platby + + + The amount to request in a single payment + Suma, ktorú chcete požiadať v jednej platbe + + + &First payment + &Prvá platba + + + Pa&yments + Pla&tby + + + To&tal amount + Cel&ková suma + + + Proposal &fee + Poplatok za &návrh + + + Next + Ďalej + + + Review proposal JSON and validate. + Skontrolujte JSON návrhu a overte. + + + Hex-encoded JSON + Hex-kódovaný JSON + + + Back + Späť + + + Validate + Overiť + + + Prepare (burn fee) and wait for confirmations. + Pripraviť (spáliť poplatok) a čakať na potvrdenia. + + + Copy + Kopírovať + + + At 1/6 confirmations: can be relayed and queued. At 6/6: accepted and processed. + Pri 1/6 potvrdeniach: môže byť preposlaný a zaradený do fronty. Pri 6/6: akceptovaný a spracovaný. + + + Confirmations progress + Priebeh potvrdení + + + Shows progress toward the required number of confirmations for the proposal fee transaction. + Zobrazuje pokrok smerom k požadovanému počtu potvrdení pre transakciu poplatku návrhu. + + + Estimated time remaining: - + Odhadovaný zostávajúci čas: - + + + Prepare Proposal + Pripraviť návrh + + + You can submit after 1 confirmation. At 6 confirmations it is accepted and processed. + Môžete odoslať po 1 potvrdení. Pri 6 potvrdeniach je akceptovaný a spracovaný. + + + Proposal ID: + ID návrhu: + + + Submit Proposal + Odoslať návrh + + + Close + Zavrieť + + + Valid + Platný + + + Invalid: %1 + Neplatný: %1 + + + Burn %1 + Spáliť %1 + + + Burn %1 to create the fee transaction? + Spáliť %1 na vytvorenie transakcie poplatku? + + + Prepare failed + Príprava zlyhala + + + Confirmations: %1 / %2 required + Potvrdenia: %1 / %2 požadovaných + + + Estimated time remaining: Ready + Odhadovaný zostávajúci čas: Pripravené + + + Estimated time remaining: %n minute(s) + Odhadovaný zostávajúci čas: %n minútaOdhadovaný zostávajúci čas: %n minútyOdhadovaný zostávajúci čas: %n minútOdhadovaný zostávajúci čas: %n minúty + + + Your proposal was submitted successfully. + Váš návrh bol úspešne odoslaný. + + + Already submitted + Už odoslaný + + + This proposal has already been submitted. + Tento návrh už bol odoslaný. + + + Submission failed + Odoslanie zlyhalo + + + Proposal submitted + Návrh odoslaný + + + A fee of %1 will be burned when you prepare the proposal. + Pri príprave návrhu bude spálený poplatok vo výške %1. + + + Prepare (burn %1) and wait for %2 confirmations. + Pripraviť (spáliť %1) a čakať na %2 potvrdení. + + QObject + + Do you want to reset settings to default values, or to abort without making changes? + Explanatory text shown on startup when the settings file cannot be read. Prompts user to make a choice between resetting or aborting. + Chcete obnoviť nastavenia na predvolené hodnoty alebo prerušiť bez vykonania zmien? + + + A fatal error occurred. Check that settings file is writable, or try running with -nosettings. + 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. + Vyskytla sa fatálna chyba. Skontrolujte, či je súbor nastavení zapisovateľný, alebo skúste spustiť s -nosettings. + Choose data directory on startup (default: %u) Vyberte dátový priečinok pri štarte (predvolené: %u) @@ -2146,6 +2922,53 @@ This can also be adjusted later in the "Appearance" tab of the preferences. Toto je tiež možné upraviť neskôr na karte „Vzhľad“ v predvoľbách. + + Ctrl+W + Ctrl+W + + + Unroutable + Nesmerovateľné + + + Internal + Interné + + + Inbound + An inbound connection from a peer. An inbound connection is a connection initiated by a peer. + Prichádzajúce + + + Outbound + An outbound connection to a peer. An outbound connection is a connection initiated by us. + Odchádzajúce + + + Full Relay + Peer connection type that relays all network information. + Úplné preposielanie + + + Block Relay + Peer connection type that relays network information about blocks and not transactions or addresses. + Preposielanie blokov + + + Manual + Peer connection type established manually through one of several methods. + Manuálne + + + Feeler + Short-lived peer connection type that tests the aliveness of known addresses. + Testovací + + + Address Fetch + Short-lived peer connection type that solicits known addresses from a peer. + Získanie adries + %1 d %1 d @@ -2207,8 +3030,8 @@ %1 B - %1 KB - %1 KB + %1 kB + %1 kB %1 MB @@ -2264,7 +3087,12 @@ Save QR Code Uložiť QR kód - + + PNG Image + Expanded name of the PNG file format. See: https://en.wikipedia.org/wiki/Portable_Network_Graphics. + PNG obrázok + + RPCConsole @@ -2371,6 +3199,14 @@ Version Verzia + + High bandwidth BIP152 compact block relay: %1 + Vysokorýchlostné preposielanie kompaktných blokov BIP152: %1 + + + High Bandwidth + Vysoká šírka pásma + Starting Block Počiatočný Blok @@ -2383,6 +3219,51 @@ Synced Blocks Synchronizované bloky + + Elapsed time since a novel block passing initial validity checks was received from this peer. + Uplynulý čas od prijatia nového bloku, ktorý prešiel počiatočnými kontrolami platnosti, od tohto peera. + + + Last Block + Posledný blok + + + Elapsed time since a novel transaction accepted into our mempool was received from this peer. + Tooltip text for the Last Transaction field in the peer details area. + Uplynulý čas od prijatia novej transakcie akceptovanej do nášho mempoolu od tohto peera. + + + Last Transaction + Posledná transakcia + + + The mapped Autonomous System used for diversifying peer selection. + Mapovaný autonómny systém používaný na diverzifikáciu výberu peerov. + + + Mapped AS + Mapovaný AS + + + Whether we relay addresses to this peer. + Tooltip text for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No). + Či preposielame adresy tomuto peerovi. + + + Address Relay + Text title for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No). + Preposielanie adries + + + Addresses Processed + 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). + Spracované adresy + + + Addresses Rate-Limited + 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. + Adresy obmedzené rýchlosťou + Rescan blockchain files 1 Znova prehľadať blockchain 1 @@ -2423,6 +3304,22 @@ To specify a non-default location of the blocks directory use the '%1' option. Ak chcete zadať iné ako predvolené umiestnenie adresára blokov, použite voľbu '%1'. + + Local Addresses + Lokálne adresy + + + Network addresses that your Dash node is currently using to communicate with other nodes. + Sieťové adresy, ktoré váš Dash uzol momentálne používa na komunikáciu s ostatnými uzlami. + + + Number of regular Masternodes + Počet bežných masternodov + + + Number of EvoNodes + Počet EvoNodov + Current block height Aktuálna výška bloku @@ -2471,10 +3368,50 @@ PoSe Score PoSe skóre + + The transport layer version: %1 + Verzia transportnej vrstvy: %1 + + + Transport + Transport + + + The BIP324 session ID string in hex. + Reťazec ID relácie BIP324 v hex. + + + Session ID + ID relácie + + + The network protocol this peer is connected through: IPv4, IPv6, Onion, I2P, or CJDNS. + Sieťový protokol, cez ktorý je tento peer pripojený: IPv4, IPv6, Onion, I2P alebo CJDNS. + + + Permissions + Oprávnenia + + + The direction and type of peer connection: %1 + Smer a typ peer pripojenia: %1 + + + Direction/Type + Smer/Typ + Services Služby + + Whether we relay transactions to this peer. + Či preposielame transakcie tomuto peerovi. + + + Transaction Relay + Preposielanie transakcií + Connection Time Čas pripojenia @@ -2511,6 +3448,16 @@ &Wallet Repair &Oprava peňaženky + + The total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting). + 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). + Celkový počet adries prijatých od tohto peera, ktoré boli spracované (nezahŕňa adresy, ktoré boli zahodené kvôli obmedzeniu rýchlosti). + + + The total number of addresses received from this peer that were dropped (not processed) due to rate-limiting. + 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. + Celkový počet adries prijatých od tohto peera, ktoré boli zahodené (nespracované) kvôli obmedzeniu rýchlosti. + Wallet repair options. Možnosti opravy peňaženky. @@ -2524,52 +3471,82 @@ -reindex: Znovu vytvoriť index reťazca blokov zo súčastného blk000??.dat súboru. - &Disconnect - &Odpojiť + Inbound: initiated by peer + Explanatory text for an inbound peer connection. + Prichádzajúce: iniciované peerom - Ban for - Zakázať na + Outbound Full Relay: default + Explanatory text for an outbound peer connection that relays all network information. This is the default behavior for outbound connections. + Odchádzajúce úplné preposielanie: predvolené - 1 &hour - 1 &hodina + Outbound Block Relay: does not relay transactions or addresses + Explanatory text for an outbound peer connection that relays network information about blocks and not transactions or addresses. + Odchádzajúce preposielanie blokov: nepreposiela transakcie ani adresy - 1 &day - 1 &deň + Outbound Manual: added using RPC %1 or %2/%3 configuration options + 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. + Odchádzajúce manuálne: pridané pomocou RPC %1 alebo %2/%3 konfiguračných možností - 1 &week - 1 &týždeň + Outbound Feeler: short-lived, for testing addresses + Explanatory text for a short-lived outbound peer connection that is used to test the aliveness of known addresses. + Odchádzajúce kontrolné: krátkodobé, na testovanie adries - 1 &year - 1 &rok + Outbound Address Fetch: short-lived, for soliciting addresses + Explanatory text for a short-lived outbound peer connection that is used to request addresses from a peer. + Odchádzajúce získavanie adries: krátkodobé, na získavanie adries - &Unban - &Zrušiť zákaz + To + Do - Welcome to the %1 RPC console. - Vitajte v %1 RPC konzole + we selected the peer for high bandwidth relay + vybrali sme peera pre vysokorýchlostné preposielanie - Use up and down arrows to navigate history, and %1 to clear screen. - Použi šipky hore a dolu pre navigáciu históriou a %1 pre vyčistenie obrazovky. + From + Od - Type %1 for an overview of available commands. - Zadajte %1 a získate prehľad dostupných príkazov. + the peer selected us for high bandwidth relay + peer nás vybral pre vysokorýchlostné preposielanie - For more information on using this console type %1. - Ďalšie informácie o používaní tejto konzoly získate zadaním %1. + No + Nie + + + no high bandwidth relay selected + nebolo vybrané žiadne vysokorýchlostné preposielanie - WARNING: Scammers have been active, telling users to type commands here, stealing their wallet contents. Do not use this console without fully understanding the ramifications of a command. - UPOZORNENIE: Podvodníci sú aktívni a hovoria používateľom, aby sem zadávali príkazy pričom kradnú obsah peňaženky. Nepoužívajte túto konzolu bez úplného pochopenia dopadov takýchto príkazov. + &Disconnect + &Odpojiť + + + Ban for + Zakázať na + + + 1 &hour + 1 &hodina + + + 1 &week + 1 &týždeň + + + 1 &year + 1 &rok + + + &Unban + &Zrušiť zákaz In: @@ -2583,6 +3560,10 @@ Network activity disabled Sieťová aktivita zakázaná + + None + Žiadne + Total: %1 (Enabled: %2) Celkovo: %1 (Povolené: %2) @@ -2591,10 +3572,105 @@ Executing command without any wallet Vykonávanie príkazu bez akejkoľvek peňaženky + + Ctrl++ + Main shortcut to increase the RPC console font size. + Ctrl++ + + + Ctrl+= + Secondary shortcut to increase the RPC console font size. + Ctrl+= + + + Ctrl+- + Main shortcut to decrease the RPC console font size. + Ctrl+- + + + Ctrl+_ + Secondary shortcut to decrease the RPC console font size. + Ctrl+_ + + + Ctrl+Shift+I + Ctrl+Shift+I + + + Ctrl+Shift+C + Ctrl+Shift+C + + + Ctrl+Shift+G + Ctrl+Shift+G + + + Ctrl+Shift+P + Ctrl+Shift+P + + + Ctrl+Shift+R + Ctrl+Shift+R + Executing command using "%1" wallet Vykonávanie príkazu použitím peňaženky "%1" + + detecting: peer could be v1 or v2 + Explanatory text for "detecting" transport type. + detekuje sa: peer môže byť v1 alebo v2 + + + v1: unencrypted, plaintext transport protocol + Explanatory text for v1 transport type. + v1: nešifrovaný, textový transportný protokol + + + v2: BIP324 encrypted transport protocol + Explanatory text for v2 transport type. + v2: šifrovaný transportný protokol BIP324 + + + &Copy address + Context menu action to copy the address of a peer + &Kopírovať adresu + + + 1 d&ay + 1 &deň + + + &Copy IP/Netmask + 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 + &Kopírovať IP/sieťovú masku + + + 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 + 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. + Vitajte v %1 RPC konzole. +Použite šípky hore a dolu na navigáciu históriou a %2 na vymazanie obrazovky. +Použite %3 a %4 na zväčšenie alebo zmenšenie veľkosti písma. +Zadajte %5 pre prehľad dostupných príkazov. +Pre viac informácií o používaní tejto konzoly zadajte %6. + +%7UPOZORNENIE: Podvodníci boli aktívni, hovorili používateľom, aby tu zadávali príkazy, a kradli obsah ich peňaženky. Nepoužívajte túto konzolu bez úplného pochopenia dôsledkov príkazu.%8 + + + Executing… + A console message indicating an entered command is currently being executed. + Vykonáva sa… + + + (peer: %1) + (peer: %1) + via %1 cez %1 @@ -2611,11 +3687,19 @@ Verified Masternode Overený masternód + + Yes + Áno + Unknown Neznáme - + + Never + Nikdy + + ReceiveCoinsDialog @@ -2634,6 +3718,10 @@ An optional message to attach to the payment request, which will be displayed when the request is opened.<br>Note: The message will not be sent with the payment over the Dash network. Pripojiť ku vyžiadanej platbe voliteľnú správu, ktorá sa zobrazí, keď bude žiadosť otvorená. <br>Poznámka: Správa nebude poslaná spolu s platbou cez sieť Dash. + + 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. + Voliteľný popis, ktorý sa priradí k novej prijímacej adrese (používate ho na identifikáciu faktúry). Tiež sa pripojí k žiadosti o platbu. + Use this form to request payments. All fields are <b>optional</b>. Použite tento formulár pre vyžiadanie platby. Všetky polia sú <b>voliteľné</b>. @@ -2691,28 +3779,60 @@ Zadajte správu, ktorá sa má priložiť k žiadosti o platbu - Copy URI - Kopírovať URI + Copy &URI + Kopírovať &URI + + + &Copy address + &Kopírovať adresu - Copy address - Kopírovať adresu + Copy &label + Kopírovať &popis - Copy label - Kopírovať popis + Copy &message + Kopírovať &správu - Copy message - Kopírovať správu + Copy &amount + Kopírovať &sumu - Copy amount - Kopírovať sumu + Could not unlock wallet. + Nepodarilo sa odomknúť peňaženku. - + + Could not generate new address + Nepodarilo sa vygenerovať novú adresu + + ReceiveRequestDialog + + Request payment to … + Vyžiadať platbu na … + + + Address: + Adresa: + + + Amount: + Suma: + + + Label: + Popis: + + + Message: + Správa: + + + Wallet: + Peňaženka: + Copy &URI Kopírovať &URI @@ -2765,6 +3885,34 @@ Požadované + + RestoreWalletActivity + + Restore Wallet + Title of progress window which is displayed when wallets are being restored. + Obnoviť peňaženku + + + Restoring Wallet <b>%1</b>… + Descriptive text of the restore wallets progress window which indicates to the user that wallets are currently being restored. + Obnovuje sa peňaženka <b>%1</b>… + + + Restore wallet failed + Title of message box which is displayed when the wallet could not be restored. + Obnovenie peňaženky zlyhalo + + + Restore wallet warning + Title of message box which is displayed when the wallet is restored with some warning. + Upozornenie pri obnovení peňaženky + + + Restore wallet message + Title of message box which is displayed when the wallet is successfully restored. + Správa obnovy peňaženky + + SendCoinsDialog @@ -2799,10 +3947,6 @@ Fee: Poplatok: - - Dust: - Prach: - Inputs… Vstupy… @@ -2827,6 +3971,14 @@ Transaction Fee: Transakčný poplatok + + 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 dash transactions than the network can process. + Keď je objem transakcií menší ako priestor v blokoch, ťažiari a preposielajúce uzly môžu vynucovať minimálny poplatok. Platenie iba tohto minimálneho poplatku je v poriadku, ale uvedomte si, že to môže viesť k nikdy nepotvrdenej transakcii, ak bude väčší dopyt po dash transakciách, než sieť dokáže spracovať. + + + A too low fee might result in a never confirming transaction (read the tooltip) + Príliš nízky poplatok môže viesť k nikdy nepotvrdenej transakcii (prečítajte tooltip) + (Smart fee not initialized yet. This usually takes a few blocks…) (Inteligentný poplatok nebol ešte inicializovaný. Obvykle to trvá nekoľko blokov…) @@ -2919,10 +4071,6 @@ Copy bytes Kopírovať bajty - - Copy dust - Kopírovať prach - Copy change Kopírovať zmenu @@ -2939,10 +4087,6 @@ %1 to %2 %1 do %2 - - Are you sure you want to send? - Určite chcete odoslať transakciu? - <b>(%1 of %2 entries displayed)</b> <b>(%1 z %2 zobrazených položiek)</b> @@ -2955,6 +4099,18 @@ Confirm the %1 send action Potvrďte akciu pre poslanie %1 + + Cr&eate Unsigned + &Vytvoriť nepodpísané + + + from wallet '%1' + z peňaženky '%1' + + + %1 to '%2' + %1 do '%2' + %1 funds only Iba %1 prostriedky @@ -3003,6 +4159,51 @@ Confirm send coins Potvrdiť odoslanie mincí + + Save Transaction Data + Uložiť údaje transakcie + + + PSBT saved + PSBT uložené + + + Watch-only balance: + Zostatok iba na sledovanie: + + + Creates a Partially Signed Blockchain Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet. + Vytvorí čiastočne podpísanú blockchainovú transakciu (PSBT) na použitie napr. s offline %1 peňaženkou alebo s PSBT-kompatibilnou hardvérovou peňaženkou. + + + Do you want to create this transaction? + 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. + Chcete vytvoriť túto transakciu? + + + Please, review your transaction proposal. This will produce a Partially Signed Blockchain Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet. + 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. + Prosím, skontrolujte svoj návrh transakcie. Toto vytvorí čiastočne podpísanú blockchainovú transakciu (PSBT), ktorú môžete uložiť alebo skopírovať a potom podpísať napr. offline %1 peňaženkou alebo PSBT-kompatibilnou hardvérovou peňaženkou. + + + Please, review your transaction. You can create and send this transaction or create a Partially Signed Blockchain Transaction (PSBT), which you can save or copy and then sign with, e.g., an offline %1 wallet, or a PSBT-compatible hardware wallet. + 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. + Prosím, skontrolujte svoju transakciu. Môžete vytvoriť a odoslať túto transakciu alebo vytvoriť čiastočne podpísanú blockchainovú transakciu (PSBT), ktorú môžete uložiť alebo skopírovať a potom podpísať napr. offline %1 peňaženkou alebo PSBT-kompatibilnou hardvérovou peňaženkou. + + + Please, review your transaction. + Text to prompt a user to review the details of the transaction they are attempting to send. + Prosím, skontrolujte svoju transakciu. + + + To review recipient list click "Show Details…" + Ak chcete skontrolovať zoznam príjemcov, kliknite na „Zobraziť podrobnosti…" + + + Partially Signed Transaction (Binary) + Expanded name of the binary PSBT file format. See: BIP 174. + Čiastočne podpísaná transakcia (binárna) + The recipient address is not valid. Please recheck. Adresa príjemcu je neplatná. Prosím, overte ju. @@ -3122,21 +4323,16 @@ A message that was attached to the dash: URI which will be stored with the transaction for your reference. Note: This message will not be sent over the Dash network. Správa ktorá bola pripojená ku dash: URI ktorá sa uchová spolu s transakciou pre vašu referenciu. Poznámka: Táto správa nebude poslaná cez sieť Dash. + + + SendConfirmationDialog - This is an unauthenticated payment request. - Toto je neoverená výzva k platbe. - - - This is an authenticated payment request. - Toto je overená výzva k platbe. - - - Pay To: - Platba pre: + Send + Odoslať - Memo: - Poznámka: + Create Unsigned + Vytvoriť nepodpísané @@ -3276,6 +4472,10 @@ Wallet unlock was cancelled. Odomknutie peňaženky bolo zrušené. + + No error + Žiadna chyba + Private key for the entered address is not available. Súkromný kľúč pre vložená adresu nieje k dispozícii. @@ -3301,19 +4501,30 @@ Podpis sa nezhoduje so zhrnutím správy - Message verification failed. - Overenie správy zlyhalo. + Message verification failed. + Overenie správy zlyhalo. + + + Message verified. + Správa overená. + + + + SplashScreen + + (press q to shutdown and continue later) + (stlačte q pre vypnutie a pokračovanie neskôr) - Message verified. - Správa overená. + press q to shutdown + stlačte q pre vypnutie TrafficGraphWidget - KB/s - KB/s + kB/s + kB/s Total @@ -3330,20 +4541,9 @@ TransactionDesc - - Open for %n more block(s) - Otvoriť pre %n ďalší blokOtvoriť pre %n ďalšie blokyOtvoriť pre %n ďalších blokovOtvoriť pre %n ďalších blokov - - - Open until %1 - Otvorené do %1 - - - conflicted - sporné - 0/unconfirmed, %1 + 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. 0/nepotvrdené, %1 @@ -3356,22 +4556,32 @@ abandoned + 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. opustené + + conflicted with a transaction with %1 confirmations + 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. + v konflikte s transakciou s %1 potvrdeniami + %1/unconfirmed + 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, and still not locked via ChainLocks. %1/nepotvrdené %1 confirmations + 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 or locked via ChainLocks. %1 potvrdení locked via ChainLocks + 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 and has been locked by ChainLocks. zamknuté pomocou ChainLocks verified via InstantSend + 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 has been locked by InstantSend. overené cez InstantSend @@ -3390,6 +4600,10 @@ Generated Vygenerované + + Platform Transfer + Prevod platformy + From Od @@ -3520,14 +4734,6 @@ Address / Label Adresa / Popis - - Open for %n more block(s) - Otvoriť pre %n ďalší blokOtvoriť pre %n ďalšie blokyOtvoriť pre %n ďalších blokovOtvoriť pre %n ďalších blokov - - - Open until %1 - Otvorené do %1 - Unconfirmed Nepotvrdené @@ -3588,6 +4794,10 @@ Mined Vyťažené + + Platform Transfer + Prevod platformy + %1 Mixing %1 miešanie @@ -3715,6 +4925,10 @@ Mined Vyťažené + + Platform Transfer + Prevod platformy + Other Iné @@ -3728,49 +4942,63 @@ Minimálna suma - Abandon transaction - Opustené transakcie + &Copy address + &Kopírovať adresu + + + Copy &label + Kopírovať &popis - Copy address - Kopírovať adresu + Copy &amount + Kopírovať &sumu - Copy label - Kopírovať popis + Copy transaction &ID + Kopírovať &ID transakcie - Copy amount - Kopírovať sumu + Copy &raw transaction + Kopírovať &nespracovanú transakciu - Copy transaction ID - Kopírovať ID transakcie + Copy full transaction &details + Kopírovať úplné &podrobnosti transakcie - Copy raw transaction - Skopírovať neupravenú transakciu + &Show transaction details + &Zobraziť podrobnosti transakcie - Copy full transaction details - Kopírovať všetky podrobnosti o transakcii + A&bandon transaction + &Opustiť transakciu - Edit address label - Upraviť štítok s adresou + Rese&nd transaction + Znova o&doslať transakciu - Show transaction details - Zobraziť podrobnosti transakcie + &Edit address label + &Upraviť popis adresy - Show address QR code - Zobraziť adresový QR kód + Show address &QR code + Zobraziť &QR kód adresy + + + Show in %1 + 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. + Zobraziť v %1 Export Transaction History Exportovať históriu transakcií + + Comma separated file + Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values. + Súbor s čiarkou oddelenými hodnotami + Confirmed Potvrdené @@ -3849,10 +5077,54 @@ Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled. Príliš dlhé zatvorenie peňaženky môže viesť k nutnosti opätovnej synchronizácie celého reťazca, ak je povolené orezávanie. - + + Close all wallets + Zavrieť všetky peňaženky + + + Are you sure you wish to close all wallets? + Naozaj chcete zavrieť všetky peňaženky? + + WalletFrame - + + No wallet has been loaded. +Go to File > Open Wallet to load a wallet. +- OR - + Nebola načítaná žiadna peňaženka. +Prejdite na Súbor > Otvoriť peňaženku a načítajte peňaženku. +- ALEBO - + + + Create a new wallet + Vytvoriť novú peňaženku + + + Error + Chyba + + + Unable to decode PSBT from clipboard (invalid base64) + Nie je možné dekódovať PSBT zo schránky (neplatný base64) + + + Load Transaction Data + Načítať údaje transakcie + + + Partially Signed Transaction (*.psbt) + Čiastočne podpísaná transakcia (*.psbt) + + + PSBT file must be smaller than 100 MiB + PSBT súbor musí byť menší ako 100 MiB + + + Unable to decode PSBT + Nie je možné dekódovať PSBT + + WalletModel @@ -3878,6 +5150,11 @@ Selected amount: Označená suma: + + Wallet Data + Name of the wallet data file format. + Dáta peňaženky + Backup Wallet Zálohovať peňaženku @@ -3905,14 +5182,6 @@ dash-core - - Error: Listening for incoming connections failed (listen returned error %s) - Chyba: Počúvanie prichádzajúcich spojení zlyhalo (vrátená chyba je %s) - - - Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee. - Odhad poplatku zlyhal. Fallbackfee je zakázaný. Počkajte niekoľko blokov alebo povoľte -fallbackfee. - 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 Táto chyba sa môže vyskytnúť, ak táto peňaženka nebola vypnutá čisto a bola naposledy načítaná pomocou zostavy s novšou verziou Berkeley DB. Ak áno, použite softvér, ktorý naposledy načítal túto peňaženku @@ -3970,16 +5239,20 @@ Chyba pri načítaní z databázy, ukončuje sa. - Failed to listen on any port. Use -listen=0 if you want this. - Nepodarilo sa počúvať na žiadnom porte. Použite -listen=0 ak to takto chcete. + Error: Missing checksum + Chyba: Chýba kontrolný súčet + + + Error: Unable to parse version %u as a uint32_t + Chyba: Nie je možné analyzovať verziu %u ako uint32_t - -maxtxfee is set very high! Fees this large could be paid on a single transaction. - -maxtxfee je nastavené veľmi vysoko! Takto vysoký poplatok môže byť zaplatebý v jednej transakcii. + Error: Unable to write record to new wallet + Chyba: Nie je možné zapísať záznam do novej peňaženky - Cannot provide specific connections and have addrman find outgoing connections at the same. - Nedajú sa poskytnúť konkrétne spojenia a nechať súčasne addrman nájsť odchádzajúce spojenia. + Failed to listen on any port. Use -listen=0 if you want this. + Nepodarilo sa počúvať na žiadnom porte. Použite -listen=0 ak to takto chcete. Found unconfirmed denominated outputs, will wait till they confirm to continue. @@ -3990,13 +5263,17 @@ Zadané neplatné -socketevents ('%s'). Podporované sú iba tieto režimy: %s - Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions) - Neplatná suma pre -maxtxfee=<amount>: '%s' (aby sa transakcia nezasekla, minimálny prenosový poplatok musí byť aspoň %s) + SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is supported + SQLiteDatabase: Neznáma verzia schémy peňaženky sqlite %d. Podporovaná je iba verzia %d Transaction index can't be disabled with governance validation enabled. Either start with -disablegovernance command line switch or enable transaction index. Transakčný index nie je možné zakázať, ak je povolené overenie riadenia. Začnite buď prepínačom príkazového riadku -disablegovernance, alebo povolte index transakcií. + + Unsupported category-specific logging level -loglevel=%s. Expected -loglevel=<category>:<loglevel>. Valid categories: %s. Valid loglevels: %s. + Nepodporovaná úroveň protokolovania pre kategóriu -loglevel=%s. Očakávané -loglevel=<kategória>:<úroveň_logovania>. Platné kategórie: %s. Platné úrovne logovania: %s. + Can't mix: no compatible inputs found! Nedá sa miešať: nezostávajú žiadne kompatibilné zdroje. @@ -4005,6 +5282,14 @@ Entry exceeds maximum size. Vstup prekračuje maximálnu veľkosť. + + Error upgrading evo database for EHF + Chyba pri aktualizácii databázy evo pre EHF + + + Failed to commit Evo database + Nepodarilo sa zapísať databázu Evo + Found enough users, signing ( waiting %s ) Nájdený dostatok používateľov, pospisuje sa ( čakanie %s ) @@ -4029,18 +5314,14 @@ Insufficient funds. Nedostatok prostriedkov. - - Invalid amount for -discardfee=<amount>: '%s' - Neplatná suma pre -discardfee=<amount>: '%s' - - - Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s) - Neplatná suma pre -paytxfee=<amount>: '%s' (musí byť aspoň %s) - Invalid minimum number of spork signers specified with -minsporkkeys Neplatný minimálny počet spork podpisovateľov určených pomocou -minsporkkeys + + Listening for incoming connections failed (listen returned error %s) + Počúvanie prichádzajúcich spojení zlyhalo (listen vrátil chybu %s) + Lock is already in place. Zámok je už na mieste. @@ -4097,6 +5378,10 @@ Synchronizing governance objects… Synchronizujú sa objekty správy… + + Transaction change output index out of range + Index výstupu transakčného výdavku je mimo rozsahu + Unable to start HTTP server. See debug log for details. Nepodarilo sa spustiť HTTP server. Pre viac detailov zobrazte debug log. @@ -4105,6 +5390,10 @@ Unknown response. Neznáma odpoveď. + + Unsupported global logging level -loglevel=%s. Valid values: %s. + Nepodporovaná globálna úroveň logovania -loglevel=%s. Platné hodnoty: %s. + User Agent comment (%s) contains unsafe characters. Komentár u typu klienta (%s) obsahuje riskantné znaky. @@ -4145,6 +5434,10 @@ Make sure to encrypt your wallet and delete all non-encrypted backups after you have verified that the wallet works! Uistite sa, že máte vašu peňaženku zašifrovanú a zmazané všetky nezašifrované zálohy potom ako ste overili, že peňaženka funguje! + + More than one onion bind address is provided. Using %s for the automatically created Tor onion service. + Bola poskytnutá viac ako jedna onion bind adresa. Používa sa %s pre automaticky vytvorenú službu Tor onion. + Prune configured below the minimum of %d MiB. Please use a higher number. Orezanie nastavené pod minimálnu hodnotu %d MiB. Prosím použite vyššiu hodnotu. @@ -4173,10 +5466,6 @@ Wallet is locked, can't replenish keypool! Automatic backups and mixing are disabled, please unlock your wallet to replenish keypool. Peňaženka je zamknutá takže sa nedá doplniť zásobník kľúčov. Automatické zálohy a miešanie sú vypnuté. Pre doplnenie musíte odomknúť vašu peňaženku. - - You need to rebuild the database using -reindex to change -timestampindex - Potrebujete prebudovať databázu použitím -reindex zmeniť -timestampindex - You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain K návratu k neorezanému režimu je treba prestavať databázu použitím -reindex. Tiež sa znova stiahne celý blockchain @@ -4218,20 +5507,32 @@ Chyba pri načítavaní %s: Súkromné kľúče je možné deaktivovať iba počas vytvárania - Error upgrading evo database - Chyba pri aktualizácii databázy evo + Error: Couldn't create cursor into database + Chyba: Nepodarilo sa vytvoriť kurzor do databázy Error: Disk space is low for %s Chyba: Miesta na disku pre %s je málo - Exceeded max tries. - Prekročený maximálny počet pokusov. + Error: Dumpfile checksum does not match. Computed %s, expected %s + Chyba: Kontrolný súčet súboru výpisu sa nezhoduje. Vypočítané %s, očakávané %s + + + Error: Got key that was not hex: %s + Chyba: Získaný kľúč nebol hex: %s + + + Error: Got value that was not hex: %s + Chyba: Získaná hodnota nebola hex: %s + + + Error: Keypool ran out, please call keypoolrefill first + Chyba: Zásobník kľúčov sa vyčerpal, najprv zavolajte keypoolrefill - Failed to commit EvoDB - Nepodarilo sa vykonať EvoDB + Error: No addresses available. + Chyba: Nie sú dostupné žiadne adresy. Failed to create backup %s! @@ -4249,17 +5550,29 @@ Failed to rescan the wallet during initialization Počas inicializácie sa nepodarilo znova naskenovať peňaženku + + Failed to verify database + Nepodarilo sa overiť databázu + + + Fee rate (%s) is lower than the minimum fee rate setting (%s) + Sadzba poplatku (%s) je nižšia ako minimálne nastavenie sadzby poplatku (%s) + Found enough users, signing… Nájdený dostatok používateľov, pospisuje sa… - Invalid P2P permission: '%s' - Neplatné povolenie P2P: '%s' + Ignoring duplicate -wallet %s. + Ignoruje sa duplicitná -wallet %s. + + + Input not found or already spent + Vstup nebol nájdený alebo už bol utratený - Invalid amount for -fallbackfee=<amount>: '%s' - Neplatná suma pre -fallbackfee=<amount>: '%s' + Invalid P2P permission: '%s' + Neplatné povolenie P2P: '%s' Invalid masternodeblsprivkey. Please see documentation. @@ -4281,6 +5594,10 @@ Mixing in progress… Prebieha miešanie… + + No addresses available + Nie sú dostupné žiadne adresy + No errors detected. Nezistená žiadna chyba. @@ -4309,6 +5626,22 @@ Prune mode is incompatible with -txindex. Orezávanie nie je kompatibilné s -txindex. + + SQLiteDatabase: Failed to execute statement to verify database: %s + SQLiteDatabase: Nepodarilo sa vykonať príkaz na overenie databázy: %s + + + SQLiteDatabase: Failed to prepare statement to verify database: %s + SQLiteDatabase: Nepodarilo sa pripraviť príkaz na overenie databázy: %s + + + SQLiteDatabase: Failed to read database verification error: %s + SQLiteDatabase: Nepodarilo sa prečítať chybu overenia databázy: %s + + + SQLiteDatabase: Unexpected application id. Expected %u, got %u + SQLiteDatabase: Neočakávané ID aplikácie. Očakávané %u, získané %u + Section [%s] is not recognized. Sekcia [%s] nie je rozpoznaná. @@ -4341,6 +5674,10 @@ This is the transaction fee you will pay if you send a transaction. Toto je poplatok za transakciu pri odoslaní transakcie. + + Topping up keypool… + Dopĺňa sa zásobník kľúčov… + Transaction amounts must not be negative Sumy transakcií nesmú byť záporné @@ -4369,13 +5706,17 @@ Unable to generate initial keys Nie je možné vygenerovať počiatočné kľúče + + Unable to open %s for writing + Nie je možné otvoriť %s na zápis + Unknown -blockfilterindex value %s. Neznáma -blockfilterindex hodnota %s. - Upgrading UTXO database - Vylepšuje sa databáza neminutých výstupov (UTXO) + Unknown new rules activated (versionbit %i) + Aktivované neznáme nové pravidlá (versionbit %i) Verifying blocks… @@ -4394,16 +5735,12 @@ Nepodarilo sa vytvorenie priečinku pre zálohu %s! - You can not start a masternode with wallet enabled. - Nie je možné spustiť masternód s povolenou peňaženkou. - - - You need to rebuild the database using -reindex to change -addressindex - Potrebujete prebudovať databázu použitím -reindex zmeniť -addressindex + Wiping wallet transactions… + Vymazávajú sa transakcie peňaženky… - You need to rebuild the database using -reindex to change -spentindex - Potrebujete prebudovať databázu použitím -reindex zmeniť -spentindex + You can not start a masternode with wallet enabled. + Nie je možné spustiť masternód s povolenou peňaženkou. no mixing available. @@ -4421,6 +5758,22 @@ %s uses exact denominated amounts to send funds, you might simply need to mix some more coins. Pre poslanie zdrojov používa %s presné denominované sumy, možno iba potrebujete zmiešať viac mincí. + + -reindex-chainstate option is not compatible with -blockfilterindex. Please temporarily disable blockfilterindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes. + Voľba -reindex-chainstate nie je kompatibilná s -blockfilterindex. Prosím dočasne zakážte blockfilterindex pri používaní -reindex-chainstate, alebo nahraďte -reindex-chainstate s -reindex pre úplné prebudovanie všetkých indexov. + + + -reindex-chainstate option is not compatible with -coinstatsindex. Please temporarily disable coinstatsindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes. + Voľba -reindex-chainstate nie je kompatibilná s -coinstatsindex. Prosím dočasne zakážte coinstatsindex pri používaní -reindex-chainstate, alebo nahraďte -reindex-chainstate s -reindex pre úplné prebudovanie všetkých indexov. + + + -reindex-chainstate option is not compatible with -txindex. Please temporarily disable txindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes. + Voľba -reindex-chainstate nie je kompatibilná s -txindex. Prosím dočasne zakážte txindex pri používaní -reindex-chainstate, alebo nahraďte -reindex-chainstate s -reindex pre úplné prebudovanie všetkých indexov. + + + Cannot downgrade wallet from version %i to version %i. Wallet version unchanged. + Nie je možné prejsť na nižšiu verziu peňaženky z verzie %i na verziu %i. Verzia peňaženky nezmenená. + Cannot obtain a lock on data directory %s. %s is probably already running. Nedá sa uzamknúť zložka %s. %s pravdepodobne už beží. @@ -4433,14 +5786,82 @@ Error loading %s: You can't enable HD on an already existing non-HD wallet Chyba pri načítaní %s: Nemôžete zapnúť HD na už existujúcej nie-HD peňaženke + + 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 + Chyba pri načítaní peňaženky. Peňaženka vyžaduje stiahnutie blokov a softvér v súčasnosti nepodporuje načítanie peňaženiek, keď sa bloky sťahujú v nesprávnom poradí pri používaní assumeutxo snímok. Peňaženka by sa mala úspešne načítať po dosiahnutí výšky %s synchronizácie uzla + Error reading %s! All keys read correctly, but transaction data or address book entries might be missing or incorrect. Nastala chyba pri čítaní súboru %s! Všetky kľúče sa prečítali správne, ale dáta o transakciách alebo záznamy v adresári môžu chýbať alebo byť nesprávne. + + Error: Dumpfile format record is incorrect. Got "%s", expected "format". + Chyba: Záznam formátu súboru výpisu je nesprávny. Získané "%s", očakávané "format". + + + Error: Dumpfile identifier record is incorrect. Got "%s", expected "%s". + Chyba: Záznam identifikátora súboru výpisu je nesprávny. Získané "%s", očakávané "%s". + + + Error: Dumpfile version is not supported. This version of bitcoin-wallet only supports version 1 dumpfiles. Got dumpfile with version %s + Chyba: Verzia súboru výpisu nie je podporovaná. Táto verzia bitcoin-wallet podporuje iba súbory výpisu verzie 1. Získaný súbor výpisu s verziou %s + + + Failed to rename invalid peers.dat file. Please move or delete it and try again. + Nepodarilo sa premenovať neplatný súbor peers.dat. Prosím presuňte ho alebo vymažte a skúste to znova. + + + Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable %s. + Odhad poplatku zlyhal. Fallbackfee je zakázaný. Počkajte niekoľko blokov alebo povoľte %s. + + + File %s already exists. If you are sure this is what you want, move it out of the way first. + Súbor %s už existuje. Ak ste si istý, že to je to, čo chcete, najprv ho presuňte preč. + + + Incompatible options: -dnsseed=1 was explicitly specified, but -onlynet forbids connections to IPv4/IPv6 + Nekompatibilné voľby: -dnsseed=1 bolo výslovne zadané, ale -onlynet zakazuje pripojenia k IPv4/IPv6 + Incorrect or no devnet genesis block found. Wrong datadir for devnet specified? Nebol nájdený správny, prípadne žiadny základný blok. Nezadali ste nesprávny dátový priečinok alebo vývojársku sieť? + + Invalid amount for %s=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions) + Neplatná suma pre %s=<suma>: '%s' (musí byť aspoň minrelay poplatok %s, aby sa zabránilo zaseknuť transakciám) + + + 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. + Neplatný alebo poškodený peers.dat (%s). Ak si myslíte, že je to chyba, nahláste ju na %s. Ako dočasné riešenie môžete presunúť súbor (%s) preč (premenovať, presunúť alebo vymazať), aby sa pri ďalšom štarte vytvoril nový. + + + No dump file provided. To use createfromdump, -dumpfile=<filename> must be provided. + Nebol poskytnutý súbor výpisu. Na použitie createfromdump musí byť zadané -dumpfile=<názov_súboru>. + + + No dump file provided. To use dump, -dumpfile=<filename> must be provided. + Nebol poskytnutý súbor výpisu. Na použitie výpisu musí byť zadané -dumpfile=<názov_súboru>. + + + No wallet file format provided. To use createfromdump, -format=<format> must be provided. + Nebol poskytnutý formát súboru peňaženky. Na použitie createfromdump musí byť zadané -format=<formát>. + + + Outbound connections restricted to CJDNS (-onlynet=cjdns) but -cjdnsreachable is not provided + Odchádzajúce pripojenia obmedzené na CJDNS (-onlynet=cjdns), ale -cjdnsreachable nie je poskytnuté + + + Outbound connections restricted to Tor (-onlynet=onion) but the proxy for reaching the Tor network is explicitly forbidden: -onion=0 + Odchádzajúce pripojenia obmedzené na Tor (-onlynet=onion), ale proxy pre dosiahnutie siete Tor je výslovne zakázané: -onion=0 + + + 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 + Odchádzajúce pripojenia obmedzené na Tor (-onlynet=onion), ale proxy pre dosiahnutie siete Tor nie je poskytnuté: nie je zadané ani -proxy, -onion alebo -listenonion + + + Outbound connections restricted to i2p (-onlynet=i2p) but -i2psam is not provided + Odchádzajúce pripojenia obmedzené na i2p (-onlynet=i2p), ale -i2psam nie je poskytnuté + Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly. Prosím skontrolujte systémový čas a dátum. Keď je váš čas nesprávny, %s nebude fungovať správne. @@ -4449,6 +5870,14 @@ Please contribute if you find %s useful. Visit %s for further information about the software. Keď si myslíte, že %s je užitočný, podporte nás. Pre viac informácií o software navštívte %s. + + Prune mode is incompatible with -reindex-chainstate. Use full -reindex instead. + Režim orezávania nie je kompatibilný s -reindex-chainstate. Použite namiesto toho úplný -reindex. + + + This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection. + Toto je maximálny transakčný poplatok, ktorý zaplatíte (okrem bežného poplatku), aby ste uprednostnili vyhýbanie sa čiastočným výdavkom pred bežným výberom mincí. + This is the transaction fee you may discard if change is smaller than dust at this level Toto je transakčný poplatok, ktorý môžete zahodiť, ak je výdavok menší ako prach pri tejto úrovni @@ -4457,14 +5886,38 @@ This is the transaction fee you may pay when fee estimates are not available. Toto je poplatok za transakciu keď odhad poplatkov ešte nie je k dispozícii. + + Transaction requires one destination of non-0 value, a non-0 feerate, or a pre-selected input + Transakcia vyžaduje jeden cieľ s hodnotou inou ako 0, sadzbu poplatku inú ako 0 alebo vopred vybraný vstup + Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate. Bloky nie je možné prehrať. Potrebujete prebudovať databázu použitím -reindex-chainstate. + + Unknown wallet file format "%s" provided. Please provide one of "bdb" or "sqlite". + Poskytnutý neznámy formát súboru peňaženky "%s". Prosím, poskytnite jeden z "bdb" alebo "sqlite". + + + Unsupported chainstate database format found. Please restart with -reindex-chainstate. This will rebuild the chainstate database. + Našiel sa nepodporovaný formát databázy chainstate. Prosím, reštartujte s -reindex-chainstate. Toto znovu vytvorí databázu chainstate. + + + Warning: Dumpfile wallet format "%s" does not match command line specified format "%s". + Upozornenie: Formát výpisového súboru peňaženky "%s" nezodpovedá formátu zadanému v príkazovom riadku "%s". + Warning: Private keys detected in wallet {%s} with disabled private keys Upozornenie: Boli zistené súkromné kľúče v peňaženke {%s} so zakázanými súkromnými kľúčmi + + You need to rebuild the database using -reindex to enable -timestampindex + Musíte prebudovať databázu pomocou -reindex, aby ste povolili -timestampindex + + + %s -- Incorrect seed, it should be a hex string + %s -- Nesprávny seed, mal by to byť hex reťazec + %s is not a valid backup folder! %s nie je platný priečinok pre zálohu! @@ -4489,10 +5942,30 @@ -rpcport must be specified when -devnet and -server are specified -rpcport musí byť zadaný, keď sú špecifikované -devnet a -server + + -statsbatchsize cannot be configured with a negative value. + -statsbatchsize nemôže byť nastavené so zápornou hodnotou. + + + -statsduration cannot be configured with a negative value. + -statsduration nemôže byť nastavené so zápornou hodnotou. + A fatal internal error occurred, see debug.log for details Vyskytla sa závažná interná chyba, podrobnosti nájdete v debug.log + + Cannot create socket (socket() returned error %s) + Nie je možné vytvoriť socket (socket() vrátil chybu %s) + + + Cannot get socket address for %s + Nie je možné získať adresu socketu pre %s + + + Cannot init Statsd client + Nie je možné inicializovať Statsd klienta + Cannot resolve -%s address: '%s' Nedá preložiť -%s adresu: '%s' @@ -4501,10 +5974,6 @@ Cannot write to data directory '%s'; check permissions. Nie je možné zapisovať do dátového adresára '%s'. Skontrolujte povolenia. - - Change index out of range - Menný index mimo rozsah - Copyright (C) Autorské práva (C) @@ -4513,6 +5982,14 @@ Disk space is too low! Príliš málo miesta na disku! + + Dump file %s does not exist. + Súbor výpisu %s neexistuje. + + + Error creating %s + Chyba pri vytváraní %s + Error loading %s Chyba načítania %s @@ -4530,8 +6007,8 @@ Chyba pri načítaní %s: Nemôžete vypnúť HD na už existujúcej HD peňaženke - Error upgrading chainstate database - Chyba pri vylepšení databáze reťzcov blokov + Error reading next record from wallet database + Chyba pri čítaní ďalšieho záznamu z databázy peňaženky Loading P2P addresses… @@ -4601,6 +6078,14 @@ Inputs vs outputs size mismatch. Nesúlad veľkosti vstupov a výstupov. + + Invalid '%s'. Allowed values: 128, 160, 192, 224, 256. + Neplatné '%s'. Povolené hodnoty: 128, 160, 192, 224, 256. + + + Invalid -i2psam address or hostname: '%s' + Neplatná adresa -i2psam alebo názov hostiteľa: '%s' + Invalid -onion address or hostname: '%s' Neplatná -onion adresa alebo hostiteľ: '%s' @@ -4645,14 +6130,78 @@ %s corrupt. Try using the wallet tool dash-wallet to salvage or restoring a backup. %s poškodený. Skúste použiť nástroj peňaženky dash-wallet na záchranu alebo obnovenie zálohy. + + %s is set very high! Fees this large could be paid on a single transaction. + %s je nastavené veľmi vysoko! Takto veľké poplatky by mohli byť zaplatené v jednej transakcii. + + + %s request to listen on port %u. This port is considered "bad" and thus it is unlikely that any Dash Core peers connect to it. See doc/p2p-bad-ports.md for details and a full list. + %s požiadavka na počúvanie na porte %u. Tento port je považovaný za "zlý", a preto je nepravdepodobné, že sa k nemu pripoja peery Dash Core. Pozrite doc/p2p-bad-ports.md pre detaily a úplný zoznam. + + + Cannot provide specific connections and have addrman find outgoing connections at the same time. + Nie je možné poskytnúť špecifické pripojenia a zároveň nechať addrman vyhľadávať odchádzajúce pripojenia. + + + Failed to upgrade Evo database + Zlyhala aktualizácia Evo databázy + + + Fee needed > fee paid + Potrebný poplatok > zaplatený poplatok + + + Host %s on unsupported network + Hostiteľ %s na nepodporovanej sieti + + + Invalid amount for %s=<amount>: '%s' (must be at least %s) + Neplatná suma pre %s=<amount>: '%s' (musí byť aspoň %s) + + + Invalid amount for %s=<amount>: '%s' + Neplatná suma pre %s=<amount>: '%s' + + + Invalid port specified in %s: '%s' + Neplatný port zadaný v %s: '%s' + Last successful action was too recent. Posledná akcia bola pred chvíľou. + + Missing solving data for estimating transaction size + Chýbajúce údaje pre odhad veľkosti transakcie + + + No host specified + Nebol určený hostiteľ + + + No host specified, malformed URL + Nebol určený hostiteľ, nesprávne formátovaná URL + + + No text before the scheme delimiter, malformed URL + Žiadny text pred oddeľovačom schémy, nesprávne formátovaná URL + + + Port must be between %d and %d, supplied %d + Port musí byť medzi %d a %d, zadané %d + + + Socket not initialized, cannot send message + Socket nie je inicializovaný, nie je možné odoslať správu + The source code is available from %s. Zdrojový kód je dostupný z %s + + The specified config file %s does not exist + Zadaný konfiguračný súbor %s neexistuje + The transaction amount is too small to pay the fee Suma transakcie je príliš malá na zaplatenie poplatku @@ -4673,6 +6222,10 @@ Transaction fees are too high. Transakčné poplatky sú príliš vysoké + + Transaction needs a change address, but we can't generate it. + Transakcia potrebuje adresu pre výdavok, ale nie je možné ju vygenerovať. + Transaction not valid. Neplatná transakcia. @@ -4693,6 +6246,18 @@ Unable to locate enough non-denominated funds for this transaction. Pre túto transakciu sa nepodarilo nájsť dostatok ne-denominovaných finančných prostriedkov. + + Unable to lookup host %s + Nie je možné vyhľadať hostiteľa %s + + + Unable to parse -maxuploadtarget: '%s' + Nie je možné analyzovať -maxuploadtarget: '%s' + + + Unable to send message to %s (::sendto() returned error %s) + Nie je možné odoslať správu na %s (::sendto() vrátila chybu %s) + Unable to sign spork message, wrong key? Nedá sa podpísať spork správa, žeby zlý kľúč? @@ -4706,12 +6271,12 @@ Neznámy stav: id = %u - Unsupported logging category %s=%s. - Nepodporovaná záznamová kategória %s =%s. + Unsupported URL scheme, must begin with udp:// + Nepodporovaná schéma URL, musí začínať udp:// - Upgrading txindex database - Aktualizácia databázy txindex + Unsupported logging category %s=%s. + Nepodporovaná záznamová kategória %s =%s. Very low number of keys left: %d @@ -4741,9 +6306,25 @@ You can not disable governance validation on a masternode. Overenie riadenia nemôžete na masternóde deaktivovať. + + You need to rebuild the database using -reindex to enable -addressindex + Musíte prebudovať databázu pomocou -reindex pre povolenie -addressindex + + + You need to rebuild the database using -reindex to enable -spentindex + Musíte prebudovať databázu pomocou -reindex pre povolenie -spentindex + Your entries added successfully. Vaše položky boli úspešne pridané. + + Settings file could not be read + Súbor nastavení sa nepodarilo načítať + + + Settings file could not be written + Súbor nastavení sa nepodarilo zapísať + \ No newline at end of file diff --git a/src/qt/locale/dash_th.ts b/src/qt/locale/dash_th.ts index d51d06e07529..2532e7f01204 100644 --- a/src/qt/locale/dash_th.ts +++ b/src/qt/locale/dash_th.ts @@ -65,14 +65,6 @@ C&hoose เลือก - - Sending addresses - ส่งที่อยู่ - - - Receiving addresses - ที่อยู่ผู้รับ - These are your Dash addresses for sending payments. Always check the amount and the receiving address before sending coins. นี่คือที่อยู่ Dash ของคุณสำหรับการส่งการชำระเงิน โปรดตรวจสอบจำนวนเงินและที่อยู่ผู้รับก่อนที่จะส่งเหรียญ @@ -93,6 +85,10 @@ &Edit &แก้ไข + + Show address &QR code + แสดงรหัส &QR ของที่อยู่ + QR code โค้ด QR @@ -101,6 +97,24 @@ Export Address List ส่งออกรายการที่อยู่ + + Comma separated file + Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values. + ไฟล์คั่นด้วยเครื่องหมายจุลภาค + + + There was an error trying to save the address list to %1. Please try again. + An error message. %1 is a stand-in argument for the name of the file we attempted to save to. + เกิดข้อผิดพลาดในการบันทึกรายการที่อยู่ไปยัง %1 โปรดลองอีกครั้ง + + + Sending addresses - %1 + ที่อยู่สำหรับส่ง - %1 + + + Receiving addresses - %1 + ที่อยู่สำหรับรับ - %1 + Exporting Failed การส่งออกล้มเหลว @@ -270,10 +284,22 @@ The passphrase entered for the wallet decryption was incorrect. รหัสผ่านของวลีสำหรับการเข้าถึงกระเป๋าสตางค์ไม่ถูกต้อง + + 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 23.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. + วลีรหัสผ่านที่ป้อนสำหรับการถอดรหัสกระเป๋าสตางค์ไม่ถูกต้อง มันมีอักขระ null (เช่น ไบต์ศูนย์) หากวลีรหัสผ่านถูกตั้งค่าด้วยซอฟต์แวร์เวอร์ชันก่อน 23.0 โปรดลองอีกครั้งด้วยเฉพาะอักขระจนถึง — แต่ไม่รวม — อักขระ null ตัวแรก หากสำเร็จ โปรดตั้งวลีรหัสผ่านใหม่เพื่อหลีกเลี่ยงปัญหานี้ในอนาคต + Wallet passphrase was successfully changed. เปลี่ยนวลีรหัสผ่านเรียบร้อยแล้ว + + Passphrase change failed + การเปลี่ยนวลีรหัสผ่านล้มเหลว + + + 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 23.0, please try again with only the characters up to — but not including — the first null character. + วลีรหัสผ่านเก่าที่ป้อนสำหรับการถอดรหัสกระเป๋าสตางค์ไม่ถูกต้อง มันมีอักขระ null (เช่น ไบต์ศูนย์) หากวลีรหัสผ่านถูกตั้งค่าด้วยซอฟต์แวร์เวอร์ชันก่อน 23.0 โปรดลองอีกครั้งด้วยเฉพาะอักขระจนถึง — แต่ไม่รวม — อักขระ null ตัวแรก + Warning: The Caps Lock key is on! คำเตือน: ปุ่มแป้นตรึงตัวอักษรใหญ่เปิดอยู่ @@ -299,7 +325,23 @@ BitcoinApplication - + + Runaway exception + ข้อยกเว้นที่หนีควบคุม + + + A fatal error occurred. %1 can no longer continue safely and will quit. + เกิดข้อผิดพลาดร้ายแรง %1 ไม่สามารถดำเนินการต่อได้อย่างปลอดภัยและจะปิดโปรแกรม + + + Internal error + ข้อผิดพลาดภายใน + + + An internal error occurred. %1 will attempt to continue safely. This is an unexpected bug which can be reported as described below. + เกิดข้อผิดพลาดภายใน %1 จะพยายามดำเนินการต่อได้อย่างปลอดภัย นี่เป็นบั๊กที่ไม่คาดคิดซึ่งสามารถรายงานได้ตามที่อธิบายด้านล่าง + + BitcoinGUI @@ -326,6 +368,10 @@ Request payments (generates QR codes and dash: URIs) เรียกเก็บการชำระเงิน (สร้างคิว อาร์ โค้ด QR codes และแหล่งที่มาของ Dash: URIs) + + Ctrl+Q + Ctrl+Q + &Options… &ตัวเลือก… @@ -354,6 +400,10 @@ &Verify message… &ยืนยันข้อความ… + + &Load PSBT from file… + &โหลด PSBT จากไฟล์… + &Sending addresses &ส่งที่อยู่ @@ -386,10 +436,6 @@ &Window &หน้าต่าง - - Minimize - ย่อเล็กสุด - Zoom ขยาย @@ -442,14 +488,6 @@ Modify configuration options for %1 ปรับปรุง ข้อมูลการตั้งค่าตัวเลือก สำหรับ %1 - - &Show / Hide - &แสดง / ซ่อน - - - Show or hide the main Window - แสดง หรือ ซ่อน หน้าหลัก - Encrypt the private keys that belong to your wallet เข้ารหัส private keys สำหรับกระเป๋าสตางค์ของท่าน @@ -514,10 +552,6 @@ Show wallet repair options แสดงตัวเลือกการซ่อมแซมกระเป๋าสตางค์ - - Open Wallet &Configuration File - เปิดกระเป๋าสตางค์ &การกำหนดค่าไฟล์ - Open configuration file เปิดไฟล์การกำหนดค่า @@ -572,10 +606,18 @@ Show information about %1 แสดงข้อมูลเกี่ยวกับ %1 + + Load PSBT from &clipboard… + โหลด PSBT จาก&คลิปบอร์ด… + Open debugging and diagnostic console เปิดคอนโซลการตรวจแก้จุดบกพร่องและการวินิจฉัย + + Open &wallet configuration file + เปิดไฟล์การกำหนดค่า&กระเป๋าสตางค์ + Open a dash: URI เปิด Dash: URI @@ -584,6 +626,20 @@ Create a new wallet สร้างกระเป๋าเงินใหม่ + + Restore Wallet… + Name of the menu item that restores wallet from a backup file. + กู้คืนกระเป๋าสตางค์… + + + Restore a wallet from a backup file + Status tip for Restore Wallet menu item + กู้คืนกระเป๋าสตางค์จากไฟล์สำรองข้อมูล + + + Close all wallets + ปิดกระเป๋าสตางค์ทั้งหมด + %1 &information %1 &ข้อมูล @@ -592,10 +648,42 @@ Show the %1 basic information แสดงข้อมูลพื้นฐานของ %1 + + &Discreet mode + โหมด&ปกปิด + + + Mask the values in the Overview tab + ซ่อนค่าในแท็บภาพรวม + + + Wallet Data + Name of the wallet data file format. + ข้อมูลกระเป๋าสตางค์ + + + Load Wallet Backup + The title for Restore Wallet File Windows + โหลดข้อมูลสำรองกระเป๋าสตางค์ + + + Restore Wallet + Title of pop-up window shown when the user is attempting to restore a wallet. + กู้คืนกระเป๋าสตางค์ + + + Wallet Name + Label of the input field where the name of the wallet is entered. + ชื่อกระเป๋าสตางค์ + &Settings &การตั้งค่า + + &Minimize + &ย่อเล็กสุด + &Help &ช่วยเหลือ @@ -612,6 +700,14 @@ View Governance Proposals ดูข้อเสนอการกำกับดูแล + + &Hide + &ซ่อน + + + S&how + แ&สดง + %n active connection(s) to Dash network A substring of the tooltip. @@ -633,10 +729,50 @@ Close Wallet… ปิดกระเป๋าสตางค์ … + + Load Partially Signed Blockchain Transaction + โหลดธุรกรรมบล็อกเชนที่ลงลายมือชื่อบางส่วน + + + Load Partially Signed Blockchain Transaction from clipboard + โหลดธุรกรรมบล็อกเชนที่ลงลายมือชื่อบางส่วนจากคลิปบอร์ด + Create Wallet… สร้างกระเป๋าสตางค์ … + + Close All Wallets… + ปิดกระเป๋าสตางค์ทั้งหมด… + + + Ctrl+Shift+D + Ctrl+Shift+D + + + Ctrl+M + Ctrl+M + + + Click for more actions. + A substring of the tooltip. "More actions" are available via the context menu. + คลิกเพื่อดำเนินการเพิ่มเติม + + + Show Peers tab + A context menu item. The "Peers tab" is an element of the "Node window". + แสดงแท็บเพียร์ + + + Disable network activity + A context menu item. + ปิดใช้งานกิจกรรมเครือข่าย + + + Enable network activity + A context menu item. The network activity was disabled previously. + เปิดใช้งานกิจกรรมเครือข่าย + Syncing Headers (%1%)… กำลังซิงค์ส่วนหัว (%1%) … @@ -653,10 +789,6 @@ Processing blocks on disk… กำลังดำเนินการกับบล็อกในดิสก์… - - Reindexing blocks on disk… - กำลังทำดัชนี ที่เก็บบล็อก ใหม่ ในดิสก์… - Connecting to peers… เชื่อมต่อกับ Peers @@ -810,10 +942,6 @@ Coin Selection การเลือก Coin - - Dust: - เศษ: - After Fee: ส่วนที่เหลือจากค่าธรรมเนียม: @@ -874,6 +1002,30 @@ Copy amount คัดลอกจำนวน + + &Copy address + &คัดลอกที่อยู่ + + + Copy &label + คัดลอก&ป้ายกำกับ + + + Copy &amount + คัดลอก&จำนวน + + + Copy transaction &ID and output index + คัดลอก&ID ธุรกรรมและดัชนีเอาต์พุต + + + L&ock unspent + &ล็อกที่ยังไม่ได้ใช้ + + + &Unlock unspent + &ปลดล็อกที่ยังไม่ได้ใช้ + Copy quantity ปริมาณการคัดลอก @@ -890,10 +1042,6 @@ Copy bytes คัดลอกหน่วยของข้อมูลคอมพิวเตอร์ - - Copy dust - คัดลอก dust - Copy change คัดลอกการเปลี่ยนแปลง @@ -906,18 +1054,6 @@ (%1 locked) (%1 ล็อค) - - yes - ใช่ - - - no - ไม่ - - - This label turns red if any recipient receives an amount smaller than the current dust threshold. - ป้ายนี้จะเปลี่ยนเป็นสีแดงถ้าตัวรับใด ๆ ได้รับจำนวนเงินน้อยกว่าขั้นต่ำในปัจจุบัน - Can vary +/- %1 duff(s) per input. สามารถเปลี่ยนแปลงได้ + / - %1 duff (s) ต่อรายการ @@ -961,6 +1097,11 @@ CreateWalletActivity + + Create Wallet + Title of window indicating the progress of creation of a new wallet. + สร้างกระเป๋าสตางค์ + Creating Wallet <b>%1</b>… Descriptive text of the create wallet progress window which indicates to the user which wallet is currently being created. @@ -985,6 +1126,10 @@ Wallet Name ชื่อกระเป๋าเงิน + + Wallet + กระเป๋าสตางค์ + Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice. เข้ารหัสกระเป๋าสตางค์กระเป๋าเงินจะถูกเข้ารหัสด้วยรหัสผ่านที่คุณเลือก @@ -993,6 +1138,10 @@ Encrypt Wallet เข้ารหัสกระเป๋าสตางค์ + + Advanced Options + ตัวเลือกขั้นสูง + 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. ปิดการใช้งานคีย์ส่วนตัวสำหรับกระเป๋าเงินนี้ กระเป๋าเงินที่ปิดการใช้งานคีย์ส่วนตัวและไม่มีคีย์ส่วนตัว HD seed หรือปุ่มส่วนตัวนำเข้าเหมาะสำหรับ จะเป็นเพียงกระเป๋าที่ไม่ได้ใช้งานเท่านั้น @@ -1009,11 +1158,23 @@ Make Blank Wallet ทำกระเป๋าเงินว่างเปล่า + + Use descriptors for scriptPubKey management. This feature is well-tested but still considered experimental and not recommended for use yet. + ใช้ตัวอธิบายสำหรับการจัดการ scriptPubKey คุณสมบัตินี้ผ่านการทดสอบมาอย่างดีแล้ว แต่ยังถือว่าเป็นการทดลองและยังไม่แนะนำให้ใช้ + + + Descriptor Wallet (EXPERIMENTAL) + กระเป๋าสตางค์แบบตัวอธิบาย (ทดลอง) + Create สร้าง - + + Compiled without sqlite support (required for descriptor wallets) + คอมไพล์โดยไม่มีการสนับสนุน sqlite (จำเป็นสำหรับกระเป๋าสตางค์แบบตัวอธิบาย) + + EditAddressDialog @@ -1106,18 +1267,102 @@ Filter proposal list กรองรายการข้อเสนอ + + Masternode Count: + จำนวนมาสเตอร์โหนด: + + + Number of masternodes this wallet can vote with (masternodes for which this wallet holds the voting key) + จำนวนมาสเตอร์โหนดที่กระเป๋าสตางค์นี้สามารถลงคะแนนได้ (มาสเตอร์โหนดที่กระเป๋าสตางค์นี้ถือคีย์การลงคะแนน) + Proposal Count: จำนวนข้อเสนอ: + + Create Proposal + สร้างข้อเสนอ + Filter by Title กรองตามชื่อ + + Unavailable + ไม่พร้อมใช้งาน + + + A synced node and an unlocked wallet are required. + ต้องการโหนดที่ซิงค์แล้วและกระเป๋าสตางค์ที่ปลดล็อก + + + Vote Yes + ลงคะแนนเห็นด้วย + + + Vote No + ลงคะแนนไม่เห็นด้วย + + + Vote Abstain + งดออกเสียง + Proposal Info: %1 ข้อมูลข้อเสนอ: %1 + + Voting Failed + การลงคะแนนล้มเหลว + + + No wallet available. + ไม่มีกระเป๋าสตางค์ที่พร้อมใช้งาน + + + No masternode voting keys found in wallet. + ไม่พบคีย์การลงคะแนนมาสเตอร์โหนดในกระเป๋าสตางค์ + + + Please select a proposal to vote on. + โปรดเลือกข้อเสนอเพื่อลงคะแนน + + + Unable to unlock wallet. + ไม่สามารถปลดล็อกกระเป๋าสตางค์ + + + Unable to get masternode list. Please try again later. + ไม่สามารถรับรายการมาสเตอร์โหนด โปรดลองอีกครั้งในภายหลัง + + + Masternode %1 not found + ไม่พบมาสเตอร์โหนด %1 + + + Failed to sign vote for masternode %1 + ไม่สามารถลงลายมือชื่อการลงคะแนนสำหรับมาสเตอร์โหนด %1 + + + Masternode %1: %2 + มาสเตอร์โหนด %1: %2 + + + Voted successfully %n time(s) + ลงคะแนนสำเร็จ %n ครั้ง + + + Failed to vote %n time(s) + การลงคะแนนล้มเหลว %n ครั้ง + + + Errors: + ข้อผิดพลาด: + + + Voting Results + ผลการลงคะแนน + HelpMessageDialog @@ -1156,10 +1401,26 @@ As this is the first time the program is launched, you can choose where %1 will store its data. นี่เป็นการรันโปรแกรมครั้งแรก ท่านสามารถเลือก ว่าจะเก็บข้อมูลไว้ที่ %1 + + Limit block chain storage to + จำกัดพื้นที่เก็บข้อมูลบล็อกเชนเป็น + + + 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. + การย้อนกลับการตั้งค่านี้ต้องดาวน์โหลดบล็อกเชนทั้งหมดใหม่ การดาวน์โหลดเชนทั้งหมดก่อนและตัดแต่งในภายหลังจะเร็วกว่า จะปิดการใช้งานคุณสมบัติขั้นสูงบางอย่าง + + + GB + GB + 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. การซิงโครไนซ์ในขั้นต้นนี้เป็นที่ต้องการอย่างมาก และอาจจะปรากฏปัญหาของฮ​าร์ดแวร์กับคอมพิวเตอร์ของคุณที่อาจจะไม่ได้สังเกตมาก่อน ในแต่ละครั้งคุณดำเนินการ %1 มันจะดำเนินการดาวน์โหลดที่ค้างไว้ + + 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. + เมื่อคุณคลิกตกลง %1 จะเริ่มดาวน์โหลดและประมวลผลบล็อกเชน %4 ทั้งหมด (%2 GB) โดยเริ่มจากธุรกรรมแรกสุดใน %3 เมื่อ %4 เปิดตัวครั้งแรก + 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. ถ้าคุณได้เลือกที่จะจำกัดตัวเก็บข้อมูลของ block chain (การตัดแต่ง) ข้อมูลในอดีตจะยังคงถูกดาวน์โหลดและดำเนินการ แต่จะถูกลบหลังจากนั้นเพื่อที่จะทำให้การใช้งานดิสก์ของคุณต่ำ @@ -1172,6 +1433,18 @@ Use a custom data directory: ใช้ไดเร็กทอรี่ข้อมูลที่ตั้งค่าเอง: + + %n GB of space available + มีพื้นที่ว่าง %n GB + + + (of %n GB needed) + (จาก %n GB ที่จำเป็น) + + + (%n GB needed for full chain) + (จำเป็น %n GB สำหรับเชนเต็ม) + At least %1 GB of data will be stored in this directory, and it will grow over time. อย่างน้อย %1 GB ของข้อมูลจะถูกเก็บในแฟ้มข้อมูล และมันจะเติบโตขึ้นเมื่อเวลาผ่านไป @@ -1180,6 +1453,11 @@ Approximately %1 GB of data will be stored in this directory. ประมาณ %1 GB ของข้อมูลจะถูกเก็บอยู่ในแฟ้มเอกสารนี้ + + (sufficient to restore backups %n day(s) old) + Explanatory text on the capability of the current prune target. + (เพียงพอสำหรับการกู้คืนข้อมูลสำรอง %n วัน) + %1 will download and store a copy of the Dash block chain. %1 จะกดาวน์โหลดและเก็บสำเนาของ Dash block chain @@ -1197,6 +1475,13 @@ ข้อผิดพลาด + + LoadWalletsActivity + + Loading wallets… + กำลังโหลดกระเป๋าสตางค์… + + MasternodeList @@ -1370,6 +1655,10 @@ Hide ซ่อน + + %1 is currently syncing. It will download headers and blocks from peers and validate them until reaching the tip of the block chain. + %1 กำลังซิงค์อยู่ จะดาวน์โหลดส่วนหัวและบลอกจากเพียร์และตรวจสอบจนกว่าจะถึงปลายสุดของบล็อกเชน + Unknown. Syncing Headers (%1, %2%)… ไม่ทราบการซิงค์ส่วนหัว (%1, %2%)… @@ -1385,6 +1674,11 @@ URI: URI: + + Paste address from clipboard + Tooltip text for button that allows you to paste an address that is in your clipboard. + วางที่อยู่จากคลิปบอร์ด + OpenWalletActivity @@ -1400,6 +1694,11 @@ default wallet กระเป๋าเงินเริ่มต้น + + Open Wallet + Title of window indicating the progress of opening of a wallet. + เปิดกระเป๋าสตางค์ + Opening Wallet <b>%1</b>… Descriptive text of the open wallet progress window which indicates to the user which wallet is currently being opened. @@ -1436,9 +1735,17 @@ &Appearance &ลักษณะ + + Show the icon in the system tray. + แสดงไอคอนในถาดระบบ + + + &Show tray icon + &แสดงไอคอนถาดระบบ + Prune &block storage to - Prune & ที่เก็บข้อมูลบล็อก เพื่อ + Prune &ที่เก็บข้อมูลบล็อก เพื่อ GB @@ -1448,17 +1755,57 @@ Reverting this setting requires re-downloading the entire blockchain. การคืนค่าการตั้งค่านี้ต้องดาวน์โหลดบล็อกเชนทั้งหมดอีกครั้ง + + 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. + Tooltip text for Options window setting that sets the size of the database cache. Explains the corresponding effects of increasing/decreasing this value. + ขนาดแคชฐานข้อมูลสูงสุด แคชที่ใหญ่กว่าสามารถช่วยให้ซิงค์เร็วขึ้น หลังจากนั้นประโยชน์จะน้อยลงสำหรับกรณีการใช้งานส่วนใหญ่ การลดขนาดแคชจะลดการใช้หน่วยความจำ หน่วยความจำ mempool ที่ไม่ได้ใช้จะถูกแบ่งปันสำหรับแคชนี้ + MiB MiB + + Set the number of script verification threads. Negative values correspond to the number of cores you want to leave free to the system. + 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. + ตั้งค่าจำนวนเธรดการตรวจสอบสคริปต์ ค่าลบตรงกับจำนวนคอร์ที่คุณต้องการปล่อยให้เป็นอิสระกับระบบ + + + This allows you or a third party tool to communicate with the node through command-line and JSON-RPC commands. + Tooltip text for Options window setting that enables the RPC server. + สิ่งนี้ช่วยให้คุณหรือเครื่องมือบุคคลที่สามสามารถสื่อสารกับโหนดผ่านคำสั่งบรรทัดคำสั่งและ JSON-RPC + + + Enable R&PC server + An Options window setting to enable the RPC server. + เปิดใช้งานเซิร์ฟเวอร์ R&PC + + + Whether to set subtract fee from amount as default or not. + Tooltip text for Options window setting that sets subtracting the fee from a sending amount as default. + จะตั้งค่าให้หักค่าธรรมเนียมจากจำนวนเป็นค่าเริ่มต้นหรือไม่ + + + Subtract &fee from amount by default + An Options window setting to set subtracting the fee from a sending amount as default. + หัก&ค่าธรรมเนียมจากจำนวนตามค่าเริ่มต้น + + + Enable &PSBT controls + An options window setting to enable PSBT controls. + เปิดใช้งานการควบคุม &PSBT + + + Whether to show PSBT controls. + Tooltip text for options window setting that enables PSBT controls. + จะแสดงการควบคุม PSBT หรือไม่ + Whether to keep the specified custom change address or not. ว่าจะเก็บที่อยู่การเปลี่ยนแปลงที่กำหนดเองที่ระบุหรือไม่ Keep custom change &address - เก็บการเปลี่ยนแปลง & ที่อยู่ที่กำหนดเอง + เก็บการเปลี่ยนแปลง &ที่อยู่ที่กำหนดเอง Show additional tab listing all your masternodes in first sub-tab<br/>and all masternodes on the network in second sub-tab. @@ -1516,6 +1863,14 @@ Enable &multi-session เปิดใช้งาน &multi-session + + Use this many separate masternodes in parallel to mix funds.<br/>Note: You must use this feature carefully.<br/>Make sure you always have recent wallet (auto)backup in a safe place! + ใช้มาสเตอร์โหนดแยกจำนวนนี้แบบขนานเพื่อผสมเงิน<br/>หมายเหตุ: คุณต้องใช้คุณสมบัตินี้อย่างระมัดระวัง<br/>ตรวจสอบให้แน่ใจว่าคุณมีสำรองข้อมูล (อัตโนมัติ) กระเป๋าสตางค์ล่าสุดไว้ในที่ปลอดภัยเสมอ! + + + Parallel sessions + เซสชันแบบขนาน + Mixing rounds รอบผสม @@ -1528,6 +1883,30 @@ Target balance ยอดเงินคงเหลือที่กำหนดไว้ในการทำธุรกรรมแบบ + + How many inputs of each denominated amount are created.<br/>Lower these numbers if you want fewer smaller denominations. + จำนวนอินพุตของแต่ละจำนวนที่ระบุไว้ถูกสร้างขึ้น<br/>ลดตัวเลขเหล่านี้หากคุณต้องการหน่วยย่อยขนาดเล็กน้อยลง + + + Inputs per denomination + อินพุตต่อหน่วย + + + Try to create at least this many inputs for each denominated amount.<br/>Lower this number if you want fewer smaller denominations. + พยายามสร้างอินพุตอย่างน้อยจำนวนนี้สำหรับแต่ละจำนวนที่ระบุไว้<br/>ลดตัวเลขนี้หากคุณต้องการหน่วยย่อยขนาดเล็กน้อยลง + + + Target + เป้าหมาย + + + Create up to this many inputs for each denominated amount.<br/>Lower this number if you want fewer smaller denominations. + สร้างอินพุตได้มากถึงจำนวนนี้สำหรับแต่ละจำนวนที่ระบุไว้<br/>ลดตัวเลขนี้หากคุณต้องการหน่วยย่อยขนาดเล็กน้อยลง + + + Maximum + สูงสุด + Automatically open the Dash Core client port on the router. This only works when your router supports UPnP and it is enabled. เปิด port ลูกค้าของ Dash Core บนเราเตอร์โดยอัตโนมัติ การทำงานนี้ใช้ได้เฉพาะเมื่อเราเตอร์ของคุณรองรับ UPnP และเปิดใช้งานแล้ว @@ -1557,20 +1936,26 @@ แสดง หากพร็อกซี SOCKS5 เป็นค่าเริ่มต้นที่ใช้เพื่อเข้าถึง Peers ผ่านเครือข่ายประเภทนี้ - Options set in this dialog are overridden by the command line or in the configuration file: - ตัวเลือกที่ตั้งไว้ในกล่องโต้ตอบนี้จะถูกแทนที่โดยบรรทัดคำสั่งหรือในไฟล์กำหนดค่า: + Language missing or translation incomplete? Help contributing translations here: +https://explore.transifex.com/dash/dash/ + ภาษาหายไปหรือแปลไม่สมบูรณ์? ช่วยสนับสนุนการแปลที่นี่: +https://explore.transifex.com/dash/dash/ - 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. - มินิไมซ์แอพ แทนการออกจากแอพพลิเคชั่น เมื่อวินโดว์ได้รับการปิด เมื่อเลือกตัวเลือกนี้ แอพพลิเคชั่น จะถูกปิด ก็ต่อเมื่อ มีการเลือกเมนู Exit/ออกจากระบบ เท่านั้น + Third-party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items.<br/>%s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |. + URL ของบุคคลที่สาม (เช่น block explorer) ที่ปรากฏในแท็บธุรกรรมเป็นรายการเมนูบริบท<br/>%s ใน URL จะถูกแทนที่ด้วยแฮชธุรกรรม URL หลายรายการจะถูกคั่นด้วยแนวตั้ง | + + + &Third-party transaction URLs + URL ธุรกรรมของบุคคลที่&สาม - Third party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items.<br/>%s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |. - URL ของบุคคลที่สาม (เช่น explorer บล็อก) ที่ปรากฏในแท็บธุรกรรมเป็นรายการในเมนู<br/> %s ใน URL ถูกแทนที่ด้วย hash การทำธุรกรรม หลาย URL ถูกแยกด้วยแถบแนวตั้ง + Options set in this dialog are overridden by the command line or in the configuration file: + ตัวเลือกที่ตั้งไว้ในกล่องโต้ตอบนี้จะถูกแทนที่โดยบรรทัดคำสั่งหรือในไฟล์กำหนดค่า: - &Third party transaction URLs - &URL ธุรกรรมของบุคคลที่สาม + 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. + มินิไมซ์แอพ แทนการออกจากแอพพลิเคชั่น เมื่อวินโดว์ได้รับการปิด เมื่อเลือกตัวเลือกนี้ แอพพลิเคชั่น จะถูกปิด ก็ต่อเมื่อ มีการเลือกเมนู Exit/ออกจากระบบ เท่านั้น Whether to show coin control features or not. @@ -1660,6 +2045,14 @@ &Display &แสดง + + Connect to the Dash network through a separate SOCKS5 proxy for Tor onion services. + เชื่อมต่อกับเครือข่าย Dash ผ่านพร็อกซี SOCKS5 แยกต่างหากสำหรับบริการ Tor onion + + + Use separate SOCKS&5 proxy to reach peers via Tor onion services: + ใช้พร็อกซี SOCKS&5 แยกต่างหากเพื่อเข้าถึงเพียร์ผ่านบริการ Tor onion: + User Interface &language: หน้าจอผู้ใช้ &ภาษา: @@ -1706,14 +2099,22 @@ Confirm options reset + Window title text of pop-up window shown when the user has chosen to reset options. ยืนยันการรีเซ็ตตัวเลือก Client restart required to activate changes. + Text explaining that the settings changed will not come into effect until the client is restarted. รีสตาร์ทเครื่องไคลเอ็นต์เพื่อเปิดใช้งานการเปลี่ยนแปลง + + Current settings will be backed up at "%1". + 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. + การตั้งค่าปัจจุบันจะถูกสำรองไว้ที่ "%1" + Client will be shut down. Do you want to proceed? + Text asking the user to confirm if they would like to proceed with a client shutdown. ไคลเอนต์จะถูกปิด คุณต้องการดำเนินการต่อหรือไม่? @@ -1851,6 +2252,10 @@ %1 Balance %1 ยอดคงเหลือ + + Discreet mode activated for the Overview tab. To unmask the values, uncheck Settings->Discreet mode. + เปิดใช้งานโหมดปกปิดสำหรับแท็บภาพรวม หากต้องการแสดงค่า ให้ยกเลิกการเลือก การตั้งค่า->โหมดปกปิด + %n Rounds %n รอบ @@ -1950,8 +2355,141 @@ PSBTOperationsDialog - - + + Dialog + กล่องโต้ตอบ + + + Sign Tx + ลงนามธุรกรรม + + + Broadcast Tx + ออกอากาศธุรกรรม + + + Copy to Clipboard + คัดลอกไปยังคลิปบอร์ด + + + Save… + บันทึก… + + + Close + ปิด + + + Failed to load transaction: %1 + โหลดธุรกรรมล้มเหลว: %1 + + + Failed to sign transaction: %1 + ลงนามธุรกรรมล้มเหลว: %1 + + + Cannot sign inputs while wallet is locked. + ไม่สามารถลงนามอินพุตขณะที่กระเป๋าสตางค์ถูกล็อก + + + Could not sign any more inputs. + ไม่สามารถลงนามอินพุตเพิ่มเติมได้ + + + Signed %1 inputs, but more signatures are still required. + ลงนามอินพุต %1 แล้ว แต่ยังต้องการลายเซ็นเพิ่มเติม + + + Signed transaction successfully. Transaction is ready to broadcast. + ลงนามธุรกรรมสำเร็จ ธุรกรรมพร้อมที่จะออกอากาศ + + + Unknown error processing transaction. + ข้อผิดพลาดที่ไม่รู้จักในการประมวลผลธุรกรรม + + + Transaction broadcast successfully! Transaction ID: %1 + ออกอากาศธุรกรรมสำเร็จ! รหัสธุรกรรม: %1 + + + Transaction broadcast failed: %1 + ออกอากาศธุรกรรมล้มเหลว: %1 + + + PSBT copied to clipboard. + คัดลอก PSBT ไปยังคลิปบอร์ดแล้ว + + + Save Transaction Data + บันทึกข้อมูลธุรกรรม + + + Partially Signed Transaction (Binary) + Expanded name of the binary PSBT file format. See: BIP 174. + ธุรกรรมที่ลงนามบางส่วน (ไบนารี) + + + PSBT saved to disk. + บันทึก PSBT ลงดิสก์แล้ว + + + * Sends %1 to %2 + * ส่ง %1 ไปยัง %2 + + + own address + ที่อยู่ของตัวเอง + + + Unable to calculate transaction fee or total transaction amount. + ไม่สามารถคำนวณค่าธรรมเนียมธุรกรรมหรือจำนวนธุรกรรมทั้งหมด + + + Pays transaction fee: + จ่ายค่าธรรมเนียมธุรกรรม: + + + Total Amount + จำนวนทั้งหมด + + + or + หรือ + + + Transaction has %1 unsigned inputs. + ธุรกรรมมีอินพุตที่ไม่ได้ลงนาม %1 รายการ + + + Transaction is missing some information about inputs. + ธุรกรรมขาดข้อมูลบางอย่างเกี่ยวกับอินพุต + + + Transaction still needs signature(s). + ธุรกรรมยังต้องการลายเซ็น + + + (But no wallet is loaded.) + (แต่ไม่มีกระเป๋าสตางค์ที่โหลด) + + + (But this wallet cannot sign transactions.) + (แต่กระเป๋าสตางค์นี้ไม่สามารถลงนามธุรกรรม) + + + (But this wallet does not have the right keys.) + (แต่กระเป๋าสตางค์นี้ไม่มีคีย์ที่ถูกต้อง) + + + Transaction is fully signed and ready for broadcast. + ธุรกรรมถูกลงนามครบถ้วนและพร้อมสำหรับการออกอากาศ + + + Transaction status is unknown. + สถานะธุรกรรมไม่ทราบ + + + PaymentServer Payment request error @@ -1969,6 +2507,12 @@ 'dash://' is not a valid URI. Use 'dash:' instead. 'dash://' ไม่ใช่ URI ที่ถูกต้องใช้ 'dash:' แทน + + Cannot process payment request as BIP70 is no longer supported. +Due to discontinued support, you should request the merchant to provide you with a BIP21 compatible URI or use a wallet that does continue to support BIP70. + ไม่สามารถประมวลผลคำขอชำระเงินได้เนื่องจาก BIP70 ไม่ได้รับการสนับสนุนอีกต่อไป +เนื่องจากการยกเลิกการสนับสนุน คุณควรขอให้ผู้ขายจัดหา URI ที่เข้ากันได้กับ BIP21 หรือใช้กระเป๋าเงินที่ยังคงสนับสนุน BIP70 + URI cannot be parsed! This can be caused by an invalid Dash address or malformed URI parameters. ไม่สามารถประมวลผล URI ได้สำเร็จ ! ซึ่งอาจเกิดจากที่อยู่ Dash ไม่ถูกต้องหรือพารามิเตอร์ URI ที่มีรูปแบบไม่ถูกต้อง @@ -1990,6 +2534,26 @@ Title of Peers Table column which indicates the current latency of the connection with the peer. Ping + + Peer + Title of Peers Table column which contains a unique number used to identify a connection. + เพียร์ + + + Age + Title of Peers Table column which indicates the duration (length of time) since the peer connection started. + อายุ + + + Direction + Title of Peers Table column which indicates the direction the peer connection was initiated from. + ทิศทาง + + + Type + Title of Peers Table column which describes the type of peer connection. The "type" describes why the connection exists. + ประเภท + Sent Title of Peers Table column which indicates the total amount of network information we have sent to the peer. @@ -2000,7 +2564,27 @@ Title of Peers Table column which indicates the total amount of network information we have received from the peer. ได้รับ - + + Address + Title of Peers Table column which contains the IP/Onion/I2P address of the connected peer. + ที่อยู่ + + + Network + Title of Peers Table column which states the network the peer connected through. + เครือข่าย + + + Inbound + An Inbound Connection from a Peer. + ขาเข้า + + + Outbound + An Outbound Connection to a Peer. + ขาออก + + Proposal @@ -2051,8 +2635,193 @@ สถานะ + + ProposalWizard + + Create Governance Proposal + สร้างข้อเสนอการกำกับดูแล + + + Enter proposal details + ใส่รายละเอียดข้อเสนอ + + + A fee will be burned when you prepare the proposal. + ค่าธรรมเนียมจะถูกเผาเมื่อคุณเตรียมข้อเสนอ + + + Proposal &name + &ชื่อข้อเสนอ + + + &Description URL + URL &คำอธิบาย + + + Payment &address + &ที่อยู่การชำระเงิน + + + Payment &amount + &จำนวนการชำระเงิน + + + The amount to request in a single payment + จำนวนที่ขอในการชำระเงินครั้งเดียว + + + &First payment + การชำระเงิน&แรก + + + Pa&yments + การ&ชำระเงิน + + + To&tal amount + จำนวน&ทั้งหมด + + + Proposal &fee + &ค่าธรรมเนียมข้อเสนอ + + + Next + ถัดไป + + + Review proposal JSON and validate. + ตรวจสอบข้อเสนอ JSON และตรวจสอบความถูกต้อง + + + Hex-encoded JSON + JSON เข้ารหัส Hex + + + Back + ย้อนกลับ + + + Validate + ตรวจสอบความถูกต้อง + + + Prepare (burn fee) and wait for confirmations. + เตรียม (เผาค่าธรรมเนียม) และรอการยืนยัน + + + Copy + คัดลอก + + + At 1/6 confirmations: can be relayed and queued. At 6/6: accepted and processed. + ที่ 1/6 การยืนยัน: สามารถรีเลย์และจัดคิวได้ ที่ 6/6: ยอมรับและประมวลผล + + + Confirmations progress + ความคืบหน้าการยืนยัน + + + Shows progress toward the required number of confirmations for the proposal fee transaction. + แสดงความคืบหน้าไปสู่จำนวนการยืนยันที่ต้องการสำหรับธุรกรรมค่าธรรมเนียมข้อเสนอ + + + Estimated time remaining: - + เวลาโดยประมาณที่เหลืออยู่: - + + + Prepare Proposal + เตรียมข้อเสนอ + + + You can submit after 1 confirmation. At 6 confirmations it is accepted and processed. + คุณสามารถส่งหลังจาก 1 การยืนยัน ที่ 6 การยืนยันจะถูกยอมรับและประมวลผล + + + Proposal ID: + รหัสข้อเสนอ: + + + Submit Proposal + ส่งข้อเสนอ + + + Close + ปิด + + + Valid + ถูกต้อง + + + Invalid: %1 + ไม่ถูกต้อง: %1 + + + Burn %1 + เผา %1 + + + Burn %1 to create the fee transaction? + เผา %1 เพื่อสร้างธุรกรรมค่าธรรมเนียม? + + + Prepare failed + การเตรียมล้มเหลว + + + Confirmations: %1 / %2 required + การยืนยัน: %1 / จำเป็น %2 + + + Estimated time remaining: Ready + เวลาโดยประมาณที่เหลืออยู่: พร้อม + + + Estimated time remaining: %n minute(s) + เวลาโดยประมาณที่เหลืออยู่: %n นาที + + + Your proposal was submitted successfully. + ข้อเสนอของคุณถูกส่งสำเร็จแล้ว + + + Already submitted + ส่งไปแล้ว + + + This proposal has already been submitted. + ข้อเสนอนี้ถูกส่งไปแล้ว + + + Submission failed + การส่งล้มเหลว + + + Proposal submitted + ส่งข้อเสนอแล้ว + + + A fee of %1 will be burned when you prepare the proposal. + ค่าธรรมเนียม %1 จะถูกเผาเมื่อคุณเตรียมข้อเสนอ + + + Prepare (burn %1) and wait for %2 confirmations. + เตรียม (เผา %1) และรอ %2 การยืนยัน + + QObject + + Do you want to reset settings to default values, or to abort without making changes? + Explanatory text shown on startup when the settings file cannot be read. Prompts user to make a choice between resetting or aborting. + คุณต้องการรีเซ็ตการตั้งค่าเป็นค่าเริ่มต้น หรือยกเลิกโดยไม่ทำการเปลี่ยนแปลง? + + + A fatal error occurred. Check that settings file is writable, or try running with -nosettings. + 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. + เกิดข้อผิดพลาดร้ายแรง ตรวจสอบว่าไฟล์การตั้งค่าสามารถเขียนได้ หรือลองเรียกใช้ด้วย -nosettings + Choose data directory on startup (default: %u) เลือกไดเร็กทอรี่ข้อมูลตั้งแต่เริ่มต้นสตาร์ทอัพ (ค่าเริ่มต้น: %u) @@ -2153,6 +2922,53 @@ This can also be adjusted later in the "Appearance" tab of the preferences. นอกจากนี้ยังสามารถปรับเปลี่ยนได้ภายหลังในแท็บ "ลักษณะ" ของการตั้งค่า + + Ctrl+W + Ctrl+W + + + Unroutable + ไม่สามารถกำหนดเส้นทางได้ + + + Internal + ภายใน + + + Inbound + An inbound connection from a peer. An inbound connection is a connection initiated by a peer. + ขาเข้า + + + Outbound + An outbound connection to a peer. An outbound connection is a connection initiated by us. + ขาออก + + + Full Relay + Peer connection type that relays all network information. + รีเลย์เต็มรูปแบบ + + + Block Relay + Peer connection type that relays network information about blocks and not transactions or addresses. + รีเลย์บลอก + + + Manual + Peer connection type established manually through one of several methods. + ด้วยตนเอง + + + Feeler + Short-lived peer connection type that tests the aliveness of known addresses. + ผู้สำรวจ + + + Address Fetch + Short-lived peer connection type that solicits known addresses from a peer. + ดึงที่อยู่ + %1 d %1 d @@ -2213,6 +3029,10 @@ %1 B %1 B + + %1 kB + %1 kB + %1 MB %1 MB @@ -2267,7 +3087,12 @@ Save QR Code บันทึกโค้ด QR - + + PNG Image + Expanded name of the PNG file format. See: https://en.wikipedia.org/wiki/Portable_Network_Graphics. + รูปภาพ PNG + + RPCConsole @@ -2374,6 +3199,14 @@ Version เวอร์ชั่น + + High bandwidth BIP152 compact block relay: %1 + การรีเลย์บลอกขนาดกะทัดรัด BIP152 แบนด์วิธสูง: %1 + + + High Bandwidth + แบนด์วิธสูง + Starting Block เริ่มต้นบล็อค @@ -2386,6 +3219,51 @@ Synced Blocks บล็อคที่ซิงโครไนซ์ + + Elapsed time since a novel block passing initial validity checks was received from this peer. + เวลาที่ผ่านไปตั้งแต่ได้รับบลอกใหม่ที่ผ่านการตรวจสอบความถูกต้องเบื้องต้นจากเพียร์นี้ + + + Last Block + บลอกล่าสุด + + + Elapsed time since a novel transaction accepted into our mempool was received from this peer. + Tooltip text for the Last Transaction field in the peer details area. + เวลาที่ผ่านไปตั้งแต่ได้รับธุรกรรมใหม่ที่ยอมรับเข้าสู่ mempool ของเราจากเพียร์นี้ + + + Last Transaction + ธุรกรรมล่าสุด + + + The mapped Autonomous System used for diversifying peer selection. + ระบบอัตโนมัติที่แมปซึ่งใช้สำหรับการกระจายการเลือกเพียร์ + + + Mapped AS + แมป AS + + + Whether we relay addresses to this peer. + Tooltip text for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No). + ว่าเรารีเลย์ที่อยู่ไปยังเพียร์นี้หรือไม่ + + + Address Relay + Text title for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No). + รีเลย์ที่อยู่ + + + Addresses Processed + 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). + ที่อยู่ที่ประมวลผล + + + Addresses Rate-Limited + 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. + ที่อยู่ที่จำกัดอัตรา + Rescan blockchain files 1 สแกน blockchain ไฟล์ 1 @@ -2426,6 +3304,22 @@ To specify a non-default location of the blocks directory use the '%1' option. ในการระบุตำแหน่งที่ไม่ใช่ค่าเริ่มต้นของไดเร็กทอรีบล็อกใช้ตัวเลือก '%1' + + Local Addresses + ที่อยู่ท้องถิ่น + + + Network addresses that your Dash node is currently using to communicate with other nodes. + ที่อยู่เครือข่ายที่โหนด Dash ของคุณกำลังใช้เพื่อสื่อสารกับโหนดอื่น + + + Number of regular Masternodes + จำนวน Masternode ปกติ + + + Number of EvoNodes + จำนวน EvoNode + Current block height ความสูงบล็อกปัจจุบัน @@ -2474,10 +3368,50 @@ PoSe Score คะแนน PoSe + + The transport layer version: %1 + เวอร์ชันชั้นการขนส่ง: %1 + + + Transport + การขนส่ง + + + The BIP324 session ID string in hex. + สตริง ID เซสชัน BIP324 ในรูปแบบเลขฐานสิบหก + + + Session ID + ID เซสชัน + + + The network protocol this peer is connected through: IPv4, IPv6, Onion, I2P, or CJDNS. + โปรโตคอลเครือข่ายที่เพียร์นี้เชื่อมต่อผ่าน: IPv4, IPv6, Onion, I2P หรือ CJDNS + + + Permissions + สิทธิ์ + + + The direction and type of peer connection: %1 + ทิศทางและประเภทของการเชื่อมต่อเพียร์: %1 + + + Direction/Type + ทิศทาง/ประเภท + Services บริการ + + Whether we relay transactions to this peer. + ว่าเรารีเลย์ธุรกรรมไปยังเพียร์นี้หรือไม่ + + + Transaction Relay + รีเลย์ธุรกรรม + Connection Time เวลาในการเชื่อมต่อ @@ -2514,6 +3448,16 @@ &Wallet Repair &ซ่อมกระเป๋าสตางค์ + + The total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting). + 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). + จำนวนที่อยู่ทั้งหมดที่ได้รับจากเพียร์นี้ที่ถูกประมวลผล (ไม่รวมที่อยู่ที่ถูกทิ้งเนื่องจากการจำกัดอัตรา) + + + The total number of addresses received from this peer that were dropped (not processed) due to rate-limiting. + 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. + จำนวนที่อยู่ทั้งหมดที่ได้รับจากเพียร์นี้ที่ถูกทิ้ง (ไม่ประมวลผล) เนื่องจากการจำกัดอัตรา + Wallet repair options. ตัวเลือกการซ่อมแซมกระเป๋าสตางค์ @@ -2526,6 +3470,60 @@ -reindex: Rebuild block chain index from current blk000??.dat files. -reindex: สร้างดัชนี blockchain ใหม่จากไฟล์ blk000??.dat ปัจจุบัน + + Inbound: initiated by peer + Explanatory text for an inbound peer connection. + ขาเข้า: เริ่มต้นโดยเพียร์ + + + Outbound Full Relay: default + Explanatory text for an outbound peer connection that relays all network information. This is the default behavior for outbound connections. + ขาออกรีเลย์เต็มรูปแบบ: ค่าเริ่มต้น + + + Outbound Block Relay: does not relay transactions or addresses + Explanatory text for an outbound peer connection that relays network information about blocks and not transactions or addresses. + ขาออกรีเลย์บลอก: ไม่รีเลย์ธุรกรรมหรือที่อยู่ + + + Outbound Manual: added using RPC %1 or %2/%3 configuration options + 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. + ขาออกด้วยตนเอง: เพิ่มโดยใช้ RPC %1 หรือตัวเลือกการกำหนดค่า %2/%3 + + + Outbound Feeler: short-lived, for testing addresses + Explanatory text for a short-lived outbound peer connection that is used to test the aliveness of known addresses. + ขาออกผู้สำรวจ: มีอายุสั้น สำหรับทดสอบที่อยู่ + + + Outbound Address Fetch: short-lived, for soliciting addresses + Explanatory text for a short-lived outbound peer connection that is used to request addresses from a peer. + ขาออกดึงที่อยู่: มีอายุสั้น สำหรับขอที่อยู่ + + + To + ถึง + + + we selected the peer for high bandwidth relay + เราเลือกเพียร์นี้สำหรับรีเลย์แบนด์วิดท์สูง + + + From + จาก + + + the peer selected us for high bandwidth relay + เพียร์เลือกเราสำหรับรีเลย์แบนด์วิดท์สูง + + + No + ไม่ + + + no high bandwidth relay selected + ไม่ได้เลือกรีเลย์แบนด์วิดท์สูง + &Disconnect &ยกเลิกการเชื่อมต่อ @@ -2562,6 +3560,10 @@ Network activity disabled ปิดการใช้งานเครือข่ายแล้ว + + None + ไม่มี + Total: %1 (Enabled: %2) ทั้งหมด: %1 (เปิดใช้งาน: %2) @@ -2570,10 +3572,105 @@ Executing command without any wallet ปฎิบัติการคำสั่งโดยไม่ต้องใช้กระเป๋าสตางค์ใด ๆ + + Ctrl++ + Main shortcut to increase the RPC console font size. + Ctrl++ + + + Ctrl+= + Secondary shortcut to increase the RPC console font size. + Ctrl+= + + + Ctrl+- + Main shortcut to decrease the RPC console font size. + Ctrl+- + + + Ctrl+_ + Secondary shortcut to decrease the RPC console font size. + Ctrl+_ + + + Ctrl+Shift+I + Ctrl+Shift+I + + + Ctrl+Shift+C + Ctrl+Shift+C + + + Ctrl+Shift+G + Ctrl+Shift+G + + + Ctrl+Shift+P + Ctrl+Shift+P + + + Ctrl+Shift+R + Ctrl+Shift+R + Executing command using "%1" wallet ปฎิบัติการคำสั่งโดยใช้ "%1" กระเป๋าสตางค์ + + detecting: peer could be v1 or v2 + Explanatory text for "detecting" transport type. + กำลังตรวจจับ: เพียร์อาจเป็น v1 หรือ v2 + + + v1: unencrypted, plaintext transport protocol + Explanatory text for v1 transport type. + v1: โปรโตคอลการส่งข้อมูลแบบไม่เข้ารหัส ข้อความธรรมดา + + + v2: BIP324 encrypted transport protocol + Explanatory text for v2 transport type. + v2: โปรโตคอลการส่งข้อมูลเข้ารหัส BIP324 + + + &Copy address + Context menu action to copy the address of a peer + &คัดลอกที่อยู่ + + + 1 d&ay + 1 &วัน + + + &Copy IP/Netmask + 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 + &คัดลอก IP/Netmask + + + 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 + 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. + ยินดีต้อนรับสู่คอนโซล RPC %1 +ใช้ลูกศรขึ้นและลงเพื่อนำทางประวัติ และ %2 เพื่อล้างหน้าจอ +ใช้ %3 และ %4 เพื่อเพิ่มหรือลดขนาดตัวอักษร +พิมพ์ %5 เพื่อดูภาพรวมของคำสั่งที่มี +สำหรับข้อมูลเพิ่มเติมเกี่ยวกับการใช้คอนโซลนี้ พิมพ์ %6 + +%7คำเตือน: มีผู้หลอกลวงที่บอกให้ผู้ใช้พิมพ์คำสั่งที่นี่ เพื่อขโมยเนื้อหาในกระเป๋าสตางค์ของพวกเขา อย่าใช้คอนโซลนี้โดยไม่เข้าใจผลกระทบของคำสั่งอย่างเต็มที่%8 + + + Executing… + A console message indicating an entered command is currently being executed. + กำลังดำเนินการ… + + + (peer: %1) + (เพียร์: %1) + via %1 via %1 @@ -2590,11 +3687,19 @@ Verified Masternode Masternode ที่ตรวจสอบแล้ว + + Yes + ใช่ + Unknown ไม่ทราบ - + + Never + ไม่เคย + + ReceiveCoinsDialog @@ -2673,9 +3778,61 @@ Enter a message to attach to the payment request ป้อนข้อความที่จะแนบไปร้องขอการชำระเงิน - + + Copy &URI + คัดลอก &URI + + + &Copy address + &คัดลอกที่อยู่ + + + Copy &label + คัดลอก&ป้ายกำกับ + + + Copy &message + คัดลอก&ข้อความ + + + Copy &amount + คัดลอก&จำนวน + + + Could not unlock wallet. + ไม่สามารถปลดล็อกกระเป๋าเงินได้ + + + Could not generate new address + ไม่สามารถสร้างที่อยู่ใหม่ได้ + + ReceiveRequestDialog + + Request payment to … + ขอการชำระเงินไปยัง … + + + Address: + ที่อยู่: + + + Amount: + จำนวน: + + + Label: + ป้ายกำกับ: + + + Message: + ข้อความ: + + + Wallet: + กระเป๋าเงิน: + Copy &URI คัดลอก &URI @@ -2728,6 +3885,34 @@ ร้องขอ + + RestoreWalletActivity + + Restore Wallet + Title of progress window which is displayed when wallets are being restored. + กู้คืนกระเป๋าเงิน + + + Restoring Wallet <b>%1</b>… + Descriptive text of the restore wallets progress window which indicates to the user that wallets are currently being restored. + กำลังกู้คืนกระเป๋าเงิน <b>%1</b>… + + + Restore wallet failed + Title of message box which is displayed when the wallet could not be restored. + การกู้คืนกระเป๋าเงินล้มเหลว + + + Restore wallet warning + Title of message box which is displayed when the wallet is restored with some warning. + คำเตือนการกู้คืนกระเป๋าเงิน + + + Restore wallet message + Title of message box which is displayed when the wallet is successfully restored. + ข้อความการกู้คืนกระเป๋าเงิน + + SendCoinsDialog @@ -2762,10 +3947,6 @@ Fee: ค่าธรรมเนียม: - - Dust: - เศษ: - Inputs… ปัจจัยการผลิต… @@ -2890,10 +4071,6 @@ Copy bytes คัดลอกไบต์ - - Copy dust - คัดลอก dust - Copy change คัดลอกการเปลี่ยนแปลง @@ -2910,10 +4087,6 @@ %1 to %2 %1 ถึง %2 - - Are you sure you want to send? - คุณแน่ใจว่าคุณต้องการส่งใช่หรือไม่? - <b>(%1 of %2 entries displayed)</b> <b>(%1 of %2 รายการที่แสดง)</b> @@ -2930,10 +4103,6 @@ Cr&eate Unsigned Cr&eate ไม่ได้ลงนาม - - Creates a Partially Signed Bitcoin Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet. - สร้างธุรกรรม Bitcoin ที่ลงนามบางส่วน (PSBT) เพื่อใช้กับเช่น กระเป๋าเงิน %1 แบบออฟไลน์ หรือกระเป๋าเงินฮาร์ดแวร์ที่เข้ากันได้กับ PSBT - from wallet '%1' จากกระเป๋าเงิน '%1' @@ -2942,10 +4111,6 @@ %1 to '%2' %1 ถึง '%2' - - Do you want to draft this transaction? - คุณต้องการร่างธุรกรรมนี้หรือไม่? - %1 funds only ทำธุรกรรมแบบ %1 เฉพาะในกองทุนเท่านั้น @@ -2995,17 +4160,50 @@ ยืนยันการส่งเหรียญ - Confirm transaction proposal - ยืนยันข้อเสนอการทำธุรกรรม + Save Transaction Data + บันทึกข้อมูลธุรกรรม - Send - ส่ง + PSBT saved + บันทึก PSBT แล้ว + + + Watch-only balance: + ยอดคงเหลือเฉพาะดู: + + + Creates a Partially Signed Blockchain Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet. + สร้าง Partially Signed Blockchain Transaction (PSBT) สำหรับใช้กับกระเป๋าเงิน %1 แบบออฟไลน์ หรือกระเป๋าเงินฮาร์ดแวร์ที่รองรับ PSBT + + + Do you want to create this transaction? + 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. + คุณต้องการสร้างธุรกรรมนี้หรือไม่? + + + Please, review your transaction proposal. This will produce a Partially Signed Blockchain Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet. + 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. + โปรดตรวจสอบข้อเสนอธุรกรรมของคุณ จะสร้าง Partially Signed Blockchain Transaction (PSBT) ที่คุณสามารถบันทึกหรือคัดลอกแล้วลงนามด้วยกระเป๋าเงิน %1 แบบออฟไลน์ หรือกระเป๋าเงินฮาร์ดแวร์ที่รองรับ PSBT + + + Please, review your transaction. You can create and send this transaction or create a Partially Signed Blockchain Transaction (PSBT), which you can save or copy and then sign with, e.g., an offline %1 wallet, or a PSBT-compatible hardware wallet. + 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. + โปรดตรวจสอบธุรกรรมของคุณ คุณสามารถสร้างและส่งธุรกรรมนี้ หรือสร้าง Partially Signed Blockchain Transaction (PSBT) ที่คุณสามารถบันทึกหรือคัดลอกแล้วลงนามด้วยกระเป๋าเงิน %1 แบบออฟไลน์ หรือกระเป๋าเงินฮาร์ดแวร์ที่รองรับ PSBT + + + Please, review your transaction. + Text to prompt a user to review the details of the transaction they are attempting to send. + โปรดตรวจสอบธุรกรรมของคุณ To review recipient list click "Show Details…" หากต้องการตรวจสอบรายชื่อผู้รับ คลิก "แสดงรายละเอียด…" + + Partially Signed Transaction (Binary) + Expanded name of the binary PSBT file format. See: BIP 174. + ธุรกรรมที่ลงนามบางส่วน (ไบนารี) + The recipient address is not valid. Please recheck. ที่อยู่ผู้รับไม่ถูกต้อง โปรดตรวจสอบอีกครั้ง @@ -3125,21 +4323,16 @@ A message that was attached to the dash: URI which will be stored with the transaction for your reference. Note: This message will not be sent over the Dash network. ข้อความที่แนบมาไปยัง Dash: URI ซึ่งจะถูกเก็บไว้กับธุรกรรมเพื่อเป็นข้อมูลอ้างอิงของคุณ หมายเหตุ: ข้อความนี้จะถูกส่งไปยังเครือข่าย Dash + + + SendConfirmationDialog - This is an unauthenticated payment request. - นี่คือคำขอชำระเงินที่ไม่ได้รับการพิสูจน์ตัวตน - - - This is an authenticated payment request. - นี่คือคำขอชำระเงินที่ได้รับการพิสูจน์ตัวตน - - - Pay To: - จ่ายไปยัง: + Send + ส่ง - Memo: - Memo: + Create Unsigned + สร้างแบบไม่ลงนาม @@ -3279,6 +4472,10 @@ Wallet unlock was cancelled. ยกเลิกการปลดล็อกกระเป๋าสตางค์แล้ว + + No error + ไม่มีข้อผิดพลาด + Private key for the entered address is not available. คีย์ส่วนตัวสำหรับที่อยู่ที่ป้อนไปไม่สามารถใช้งานได้ @@ -3314,9 +4511,21 @@ SplashScreen - + + (press q to shutdown and continue later) + (กด q เพื่อปิดและดำเนินการต่อในภายหลัง) + + + press q to shutdown + กด q เพื่อปิด + + TrafficGraphWidget + + kB/s + กิโลไบต์/วินาที + Total ยอดรวม: @@ -3332,20 +4541,9 @@ TransactionDesc - - Open for %n more block(s) - เปิดสำหรับ %n บล็อกเพิ่มเติม - - - Open until %1 - เปิดจนถึง %1 - - - conflicted - ขัดแย้ง - 0/unconfirmed, %1 + 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. 0 / ยังไม่ได้ยืนยัน %1 @@ -3358,22 +4556,32 @@ abandoned + 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. ถูกละทิ้ง + + conflicted with a transaction with %1 confirmations + 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. + ขัดแย้งกับธุรกรรมที่มี %1 การยืนยัน + %1/unconfirmed + 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, and still not locked via ChainLocks. %1 / ยังไม่ได้ยืนยัน %1 confirmations + 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 or locked via ChainLocks. %1 ยืนยัน locked via ChainLocks + 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 and has been locked by ChainLocks. ล็อกผ่าน Chainlocks verified via InstantSend + 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 has been locked by InstantSend. ยืนยันผ่าน InstantSend @@ -3392,6 +4600,10 @@ Generated สร้าง + + Platform Transfer + การโอนแพลตฟอร์ม + From จาก @@ -3522,14 +4734,6 @@ Address / Label ที่อยู่ / ป้ายชื่อ - - Open for %n more block(s) - เปิดอีก %n บล็อค - - - Open until %1 - เปิดจนถึง %1 - Unconfirmed ไม่มีการยืนยัน @@ -3590,6 +4794,10 @@ Mined Mined + + Platform Transfer + การโอนแพลตฟอร์ม + %1 Mixing %1 ผสม @@ -3717,6 +4925,10 @@ Mined ขุด + + Platform Transfer + การโอนแพลตฟอร์ม + Other อื่นๆ @@ -3729,10 +4941,64 @@ Min amount จำนวนเงินขั้นต่ำ + + &Copy address + &คัดลอกที่อยู่ + + + Copy &label + คัดลอก&ป้ายกำกับ + + + Copy &amount + คัดลอก&จำนวน + + + Copy transaction &ID + คัดลอก&ID ธุรกรรม + + + Copy &raw transaction + คัดลอกธุรกรรม&ดิบ + + + Copy full transaction &details + คัดลอก&รายละเอียดธุรกรรมทั้งหมด + + + &Show transaction details + &แสดงรายละเอียดธุรกรรม + + + A&bandon transaction + ละ&ทิ้งธุรกรรม + + + Rese&nd transaction + ส่งธุรกรรมอีก&ครั้ง + + + &Edit address label + &แก้ไขป้ายกำกับที่อยู่ + + + Show address &QR code + แสดงรหัส &QR ของที่อยู่ + + + Show in %1 + 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. + แสดงใน %1 + Export Transaction History ส่งออกประวัติการทำธุรกรรม + + Comma separated file + Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values. + ไฟล์แยกด้วยจุลภาค + Confirmed ยืนยันแล้ว @@ -3811,7 +5077,15 @@ Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled. การปิดกระเป๋าเงินค้างไว้นานเกินไปอาจส่งผลให้มีการเข้าถึงเชนทั้งหมดหากเปิดใช้งาน pruning - + + Close all wallets + ปิดกระเป๋าเงินทั้งหมด + + + Are you sure you wish to close all wallets? + คุณแน่ใจหรือไม่ว่าต้องการปิดกระเป๋าเงินทั้งหมด? + + WalletFrame @@ -3826,7 +5100,31 @@ Go to File > Open Wallet to load a wallet. Create a new wallet สร้างกระเป๋าเงินใหม่ - + + Error + ข้อผิดพลาด + + + Unable to decode PSBT from clipboard (invalid base64) + ไม่สามารถถอดรหัส PSBT จากคลิปบอร์ด (base64 ไม่ถูกต้อง) + + + Load Transaction Data + โหลดข้อมูลธุรกรรม + + + Partially Signed Transaction (*.psbt) + ธุรกรรมที่ลงนามบางส่วน (*.psbt) + + + PSBT file must be smaller than 100 MiB + ไฟล์ PSBT ต้องมีขนาดเล็กกว่า 100 MiB + + + Unable to decode PSBT + ไม่สามารถถอดรหัส PSBT + + WalletModel @@ -3852,6 +5150,11 @@ Go to File > Open Wallet to load a wallet. Selected amount: จำนวนที่เลือก: + + Wallet Data + Name of the wallet data file format. + ข้อมูลกระเป๋าเงิน + Backup Wallet สำรองกระเป๋าสตางค์ @@ -3879,14 +5182,6 @@ Go to File > Open Wallet to load a wallet. dash-core - - Error: Listening for incoming connections failed (listen returned error %s) - ข้อผิดพลาด: ฟังการเชื่อมต่อขาเข้าล้มเหลว (ฟังข้อผิดพลาด %s) - - - Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee. - การประมาณค่าธรรมเนียมล้มเหลว Fallbackfee ถูกปิดการใช้งาน รอสองสามช่วงบล็อกหรือเปิดใช้งาน -fallbackfee - 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 ข้อผิดพลาดนี้อาจเกิดขึ้นหากกระเป๋าเงินนี้ไม่ได้ปิดระบบอย่างหมดจดและถูกโหลดครั้งสุดท้ายโดยใช้การสร้างที่มีรุ่นใหม่กว่าของ Berkeley DB ถ้าเป็นเช่นนั้นโปรดใช้ซอฟต์แวร์ที่โหลดล่าสุดกระเป๋าเงินนี้ @@ -3944,16 +5239,20 @@ Go to File > Open Wallet to load a wallet. เกิดข้อผิดพลาดในการอ่านจากฐานข้อมูล, กำลังปิดเครื่อง - Failed to listen on any port. Use -listen=0 if you want this. - เกิดข้อผิดพลาดในการฟัง port ใด ๆ ใช้ -listen = 0 ถ้าต้องการ + Error: Missing checksum + ข้อผิดพลาด: ไม่มีเช็คซัม + + + Error: Unable to parse version %u as a uint32_t + ข้อผิดพลาด: ไม่สามารถแยกวิเคราะห์เวอร์ชัน %u เป็น uint32_t - -maxtxfee is set very high! Fees this large could be paid on a single transaction. - -maxtxfee ตั้งค่าไว้สูงมาก! ค่าธรรมเนียมที่มีขนาดใหญ่นี้สามารถจ่ายได้เมื่อทำธุรกรรมครั้งเดียว + Error: Unable to write record to new wallet + ข้อผิดพลาด: ไม่สามารถเขียนบันทึกไปยังกระเป๋าเงินใหม่ - Cannot provide specific connections and have addrman find outgoing connections at the same. - ไม่สามารถให้การเชื่อมต่อที่เฉพาะเจาะจงและมี addrman พบการเชื่อมต่อขาออกในเวลาเดียวกัน + Failed to listen on any port. Use -listen=0 if you want this. + เกิดข้อผิดพลาดในการฟัง port ใด ๆ ใช้ -listen = 0 ถ้าต้องการ Found unconfirmed denominated outputs, will wait till they confirm to continue. @@ -3963,10 +5262,6 @@ Go to File > Open Wallet to load a wallet. Invalid -socketevents ('%s') specified. Only these modes are supported: %s -socketevents ไม่ถูกต้อง ('%s') ที่ระบุไว้ เฉพาะโหมดเหล่านี้ได้รับการสนับสนุน: %s - - Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions) - จำนวนเงินไม่ถูกต้องสำหรับ -maxtxfee = <amount>'%s' (ต้องมีอย่างน้อยค่าธรรมเนียงการส่งของ %s เพื่อป้องกันธุรกรรมที่ติดค้าง) - SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is supported SQLiteDatabase: ไม่รู้จัก sqlite wallet schema เวอร์ชัน %d. รองรับเฉพาะเวอร์ชัน %d เท่านั้น @@ -3975,6 +5270,10 @@ Go to File > Open Wallet to load a wallet. Transaction index can't be disabled with governance validation enabled. Either start with -disablegovernance command line switch or enable transaction index. ดัชนีการทำธุรกรรมไม่สามารถปิดการใช้งานกับการตรวจสอบการกำกับดูแลการเปิดใช้งาน ทั้งสองเริ่มต้นด้วย -disablegovernance command line switch หรือเปิดใช้งานดัชนีการทำธุรกรรม + + Unsupported category-specific logging level -loglevel=%s. Expected -loglevel=<category>:<loglevel>. Valid categories: %s. Valid loglevels: %s. + ระดับการบันทึกเฉพาะหมวดหมู่ที่ไม่รองรับ -loglevel=%s คาดว่า -loglevel=<category>:<loglevel> หมวดหมู่ที่ถูกต้อง: %s ระดับบันทึกที่ถูกต้อง: %s + Can't mix: no compatible inputs found! ไม่สามารถผสมได้: ไม่พบอินพุตที่เข้ากันได้! @@ -3983,6 +5282,14 @@ Go to File > Open Wallet to load a wallet. Entry exceeds maximum size. รายการมีขนาดสูงเกินไป + + Error upgrading evo database for EHF + ข้อผิดพลาดในการอัปเกรดฐานข้อมูล evo สำหรับ EHF + + + Failed to commit Evo database + ล้มเหลวในการคอมมิตฐานข้อมูล Evo + Found enough users, signing ( waiting %s ) พบผู้ใช้เพียงพอ, กำลังลงนาม… ( กำลังรอ %s ) @@ -4007,18 +5314,14 @@ Go to File > Open Wallet to load a wallet. Insufficient funds. เงินทุนไม่เพียงพอ - - Invalid amount for -discardfee=<amount>: '%s' - จำนวนเงินไม่ถูกต้องสำหรับ -discardfee=<amount>: '%s' - - - Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s) - จำนวนที่ไม่ถูกต้องสำหรับ -paytxfee = <amount>: '%s' (ต้องมีอย่างน้อย %s) - Invalid minimum number of spork signers specified with -minsporkkeys จำนวนขั้นต่ำ spork signers ไม่ถูกต้องระบุด้วย -minsporkkeys + + Listening for incoming connections failed (listen returned error %s) + การรอรับการเชื่อมต่อขาเข้าล้มเหลว (listen ส่งคืนข้อผิดพลาด %s) + Lock is already in place. ล็อกอยู่ในตำแหน่งแล้ว @@ -4075,6 +5378,10 @@ Go to File > Open Wallet to load a wallet. Synchronizing governance objects… กำลังปรับเทียบออบเจคการกำกับ … + + Transaction change output index out of range + ดัชนีเอาต์พุตเงินทอนของธุรกรรมอยู่นอกช่วง + Unable to start HTTP server. See debug log for details. ไม่สามารถเริ่มต้นเซิร์ฟเวอร์ HTTPได้ ดูบันทึกดีบักเพื่อดูรายละเอียด @@ -4083,6 +5390,10 @@ Go to File > Open Wallet to load a wallet. Unknown response. การตอบสนองที่ไม่รู้จัก + + Unsupported global logging level -loglevel=%s. Valid values: %s. + ระดับการบันทึกระดับโลกที่ไม่รองรับ -loglevel=%s ค่าที่ถูกต้อง: %s + User Agent comment (%s) contains unsafe characters. ตัวแทนผู้ใช้แสดงความคิดเห็น (%s) มีอักขระที่ไม่ปลอดภัย @@ -4123,6 +5434,10 @@ Go to File > Open Wallet to load a wallet. Make sure to encrypt your wallet and delete all non-encrypted backups after you have verified that the wallet works! ตรวจสอบให้แน่ใจว่าได้เข้ารหัสกระเป๋าสตางค์ของคุณและลบสำเนาสำรองที่ไม่ได้เข้ารหัสทั้งหมดหลังจากยืนยันว่า wallet ของคุณทำงานได้! + + More than one onion bind address is provided. Using %s for the automatically created Tor onion service. + มีการระบุที่อยู่ผูกมัด onion มากกว่าหนึ่งรายการ ใช้ %s สำหรับบริการ Tor onion ที่สร้างขึ้นโดยอัตโนมัติ + Prune configured below the minimum of %d MiB. Please use a higher number. Prune มีการกำหนดค่าขั้นต่ำ %d MiB โปรดใช้หมายเลขที่สูงกว่า @@ -4192,20 +5507,32 @@ Go to File > Open Wallet to load a wallet. ข้อผิดพลาดในการโหลด %s: คีย์ส่วนตัวสามารถปิดการใช้งานได้ในระหว่างการสร้างเท่านั้น - Error upgrading evo database - ฐานข้อมูลข้อผิดพลาดในการอัพเกรด evo + Error: Couldn't create cursor into database + ข้อผิดพลาด: ไม่สามารถสร้างเคอร์เซอร์ในฐานข้อมูล Error: Disk space is low for %s ข้อผิดพลาด: พื้นที่ดิสก์ต่ำสำหรับ %s - Exceeded max tries. - เกินความพยายามสูงสุด + Error: Dumpfile checksum does not match. Computed %s, expected %s + ข้อผิดพลาด: เช็คซัมไฟล์ดัมป์ไม่ตรงกัน คำนวณได้ %s คาดว่า %s + + + Error: Got key that was not hex: %s + ข้อผิดพลาด: ได้รับคีย์ที่ไม่ใช่ hex: %s + + + Error: Got value that was not hex: %s + ข้อผิดพลาด: ได้รับค่าที่ไม่ใช่ hex: %s + + + Error: Keypool ran out, please call keypoolrefill first + ข้อผิดพลาด: คีย์พูลหมดแล้ว โปรดเรียก keypoolrefill ก่อน - Failed to commit EvoDB - ล้มเหลวในการกระทำ EvoDB + Error: No addresses available. + ข้อผิดพลาด: ไม่มีที่อยู่ที่ใช้งานได้ Failed to create backup %s! @@ -4227,6 +5554,10 @@ Go to File > Open Wallet to load a wallet. Failed to verify database ตรวจสอบฐานข้อมูลไม่สำเร็จ + + Fee rate (%s) is lower than the minimum fee rate setting (%s) + อัตราค่าธรรมเนียม (%s) ต่ำกว่าการตั้งค่าอัตราค่าธรรมเนียมขั้นต่ำ (%s) + Found enough users, signing… พบผู้ใช้เพียงพอ, กำลังลงนาม… @@ -4236,12 +5567,12 @@ Go to File > Open Wallet to load a wallet. ละเว้น duplicate -wallet %s. - Invalid P2P permission: '%s' - การอนุญาต P2P ไม่ถูกต้อง: '%s' + Input not found or already spent + ไม่พบอินพุตหรือใช้จ่ายไปแล้ว - Invalid amount for -fallbackfee=<amount>: '%s' - จำนวนเงินที่ไม่ถูกต้องสำหรับ -fallbackfee = 1: '%s' + Invalid P2P permission: '%s' + การอนุญาต P2P ไม่ถูกต้อง: '%s' Invalid masternodeblsprivkey. Please see documentation. @@ -4263,6 +5594,10 @@ Go to File > Open Wallet to load a wallet. Mixing in progress… อยู่ระหว่างการผสม… + + No addresses available + ไม่มีที่อยู่ที่ใช้งานได้ + No errors detected. ไม่พบข้อผิดพลาด @@ -4339,6 +5674,10 @@ Go to File > Open Wallet to load a wallet. This is the transaction fee you will pay if you send a transaction. นี่คือค่าธรรมเนียมการทำธุรกรรมที่คุณจะจ่ายหากคุณส่งธุรกรรม + + Topping up keypool… + กำลังเติมคีย์พูล… + Transaction amounts must not be negative ธุรกรรมจะต้องไม่เป็นลบ @@ -4367,13 +5706,17 @@ Go to File > Open Wallet to load a wallet. Unable to generate initial keys ไม่สามารถสร้างคีย์เริ่มต้น + + Unable to open %s for writing + ไม่สามารถเปิด %s เพื่อเขียน + Unknown -blockfilterindex value %s. ไม่ทราบค่า blockfilterindex %s - Upgrading UTXO database - การอัพเกรดฐานข้อมูล UTXO + Unknown new rules activated (versionbit %i) + กฎใหม่ที่ไม่รู้จักถูกเปิดใช้งาน (versionbit %i) Verifying blocks… @@ -4391,6 +5734,10 @@ Go to File > Open Wallet to load a wallet. Wasn't able to create wallet backup folder %s! ไม่สามารถสร้างโฟลเดอร์สำรองกระเป๋าสตางค์ได้ %s! + + Wiping wallet transactions… + กำลังลบธุรกรรมกระเป๋าเงิน… + You can not start a masternode with wallet enabled. คุณไม่สามารถเริ่มต้น masternode กับกระเป๋าสตางค์เปิดการใช้งาน @@ -4411,6 +5758,22 @@ Go to File > Open Wallet to load a wallet. %s uses exact denominated amounts to send funds, you might simply need to mix some more coins. การทำธุรกรรมแบบปกปิดข้อมูล %s ใช้จำนวนเงินตามสกุลเงินที่แน่นอน คุณอาจเพียงต้องผสมเหรียญเพิ่มเติม + + -reindex-chainstate option is not compatible with -blockfilterindex. Please temporarily disable blockfilterindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes. + ตัวเลือก -reindex-chainstate ไม่สามารถใช้งานร่วมกับ -blockfilterindex ได้ โปรดปิดการใช้งาน blockfilterindex ชั่วคราวขณะใช้ -reindex-chainstate หรือแทนที่ -reindex-chainstate ด้วย -reindex เพื่อสร้างดัชนีทั้งหมดใหม่อย่างสมบูรณ์ + + + -reindex-chainstate option is not compatible with -coinstatsindex. Please temporarily disable coinstatsindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes. + ตัวเลือก -reindex-chainstate ไม่สามารถใช้งานร่วมกับ -coinstatsindex ได้ โปรดปิดการใช้งาน coinstatsindex ชั่วคราวขณะใช้ -reindex-chainstate หรือแทนที่ -reindex-chainstate ด้วย -reindex เพื่อสร้างดัชนีทั้งหมดใหม่อย่างสมบูรณ์ + + + -reindex-chainstate option is not compatible with -txindex. Please temporarily disable txindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes. + ตัวเลือก -reindex-chainstate ไม่สามารถใช้งานร่วมกับ -txindex ได้ โปรดปิดการใช้งาน txindex ชั่วคราวขณะใช้ -reindex-chainstate หรือแทนที่ -reindex-chainstate ด้วย -reindex เพื่อสร้างดัชนีทั้งหมดใหม่อย่างสมบูรณ์ + + + Cannot downgrade wallet from version %i to version %i. Wallet version unchanged. + ไม่สามารถดาวน์เกรดกระเป๋าเงินจากเวอร์ชัน %i เป็นเวอร์ชัน %i ได้ เวอร์ชันกระเป๋าเงินไม่เปลี่ยนแปลง + Cannot obtain a lock on data directory %s. %s is probably already running. ไม่สามารถรับการล็อกไดเรกทอรี่ข้อมูล %s ได้ %s ซึ่งมันอาจทำงานอยู่แล้ว @@ -4423,14 +5786,82 @@ Go to File > Open Wallet to load a wallet. Error loading %s: You can't enable HD on an already existing non-HD wallet เกิดข้อผิดพลาดในการโหลด %s: คุณไม่สามารถเปิดใช้งาน HD บนกระเป๋าสตางค์ที่ไม่ใช่ของ HD ที่มีอยู่แล้ว + + 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 + ข้อผิดพลาดในการโหลดกระเป๋าเงิน กระเป๋าเงินต้องการให้ดาวน์โหลดบล็อก และซอฟต์แวร์ปัจจุบันไม่รองรับการโหลดกระเป๋าเงินในขณะที่กำลังดาวน์โหลดบล็อกแบบไม่เป็นลำดับเมื่อใช้ assumeutxo snapshots กระเป๋าเงินควรสามารถโหลดได้สำเร็จหลังจากการซิงค์โหนดถึงความสูง %s + Error reading %s! All keys read correctly, but transaction data or address book entries might be missing or incorrect. เกิดข้อผิดพลาดในการอ่าน %s! คีย์ทั้งหมดอ่านได้อย่างถูกต้อง แต่ข้อมูลธุรกรรมหรือรายการสมุดที่อยู่อาจหายไปหรือไม่ถูกต้อง + + Error: Dumpfile format record is incorrect. Got "%s", expected "format". + ข้อผิดพลาด: บันทึกรูปแบบไฟล์ดัมป์ไม่ถูกต้อง ได้รับ "%s" คาดว่า "format" + + + Error: Dumpfile identifier record is incorrect. Got "%s", expected "%s". + ข้อผิดพลาด: บันทึกตัวระบุไฟล์ดัมป์ไม่ถูกต้อง ได้รับ "%s" คาดว่า "%s" + + + Error: Dumpfile version is not supported. This version of bitcoin-wallet only supports version 1 dumpfiles. Got dumpfile with version %s + ข้อผิดพลาด: ไม่รองรับเวอร์ชันไฟล์ดัมป์ เวอร์ชันนี้ของ bitcoin-wallet รองรับเฉพาะไฟล์ดัมป์เวอร์ชัน 1 ได้รับไฟล์ดัมป์เวอร์ชัน %s + + + Failed to rename invalid peers.dat file. Please move or delete it and try again. + ล้มเหลวในการเปลี่ยนชื่อไฟล์ peers.dat ที่ไม่ถูกต้อง โปรดย้ายหรือลบแล้วลองอีกครั้ง + + + Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable %s. + การประมาณค่าธรรมเนียมล้มเหลว Fallbackfee ถูกปิดการใช้งาน รอสองสามบล็อกหรือเปิดใช้งาน %s + + + File %s already exists. If you are sure this is what you want, move it out of the way first. + ไฟล์ %s มีอยู่แล้ว ถ้าคุณแน่ใจว่านี่คือสิ่งที่คุณต้องการ ให้ย้ายออกจากทางก่อน + + + Incompatible options: -dnsseed=1 was explicitly specified, but -onlynet forbids connections to IPv4/IPv6 + ตัวเลือกที่เข้ากันไม่ได้: -dnsseed=1 ถูกระบุอย่างชัดเจน แต่ -onlynet ห้ามการเชื่อมต่อกับ IPv4/IPv6 + Incorrect or no devnet genesis block found. Wrong datadir for devnet specified? ไม่พบหรือไม่พบแหล่งกำเนิด devnet genesis ระบุข้อมูลที่ผิดสำหรับ devnet หรือไม่ ? + + Invalid amount for %s=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions) + จำนวนเงินไม่ถูกต้องสำหรับ %s=<amount>: '%s' (ต้องอย่างน้อยค่าธรรมเนียม minrelay %s เพื่อป้องกันธุรกรรมค้าง) + + + 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. + ไฟล์ peers.dat ไม่ถูกต้องหรือเสียหาย (%s) หากคุณเชื่อว่านี่เป็นบั๊ก โปรดรายงานไปที่ %s วิธีแก้ปัญหาชั่วคราว คุณสามารถย้ายไฟล์ (%s) ออกจากทาง (เปลี่ยนชื่อ ย้าย หรือลบ) เพื่อสร้างไฟล์ใหม่ในการเริ่มครั้งถัดไป + + + No dump file provided. To use createfromdump, -dumpfile=<filename> must be provided. + ไม่มีไฟล์ดัมป์ เพื่อใช้ createfromdump ต้องระบุ -dumpfile=<filename> + + + No dump file provided. To use dump, -dumpfile=<filename> must be provided. + ไม่มีไฟล์ดัมป์ เพื่อใช้ dump ต้องระบุ -dumpfile=<filename> + + + No wallet file format provided. To use createfromdump, -format=<format> must be provided. + ไม่ได้ระบุรูปแบบไฟล์กระเป๋าเงิน เพื่อใช้ createfromdump ต้องระบุ -format=<format> + + + Outbound connections restricted to CJDNS (-onlynet=cjdns) but -cjdnsreachable is not provided + การเชื่อมต่อขาออกจำกัดเฉพาะ CJDNS (-onlynet=cjdns) แต่ไม่ได้ระบุ -cjdnsreachable + + + Outbound connections restricted to Tor (-onlynet=onion) but the proxy for reaching the Tor network is explicitly forbidden: -onion=0 + การเชื่อมต่อขาออกจำกัดเฉพาะ Tor (-onlynet=onion) แต่พร็อกซีสำหรับเข้าถึงเครือข่าย Tor ถูกห้ามอย่างชัดเจน: -onion=0 + + + 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 + การเชื่อมต่อขาออกจำกัดเฉพาะ Tor (-onlynet=onion) แต่ไม่ได้ระบุพร็อกซีสำหรับเข้าถึงเครือข่าย Tor: ไม่ได้ระบุ -proxy, -onion หรือ -listenonion + + + Outbound connections restricted to i2p (-onlynet=i2p) but -i2psam is not provided + การเชื่อมต่อขาออกจำกัดเฉพาะ i2p (-onlynet=i2p) แต่ไม่ได้ระบุ -i2psam + Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly. โปรดตรวจสอบว่าวันที่และเวลาของคอมพิวเตอร์ของคุณถูกต้อง! ถ้านาฬิกาของคุณไม่ตรง %s มันจะทำงานได้ไม่ถูกต้อง @@ -4439,6 +5870,14 @@ Go to File > Open Wallet to load a wallet. Please contribute if you find %s useful. Visit %s for further information about the software. โปรดให้การสนับสนุนหากคุณพบ %s ที่เป็นประโยชน์ ไปที่ %s เพื่อดูข้อมูลเพิ่มเติมเกี่ยวกับซอฟต์แวร์ + + Prune mode is incompatible with -reindex-chainstate. Use full -reindex instead. + โหมด Prune ใช้งานร่วมกับ -reindex-chainstate ไม่ได้ ใช้ -reindex แบบเต็มแทน + + + This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection. + นี่คือค่าธรรมเนียมธุรกรรมสูงสุดที่คุณจ่าย (นอกเหนือจากค่าธรรมเนียมปกติ) เพื่อจัดลำดับความสำคัญการหลีกเลี่ยงการใช้จ่ายบางส่วนเหนือการเลือกเหรียญปกติ + This is the transaction fee you may discard if change is smaller than dust at this level นี่คือค่าธรรมเนียมการทำธุรกรรมที่คุณอาจจะละทิ้ง ถ้าการเปลี่ยนแปลงเล็กกว่า dust ในเลเวลนี้ @@ -4447,14 +5886,38 @@ Go to File > Open Wallet to load a wallet. This is the transaction fee you may pay when fee estimates are not available. นี่คือค่าธรรมเนียมการทำธุรกรรมที่คุณอาจจะต้องจ่าย เมื่อประมาณการค่าบริการไม่พร้อมใช้งาน + + Transaction requires one destination of non-0 value, a non-0 feerate, or a pre-selected input + ธุรกรรมต้องการปลายทางหนึ่งที่มีค่าไม่เป็น 0 อัตราค่าธรรมเนียมที่ไม่เป็น 0 หรืออินพุตที่เลือกไว้ล่วงหน้า + Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate. ไม่สามารถ replay blocks คุณจะต้องสร้างฐานข้อมูลโดยใช้ -reindex-chainstate + + Unknown wallet file format "%s" provided. Please provide one of "bdb" or "sqlite". + ระบุรูปแบบไฟล์กระเป๋าเงินที่ไม่รู้จัก "%s" โปรดระบุ "bdb" หรือ "sqlite" + + + Unsupported chainstate database format found. Please restart with -reindex-chainstate. This will rebuild the chainstate database. + พบรูปแบบฐานข้อมูล chainstate ที่ไม่รองรับ โปรดรีสตาร์ทด้วย -reindex-chainstate สิ่งนี้จะสร้างฐานข้อมูล chainstate ใหม่ + + + Warning: Dumpfile wallet format "%s" does not match command line specified format "%s". + คำเตือน: รูปแบบกระเป๋าเงินไฟล์ดัมป์ "%s" ไม่ตรงกับรูปแบบที่ระบุในบรรทัดคำสั่ง "%s" + Warning: Private keys detected in wallet {%s} with disabled private keys คำเตือน: คีย์ส่วนตัวที่ตรวจพบในกระเป๋าเงิน {%s} พร้อมคีย์ส่วนตัวปิดใช้งาน + + You need to rebuild the database using -reindex to enable -timestampindex + คุณต้องสร้างฐานข้อมูลใหม่โดยใช้ -reindex เพื่อเปิดใช้งาน -timestampindex + + + %s -- Incorrect seed, it should be a hex string + %s -- Seed ไม่ถูกต้อง ควรเป็นสตริง hex + %s is not a valid backup folder! %s ไม่ใช่โฟลเดอร์สำรองที่ถูกต้อง! @@ -4479,10 +5942,30 @@ Go to File > Open Wallet to load a wallet. -rpcport must be specified when -devnet and -server are specified -rpcport ควรระบุเฉพาะเมื่อระบุ -devnet และ -server + + -statsbatchsize cannot be configured with a negative value. + -statsbatchsize ไม่สามารถกำหนดค่าเป็นค่าลบได้ + + + -statsduration cannot be configured with a negative value. + -statsduration ไม่สามารถกำหนดค่าเป็นค่าลบได้ + A fatal internal error occurred, see debug.log for details เกิดข้อผิดพลาดภายในที่ร้ายแรงให้ดูที่ debug.log สำหรับรายละเอียด + + Cannot create socket (socket() returned error %s) + ไม่สามารถสร้างซ็อกเก็ต (socket() ส่งคืนข้อผิดพลาด %s) + + + Cannot get socket address for %s + ไม่สามารถรับที่อยู่ซ็อกเก็ตสำหรับ %s + + + Cannot init Statsd client + ไม่สามารถเริ่มต้นไคลเอนต์ Statsd + Cannot resolve -%s address: '%s' ไม่สามารถแก้ไขได้ -%s ที่อยู่: '%s' @@ -4491,10 +5974,6 @@ Go to File > Open Wallet to load a wallet. Cannot write to data directory '%s'; check permissions. ไม่สามารถเขียนไปยังไดเรกทอรีข้อมูล '%s'; ตรวจสอบการอนุญาต - - Change index out of range - ปรับเปลี่ยนดัชนีนอกช่วง - Copyright (C) ลิขสิทธิ์ (C) @@ -4503,6 +5982,14 @@ Go to File > Open Wallet to load a wallet. Disk space is too low! พื้นที่ดิสก์ต่ำเกินไป! + + Dump file %s does not exist. + ไฟล์ดัมป์ %s ไม่มีอยู่ + + + Error creating %s + ข้อผิดพลาดในการสร้าง %s + Error loading %s เกิดข้อผิดพลาดในการโหลด %s @@ -4520,8 +6007,8 @@ Go to File > Open Wallet to load a wallet. เกิดข้อผิดพลาดในการโหลด %s: คุณไม่สามารถปิดการใช้งาน HD บน HD wallet ที่มีอยู่แล้ว - Error upgrading chainstate database - เกิดข้อผิดพลาดในการอัพเกรดฐานข้อมูล chainstate + Error reading next record from wallet database + ข้อผิดพลาดในการอ่านบันทึกถัดไปจากฐานข้อมูลกระเป๋าเงิน Loading P2P addresses… @@ -4591,6 +6078,14 @@ Go to File > Open Wallet to load a wallet. Inputs vs outputs size mismatch. ขนาดของ inputs และ outputs ไม่สัมพันธ์กัน + + Invalid '%s'. Allowed values: 128, 160, 192, 224, 256. + '%s' ไม่ถูกต้อง ค่าที่อนุญาต: 128, 160, 192, 224, 256 + + + Invalid -i2psam address or hostname: '%s' + ที่อยู่ -i2psam หรือชื่อโฮสต์ไม่ถูกต้อง: '%s' + Invalid -onion address or hostname: '%s' ที่อยู่ - onion หรือ hostname ไม่ถูกต้อง: '%s' @@ -4635,14 +6130,78 @@ Go to File > Open Wallet to load a wallet. %s corrupt. Try using the wallet tool dash-wallet to salvage or restoring a backup. %s ทุจริต ลองใช้ wallet tool dash-wallet เพื่อกอบกู้หรือกู้คืนการสำรองข้อมูล + + %s is set very high! Fees this large could be paid on a single transaction. + %s ถูกตั้งค่าสูงมาก! ค่าธรรมเนียมขนาดนี้อาจจ่ายในธุรกรรมเดียว + + + %s request to listen on port %u. This port is considered "bad" and thus it is unlikely that any Dash Core peers connect to it. See doc/p2p-bad-ports.md for details and a full list. + %s ขอให้รับฟังที่พอร์ต %u พอร์ตนี้ถือว่า "ไม่ดี" ดังนั้นไม่น่าจะมีเพียร์ Dash Core ใดเชื่อมต่อกับมัน ดูรายละเอียดและรายการทั้งหมดที่ doc/p2p-bad-ports.md + + + Cannot provide specific connections and have addrman find outgoing connections at the same time. + ไม่สามารถให้การเชื่อมต่อเฉพาะและให้ addrman ค้นหาการเชื่อมต่อขาออกในเวลาเดียวกัน + + + Failed to upgrade Evo database + ล้มเหลวในการอัปเกรดฐานข้อมูล Evo + + + Fee needed > fee paid + ค่าธรรมเนียมที่ต้องการ > ค่าธรรมเนียมที่จ่าย + + + Host %s on unsupported network + โฮสต์ %s บนเครือข่ายที่ไม่รองรับ + + + Invalid amount for %s=<amount>: '%s' (must be at least %s) + จำนวนเงินไม่ถูกต้องสำหรับ %s=<amount>: '%s' (ต้องอย่างน้อย %s) + + + Invalid amount for %s=<amount>: '%s' + จำนวนเงินไม่ถูกต้องสำหรับ %s=<amount>: '%s' + + + Invalid port specified in %s: '%s' + ระบุพอร์ตที่ไม่ถูกต้องใน %s: '%s' + Last successful action was too recent. การกระทำที่ประสบความสำเร็จล่าสุดเป็นข้อมูลล่าสุด + + Missing solving data for estimating transaction size + ขาดข้อมูลการแก้ปัญหาสำหรับการประมาณขนาดธุรกรรม + + + No host specified + ไม่ได้ระบุโฮสต์ + + + No host specified, malformed URL + ไม่ได้ระบุโฮสต์ URL มีรูปแบบไม่ถูกต้อง + + + No text before the scheme delimiter, malformed URL + ไม่มีข้อความก่อนตัวคั่น scheme URL มีรูปแบบไม่ถูกต้อง + + + Port must be between %d and %d, supplied %d + พอร์ตต้องอยู่ระหว่าง %d และ %d ระบุ %d + + + Socket not initialized, cannot send message + ซ็อกเก็ตไม่เริ่มต้น ไม่สามารถส่งข้อความ + The source code is available from %s. ซอร์สโค้ดที่ใช้ได้จาก %s + + The specified config file %s does not exist + ไฟล์กำหนดค่าที่ระบุ %s ไม่มีอยู่ + The transaction amount is too small to pay the fee จำนวนเงินที่ทำธุรกรรมมีน้อยเกินไปที่จะจ่ายค่าธรรมเนียม @@ -4663,6 +6222,10 @@ Go to File > Open Wallet to load a wallet. Transaction fees are too high. ค่าธรรมเนียมการทำธุรกรรมสูงเกินไป + + Transaction needs a change address, but we can't generate it. + ธุรกรรมต้องการที่อยู่เงินทอน แต่เราไม่สามารถสร้างได้ + Transaction not valid. ธุรกรรมไม่ถูกต้อง @@ -4683,6 +6246,18 @@ Go to File > Open Wallet to load a wallet. Unable to locate enough non-denominated funds for this transaction. ไม่สามารถหาเงินทุนที่ไม่ใช่สกุลเงินที่ระบุได้มากพอสำหรับธุรกรรมนี้ + + Unable to lookup host %s + ไม่สามารถค้นหาโฮสต์ %s + + + Unable to parse -maxuploadtarget: '%s' + ไม่สามารถแยกวิเคราะห์ -maxuploadtarget: '%s' + + + Unable to send message to %s (::sendto() returned error %s) + ไม่สามารถส่งข้อความไปยัง %s (::sendto() ส่งคืนข้อผิดพลาด %s) + Unable to sign spork message, wrong key? ไม่สามารถลงชื่อเข้าใช้ข้อความ spork ได้ คีย์ผิดหรือไม่? @@ -4695,6 +6270,10 @@ Go to File > Open Wallet to load a wallet. Unknown state: id = %u ไม่ทราบสถานะ : ไอดี = %u + + Unsupported URL scheme, must begin with udp:// + โครงสร้าง URL ที่ไม่รองรับ ต้องเริ่มด้วย udp:// + Unsupported logging category %s=%s. การบันทึกประเภทที่ไม่ได้รับการสนับสนุน %s=%s @@ -4727,9 +6306,25 @@ Go to File > Open Wallet to load a wallet. You can not disable governance validation on a masternode. คุณไม่สามารถตรวจสอบการกำกับดูแลปิดการใช้งานบน masternode + + You need to rebuild the database using -reindex to enable -addressindex + คุณต้องสร้างฐานข้อมูลใหม่โดยใช้ -reindex เพื่อเปิดใช้งาน -addressindex + + + You need to rebuild the database using -reindex to enable -spentindex + คุณต้องสร้างฐานข้อมูลใหม่โดยใช้ -reindex เพื่อเปิดใช้งาน -spentindex + Your entries added successfully. เพิ่มรายการของคุณเรียบร้อยแล้ว - + + Settings file could not be read + ไม่สามารถอ่านไฟล์การตั้งค่า + + + Settings file could not be written + ไม่สามารถเขียนไฟล์การตั้งค่า + + \ No newline at end of file diff --git a/src/qt/locale/dash_tr.ts b/src/qt/locale/dash_tr.ts index 5b441cfb3d9f..bdbb5c17770a 100644 --- a/src/qt/locale/dash_tr.ts +++ b/src/qt/locale/dash_tr.ts @@ -65,14 +65,6 @@ C&hoose S&eçiniz - - Sending addresses - Gönderilen adresler - - - Receiving addresses - Alım adresleri - These are your Dash addresses for sending payments. Always check the amount and the receiving address before sending coins. Bunlar ödemeleri göndermek için kullanacağınız Dash adreslerinizdir. Dash yollamadan önce tutarı ve alıcının alım adresini her zaman kontrol ediniz. @@ -94,8 +86,8 @@ &Değiştir - &Show address QR code - &Adresin QR kodunu göster + Show address &QR code + Adres &QR kodunu göster QR code @@ -105,6 +97,24 @@ Export Address List Adres Listesini Dışarı Aktar + + Comma separated file + Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values. + Virgülle ayrılmış dosya + + + There was an error trying to save the address list to %1. Please try again. + An error message. %1 is a stand-in argument for the name of the file we attempted to save to. + Adres listesini %1 konumuna kaydederken bir hata oluştu. Lütfen tekrar deneyin. + + + Sending addresses - %1 + Gönderme adresleri - %1 + + + Receiving addresses - %1 + Alma adresleri - %1 + Exporting Failed Dışarı aktarmada hata @@ -274,10 +284,22 @@ The passphrase entered for the wallet decryption was incorrect. Cüzdan şifresinin açılması için girilen parola yanlıştı. + + 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 23.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. + Cüzdan şifresinin açılması için girilen parola yanlış. Null karakter içeriyor (yani - sıfır bayt). Parola bu yazılımın 23.0 öncesi bir sürümüyle ayarlandıysa, lütfen yalnızca ilk null karaktere kadarki karakterlerle tekrar deneyin (ilk null karakter hariç). Bu başarılı olursa, gelecekte bu sorundan kaçınmak için lütfen yeni bir parola belirleyin. + Wallet passphrase was successfully changed. Cüzdan parolası başarılı bir şekilde değiştirildi. + + Passphrase change failed + Parola değiştirme başarısız oldu + + + 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 23.0, please try again with only the characters up to — but not including — the first null character. + Cüzdan şifresinin açılması için girilen eski parola yanlış. Null karakter içeriyor (yani - sıfır bayt). Parola bu yazılımın 23.0 öncesi bir sürümüyle ayarlandıysa, lütfen yalnızca ilk null karaktere kadarki karakterlerle tekrar deneyin (ilk null karakter hariç). + Warning: The Caps Lock key is on! Uyarı: Caps Lock tuşu etkin durumda! @@ -303,7 +325,23 @@ BitcoinApplication - + + Runaway exception + Kontrolsüz istisna + + + A fatal error occurred. %1 can no longer continue safely and will quit. + Kritik bir hata oluştu. %1 artık güvenli bir şekilde devam edemez ve kapanacak. + + + Internal error + Dahili hata + + + An internal error occurred. %1 will attempt to continue safely. This is an unexpected bug which can be reported as described below. + Dahili bir hata oluştu. %1 güvenli bir şekilde devam etmeye çalışacak. Bu beklenmeyen bir hata olup aşağıda açıklandığı gibi raporlanabilir. + + BitcoinGUI @@ -330,6 +368,10 @@ Request payments (generates QR codes and dash: URIs) Ödeme talep et (QR kodu ve Dash URI'si oluşturur) + + Ctrl+Q + Ctrl+Q + &Options… &Seçenekler… @@ -358,6 +400,10 @@ &Verify message… İletiyi &kontrol et… + + &Load PSBT from file… + PSBT'yi dosyadan &yükle… + &Sending addresses &Gönderilen adresler @@ -390,10 +436,6 @@ &Window &Pencere - - Minimize - Küçült - Zoom Yakınlaştır @@ -446,14 +488,6 @@ Modify configuration options for %1 %1 için yapılandırma ayarlarını değiştir - - &Show / Hide - &Göster / Gizle - - - Show or hide the main Window - Ana pencereyi göster ya da gizle - Encrypt the private keys that belong to your wallet Cüzdanınıza ait özel anahtarları şifreleyin @@ -518,10 +552,6 @@ Show wallet repair options Cüzdan tamir seçeneklerini göster - - Open Wallet &Configuration File - Cüzdan &Ayar Dosyasını Aç - Open configuration file Yapılandırma Dosyasını Aç @@ -576,10 +606,40 @@ Show information about %1 %1 ile ilgili bilgileri göster + + Load PSBT from &clipboard… + PSBT'yi &panodan yükle… + + + Open debugging and diagnostic console + Hata ayıklama ve tanı konsolunu aç + + + Open &wallet configuration file + &Cüzdan yapılandırma dosyasını aç + + + Open a dash: URI + Bir dash: URI aç + Create a new wallet Yeni bir cüzdan oluştur + + Restore Wallet… + Name of the menu item that restores wallet from a backup file. + Cüzdanı Geri Yükle… + + + Restore a wallet from a backup file + Status tip for Restore Wallet menu item + Yedekleme dosyasından bir cüzdanı geri yükle + + + Close all wallets + Tüm cüzdanları kapat + %1 &information %1 &Bilgi @@ -588,10 +648,42 @@ Show the %1 basic information %1 temel bilgilerini göster + + &Discreet mode + &Gizli mod + + + Mask the values in the Overview tab + Genel Bakış sekmesindeki değerleri gizle + + + Wallet Data + Name of the wallet data file format. + Cüzdan Verisi + + + Load Wallet Backup + The title for Restore Wallet File Windows + Cüzdan Yedeğini Yükle + + + Restore Wallet + Title of pop-up window shown when the user is attempting to restore a wallet. + Cüzdanı Geri Yükle + + + Wallet Name + Label of the input field where the name of the wallet is entered. + Cüzdan Adı + &Settings &Ayarlar + + &Minimize + &Küçült + &Help &Yardım @@ -608,8 +700,17 @@ View Governance Proposals Yönetim Tekliflerini Görüntüle + + &Hide + &Gizle + + + S&how + &Göster + %n active connection(s) to Dash network + A substring of the tooltip. Dash ağına %n aktif bağlantıDash ağına %n aktif bağlantı @@ -628,10 +729,50 @@ Close Wallet… Kapalı Cüzdan… + + Load Partially Signed Blockchain Transaction + Kısmen İmzalanmış Blokzincir İşlemini Yükle + + + Load Partially Signed Blockchain Transaction from clipboard + Panodan Kısmen İmzalanmış Blokzincir İşlemini Yükle + Create Wallet… Cüzdan Oluştur… + + Close All Wallets… + Tüm Cüzdanları Kapat… + + + Ctrl+Shift+D + Ctrl+Shift+D + + + Ctrl+M + Ctrl+M + + + Click for more actions. + A substring of the tooltip. "More actions" are available via the context menu. + Daha fazla eylem için tıklayın. + + + Show Peers tab + A context menu item. The "Peers tab" is an element of the "Node window". + Eşler sekmesini göster + + + Disable network activity + A context menu item. + Ağ etkinliğini devre dışı bırak + + + Enable network activity + A context menu item. The network activity was disabled previously. + Ağ etkinliğini etkinleştir + Syncing Headers (%1%)… Üstbilgiler Senkronize Ediliyor (%1%)… @@ -648,10 +789,6 @@ Processing blocks on disk… Bloklar diske işleniyor… - - Reindexing blocks on disk… - Diskteki bloklar yeniden indeksleniyor… - Connecting to peers… Eşlere bağlanılıyor… @@ -805,10 +942,6 @@ Coin Selection Bitcoin Seçimi - - Dust: - Toz: - After Fee: Ücretten sonra: @@ -866,28 +999,32 @@ Doğrulandı - Copy address - Adres kopyala + Copy amount + Tutarı kopyala + + + &Copy address + &Adresi kopyala - Copy label - Etiket kopyala + Copy &label + &Etiketi kopyala - Copy amount - Tutarı kopyala + Copy &amount + &Miktarı kopyala - Copy transaction ID - İşlem ID'sini kopyala + Copy transaction &ID and output index + İşlem &kimliğini ve çıktı dizinini kopyala - Lock unspent - Harcanmamışı kilitle + L&ock unspent + Harcanmamışı &kilitle - Unlock unspent - Harcanmamışın kilidini aç + &Unlock unspent + Harcanmamışın &kilidini aç Copy quantity @@ -905,10 +1042,6 @@ Copy bytes Baytları kopyala - - Copy dust - Tozu kopyala - Copy change Para üstünü kopyala @@ -921,18 +1054,6 @@ (%1 locked) (%1 kilitlendi) - - yes - Evet - - - no - Hayır - - - This label turns red if any recipient receives an amount smaller than the current dust threshold. - Eğer herhangi bir alıcı mevcut toz eşiğinden daha düşük bir tutar alırsa bu etiket kırmızıya dönüşür. - Can vary +/- %1 duff(s) per input. Girdi başına +/- %1 duff değişebilir. @@ -976,8 +1097,14 @@ CreateWalletActivity + + Create Wallet + Title of window indicating the progress of creation of a new wallet. + Cüzdan Oluştur + Creating Wallet <b>%1</b>… + Descriptive text of the create wallet progress window which indicates to the user which wallet is currently being created. <b>%1</b> Cüzdan Oluşturuluyor… @@ -999,6 +1126,10 @@ Wallet Name Cüzdan Adı + + Wallet + Cüzdan + Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice. Cüzdanı şifreleyin. Cüzdan, seçtiğiniz parola ile şifrelenecektir. @@ -1007,6 +1138,10 @@ Encrypt Wallet Cüzdanı Şifrele + + Advanced Options + Gelişmiş Seçenekler + 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. Bu cüzdan için özel anahtarları devre dışı bırakın. Özel anahtarların devre dışı bırakıldığı cüzdanlarda özel anahtar bulunmaz ve HD tohum veya içe aktarılan özel anahtarlar olamaz. Bu, yalnızca izlenebilen cüzdanlar için idealdir. @@ -1023,11 +1158,23 @@ Make Blank Wallet Boş Bir Cüzdan Oluşturun + + Use descriptors for scriptPubKey management. This feature is well-tested but still considered experimental and not recommended for use yet. + scriptPubKey yönetimi için tanımlayıcıları kullanın. Bu özellik iyi test edilmiştir ancak hala deneysel olarak kabul edilir ve henüz kullanımı önerilmez. + + + Descriptor Wallet (EXPERIMENTAL) + Tanımlayıcı Cüzdan (DENEYSEL) + Create Oluştur - + + Compiled without sqlite support (required for descriptor wallets) + SQLite desteği olmadan derlenmiş (tanımlayıcı cüzdanlar için gerekli) + + EditAddressDialog @@ -1116,18 +1263,106 @@ Filter List: Filtre Listesi: + + Filter proposal list + Teklif listesini filtrele + + + Masternode Count: + Masternode Sayısı: + + + Number of masternodes this wallet can vote with (masternodes for which this wallet holds the voting key) + Bu cüzdanın oy verebileceği masternode sayısı (bu cüzdanın oy anahtarını tuttuğu masternodelar) + Proposal Count: Teklif Sayısı: + + Create Proposal + Teklif Oluştur + Filter by Title Başlığa göre filtrele + + Unavailable + Kullanılamıyor + + + A synced node and an unlocked wallet are required. + Senkronize edilmiş bir düğüm ve kilidi açılmış bir cüzdan gereklidir. + + + Vote Yes + Evet Oyu + + + Vote No + Hayır Oyu + + + Vote Abstain + Çekimser Oy + Proposal Info: %1 Teklif Bilgisi: %1 + + Voting Failed + Oylama Başarısız + + + No wallet available. + Kullanılabilir cüzdan yok. + + + No masternode voting keys found in wallet. + Cüzdanda masternode oylama anahtarı bulunamadı. + + + Please select a proposal to vote on. + Lütfen oy verilecek bir teklif seçin. + + + Unable to unlock wallet. + Cüzdanın kilidi açılamıyor. + + + Unable to get masternode list. Please try again later. + Masternode listesi alınamıyor. Lütfen daha sonra tekrar deneyin. + + + Masternode %1 not found + Masternode %1 bulunamadı + + + Failed to sign vote for masternode %1 + Masternode %1 için oy imzalanamadı + + + Masternode %1: %2 + Masternode %1: %2 + + + Voted successfully %n time(s) + %n kez başarıyla oy verildi%n kez başarıyla oy verildi + + + Failed to vote %n time(s) + %n kez oy verilemedi%n kez oy verilemedi + + + Errors: + Hatalar: + + + Voting Results + Oylama Sonuçları + HelpMessageDialog @@ -1166,10 +1401,26 @@ As this is the first time the program is launched, you can choose where %1 will store its data. Bu programın ilk kez başlatılmasından dolayı %1 yazılımının verilerini nerede saklayacağını seçebilirsiniz. + + Limit block chain storage to + Blok zinciri depolamasını sınırla + + + 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. + Bu ayarı geri almak tüm blok zincirinin yeniden indirilmesini gerektirir. Önce tam zinciri indirip daha sonra budamak daha hızlıdır. Bazı gelişmiş özellikleri devre dışı bırakır. + + + GB + GB + 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. Bu başlangıç senkronizasyonu çok zorlayıcıdır ve bilgisayarınızdaki daha önce fark edilmemiş olan donanım sorunlarını ortaya çıkarabilir. %1'i her çalıştırdığınızda, kaldığı yerden devam edecektir. + + 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. + Tamam'a tıkladığınızda, %1, %4 ilk başlatıldığında %3'teki en eski işlemlerden başlayarak tam %4 blok zincirini (%2 GB) indirmeye ve işlemeye başlayacaktır. + 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. Blok zinciri saklamayı sınırlamayı seçtiyseniz (budama), geçmiş veriler yine de indirilmeli ve işlenmelidir, ancak disk kullanımınızı düşük tutmak için daha sonra silinmelidir. @@ -1182,6 +1433,18 @@ Use a custom data directory: Özel bir veri klasörü kullan: + + %n GB of space available + %n GB alan mevcut%n GB alan mevcut + + + (of %n GB needed) + (%n GB gerekli)(%n GB gerekli) + + + (%n GB needed for full chain) + (tam zincir için %n GB gerekli)(tam zincir için %n GB gerekli) + At least %1 GB of data will be stored in this directory, and it will grow over time. Bu dizinde en az %1 GB lık veri depolanacak ve zamanla büyüyecek. @@ -1190,6 +1453,11 @@ Approximately %1 GB of data will be stored in this directory. Yaklaşık %1 GB veri bu dizinde depolanacak. + + (sufficient to restore backups %n day(s) old) + Explanatory text on the capability of the current prune target. + (%n gün önceki yedekleri geri yüklemek için yeterli)(%n gün önceki yedekleri geri yüklemek için yeterli) + %1 will download and store a copy of the Dash block chain. %1 lik Dash blok zinciri nin bir kopyasını indirecek ve depolayacak. @@ -1207,6 +1475,13 @@ Hata + + LoadWalletsActivity + + Loading wallets… + Cüzdanlar yükleniyor… + + MasternodeList @@ -1241,6 +1516,10 @@ Service Hizmet + + Type + Tür + PoSe Score PoSe Puanı @@ -1376,6 +1655,10 @@ Hide Gizle + + %1 is currently syncing. It will download headers and blocks from peers and validate them until reaching the tip of the block chain. + %1 şu anda senkronize oluyor. Eşlerden başlıkları ve blokları indirecek ve blok zincirinin ucuna ulaşana kadar bunları doğrulayacak. + Unknown. Syncing Headers (%1, %2%)… Bilinmeyen. Başlıklar Senkronize Ediliyor (%1, %2%)… @@ -1391,6 +1674,11 @@ URI: URI: + + Paste address from clipboard + Tooltip text for button that allows you to paste an address that is in your clipboard. + Panodan adresi yapıştır + OpenWalletActivity @@ -1406,8 +1694,14 @@ default wallet varsayılan cüzdan + + Open Wallet + Title of window indicating the progress of opening of a wallet. + Cüzdan Aç + Opening Wallet <b>%1</b>… + Descriptive text of the open wallet progress window which indicates to the user which wallet is currently being opened. <b>%1</b> Cüzdan Açılıyor… @@ -1441,6 +1735,14 @@ &Appearance &Görünüm + + Show the icon in the system tray. + Sistem tepsisinde simgeyi göster. + + + &Show tray icon + &Tepsi simgesini göster + Prune &block storage to Depolamak için buda &engelle @@ -1453,10 +1755,58 @@ Reverting this setting requires re-downloading the entire blockchain. Bu ayarın geri alınması, tüm blok zincirinin yeniden indirilmesini gerektirir. + + 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. + Tooltip text for Options window setting that sets the size of the database cache. Explains the corresponding effects of increasing/decreasing this value. + Maksimum veritabanı önbellek boyutu. Daha büyük bir önbellek daha hızlı senkronizasyona katkıda bulunabilir, bundan sonra fayda çoğu kullanım durumunda daha az belirgindir. Önbellek boyutunu düşürmek bellek kullanımını azaltacaktır. Kullanılmayan mempool belleği bu önbellek için paylaşılır. + MiB MiB + + Set the number of script verification threads. Negative values correspond to the number of cores you want to leave free to the system. + 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. + Betik doğrulama iş parçacığı sayısını ayarlayın. Negatif değerler, sisteme boş bırakmak istediğiniz çekirdek sayısına karşılık gelir. + + + This allows you or a third party tool to communicate with the node through command-line and JSON-RPC commands. + Tooltip text for Options window setting that enables the RPC server. + Bu, sizin veya üçüncü taraf bir aracın komut satırı ve JSON-RPC komutları aracılığıyla düğümle iletişim kurmasına olanak tanır. + + + Enable R&PC server + An Options window setting to enable the RPC server. + R&PC sunucusunu etkinleştir + + + Whether to set subtract fee from amount as default or not. + Tooltip text for Options window setting that sets subtracting the fee from a sending amount as default. + Varsayılan olarak ücreti tutardan çıkarma ayarının yapılıp yapılmayacağı. + + + Subtract &fee from amount by default + An Options window setting to set subtracting the fee from a sending amount as default. + Varsayılan olarak tutardan &ücreti çıkar + + + Enable &PSBT controls + An options window setting to enable PSBT controls. + &PSBT kontrollerini etkinleştir + + + Whether to show PSBT controls. + Tooltip text for options window setting that enables PSBT controls. + PSBT kontrollerinin gösterilip gösterilmeyeceği. + + + Whether to keep the specified custom change address or not. + Belirtilen özel para üstü adresinin tutulup tutulmayacağı. + + + Keep custom change &address + Özel para üstü &adresini tut + Show additional tab listing all your masternodes in first sub-tab<br/>and all masternodes on the network in second sub-tab. İlk alt sekmede tüm ana düğümlerinizi gösteren ve<br/>ikinci alt sekmede tüm ana düğümleri gösteren ek bir sekme göster. @@ -1513,6 +1863,14 @@ Enable &multi-session &Çoklu oturumu etkinleştir + + Use this many separate masternodes in parallel to mix funds.<br/>Note: You must use this feature carefully.<br/>Make sure you always have recent wallet (auto)backup in a safe place! + Fonları karıştırmak için paralel olarak bu kadar ayrı masternode kullanın.<br/>Not: Bu özelliği dikkatli kullanmalısınız.<br/>Cüzdanınızın güncel (otomatik) yedeğinin güvenli bir yerde olduğundan her zaman emin olun! + + + Parallel sessions + Paralel oturumlar + Mixing rounds Karıştırma Turları @@ -1525,6 +1883,30 @@ Target balance Bakiyesi hedefle + + How many inputs of each denominated amount are created.<br/>Lower these numbers if you want fewer smaller denominations. + Her bir değerden kaç adet girdi oluşturulacağı.<br/>Daha az küçük değer istiyorsanız bu sayıları düşürün. + + + Inputs per denomination + Değer başına girdiler + + + Try to create at least this many inputs for each denominated amount.<br/>Lower this number if you want fewer smaller denominations. + Her bir değer için en az bu kadar girdi oluşturmayı deneyin.<br/>Daha az küçük değer istiyorsanız bu sayıyı düşürün. + + + Target + Hedef + + + Create up to this many inputs for each denominated amount.<br/>Lower this number if you want fewer smaller denominations. + Her bir değer için en fazla bu kadar girdi oluşturun.<br/>Daha az küçük değer istiyorsanız bu sayıyı düşürün. + + + Maximum + Maksimum + Automatically open the Dash Core client port on the router. This only works when your router supports UPnP and it is enabled. Router'da otomatik olarak Dash Core istemcisi portu aç. Bu sadece router'ınız UPnP destekliyorsa ve etkinse çalışır. @@ -1554,20 +1936,26 @@ Bu ağ türünde eşlere ulaşmak için varsayılan SOCKS5 proxy'nin kullanılıp kullanılmadığını gösterir. - Options set in this dialog are overridden by the command line or in the configuration file: - Bu iletişim kutusunda ayarlanan seçenekler, komut satırı veya yapılandırma dosyası tarafından geçersiz kılınır: + Language missing or translation incomplete? Help contributing translations here: +https://explore.transifex.com/dash/dash/ + Dil eksik veya çeviri tamamlanmamış mı? Çevirilere katkıda bulunmak için buraya bakın: +https://explore.transifex.com/dash/dash/ - 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. - 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. + Third-party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items.<br/>%s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |. + İşlemler sekmesinde bağlam menüsü öğeleri olarak görünen üçüncü taraf URL'ler (örneğin bir blok gezgini).<br/>URL'deki %s, işlem hash'i ile değiştirilir. Birden fazla URL dikey çubuk | ile ayrılır. + + + &Third-party transaction URLs + &Üçüncü taraf işlem URL'leri - Third party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items.<br/>%s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |. - İşlemler sekmesinde bağlam menüsü ögeleri gibi görünen üçüncü parti URLleri (ör. bir blok tarayıcısı).<br/>URL'deki %s işlem hashi ile değiştirilir. Birden fazla URL dikey çizgi | ile ayrılır. + Options set in this dialog are overridden by the command line or in the configuration file: + Bu iletişim kutusunda ayarlanan seçenekler, komut satırı veya yapılandırma dosyası tarafından geçersiz kılınır: - &Third party transaction URLs - &Üçüncü taraf işlem URL'leri + 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. + 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. Whether to show coin control features or not. @@ -1606,7 +1994,11 @@ Portları &UPnP kullanarak haritala - Proxy &IP: + Automatically open the Dash Core client port on the router. This only works when your router supports NAT-PMP and it is enabled. The external port could be random. + Yönlendiricide Dash Core istemci portunu otomatik olarak açın. Bu yalnızca yönlendiriciniz NAT-PMP'yi desteklediğinde ve etkinleştirildiğinde çalışır. Harici port rastgele olabilir. + + + Proxy &IP: Vekil &İP: @@ -1653,6 +2045,14 @@ &Display &Görünüm + + Connect to the Dash network through a separate SOCKS5 proxy for Tor onion services. + Tor onion servisleri için ayrı bir SOCKS5 proxy üzerinden Dash ağına bağlanın. + + + Use separate SOCKS&5 proxy to reach peers via Tor onion services: + Tor onion servisleri üzerinden eşlere ulaşmak için ayrı SOCKS&5 proxy kullanın: + User Interface &language: Kullanıcı arayüzü &lisanı: @@ -1699,14 +2099,22 @@ Confirm options reset + Window title text of pop-up window shown when the user has chosen to reset options. Seçeneklerin sıfırlanmasını teyit et Client restart required to activate changes. + Text explaining that the settings changed will not come into effect until the client is restarted. Değişikliklerin uygulanması için istemcinin yeniden başlatılması lazımdır. + + Current settings will be backed up at "%1". + 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. + Mevcut ayarlar "%1" konumunda yedeklenecektir. + Client will be shut down. Do you want to proceed? + Text asking the user to confirm if they would like to proceed with a client shutdown. İstemci kapanacaktır. Devam etmek istiyor musunuz? @@ -1844,6 +2252,10 @@ %1 Balance %1 Bakiye + + Discreet mode activated for the Overview tab. To unmask the values, uncheck Settings->Discreet mode. + Genel Bakış sekmesi için gizli mod etkinleştirildi. Değerleri göstermek için Ayarlar->Gizli mod işaretini kaldırın. + %n Rounds %n Tur%n Tur @@ -1943,7 +2355,140 @@ PSBTOperationsDialog - + + Dialog + Diyalog + + + Sign Tx + İşlemi İmzala + + + Broadcast Tx + İşlemi Yayınla + + + Copy to Clipboard + Panoya Kopyala + + + Save… + Kaydet… + + + Close + Kapat + + + Failed to load transaction: %1 + İşlem yüklenemedi: %1 + + + Failed to sign transaction: %1 + İşlem imzalanamadı: %1 + + + Cannot sign inputs while wallet is locked. + Cüzdan kilitliyken girdiler imzalanamaz. + + + Could not sign any more inputs. + Daha fazla girdi imzalanamadı. + + + Signed %1 inputs, but more signatures are still required. + %1 girdi imzalandı, ancak daha fazla imza gerekiyor. + + + Signed transaction successfully. Transaction is ready to broadcast. + İşlem başarıyla imzalandı. İşlem yayınlanmaya hazır. + + + Unknown error processing transaction. + İşlem işlenirken bilinmeyen hata. + + + Transaction broadcast successfully! Transaction ID: %1 + İşlem başarıyla yayınlandı! İşlem ID: %1 + + + Transaction broadcast failed: %1 + İşlem yayını başarısız: %1 + + + PSBT copied to clipboard. + PSBT panoya kopyalandı. + + + Save Transaction Data + İşlem Verisini Kaydet + + + Partially Signed Transaction (Binary) + Expanded name of the binary PSBT file format. See: BIP 174. + Kısmen İmzalanmış İşlem (İkili) + + + PSBT saved to disk. + PSBT diske kaydedildi. + + + * Sends %1 to %2 + * %1'i %2'ye gönderir + + + own address + kendi adres + + + Unable to calculate transaction fee or total transaction amount. + İşlem ücreti veya toplam işlem tutarı hesaplanamıyor. + + + Pays transaction fee: + İşlem ücretini öder: + + + Total Amount + Toplam Tutar + + + or + veya + + + Transaction has %1 unsigned inputs. + İşlemde %1 imzalanmamış girdi var. + + + Transaction is missing some information about inputs. + İşlemde girdiler hakkında bazı bilgiler eksik. + + + Transaction still needs signature(s). + İşlem hala imza(lar) gerektiriyor. + + + (But no wallet is loaded.) + (Ancak hiçbir cüzdan yüklenmemiş.) + + + (But this wallet cannot sign transactions.) + (Ancak bu cüzdan işlemleri imzalayamaz.) + + + (But this wallet does not have the right keys.) + (Ancak bu cüzdanda doğru anahtarlar yok.) + + + Transaction is fully signed and ready for broadcast. + İşlem tamamen imzalanmış ve yayınlanmaya hazır. + + + Transaction status is unknown. + İşlem durumu bilinmiyor. + + PaymentServer @@ -1962,6 +2507,12 @@ 'dash://' is not a valid URI. Use 'dash:' instead. 'dash://' geçerli bir URI değil. Bunun yerine 'dash:' kullanın. + + Cannot process payment request as BIP70 is no longer supported. +Due to discontinued support, you should request the merchant to provide you with a BIP21 compatible URI or use a wallet that does continue to support BIP70. + BIP70 artık desteklenmediği için ödeme talebi işlenemiyor. +Desteğin sonlandırılması nedeniyle, satıcıdan size BIP21 uyumlu bir URI sağlamasını istemelisiniz veya BIP70'i desteklemeye devam eden bir cüzdan kullanmalısınız. + URI cannot be parsed! This can be caused by an invalid Dash address or malformed URI parameters. URI ayrıştırılamıyor! Bunun nedeni geçersiz bir Dash adresi veya hatalı biçimlendirilmiş URI değişkenleri olabilir. @@ -1983,6 +2534,26 @@ Title of Peers Table column which indicates the current latency of the connection with the peer. Ping + + Peer + Title of Peers Table column which contains a unique number used to identify a connection. + + + + Age + Title of Peers Table column which indicates the duration (length of time) since the peer connection started. + Yaş + + + Direction + Title of Peers Table column which indicates the direction the peer connection was initiated from. + Yön + + + Type + Title of Peers Table column which describes the type of peer connection. The "type" describes why the connection exists. + Tür + Sent Title of Peers Table column which indicates the total amount of network information we have sent to the peer. @@ -1993,7 +2564,27 @@ Title of Peers Table column which indicates the total amount of network information we have received from the peer. Alındı - + + Address + Title of Peers Table column which contains the IP/Onion/I2P address of the connected peer. + Adres + + + Network + Title of Peers Table column which states the network the peer connected through. + + + + Inbound + An Inbound Connection from a Peer. + Gelen + + + Outbound + An Outbound Connection to a Peer. + Giden + + Proposal @@ -2044,8 +2635,193 @@ Durum + + ProposalWizard + + Create Governance Proposal + Yönetim Teklifi Oluştur + + + Enter proposal details + Teklif detaylarını girin + + + A fee will be burned when you prepare the proposal. + Teklifi hazırladığınızda bir ücret yakılacaktır. + + + Proposal &name + Teklif &adı + + + &Description URL + &Açıklama URL'si + + + Payment &address + Ödeme &adresi + + + Payment &amount + Ödeme &tutarı + + + The amount to request in a single payment + Tek bir ödemede talep edilecek tutar + + + &First payment + &İlk ödeme + + + Pa&yments + Ö&demeler + + + To&tal amount + Top&lam tutar + + + Proposal &fee + Teklif &ücreti + + + Next + İleri + + + Review proposal JSON and validate. + Teklif JSON'unu inceleyin ve doğrulayın. + + + Hex-encoded JSON + Hex-kodlu JSON + + + Back + Geri + + + Validate + Doğrula + + + Prepare (burn fee) and wait for confirmations. + Hazırlayın (ücreti yakın) ve onayları bekleyin. + + + Copy + Kopyala + + + At 1/6 confirmations: can be relayed and queued. At 6/6: accepted and processed. + 1/6 onayda: aktarılabilir ve kuyruğa alınabilir. 6/6'da: kabul edilir ve işlenir. + + + Confirmations progress + Onay ilerlemesi + + + Shows progress toward the required number of confirmations for the proposal fee transaction. + Teklif ücreti işlemi için gereken onay sayısına doğru ilerlemeyi gösterir. + + + Estimated time remaining: - + Tahmini kalan süre: - + + + Prepare Proposal + Teklifi Hazırla + + + You can submit after 1 confirmation. At 6 confirmations it is accepted and processed. + 1 onaydan sonra gönderebilirsiniz. 6 onayda kabul edilir ve işlenir. + + + Proposal ID: + Teklif ID: + + + Submit Proposal + Teklifi Gönder + + + Close + Kapat + + + Valid + Geçerli + + + Invalid: %1 + Geçersiz: %1 + + + Burn %1 + %1 Yak + + + Burn %1 to create the fee transaction? + Ücret işlemini oluşturmak için %1 yakılsın mı? + + + Prepare failed + Hazırlama başarısız + + + Confirmations: %1 / %2 required + Onaylar: %1 / %2 gerekli + + + Estimated time remaining: Ready + Tahmini kalan süre: Hazır + + + Estimated time remaining: %n minute(s) + Tahmini kalan süre: %n dakikaTahmini kalan süre: %n dakika + + + Your proposal was submitted successfully. + Teklifiniz başarıyla gönderildi. + + + Already submitted + Zaten gönderildi + + + This proposal has already been submitted. + Bu teklif zaten gönderilmiş. + + + Submission failed + Gönderim başarısız + + + Proposal submitted + Teklif gönderildi + + + A fee of %1 will be burned when you prepare the proposal. + Teklifi hazırladığınızda %1 tutarında bir ücret yakılacaktır. + + + Prepare (burn %1) and wait for %2 confirmations. + Hazırlayın (%1 yakın) ve %2 onay bekleyin. + + QObject + + Do you want to reset settings to default values, or to abort without making changes? + Explanatory text shown on startup when the settings file cannot be read. Prompts user to make a choice between resetting or aborting. + Ayarları varsayılan değerlere sıfırlamak mı, yoksa değişiklik yapmadan iptal etmek mi istiyorsunuz? + + + A fatal error occurred. Check that settings file is writable, or try running with -nosettings. + 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. + Ölümcül bir hata oluştu. Ayarlar dosyasının yazılabilir olduğunu kontrol edin veya -nosettings ile çalıştırmayı deneyin. + Choose data directory on startup (default: %u) Başlangıçta veri klasörü seç (varsayılan: %u) @@ -2146,6 +2922,53 @@ This can also be adjusted later in the "Appearance" tab of the preferences. Bu, daha sonra tercihlerin "Görünüm" sekmesinden de ayarlanabilir. + + Ctrl+W + Ctrl+W + + + Unroutable + Yönlendirilemiyor + + + Internal + Dahili + + + Inbound + An inbound connection from a peer. An inbound connection is a connection initiated by a peer. + Gelen + + + Outbound + An outbound connection to a peer. An outbound connection is a connection initiated by us. + Giden + + + Full Relay + Peer connection type that relays all network information. + Tam Aktarım + + + Block Relay + Peer connection type that relays network information about blocks and not transactions or addresses. + Blok Aktarımı + + + Manual + Peer connection type established manually through one of several methods. + Manuel + + + Feeler + Short-lived peer connection type that tests the aliveness of known addresses. + Yoklayıcı + + + Address Fetch + Short-lived peer connection type that solicits known addresses from a peer. + Adres Getirme + %1 d %1 g @@ -2207,8 +3030,8 @@ %1 B - %1 KB - %1 KB + %1 kB + %1 kB %1 MB @@ -2264,7 +3087,12 @@ Save QR Code QR Kodu Kaydet - + + PNG Image + Expanded name of the PNG file format. See: https://en.wikipedia.org/wiki/Portable_Network_Graphics. + PNG Görüntü + + RPCConsole @@ -2371,6 +3199,14 @@ Version Sürüm + + High bandwidth BIP152 compact block relay: %1 + Yüksek bant genişliği BIP152 kompakt blok aktarımı: %1 + + + High Bandwidth + Yüksek Bant Genişliği + Starting Block Başlangıç Bloku @@ -2383,6 +3219,51 @@ Synced Blocks Eşleşmiş Bloklar + + Elapsed time since a novel block passing initial validity checks was received from this peer. + Bu eşten ilk geçerlilik kontrollerini geçen yeni bir bloğun alınmasından bu yana geçen süre. + + + Last Block + Son Blok + + + Elapsed time since a novel transaction accepted into our mempool was received from this peer. + Tooltip text for the Last Transaction field in the peer details area. + Bu eşten mempool'umuza kabul edilen yeni bir işlemin alınmasından bu yana geçen süre. + + + Last Transaction + Son İşlem + + + The mapped Autonomous System used for diversifying peer selection. + Eş seçimini çeşitlendirmek için kullanılan eşlenmiş Otonom Sistem. + + + Mapped AS + Eşlenmiş AS + + + Whether we relay addresses to this peer. + Tooltip text for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No). + Bu eşe adresleri aktarıp aktarmadığımız. + + + Address Relay + Text title for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No). + Adres Aktarımı + + + Addresses Processed + 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). + İşlenen Adresler + + + Addresses Rate-Limited + 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. + Hız Sınırlı Adresler + Rescan blockchain files 1 Blok zinciri dosyalarını yeniden tara 1 @@ -2423,6 +3304,22 @@ To specify a non-default location of the blocks directory use the '%1' option. Bloklar dizininin varsayılan olmayan bir konumunu belirtmek için '%1' seçeneğini kullanın. + + Local Addresses + Yerel Adresler + + + Network addresses that your Dash node is currently using to communicate with other nodes. + Dash düğümünüzün diğer düğümlerle iletişim kurmak için şu anda kullandığı ağ adresleri. + + + Number of regular Masternodes + Normal Masternode sayısı + + + Number of EvoNodes + EvoNode sayısı + Current block height Mevcut blok yüksekliği @@ -2471,10 +3368,50 @@ PoSe Score PoSe Puanı + + The transport layer version: %1 + Taşıma katmanı sürümü: %1 + + + Transport + Taşıma + + + The BIP324 session ID string in hex. + Onaltılık sistemde BIP324 oturum kimliği dizesi. + + + Session ID + Oturum Kimliği + + + The network protocol this peer is connected through: IPv4, IPv6, Onion, I2P, or CJDNS. + Bu eşin bağlandığı ağ protokolü: IPv4, IPv6, Onion, I2P veya CJDNS. + + + Permissions + İzinler + + + The direction and type of peer connection: %1 + Eş bağlantısının yönü ve türü: %1 + + + Direction/Type + Yön/Tür + Services Servisler + + Whether we relay transactions to this peer. + Bu eşe işlemleri aktarıp aktarmadığımız. + + + Transaction Relay + İşlem Aktarımı + Connection Time Bağlantı Süresi @@ -2511,6 +3448,16 @@ &Wallet Repair &Cüzdan Tamiri + + The total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting). + 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). + Bu eşten alınan ve işlenen adreslerin toplam sayısı (hız sınırlaması nedeniyle bırakılan adresler hariç). + + + The total number of addresses received from this peer that were dropped (not processed) due to rate-limiting. + 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. + Bu eşten alınan ve hız sınırlaması nedeniyle bırakılan (işlenmeyen) adreslerin toplam sayısı. + Wallet repair options. Cüzdan tamir seçenekleri. @@ -2524,52 +3471,82 @@ -reindex: Blok zinciri dizinini mevcut blk000??.dat dosyalarından yeniden oluşturma. - &Disconnect - &Bağlantıyı Kes + Inbound: initiated by peer + Explanatory text for an inbound peer connection. + Gelen: eş tarafından başlatıldı - Ban for - Yasakla + Outbound Full Relay: default + Explanatory text for an outbound peer connection that relays all network information. This is the default behavior for outbound connections. + Giden Tam Aktarım: varsayılan - 1 &hour - 1 &saat + Outbound Block Relay: does not relay transactions or addresses + Explanatory text for an outbound peer connection that relays network information about blocks and not transactions or addresses. + Giden Blok Aktarımı: işlemleri veya adresleri aktarmaz - 1 &day - 1 &gün + Outbound Manual: added using RPC %1 or %2/%3 configuration options + 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. + Giden Manuel: RPC %1 veya %2/%3 yapılandırma seçenekleri kullanılarak eklendi - 1 &week - 1 &hafta + Outbound Feeler: short-lived, for testing addresses + Explanatory text for a short-lived outbound peer connection that is used to test the aliveness of known addresses. + Giden Yoklayıcı: kısa ömürlü, adresleri test etmek için - 1 &year - 1 &yıl + Outbound Address Fetch: short-lived, for soliciting addresses + Explanatory text for a short-lived outbound peer connection that is used to request addresses from a peer. + Giden Adres Getirme: kısa ömürlü, adres talep etmek için - &Unban - &Yasaklamayı Kaldır + To + Kime + + + we selected the peer for high bandwidth relay + yüksek bant genişliği aktarımı için eşi seçtik + + + From + Kimden + + + the peer selected us for high bandwidth relay + eş yüksek bant genişliği aktarımı için bizi seçti - Welcome to the %1 RPC console. - %1 RPC konsoluna hoş geldiniz. + No + Hayır + + + no high bandwidth relay selected + yüksek bant genişliği aktarımı seçilmedi + + + &Disconnect + &Bağlantıyı Kes - Use up and down arrows to navigate history, and %1 to clear screen. - Tarihçede gezinmek için imleç tuşlarını kullanınız, %1 ile de ekranı temizleyebilirsiniz. + Ban for + Yasakla + + + 1 &hour + 1 &saat - Type %1 for an overview of available commands. - Kullanılabilir komutlara genel bakış için %1 yazın. + 1 &week + 1 &hafta - For more information on using this console type %1. - Bu konsolun kullanımı hakkında daha fazla bilgi için %1 yazın. + 1 &year + 1 &yıl - WARNING: Scammers have been active, telling users to type commands here, stealing their wallet contents. Do not use this console without fully understanding the ramifications of a command. - UYARI: Kullanıcıların cüzdan içeriğini çalmak için buraya komut girmenizi söyleyen dolandırıcılar olabilir. Bir komutun ne anlama geldiğini tam olarak bilmiyorsanız bu konsolu kullanmayın. + &Unban + &Yasaklamayı Kaldır In: @@ -2583,6 +3560,10 @@ Network activity disabled Ağ etkinliği devre dışı bırakıldı + + None + Yok + Total: %1 (Enabled: %2) Toplam: %1 (Etkinleştirilen: %2) @@ -2591,10 +3572,105 @@ Executing command without any wallet Cüzdan olmaksızın komut yürütme + + Ctrl++ + Main shortcut to increase the RPC console font size. + Ctrl++ + + + Ctrl+= + Secondary shortcut to increase the RPC console font size. + Ctrl+= + + + Ctrl+- + Main shortcut to decrease the RPC console font size. + Ctrl+- + + + Ctrl+_ + Secondary shortcut to decrease the RPC console font size. + Ctrl+_ + + + Ctrl+Shift+I + Ctrl+Shift+I + + + Ctrl+Shift+C + Ctrl+Shift+C + + + Ctrl+Shift+G + Ctrl+Shift+G + + + Ctrl+Shift+P + Ctrl+Shift+P + + + Ctrl+Shift+R + Ctrl+Shift+R + Executing command using "%1" wallet "%1" cüzdanı kullanılarak komut yürütülüyor + + detecting: peer could be v1 or v2 + Explanatory text for "detecting" transport type. + tespit ediliyor: eş v1 veya v2 olabilir + + + v1: unencrypted, plaintext transport protocol + Explanatory text for v1 transport type. + v1: şifrelenmemiş, düz metin taşıma protokolü + + + v2: BIP324 encrypted transport protocol + Explanatory text for v2 transport type. + v2: BIP324 şifreli taşıma protokolü + + + &Copy address + Context menu action to copy the address of a peer + &Adresi kopyala + + + 1 d&ay + 1 g&ün + + + &Copy IP/Netmask + 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 + &IP/Netmask'i kopyala + + + 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 + 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. + %1 RPC konsoluna hoş geldiniz. +Geçmişte gezinmek için yukarı ve aşağı okları, ekranı temizlemek için %2 kullanın. +Yazı tipi boyutunu büyütmek veya küçültmek için %3 ve %4 kullanın. +Kullanılabilir komutlara genel bakış için %5 yazın. +Bu konsolu kullanma hakkında daha fazla bilgi için %6 yazın. + +%7UYARI: Dolandırıcılar aktif olarak kullanıcılara buraya komutlar yazmalarını söyleyerek cüzdan içeriklerini çalıyorlar. Bir komutun sonuçlarını tam olarak anlamadan bu konsolu kullanmayın.%8 + + + Executing… + A console message indicating an entered command is currently being executed. + Yürütülüyor… + + + (peer: %1) + (eş: %1) + via %1 %1 vasıtasıyla @@ -2611,11 +3687,19 @@ Verified Masternode Doğrulanmış Ana Düğüm + + Yes + Evet + Unknown bilinmiyor - + + Never + Asla + + ReceiveCoinsDialog @@ -2634,6 +3718,10 @@ An optional message to attach to the payment request, which will be displayed when the request is opened.<br>Note: The message will not be sent with the payment over the Dash network. Ödeme talebine eklenecek isteğe bağlı bir mesaj, talep açıldığında gösterilecektir.<br>Not: Mesaj ödeme ile birlikte Dash ağı üzerinden gönderilmez. + + 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. + Yeni alıcı adresiyle ilişkilendirilecek seçime bağlı etiket (bir faturayı tanımlamak için kullanılır). Ödeme talebine de eklenir. + Use this form to request payments. All fields are <b>optional</b>. Ödeme talep etmek için bu formu kullanın. Tüm alanlar <b>seçime dayalıdır</b>. @@ -2691,28 +3779,60 @@ Ödeme talebine eklemek için bir mesaj girin - Copy URI - URI'yi kopyala + Copy &URI + &URI'yi kopyala + + + &Copy address + &Adresi kopyala - Copy address - Adresi kopyala + Copy &label + &Etiketi kopyala - Copy label - Etiket kopyala + Copy &message + &Mesajı kopyala - Copy message - İletiyi kopyala + Copy &amount + &Miktarı kopyala - Copy amount - Tutarı kopyala + Could not unlock wallet. + Cüzdanın kilidi açılamadı. - + + Could not generate new address + Yeni adres oluşturulamadı + + ReceiveRequestDialog + + Request payment to … + Ödeme talep et … + + + Address: + Adres: + + + Amount: + Miktar: + + + Label: + Etiket: + + + Message: + Mesaj: + + + Wallet: + Cüzdan: + Copy &URI &URI'yi kopyala @@ -2765,6 +3885,34 @@ Talep edilen + + RestoreWalletActivity + + Restore Wallet + Title of progress window which is displayed when wallets are being restored. + Cüzdanı Geri Yükle + + + Restoring Wallet <b>%1</b>… + Descriptive text of the restore wallets progress window which indicates to the user that wallets are currently being restored. + <b>%1</b> Cüzdanı Geri Yükleniyor… + + + Restore wallet failed + Title of message box which is displayed when the wallet could not be restored. + Cüzdan geri yükleme başarısız + + + Restore wallet warning + Title of message box which is displayed when the wallet is restored with some warning. + Cüzdan geri yükleme uyarısı + + + Restore wallet message + Title of message box which is displayed when the wallet is successfully restored. + Cüzdan geri yükleme mesajı + + SendCoinsDialog @@ -2799,10 +3947,6 @@ Fee: Ücret: - - Dust: - Toz: - Inputs… Girdiler… @@ -2827,6 +3971,14 @@ Transaction Fee: İşlem ücreti: + + 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 dash transactions than the network can process. + Blokların boşluğundan daha az işlem hacmi olduğunda, madenciler ve aktarıcı düğümler minimum bir ücret uygulayabilir. Sadece bu minimum ücreti ödemek sorun değildir, ancak ağın işleyebileceğinden daha fazla dash işlemi talebi olduğunda bunun asla onaylanmayan bir işlemle sonuçlanabileceğini unutmayın. + + + A too low fee might result in a never confirming transaction (read the tooltip) + Çok düşük bir ücret asla onaylanmayan bir işlemle sonuçlanabilir (araç ipucunu okuyun) + (Smart fee not initialized yet. This usually takes a few blocks…) (Zeki ücret henüz başlatılmadı. Bu genelde birkaç blok alır…) @@ -2919,10 +4071,6 @@ Copy bytes Baytları kopyala - - Copy dust - Tozu kopyala - Copy change Para üstünü kopyala @@ -2939,10 +4087,6 @@ %1 to %2 %1 ögesinden %2 unsuruna - - Are you sure you want to send? - Göndermek istediğinizden emin misiniz? - <b>(%1 of %2 entries displayed)</b> <b>(%1 / %2 girdi gösteriliyor)</b> @@ -2955,6 +4099,18 @@ Confirm the %1 send action %1 Gönderme işlemini onaylayın + + Cr&eate Unsigned + İmzasız &Oluştur + + + from wallet '%1' + '%1' cüzdanından + + + %1 to '%2' + %1 '%2' adresine + %1 funds only Yalnızca %1 fonları @@ -3003,6 +4159,51 @@ Confirm send coins Bitcoin gönderimini onaylayın + + Save Transaction Data + İşlem Verilerini Kaydet + + + PSBT saved + PSBT kaydedildi + + + Watch-only balance: + Sadece-izleme bakiyesi: + + + Creates a Partially Signed Blockchain Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet. + Örneğin çevrimdışı %1 cüzdanı veya PSBT uyumlu bir donanım cüzdanı ile kullanmak için Kısmen İmzalanmış Blokzincir İşlemi (PSBT) oluşturur. + + + Do you want to create this transaction? + 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. + Bu işlemi oluşturmak istiyor musunuz? + + + Please, review your transaction proposal. This will produce a Partially Signed Blockchain Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet. + 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. + Lütfen işlem önerinizi gözden geçirin. Bu, kaydedebileceğiniz veya kopyalayabileceğiniz ve ardından örneğin çevrimdışı %1 cüzdanı veya PSBT uyumlu bir donanım cüzdanı ile imzalayabileceğiniz Kısmen İmzalanmış Blokzincir İşlemi (PSBT) üretecektir. + + + Please, review your transaction. You can create and send this transaction or create a Partially Signed Blockchain Transaction (PSBT), which you can save or copy and then sign with, e.g., an offline %1 wallet, or a PSBT-compatible hardware wallet. + 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. + Lütfen işleminizi gözden geçirin. Bu işlemi oluşturup gönderebilir veya kaydedebileceğiniz veya kopyalayabileceğiniz ve ardından örneğin çevrimdışı %1 cüzdanı veya PSBT uyumlu bir donanım cüzdanı ile imzalayabileceğiniz Kısmen İmzalanmış Blokzincir İşlemi (PSBT) oluşturabilirsiniz. + + + Please, review your transaction. + Text to prompt a user to review the details of the transaction they are attempting to send. + Lütfen işleminizi gözden geçirin. + + + To review recipient list click "Show Details…" + Alıcı listesini gözden geçirmek için "Detayları Göster…" öğesine tıklayın + + + Partially Signed Transaction (Binary) + Expanded name of the binary PSBT file format. See: BIP 174. + Kısmen İmzalanmış İşlem (İkili) + The recipient address is not valid. Please recheck. Alıcı adresi geçerli değildir. Lütfen tekrar kontrol ediniz. @@ -3122,21 +4323,16 @@ A message that was attached to the dash: URI which will be stored with the transaction for your reference. Note: This message will not be sent over the Dash network. Referans için Dash: URI'siyle iliştirilmiş işlemle birlikte depolanacak bir ileti. Not: Bu mesaj Dash ağı üzerinden gönderilmeyecektir. + + + SendConfirmationDialog - This is an unauthenticated payment request. - Bu, kimliği doğrulanmamış bir ödeme talebidir. - - - This is an authenticated payment request. - Bu, kimliği doğrulanmış bir ödeme talebidir. - - - Pay To: - Şu adrese öde: + Send + Gönder - Memo: - Not: + Create Unsigned + İmzasız Oluştur @@ -3276,6 +4472,10 @@ Wallet unlock was cancelled. Cüzdan kilidinin açılması iptal edildi. + + No error + Hata yok + Private key for the entered address is not available. Girilen adres için özel anahtar mevcut değildir. @@ -3309,11 +4509,22 @@ İleti doğrulandı. + + SplashScreen + + (press q to shutdown and continue later) + (kapatmak ve daha sonra devam etmek için q tuşuna basın) + + + press q to shutdown + kapatmak için q tuşuna basın + + TrafficGraphWidget - KB/s - KB/s + kB/s + kB/s Total @@ -3330,20 +4541,9 @@ TransactionDesc - - Open for %n more block(s) - %n daha blok için açık%n daha blok için açık - - - Open until %1 - %1 değerine dek açık - - - conflicted - Uyuşmadı - 0/unconfirmed, %1 + 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. 0/doğrulanmamış, %1 @@ -3356,22 +4556,32 @@ abandoned + 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. Terk edilmiş + + conflicted with a transaction with %1 confirmations + 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. + %1 doğrulamalı bir işlemle çakıştı + %1/unconfirmed + 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, and still not locked via ChainLocks. %1/doğrulanmadı %1 confirmations + 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 or locked via ChainLocks. %1 doğrulama locked via ChainLocks + 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 and has been locked by ChainLocks. ZincirKilidi ile kilitli verified via InstantSend + 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 has been locked by InstantSend. AnındaGönder ile onaylandı @@ -3390,6 +4600,10 @@ Generated Oluşturuldu + + Platform Transfer + Platform Transferi + From Gönderen @@ -3520,14 +4734,6 @@ Address / Label Adres / Etiket - - Open for %n more block(s) - %n daha blok için açık%n daha blok için açık - - - Open until %1 - %1 değerine dek açık - Unconfirmed Doğrulanmamış @@ -3588,6 +4794,10 @@ Mined Madenden çıkarılan + + Platform Transfer + Platform Transferi + %1 Mixing %1 Karıştırma @@ -3715,6 +4925,10 @@ Mined Madenden çıkarılan + + Platform Transfer + Platform Transferi + Other Diğer @@ -3728,49 +4942,63 @@ En düşük tutar - Abandon transaction - İşlemden vazgeç + &Copy address + &Adresi kopyala - Copy address - Adres kopyala + Copy &label + &Etiketi kopyala - Copy label - Etiket kopyala + Copy &amount + &Miktarı kopyala - Copy amount - Tutarı kopyala + Copy transaction &ID + İşlem &ID'sini kopyala + + + Copy &raw transaction + &Ham işlemi kopyala + + + Copy full transaction &details + Tüm işlem &detaylarını kopyala - Copy transaction ID - İşlem ID'sini kopyala + &Show transaction details + İşlem detaylarını &göster - Copy raw transaction - Ham işlemi kopyala + A&bandon transaction + İşlemi &terk et - Copy full transaction details - Tüm işlem ayrıntılarını kopyala + Rese&nd transaction + İşlemi yeniden &gönder - Edit address label - Adres etiketini düzenle + &Edit address label + Adres etiketini &düzenle - Show transaction details - İşlem ayrıntılarını göster + Show address &QR code + Adres &QR kodunu göster - Show address QR code - Adresin QR kodunu göster + Show in %1 + 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. + %1 içinde göster Export Transaction History İşlem Tarihçesini Dışarı Aktar + + Comma separated file + Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values. + Virgülle ayrılmış dosya + Confirmed Doğrulandı @@ -3849,10 +5077,54 @@ Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled. Budama etkinse cüzdanı çok uzun süre kapatmak tüm zinciri yeniden senkronize etmek zorunda kalmanıza neden olabilir. - + + Close all wallets + Tüm cüzdanları kapat + + + Are you sure you wish to close all wallets? + Tüm cüzdanları kapatmak istediğinizden emin misiniz? + + WalletFrame - + + No wallet has been loaded. +Go to File > Open Wallet to load a wallet. +- OR - + Hiçbir cüzdan yüklenmedi. +Bir cüzdan yüklemek için Dosya > Cüzdan Aç'a gidin. +- VEYA - + + + Create a new wallet + Yeni bir cüzdan oluştur + + + Error + Hata + + + Unable to decode PSBT from clipboard (invalid base64) + Panodan PSBT kodu çözülemiyor (geçersiz base64) + + + Load Transaction Data + İşlem Verilerini Yükle + + + Partially Signed Transaction (*.psbt) + Kısmen İmzalanmış İşlem (*.psbt) + + + PSBT file must be smaller than 100 MiB + PSBT dosyası 100 MiB'den küçük olmalıdır + + + Unable to decode PSBT + PSBT kodu çözülemiyor + + WalletModel @@ -3878,6 +5150,11 @@ Selected amount: Seçilen tutar: + + Wallet Data + Name of the wallet data file format. + Cüzdan Verisi + Backup Wallet Cüzdanı Yedekle @@ -3905,14 +5182,6 @@ dash-core - - Error: Listening for incoming connections failed (listen returned error %s) - Hata: İçeri gelen bağlantıların dinlenmesi başarısız oldu (dinleme %s hatasını verdi) - - - Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee. - Ücret tahmini başarısız oldu. YedekÜcret devre dışı. Birkaç blok bekleyin veya -yedekücret'i etkinleştirin. - 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 Bu hata, bu cüzdan düzgün bir şekilde kapatılmamışsa ve en son Berkeley DB'nin daha yeni bir sürümüne sahip bir yapı kullanılarak yüklenmişse oluşabilir. Eğer öyleyse, lütfen bu cüzdanın en son yüklendiği yazılımı kullanın. @@ -3970,16 +5239,20 @@ Veritabanından okumada hata, kapatılıyor. - Failed to listen on any port. Use -listen=0 if you want this. - Herhangi bir portun dinlenmesi başarısız oldu. Bunu istiyorsanız -listen=0 seçeneğini kullanınız. + Error: Missing checksum + Hata: Sağlama toplamı eksik - -maxtxfee is set very high! Fees this large could be paid on a single transaction. - -maxtxfee çok yüksek bir değere ayarlanmış! Bu denli yüksek ücretler tek bir işlemde ödenebilir. + Error: Unable to parse version %u as a uint32_t + Hata: %u sürümü uint32_t olarak ayrıştırılamıyor - Cannot provide specific connections and have addrman find outgoing connections at the same. - Giden bağlantıları addrman araması ile aynı zamanda belirli bağlantılar sağlayamaz. + Error: Unable to write record to new wallet + Hata: Yeni cüzdana kayıt yazılamıyor + + + Failed to listen on any port. Use -listen=0 if you want this. + Herhangi bir portun dinlenmesi başarısız oldu. Bunu istiyorsanız -listen=0 seçeneğini kullanınız. Found unconfirmed denominated outputs, will wait till they confirm to continue. @@ -3990,13 +5263,17 @@ Geçersiz -socketevents ('%s') belirtildi. Yalnızca şu modlar desteklenir: %s - Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions) - -maxtxfee=<tutar> için geçersiz tutar: '%s' (Sıkışmış işlemleri önlemek için en az %s değerinde en düşük aktarım ücretine eşit olmalıdır) + SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is supported + SQLiteDatabase: Bilinmeyen sqlite cüzdan şema sürümü %d. Yalnızca %d sürümü destekleniyor Transaction index can't be disabled with governance validation enabled. Either start with -disablegovernance command line switch or enable transaction index. Yönetim doğrulaması etkinken işlem endeksi devre dışı bırakılamaz. Ya -disablegovernance komut satırı anahtarıyla başlayın ya da işlem endeksini etkinleştirin. + + Unsupported category-specific logging level -loglevel=%s. Expected -loglevel=<category>:<loglevel>. Valid categories: %s. Valid loglevels: %s. + Desteklenmeyen kategoriye özgü günlük kaydı seviyesi -loglevel=%s. Beklenen -loglevel=<category>:<loglevel>. Geçerli kategoriler: %s. Geçerli günlük seviyeleri: %s. + Can't mix: no compatible inputs found! Karıştırılamıyor: hiç uyumlu girdi bulunamadı! @@ -4005,6 +5282,14 @@ Entry exceeds maximum size. Girdi maksimum boyutu aşıyor. + + Error upgrading evo database for EHF + EHF için evo veritabanı yükseltilirken hata + + + Failed to commit Evo database + Evo veritabanı işlenemedi + Found enough users, signing ( waiting %s ) Yeterli kullanıcı bulundu, imzalanıyor ( %s bekleniyor ) @@ -4029,18 +5314,14 @@ Insufficient funds. Yetersiz bakiye. - - Invalid amount for -discardfee=<amount>: '%s' - -discardfee=<meblağ> için geçersiz meblağ: '%s' - - - Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s) - -paytxfee=<tutar>:'%s' unsurunda geçersiz tutar (asgari %s olması lazımdır) - Invalid minimum number of spork signers specified with -minsporkkeys -minsporkkeys ile belirtilmiş geçersiz minimum spork imzacısı sayısı + + Listening for incoming connections failed (listen returned error %s) + Gelen bağlantıları dinleme başarısız oldu (dinleme %s hatası döndürdü) + Lock is already in place. Kilit zaten yerinde. @@ -4097,6 +5378,10 @@ Synchronizing governance objects… Yönetim nesneleri eşleniyor… + + Transaction change output index out of range + İşlem para üstü çıktı endeksi aralık dışında + Unable to start HTTP server. See debug log for details. HTTP sunucusu başlatılamadı. Ayrıntılar için debug.log dosyasına bakınız. @@ -4105,6 +5390,10 @@ Unknown response. Bilinmeyen cevap. + + Unsupported global logging level -loglevel=%s. Valid values: %s. + Desteklenmeyen genel günlük kaydı seviyesi -loglevel=%s. Geçerli değerler: %s. + User Agent comment (%s) contains unsafe characters. Kullanıcı Aracı açıklaması (%s) güvensiz karakterler içermektedir. @@ -4145,6 +5434,10 @@ Make sure to encrypt your wallet and delete all non-encrypted backups after you have verified that the wallet works! Cüzdanın çalıştığından emin olduktan sonra mutlaka cüzdanınızı şifreleyip şifrelenmemiş tüm yedekleri silin! + + More than one onion bind address is provided. Using %s for the automatically created Tor onion service. + Birden fazla onion bağlama adresi sağlandı. Otomatik olarak oluşturulan Tor onion servisi için %s kullanılıyor. + Prune configured below the minimum of %d MiB. Please use a higher number. Budama, en düşük değer olan %d MiB'den düşük olarak ayarlanmıştır. Lütfen daha yüksek bir sayı kullanınız. @@ -4173,10 +5466,6 @@ Wallet is locked, can't replenish keypool! Automatic backups and mixing are disabled, please unlock your wallet to replenish keypool. Cüzdanınız kilitli, anahtar havuzu yenilenemiyor! Otomatik yedekleme ve karışım kapalı, anahtar havuzunu yenilemek için lütfen cüzdanınızın kilidini açın. - - You need to rebuild the database using -reindex to change -timestampindex - -timestampindex'i değiştirmek için -reindex'i kullanarak veritabanını baştan kurmalısınız - You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain Budama olmayan kipe dönmek için veritabanını -reindex ile tekrar derlemeniz gerekir. Bu, tüm blok zincirini tekrar indirecektir @@ -4218,20 +5507,32 @@ %s yüklenirken hata oluştu: Özel anahtarlar yalnızca oluşturma sırasında devre dışı bırakılabilir - Error upgrading evo database - Evo veritabanını yükseltirken hata oluştu + Error: Couldn't create cursor into database + Hata: Veritabanında imleç oluşturulamadı Error: Disk space is low for %s Hata: %s için disk alanı yetersiz - Exceeded max tries. - Maksimum deneme aşıldı. + Error: Dumpfile checksum does not match. Computed %s, expected %s + Hata: Döküm dosyası sağlama toplamı eşleşmiyor. Hesaplanan %s, beklenen %s + + + Error: Got key that was not hex: %s + Hata: Onaltılık olmayan anahtar alındı: %s + + + Error: Got value that was not hex: %s + Hata: Onaltılık olmayan değer alındı: %s - Failed to commit EvoDB - EvoDB gerçekleştirilemedi + Error: Keypool ran out, please call keypoolrefill first + Hata: Anahtar havuzu tükendi, lütfen önce keypoolrefill çağırın + + + Error: No addresses available. + Hata: Kullanılabilir adres yok. Failed to create backup %s! @@ -4249,17 +5550,29 @@ Failed to rescan the wallet during initialization Başlatma sırasında cüzdan yeniden taranamadı + + Failed to verify database + Veritabanı doğrulanamadı + + + Fee rate (%s) is lower than the minimum fee rate setting (%s) + Ücret oranı (%s) minimum ücret oranı ayarından (%s) düşük + Found enough users, signing… Yeterli kullanıcı bulundu, imzalanıyor… - Invalid P2P permission: '%s' - Geçersiz P2P izni: '%s' + Ignoring duplicate -wallet %s. + Yinelenen -wallet %s yoksayılıyor. - Invalid amount for -fallbackfee=<amount>: '%s' - -fallbackfee=<tutar> için geçersiz tutar: '%s' + Input not found or already spent + Girdi bulunamadı veya zaten harcanmış + + + Invalid P2P permission: '%s' + Geçersiz P2P izni: '%s' Invalid masternodeblsprivkey. Please see documentation. @@ -4281,6 +5594,10 @@ Mixing in progress… Karışım devam ediyor… + + No addresses available + Kullanılabilir adres yok + No errors detected. Hata tespit edilmedi. @@ -4309,6 +5626,22 @@ Prune mode is incompatible with -txindex. Budama kipi -txindex ile uyumsuzdur. + + SQLiteDatabase: Failed to execute statement to verify database: %s + SQLiteDatabase: Veritabanını doğrulama ifadesi yürütülemedi: %s + + + SQLiteDatabase: Failed to prepare statement to verify database: %s + SQLiteDatabase: Veritabanını doğrulama ifadesi hazırlanamadı: %s + + + SQLiteDatabase: Failed to read database verification error: %s + SQLiteDatabase: Veritabanı doğrulama hatası okunamadı: %s + + + SQLiteDatabase: Unexpected application id. Expected %u, got %u + SQLiteDatabase: Beklenmeyen uygulama kimliği. Beklenen %u, alınan %u + Section [%s] is not recognized. [%s] bölümü tanınmadı. @@ -4341,6 +5674,10 @@ This is the transaction fee you will pay if you send a transaction. Eğer bir gönderme işlemi yaparsanız bu ödeyeceğiniz işlem ücretidir. + + Topping up keypool… + Anahtar havuzu doldruluyor… + Transaction amounts must not be negative İşlem tutarı negatif olmamalıdır @@ -4369,13 +5706,17 @@ Unable to generate initial keys Başlangıç anahtarları oluşturulamıyor + + Unable to open %s for writing + Yazmak için %s açılamıyor + Unknown -blockfilterindex value %s. Bilinmeyen -blokfiltresiindeksi değeri %s. - Upgrading UTXO database - UTXO veritabanı yükseltiliyor + Unknown new rules activated (versionbit %i) + Bilinmeyen yeni kurallar etkinleştirildi (versionbit %i) Verifying blocks… @@ -4394,16 +5735,12 @@ Cüzdan yedeği klasörü %s oluşturulamadı! - You can not start a masternode with wallet enabled. - Cüzdan etkinleştirilmişken bir ana düğüm başlatamazsınız. - - - You need to rebuild the database using -reindex to change -addressindex - -addressindex'i değiştirmek için -reindex'i kullanarak veritabanını baştan kurmalısınız + Wiping wallet transactions… + Cüzdan işlemleri siliniyor… - You need to rebuild the database using -reindex to change -spentindex - -spentindex'i değiştirmek için -spentindex'i kullanarak veritabanını baştan kurmalısınız + You can not start a masternode with wallet enabled. + Cüzdan etkinleştirilmişken bir ana düğüm başlatamazsınız. no mixing available. @@ -4421,6 +5758,22 @@ %s uses exact denominated amounts to send funds, you might simply need to mix some more coins. %s para göndermek için tam olarak birimlendirilmiş meblağlar kullanır, sadece biraz daha fazla parayı anonim hale getirmeniz gerekiyor. + + -reindex-chainstate option is not compatible with -blockfilterindex. Please temporarily disable blockfilterindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes. + -reindex-chainstate seçeneği -blockfilterindex ile uyumlu değil. Lütfen -reindex-chainstate kullanırken blockfilterindex'i geçici olarak devre dışı bırakın veya tüm indeksleri tamamen yeniden oluşturmak için -reindex-chainstate yerine -reindex kullanın. + + + -reindex-chainstate option is not compatible with -coinstatsindex. Please temporarily disable coinstatsindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes. + -reindex-chainstate seçeneği -coinstatsindex ile uyumlu değil. Lütfen -reindex-chainstate kullanırken coinstatsindex'i geçici olarak devre dışı bırakın veya tüm indeksleri tamamen yeniden oluşturmak için -reindex-chainstate yerine -reindex kullanın. + + + -reindex-chainstate option is not compatible with -txindex. Please temporarily disable txindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes. + -reindex-chainstate seçeneği -txindex ile uyumlu değil. Lütfen -reindex-chainstate kullanırken txindex'i geçici olarak devre dışı bırakın veya tüm indeksleri tamamen yeniden oluşturmak için -reindex-chainstate yerine -reindex kullanın. + + + Cannot downgrade wallet from version %i to version %i. Wallet version unchanged. + Cüzdan %i sürümünden %i sürümüne düşürülemiyor. Cüzdan sürümü değişmedi. + Cannot obtain a lock on data directory %s. %s is probably already running. %s veri dizininde kilit elde edilemedi. %s muhtemelen hâlihazırda çalışmaktadır. @@ -4433,14 +5786,82 @@ Error loading %s: You can't enable HD on an already existing non-HD wallet %s yüklenirken hata: Zaten var olan bir HD olmayan cüzdanda HD etkinleştiremezsiniz + + 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 + Cüzdan yüklenirken hata. Cüzdan blokların indirilmesini gerektiriyor ve yazılım şu anda assumeutxo anlık görüntüleri kullanılırken bloklar sıra dışı indirilirken cüzdanları yüklemeyi desteklemiyor. Düğüm senkronizasyonu %s yüksekliğine ulaştıktan sonra cüzdan başarıyla yüklenebilmelidir + Error reading %s! All keys read correctly, but transaction data or address book entries might be missing or incorrect. %s dosyasının okunması sırasında bir hata meydana geldi! Tüm anahtarlar doğru bir şekilde okundu, ancak işlem verileri ya da adres defteri ögeleri hatalı veya eksik olabilir. + + Error: Dumpfile format record is incorrect. Got "%s", expected "format". + Hata: Döküm dosyası format kaydı yanlış. Alınan "%s", beklenen "format". + + + Error: Dumpfile identifier record is incorrect. Got "%s", expected "%s". + Hata: Döküm dosyası tanımlayıcı kaydı yanlış. Alınan "%s", beklenen "%s". + + + Error: Dumpfile version is not supported. This version of bitcoin-wallet only supports version 1 dumpfiles. Got dumpfile with version %s + Hata: Döküm dosyası sürümü desteklenmiyor. Bitcoin-wallet'ın bu sürümü yalnızca sürüm 1 döküm dosyalarını destekler. Alınan döküm dosyası sürümü %s + + + Failed to rename invalid peers.dat file. Please move or delete it and try again. + Geçersiz peers.dat dosyası yeniden adlandırılamadı. Lütfen taşıyın veya silin ve tekrar deneyin. + + + Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable %s. + Ücret tahmini başarısız oldu. Fallbackfee devre dışı. Birkaç blok bekleyin veya %s'yi etkinleştirin. + + + File %s already exists. If you are sure this is what you want, move it out of the way first. + %s dosyası zaten mevcut. Bunu istediğinizden eminseniz, önce dosyayı başka bir yere taşıyın. + + + Incompatible options: -dnsseed=1 was explicitly specified, but -onlynet forbids connections to IPv4/IPv6 + Uyumsuz seçenekler: -dnsseed=1 açıkça belirtildi, ancak -onlynet IPv4/IPv6 bağlantılarını yasaklıyor + Incorrect or no devnet genesis block found. Wrong datadir for devnet specified? Geçersiz veya sıfır devnet genesis bloğu bulundu. Devnet için belirtilen datadir yanlış mı? + + Invalid amount for %s=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions) + %s=<amount> için geçersiz miktar: '%s' (takılan işlemleri önlemek için en az %s minrelay ücreti olmalıdır) + + + 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. + Geçersiz veya bozuk peers.dat (%s). Bunun bir hata olduğuna inanıyorsanız, lütfen %s'ye bildirin. Geçici çözüm olarak, bir sonraki başlatmada yeni bir tane oluşturulmak için dosyayı (%s) yoldan çıkarabilirsiniz (yeniden adlandırın, taşıyın veya silin). + + + No dump file provided. To use createfromdump, -dumpfile=<filename> must be provided. + Döküm dosyası sağlanmadı. createfromdump kullanmak için -dumpfile=<filename> sağlanmalıdır. + + + No dump file provided. To use dump, -dumpfile=<filename> must be provided. + Döküm dosyası sağlanmadı. dump kullanmak için -dumpfile=<filename> sağlanmalıdır. + + + No wallet file format provided. To use createfromdump, -format=<format> must be provided. + Cüzdan dosya formatı sağlanmadı. createfromdump kullanmak için -format=<format> sağlanmalıdır. + + + Outbound connections restricted to CJDNS (-onlynet=cjdns) but -cjdnsreachable is not provided + Giden bağlantılar CJDNS ile sınırlı (-onlynet=cjdns) ancak -cjdnsreachable sağlanmadı + + + Outbound connections restricted to Tor (-onlynet=onion) but the proxy for reaching the Tor network is explicitly forbidden: -onion=0 + Giden bağlantılar Tor ile sınırlı (-onlynet=onion) ancak Tor ağına ulaşmak için proxy açıkça yasaklandı: -onion=0 + + + 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 + Giden bağlantılar Tor ile sınırlı (-onlynet=onion) ancak Tor ağına ulaşmak için proxy sağlanmadı: -proxy, -onion veya -listenonion'dan hiçbiri verilmedi + + + Outbound connections restricted to i2p (-onlynet=i2p) but -i2psam is not provided + Giden bağlantılar i2p ile sınırlı (-onlynet=i2p) ancak -i2psam sağlanmadı + Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly. Lütfen bilgisayarınızın saat ve tarihinin doğru olduğunu kontrol ediniz! Saatinizde gecikme varsa %s doğru şekilde çalışamaz. @@ -4449,6 +5870,14 @@ Please contribute if you find %s useful. Visit %s for further information about the software. %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. + + Prune mode is incompatible with -reindex-chainstate. Use full -reindex instead. + Budama modu -reindex-chainstate ile uyumlu değil. Bunun yerine tam -reindex kullanın. + + + This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection. + Bu, normal coin seçimi yerine kısmi harcama önlemeye öncelik vermek için ödediğiniz maksimum işlem ücretidir (normal ücrete ek olarak). + This is the transaction fee you may discard if change is smaller than dust at this level Bu, para üstü seviyesi tozdan daha küçükse, iptal edebileceğiniz işlem ücretidir. @@ -4457,14 +5886,38 @@ This is the transaction fee you may pay when fee estimates are not available. İşlem ücret tahminleri mevcut olmadığında ödeyebileceğiniz işlem ücreti budur. + + Transaction requires one destination of non-0 value, a non-0 feerate, or a pre-selected input + İşlem, sıfır olmayan değerli bir hedef, sıfır olmayan bir ücret oranı veya önceden seçilmiş bir girdi gerektirir + Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate. Bloklar tekrarlanamıyor. -Reindex-chainstate kullanarak veritabanını yeniden kurmanız gerekecek. + + Unknown wallet file format "%s" provided. Please provide one of "bdb" or "sqlite". + Bilinmeyen cüzdan dosya formatı "%s" sağlandı. Lütfen "bdb" veya "sqlite"'den birini sağlayın. + + + Unsupported chainstate database format found. Please restart with -reindex-chainstate. This will rebuild the chainstate database. + Desteklenmeyen chainstate veritabanı formatı bulundu. Lütfen -reindex-chainstate ile yeniden başlatın. Bu, chainstate veritabanını yeniden oluşturacaktır. + + + Warning: Dumpfile wallet format "%s" does not match command line specified format "%s". + Uyarı: Döküm dosyası cüzdan formatı "%s" komut satırında belirtilen format "%s" ile eşleşmiyor. + Warning: Private keys detected in wallet {%s} with disabled private keys Uyarı: Özel anahtarların devre dışı bırakıldığı {%s} cüzdanında özel anahtarlar algılandı + + You need to rebuild the database using -reindex to enable -timestampindex + -timestampindex etkinleştirmek için -reindex kullanarak veritabanını yeniden oluşturmanız gerekiyor + + + %s -- Incorrect seed, it should be a hex string + %s -- Yanlış seed, onaltılık bir dize olmalı + %s is not a valid backup folder! %s geçerli bir yedek klasörü değil! @@ -4489,10 +5942,30 @@ -rpcport must be specified when -devnet and -server are specified -devnet ve -server belirtildiğinde -rpcport da belirtilmelidir + + -statsbatchsize cannot be configured with a negative value. + -statsbatchsize negatif bir değerle yapılandırılamaz. + + + -statsduration cannot be configured with a negative value. + -statsduration negatif bir değerle yapılandırılamaz. + A fatal internal error occurred, see debug.log for details Önemli bir dahili hata oluştu, ayrıntılar için debug.log'a bakın + + Cannot create socket (socket() returned error %s) + Soket oluşturulamıyor (socket() %s hatası döndürdü) + + + Cannot get socket address for %s + %s için soket adresi alınamıyor + + + Cannot init Statsd client + Statsd istemcisi başlatılamıyor + Cannot resolve -%s address: '%s' Çözümlenemedi - %s adres: '%s' @@ -4501,10 +5974,6 @@ Cannot write to data directory '%s'; check permissions. '%s' veri dizinine yazılamıyor; izinleri kontrol edin. - - Change index out of range - Aralık dışında değişiklik indeksi - Copyright (C) Copyright (C) @@ -4513,6 +5982,14 @@ Disk space is too low! Disk alanı çok düşük! + + Dump file %s does not exist. + Döküm dosyası %s mevcut değil. + + + Error creating %s + %s oluşturulurken hata + Error loading %s %s unsurunun yüklenmesinde hata oluştu @@ -4530,8 +6007,8 @@ %s yüklenirken hata: Zaten var olan bir HD cüzdanda HD'yi kapatamazsınız. - Error upgrading chainstate database - Zincirdurumu veritabanı yükseltme hatası + Error reading next record from wallet database + Cüzdan veritabanından sonraki kayıt okunurken hata Loading P2P addresses… @@ -4601,6 +6078,14 @@ Inputs vs outputs size mismatch. Girdi ve çıktı boyutları tutarsız. + + Invalid '%s'. Allowed values: 128, 160, 192, 224, 256. + Geçersiz '%s'. İzin verilen değerler: 128, 160, 192, 224, 256. + + + Invalid -i2psam address or hostname: '%s' + Geçersiz -i2psam adresi veya ana makine adı: '%s' + Invalid -onion address or hostname: '%s' Geçersiz -onion adresi veya ana makine adı: '%s' @@ -4645,14 +6130,74 @@ %s corrupt. Try using the wallet tool dash-wallet to salvage or restoring a backup. %s bozuk. Bir yedeği kurtarmak veya geri yüklemek için cüzdan aracı dash-wallet'ı kullanmayı deneyin. + + %s is set very high! Fees this large could be paid on a single transaction. + %s çok yüksek ayarlanmış! Bu kadar büyük ücretler tek bir işlemde ödenebilir. + + + Cannot provide specific connections and have addrman find outgoing connections at the same time. + Belirli bağlantılar sağlanamaz ve addrman aynı anda giden bağlantıları bulamaz. + + + Failed to upgrade Evo database + Evo veritabanı yükseltilemedi + + + Fee needed > fee paid + Gereken ücret > ödenen ücret + + + Host %s on unsupported network + Desteklenmeyen ağda %s ana bilgisayarı + + + Invalid amount for %s=<amount>: '%s' (must be at least %s) + %s=<amount> için geçersiz miktar: '%s' (en az %s olmalıdır) + + + Invalid amount for %s=<amount>: '%s' + %s=<amount> için geçersiz miktar: '%s' + + + Invalid port specified in %s: '%s' + %s içinde geçersiz port belirtildi: '%s' + Last successful action was too recent. Son başarılı eylemi çok yakında yapıldı. + + Missing solving data for estimating transaction size + İşlem boyutunu tahmin etmek için çözme verileri eksik + + + No host specified + Ana bilgisayar belirtilmedi + + + No host specified, malformed URL + Ana bilgisayar belirtilmedi, bozuk URL + + + No text before the scheme delimiter, malformed URL + Şema sınırlayıcısından önce metin yok, bozuk URL + + + Port must be between %d and %d, supplied %d + Port %d ile %d arasında olmalıdır, sağlanan %d + + + Socket not initialized, cannot send message + Soket başlatılmadı, mesaj gönderilemiyor + The source code is available from %s. Kaynak kod şuradan elde edilebilir: %s. + + The specified config file %s does not exist + Belirtilen yapılandırma dosyası %s mevcut değil + The transaction amount is too small to pay the fee İşlemdeki bitcoin tutarı ücreti ödemek için çok düşük @@ -4673,6 +6218,10 @@ Transaction fees are too high. İşlem ücretleri çok yüksek. + + Transaction needs a change address, but we can't generate it. + İşlem bir para üstü adresi gerektiriyor, ancak oluşturamıyoruz. + Transaction not valid. İşlem geçerli değil. @@ -4693,6 +6242,18 @@ Unable to locate enough non-denominated funds for this transaction. Bu işlem için yeterli cinsten olmayan bakiye bulunamadı. + + Unable to lookup host %s + Ana bilgisayar %s aranamıyor + + + Unable to parse -maxuploadtarget: '%s' + -maxuploadtarget ayrıştırılamıyor: '%s' + + + Unable to send message to %s (::sendto() returned error %s) + %s'ye mesaj gönderilemiyor (::sendto() %s hatası döndürdü) + Unable to sign spork message, wrong key? Spork mesajı imzalanamadı, anahtar mı yanlış? @@ -4706,12 +6267,12 @@ Bilinmeyen durum: id = %u - Unsupported logging category %s=%s. - Desteklenmeyen günlük kaydı kategorisi %s=%s. + Unsupported URL scheme, must begin with udp:// + Desteklenmeyen URL şeması, udp:// ile başlamalıdır - Upgrading txindex database - txindex veritabanını yükseltme + Unsupported logging category %s=%s. + Desteklenmeyen günlük kaydı kategorisi %s=%s. Very low number of keys left: %d @@ -4741,9 +6302,25 @@ You can not disable governance validation on a masternode. Bir anadüğümde yönetim doğrulamasını devre dışı bırakamazsınız. + + You need to rebuild the database using -reindex to enable -addressindex + -addressindex etkinleştirmek için -reindex kullanarak veritabanını yeniden oluşturmanız gerekiyor + + + You need to rebuild the database using -reindex to enable -spentindex + -spentindex etkinleştirmek için -reindex kullanarak veritabanını yeniden oluşturmanız gerekiyor + Your entries added successfully. Girdileriniz başarıyla eklendi. + + Settings file could not be read + Ayarlar dosyası okunamadı + + + Settings file could not be written + Ayarlar dosyası yazılamadı + \ No newline at end of file diff --git a/src/qt/locale/dash_vi.ts b/src/qt/locale/dash_vi.ts index c1e74f200373..1443591414d3 100644 --- a/src/qt/locale/dash_vi.ts +++ b/src/qt/locale/dash_vi.ts @@ -1,6 +1,10 @@ AddressBookPage + + Enter address or label to search + Nhập địa chỉ hoặc nhãn để tìm kiếm + Right-click to edit address or label Bấm phải chuột để sửa địa chỉ hoặc nhãn @@ -61,18 +65,14 @@ C&hoose C&họn - - Sending addresses - Đia chỉ gửi - - - Receiving addresses - Địa chỉ nhận - These are your Dash addresses for sending payments. Always check the amount and the receiving address before sending coins. Đây là các địa chỉ Dash của bạn để gửi thanh toán. Luôn luôn kiểm tra số tiền và địa chỉ nhận trước khi bạn gửi tiền. + + These are your Dash addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses. + Đây là các địa chỉ Dash của bạn để nhận thanh toán. Sử dụng nút 'Tạo địa chỉ nhận mới' trong tab nhận để tạo địa chỉ mới. + &Copy Address &Sao chép Địa chỉ @@ -86,8 +86,8 @@ &Sửa - &Show address QR code - &Hiển thị mã QR của địa chỉ + Show address &QR code + Hiển thị mã &QR của địa chỉ QR code @@ -97,11 +97,24 @@ Export Address List Kết xuất danh sách Địa chỉ + + Comma separated file + Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values. + Tập tin giá trị được phân cách bằng dấu phẩy + There was an error trying to save the address list to %1. Please try again. An error message. %1 is a stand-in argument for the name of the file we attempted to save to. Có lỗi xảy ra khi lưu các địa chỉ vào %1. Hãy thử lại. + + Sending addresses - %1 + Địa chỉ gửi - %1 + + + Receiving addresses - %1 + Địa chỉ nhận - %1 + Exporting Failed Kết xuất không thành công @@ -179,6 +192,10 @@ Repeat new passphrase Nhập lại mật khẩu mới + + Show passphrase + Hiển thị mật khẩu + Encrypt wallet Mã hoá ví @@ -215,6 +232,30 @@ Wallet encrypted Ví đã được mã hoá. + + 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>. + Nhập mật khẩu mới cho ví.<br/>Vui lòng sử dụng mật khẩu có <b>mười ký tự ngẫu nhiên trở lên</b>, hoặc <b>tám từ trở lên</b>. + + + Enter the old passphrase and new passphrase for the wallet. + Nhập mật khẩu cũ và mật khẩu mới cho ví. + + + Remember that encrypting your wallet cannot fully protect your funds from being stolen by malware infecting your computer. + Xin lưu ý rằng việc mã hóa ví của bạn không thể bảo vệ hoàn toàn tiền của bạn khỏi bị đánh cắp bởi phần mềm độc hại lây nhiễm máy tính của bạn. + + + Wallet to be encrypted + Ví sẽ được mã hóa + + + Your wallet is about to be encrypted. + Ví của bạn sắp được mã hóa. + + + Your wallet is now encrypted. + Ví của bạn bây giờ đã được mã hóa. + IMPORTANT: Any previous backups you have made of your wallet file should be replaced with the newly generated, encrypted wallet file. Previous backups of the unencrypted wallet file contain the same HD seed and still have full access to all your funds just like the new, encrypted wallet. QUAN TRỌNG: Bất cứ sao lưu nào bạn đã làm trước đó với ví của bạn thì nên thay thế bằng phiên bản sao lưu mới nhất đã được mã hoá. Những bản sao lưu trước mà không mã hoá mà chứa HD Seed thì vẫn có toàn quyền truy cập đến tiền trong ví của bạn giống y như phiên bản ví mới đã được mã hoá. @@ -243,10 +284,22 @@ The passphrase entered for the wallet decryption was incorrect. Mật khẩu bạn nhập để giải mã ví không chính xác. + + 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 23.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. + Mật khẩu đã nhập để giải mã ví không chính xác. Nó chứa một ký tự null (tức là - một byte không). Nếu mật khẩu được đặt bằng phiên bản phần mềm này trước 23.0, vui lòng thử lại chỉ với các ký tự cho đến — nhưng không bao gồm — ký tự null đầu tiên. Nếu thành công, vui lòng đặt mật khẩu mới để tránh vấn đề này trong tương lai. + Wallet passphrase was successfully changed. Mật khẩu ví đã được đổi thành công. + + Passphrase change failed + Thay đổi mật khẩu thất bại + + + 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 23.0, please try again with only the characters up to — but not including — the first null character. + Mật khẩu cũ đã nhập để giải mã ví không chính xác. Nó chứa một ký tự null (tức là - một byte không). Nếu mật khẩu được đặt bằng phiên bản phần mềm này trước 23.0, vui lòng thử lại chỉ với các ký tự cho đến — nhưng không bao gồm — ký tự null đầu tiên. + Warning: The Caps Lock key is on! Cảnh báo: Khoá Caps Lock đang được bật! @@ -272,7 +325,23 @@ BitcoinApplication - + + Runaway exception + Ngoại lệ không kiểm soát + + + A fatal error occurred. %1 can no longer continue safely and will quit. + Đã xảy ra lỗi nghiêm trọng. %1 không thể tiếp tục an toàn và sẽ thoát. + + + Internal error + Lỗi nội bộ + + + An internal error occurred. %1 will attempt to continue safely. This is an unexpected bug which can be reported as described below. + Đã xảy ra lỗi nội bộ. %1 sẽ cố gắng tiếp tục an toàn. Đây là một lỗi không mong đợi có thể được báo cáo như được mô tả bên dưới. + + BitcoinGUI @@ -299,6 +368,10 @@ Request payments (generates QR codes and dash: URIs) Yêu cầu thanh toán (sinh mã QR và dash: URIs) + + Ctrl+Q + Ctrl+Q + &Options… &Tuỳ chọn… @@ -327,10 +400,50 @@ &Verify message… &Kiểm tra thông điệp… + + &Load PSBT from file… + &Tải PSBT từ tệp… + + + &Sending addresses + &Địa chỉ gửi + + + &Receiving addresses + &Địa chỉ nhận + Open &URI… Mở &URI… + + Open Wallet + Mở Ví + + + Open a wallet + Mở một ví + + + Close wallet + Đóng ví + + + No wallets available + Không có ví nào khả dụng + + + &Window + &Cửa sổ + + + Zoom + Thu phóng + + + Main Window + Cửa sổ chính + &Transactions Các &Giao dịch @@ -368,16 +481,12 @@ &Khoảng %1 - Modify configuration options for %1 - Sửa đổi tùy chỉnh cấu hình cho %1 - - - &Show / Hide - Ẩ&n / Hiện + Send %1 funds to a Dash address + Gửi %1 tiền đến một địa chỉ Dash - Show or hide the main Window - Hiển thị hoặc ẩn cửa sổ chính + Modify configuration options for %1 + Sửa đổi tùy chỉnh cấu hình cho %1 Encrypt the private keys that belong to your wallet @@ -443,10 +552,6 @@ Show wallet repair options Hiển thị các tuỳ chọn để sửa ví - - Open Wallet &Configuration File - Mở ví và file &Cấu hình - Open configuration file Mở tệp cấu hình @@ -475,10 +580,20 @@ Show the %1 help message to get a list with possible Dash command-line options Hiển thị %1 tin nhắn hỗ trợ để nhận được danh sách Dash command-line khả dụng + + default wallet + ví mặc định + %1 client %1 khách + + Wallet: %1 + + Ví: %1 + + Wallet is <b>unencrypted</b> Ví được <b>mở mã hoá</b> @@ -487,10 +602,88 @@ &File &Tệp + + Show information about %1 + Hiển thị thông tin về %1 + + + Load PSBT from &clipboard… + Tải PSBT từ &clipboard… + + + Open debugging and diagnostic console + Mở bảng điều khiển gỡ lỗi và chẩn đoán + + + Open &wallet configuration file + Mở tệp cấu hình &ví + + + Open a dash: URI + Mở một dash: URI + + + Create a new wallet + Tạo ví mới + + + Restore Wallet… + Name of the menu item that restores wallet from a backup file. + Khôi phục Ví… + + + Restore a wallet from a backup file + Status tip for Restore Wallet menu item + Khôi phục ví từ tệp sao lưu + + + Close all wallets + Đóng tất cả các ví + + + %1 &information + %1 &thông tin + + + Show the %1 basic information + Hiển thị thông tin cơ bản %1 + + + &Discreet mode + Chế độ &Kín đáo + + + Mask the values in the Overview tab + Che giấu các giá trị trong tab Tổng quan + + + Wallet Data + Name of the wallet data file format. + Dữ liệu Ví + + + Load Wallet Backup + The title for Restore Wallet File Windows + Tải Bản sao lưu Ví + + + Restore Wallet + Title of pop-up window shown when the user is attempting to restore a wallet. + Khôi phục Ví + + + Wallet Name + Label of the input field where the name of the wallet is entered. + Tên Ví + &Settings &Thiết đặt + + &Minimize + &Thu nhỏ + &Help &Trợ giúp @@ -499,8 +692,25 @@ Tabs toolbar Bảng Thanh công cụ + + &Governance + &Quản trị + + + View Governance Proposals + Xem Đề xuất Quản trị + + + &Hide + &Ẩn + + + S&how + &Hiển thị + %n active connection(s) to Dash network + A substring of the tooltip. %n kết nối hiện thời tới mạng lưới của Dash @@ -515,6 +725,54 @@ %1 behind %1 đằng sau + + Close Wallet… + Đóng Ví… + + + Load Partially Signed Blockchain Transaction + Tải Giao dịch Blockchain Đã Ký Một phần + + + Load Partially Signed Blockchain Transaction from clipboard + Tải Giao dịch Blockchain Đã Ký Một phần từ clipboard + + + Create Wallet… + Tạo Ví… + + + Close All Wallets… + Đóng Tất cả Ví… + + + Ctrl+Shift+D + Ctrl+Shift+D + + + Ctrl+M + Ctrl+M + + + Click for more actions. + A substring of the tooltip. "More actions" are available via the context menu. + Nhấp để thực hiện thêm hành động. + + + Show Peers tab + A context menu item. The "Peers tab" is an element of the "Node window". + Hiển thị tab Máy ngang hàng + + + Disable network activity + A context menu item. + Tắt hoạt động mạng + + + Enable network activity + A context menu item. The network activity was disabled previously. + Bật hoạt động mạng + Syncing Headers (%1%)… Đang đồng bộ phần đầu (%1%)… @@ -531,10 +789,6 @@ Processing blocks on disk… Đang xử lý các khối trên đĩa… - - Reindexing blocks on disk… - Sắp xếp lại các khối trên đĩa… - Connecting to peers… Đang kết nối với các máy ngang hàng… @@ -563,10 +817,18 @@ Error Lỗi + + Error: %1 + Lỗi: %1 + Warning Cảnh báo + + Warning: %1 + Cảnh báo: %1 + Information Thông tin @@ -649,7 +911,15 @@ Wallet is <b>encrypted</b> and currently <b>locked</b> Ví <b>đã được mã hoá</b> và hiện tại <b>đã được khoá</b> - + + Proxy is <b>enabled</b>: %1 + Proxy đã <b>được kích hoạt</b>: %1 + + + Original message: + Thông điệp gốc: + + CoinControlDialog @@ -672,10 +942,6 @@ Coin Selection Chọn lựa coin - - Dust: - Bụi - After Fee: Phí sau: @@ -733,28 +999,32 @@ Đã được xác nhận - Copy address - Sao chép địa chỉ + Copy amount + Sao chép số tiền + + + &Copy address + &Sao chép địa chỉ - Copy label - Sao chép nhãn + Copy &label + Sao chép &nhãn - Copy amount - Sao chép số tiền + Copy &amount + Sao chép &số tiền - Copy transaction ID - Sao chép mã giao dịch + Copy transaction &ID and output index + Sao chép &ID giao dịch và chỉ số đầu ra - Lock unspent - Khoá khoản chưa tiêu + L&ock unspent + K&hóa chưa tiêu - Unlock unspent - Mở khoản chưa tiêu + &Unlock unspent + &Mở khóa chưa tiêu Copy quantity @@ -772,10 +1042,6 @@ Copy bytes Sao chép các bytes - - Copy dust - Sao chép bụi - Copy change Sao chép tiền trả lại @@ -788,18 +1054,6 @@ (%1 locked) (%1 được khoá) - - yes - - - - no - không - - - This label turns red if any recipient receives an amount smaller than the current dust threshold. - Nhãn này sẽ chuyển sang đỏ nếu có địa chỉ nào nhận được một khoản nhỏ hơn ngưỡng nhỏ nhất định được gọi là bụi. - Can vary +/- %1 duff(s) per input. Có thể thay đổi +/- %1 duff(s) cho mỗi đầu vào. @@ -812,6 +1066,14 @@ Show all coins Hiển thị toàn bộ coin + + Hide %1 coins + Ẩn %1 coin + + + Show all %1 coins + Hiển thị tất cả %1 coin + Show spendable coins only Chỉ hiển thị những coin tiêu được @@ -835,10 +1097,84 @@ CreateWalletActivity - + + Create Wallet + Title of window indicating the progress of creation of a new wallet. + Tạo Ví + + + Creating Wallet <b>%1</b>… + Descriptive text of the create wallet progress window which indicates to the user which wallet is currently being created. + Đang tạo Ví <b>%1</b>… + + + Create wallet failed + Tạo ví thất bại + + + Create wallet warning + Cảnh báo tạo ví + + CreateWalletDialog - + + Create Wallet + Tạo Ví + + + Wallet Name + Tên Ví + + + Wallet + + + + Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice. + Mã hóa ví. Ví sẽ được mã hóa bằng cụm mật khẩu bạn chọn. + + + Encrypt Wallet + Mã hóa Ví + + + Advanced Options + Tùy chọn Nâng cao + + + 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. + Vô hiệu hóa khóa riêng cho ví này. Ví có khóa riêng bị vô hiệu hóa sẽ không có khóa riêng và không thể có seed HD hoặc nhập khóa riêng. Điều này lý tưởng cho ví chỉ xem. + + + Disable Private Keys + Vô hiệu hóa Khóa Riêng + + + 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. + Tạo ví trống. Ví trống ban đầu không có khóa riêng hoặc script. Khóa riêng và địa chỉ có thể được nhập, hoặc seed HD có thể được đặt sau. + + + Make Blank Wallet + Tạo Ví Trống + + + Use descriptors for scriptPubKey management. This feature is well-tested but still considered experimental and not recommended for use yet. + Sử dụng descriptor để quản lý scriptPubKey. Tính năng này đã được kiểm tra kỹ nhưng vẫn được coi là thử nghiệm và chưa được khuyến nghị sử dụng. + + + Descriptor Wallet (EXPERIMENTAL) + Ví Descriptor (THỬ NGHIỆM) + + + Create + Tạo + + + Compiled without sqlite support (required for descriptor wallets) + Được biên dịch mà không có hỗ trợ sqlite (cần thiết cho ví descriptor) + + EditAddressDialog @@ -877,6 +1213,14 @@ The entered address "%1" is not a valid Dash address. Địa chỉ vừa nhập "%1" không phải địa chỉ Dash hợp lệ. + + Address "%1" already exists as a receiving address with label "%2" and so cannot be added as a sending address. + Địa chỉ "%1" đã tồn tại như một địa chỉ nhận với nhãn "%2" và do đó không thể được thêm như địa chỉ gửi. + + + The entered address "%1" is already in the address book with label "%2". + Địa chỉ vừa nhập "%1" đã có trong danh bạ với nhãn "%2". + Could not unlock wallet. Không thể mở khoá ví. @@ -911,85 +1255,233 @@ GovernanceList - - - HelpMessageDialog - version - phiên bản + Form + Biểu mẫu - About %1 - About %1 + Filter List: + Danh sách Lọc: - Command-line options - Các tuỳ chọn dòng lệnh + Filter proposal list + Lọc danh sách đề xuất - - - Intro - Welcome - Chào mừng + Masternode Count: + Số lượng Masternode: - Welcome to %1. - Welcome to %1. + Number of masternodes this wallet can vote with (masternodes for which this wallet holds the voting key) + Số lượng masternode mà ví này có thể bỏ phiếu (các masternode mà ví này giữ khóa bỏ phiếu) - As this is the first time the program is launched, you can choose where %1 will store its data. - Đây là lần đầu chương trình khởi chạy, bạn có thể chọn nơi %1 sẽ lưu trữ data. + Proposal Count: + Số lượng Đề xuất: - 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. - Đồng bộ hóa ban đầu này rất đòi hỏi, và có thể phơi bày các sự cố về phần cứng với máy tính của bạn trước đó đã không được chú ý. Mỗi khi bạn chạy %1, nó sẽ tiếp tục tải về nơi nó dừng lại. + Create Proposal + Tạo Đề xuất - 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. - Nếu bạn đã chọn giới hạn block chain lưu trữ (pruning),dữ liệu lịch sử vẫn phải được tải xuống và xử lý, nhưng sẽ bị xóa sau đó để giữ cho việc sử dụng đĩa của bạn ở mức usage thấp. + Filter by Title + Lọc theo Tiêu đề - Use the default data directory - Sử dụng thư mục dữ liệu ngầm định + Unavailable + Không khả dụng - Use a custom data directory: - Sử dụng thư mục dữ liệu tuỳ chọn: + A synced node and an unlocked wallet are required. + Cần có một nút đã đồng bộ và ví đã mở khóa. - %1 GB of free space available - %1 GB còn trống + Vote Yes + Bỏ phiếu Có - (of %1 GB needed) - (của %1 GB cần đến) + Vote No + Bỏ phiếu Không - At least %1 GB of data will be stored in this directory, and it will grow over time. - Ít nhất %1 GB data sẽ được trữ tại danh mục này, và nó sẽ lớn theo thời gian. + Vote Abstain + Bỏ phiếu Trắng - Approximately %1 GB of data will be stored in this directory. - Gần đúng %1 GB of data sẽ được lưu giữ trong danh mục này. + Proposal Info: %1 + Thông tin Đề xuất: %1 - %1 will download and store a copy of the Dash block chain. - %1 sẽ download và lưu trữ một bản copy của Dash block chain. + Voting Failed + Bỏ phiếu Thất bại - The wallet will also be stored in this directory. - Wallet sẽ cùng được lưu giữ trong danh mục này. + No wallet available. + Không có ví khả dụng. - Error: Specified data directory "%1" cannot be created. - Lỗi: Thư mục bạn cọn "%1" không thể tạo được. + No masternode voting keys found in wallet. + Không tìm thấy khóa bỏ phiếu masternode trong ví. + + + Please select a proposal to vote on. + Vui lòng chọn một đề xuất để bỏ phiếu. + + + Unable to unlock wallet. + Không thể mở khóa ví. + + + Unable to get masternode list. Please try again later. + Không thể lấy danh sách masternode. Vui lòng thử lại sau. + + + Masternode %1 not found + Không tìm thấy Masternode %1 + + + Failed to sign vote for masternode %1 + Không thể ký phiếu bầu cho masternode %1 + + + Masternode %1: %2 + Masternode %1: %2 + + + Voted successfully %n time(s) + Đã bỏ phiếu thành công %n lần + + + Failed to vote %n time(s) + Không thể bỏ phiếu %n lần + + + Errors: + Lỗi: + + + Voting Results + Kết quả Bỏ phiếu + + + + HelpMessageDialog + + version + phiên bản + + + About %1 + About %1 + + + Command-line options + Các tuỳ chọn dòng lệnh + + + %1 information + Thông tin %1 + + + <h3>%1 Basics</h3> %1 gives you true financial privacy by obscuring the origins of your funds. All the Dash in your wallet is comprised of different "inputs" which you can think of as separate, discrete coins.<br> %1 uses an innovative process to mix your inputs with the inputs of two or more other people, without having your coins ever leave your wallet. You retain control of your money at all times.<hr> <b>The %1 process works like this:</b><ol type="1"> <li>%1 begins by breaking your transaction inputs down into standard denominations. These denominations are 0.001 DASH, 0.01 DASH, 0.1 DASH, 1 DASH and 10 DASH -- sort of like the paper money you use every day.</li> <li>Your wallet then sends requests to specially configured software nodes on the network, called "masternodes." These masternodes are informed then that you are interested in mixing a certain denomination. No identifiable information is sent to the masternodes, so they never know "who" you are.</li> <li>When two or more other people send similar messages, indicating that they wish to mix the same denomination, a mixing session begins. The masternode mixes up the inputs and instructs all three users' wallets to pay the now-transformed input back to themselves. Your wallet pays that denomination directly to itself, but in a different address (called a change address).</li> <li>In order to fully obscure your funds, your wallet must repeat this process a number of times with each denomination. Each time the process is completed, it's called a "round." Each round of %1 makes it exponentially more difficult to determine where your funds originated.</li> <li>This mixing process happens in the background without any intervention on your part. When you wish to make a transaction, your funds will already be mixed. No additional waiting is required.</li> </ol> <hr><b>IMPORTANT:</b> Your wallet only contains 1000 of these "change addresses." Every time a mixing event happens, up to 9 of your addresses are used up. This means those 1000 addresses last for about 100 mixing events. When 900 of them are used, your wallet must create more addresses. It can only do this, however, if you have automatic backups enabled.<br> Consequently, users who have backups disabled will also have %1 disabled. <hr>For more information, see the <a style="%2" href="%3">%1 documentation</a>. + <h3>Cơ bản về %1</h3> %1 mang lại cho bạn sự riêng tư tài chính thực sự bằng cách che giấu nguồn gốc tiền của bạn. Tất cả Dash trong ví của bạn được tạo thành từ các "đầu vào" khác nhau mà bạn có thể coi như các đồng xu riêng biệt.<br> %1 sử dụng một quy trình sáng tạo để trộn đầu vào của bạn với đầu vào của hai hoặc nhiều người khác, mà không cần coin của bạn rời khỏi ví. Bạn giữ quyền kiểm soát tiền của mình mọi lúc.<hr> <b>Quy trình %1 hoạt động như sau:</b><ol type="1"> <li>%1 bắt đầu bằng cách chia nhỏ đầu vào giao dịch của bạn thành các mệnh giá tiêu chuẩn. Các mệnh giá này là 0.001 DASH, 0.01 DASH, 0.1 DASH, 1 DASH và 10 DASH -- giống như tiền giấy bạn sử dụng hàng ngày.</li> <li>Ví của bạn sau đó gửi yêu cầu đến các nút phần mềm được cấu hình đặc biệt trên mạng, được gọi là "masternode". Các masternode này sau đó được thông báo rằng bạn quan tâm đến việc trộn một mệnh giá nhất định. Không có thông tin nhận dạng nào được gửi đến masternode, vì vậy chúng không bao giờ biết bạn "là ai".</li> <li>Khi hai hoặc nhiều người khác gửi thông điệp tương tự, cho biết họ muốn trộn cùng một mệnh giá, một phiên trộn bắt đầu. Masternode trộn lẫn các đầu vào và hướng dẫn ví của cả ba người dùng trả đầu vào đã chuyển đổi về cho chính họ. Ví của bạn trả mệnh giá đó trực tiếp cho chính nó, nhưng ở một địa chỉ khác (được gọi là địa chỉ tiền thối).</li> <li>Để che giấu hoàn toàn tiền của bạn, ví của bạn phải lặp lại quy trình này nhiều lần với mỗi mệnh giá. Mỗi lần quy trình hoàn thành, nó được gọi là một "vòng". Mỗi vòng %1 làm cho việc xác định nguồn gốc tiền của bạn trở nên khó khăn hơn theo cấp số nhân.</li> <li>Quy trình trộn này diễn ra trong nền mà không cần sự can thiệp của bạn. Khi bạn muốn thực hiện giao dịch, tiền của bạn sẽ đã được trộn sẵn. Không cần chờ đợi thêm.</li> </ol> <hr><b>QUAN TRỌNG:</b> Ví của bạn chỉ chứa 1000 "địa chỉ tiền thối" này. Mỗi lần một sự kiện trộn xảy ra, tối đa 9 địa chỉ của bạn được sử dụng. Điều này có nghĩa là 1000 địa chỉ đó tồn tại cho khoảng 100 sự kiện trộn. Khi 900 trong số chúng được sử dụng, ví của bạn phải tạo thêm địa chỉ. Tuy nhiên, nó chỉ có thể làm điều này nếu bạn đã bật sao lưu tự động.<br> Do đó, người dùng tắt sao lưu cũng sẽ bị tắt %1. <hr>Để biết thêm thông tin, xem <a style="%2" href="%3">tài liệu %1</a>. + + + + Intro + + Welcome + Chào mừng + + + Welcome to %1. + Welcome to %1. + + + As this is the first time the program is launched, you can choose where %1 will store its data. + Đây là lần đầu chương trình khởi chạy, bạn có thể chọn nơi %1 sẽ lưu trữ data. + + + Limit block chain storage to + Giới hạn lưu trữ blockchain tới + + + 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. + Hoàn nguyên cài đặt này yêu cầu tải lại toàn bộ blockchain. Tải xuống toàn bộ chuỗi trước và cắt tỉa sau sẽ nhanh hơn. Vô hiệu hóa một số tính năng nâng cao. + + + GB + GB + + + 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. + Đồng bộ hóa ban đầu này rất đòi hỏi, và có thể phơi bày các sự cố về phần cứng với máy tính của bạn trước đó đã không được chú ý. Mỗi khi bạn chạy %1, nó sẽ tiếp tục tải về nơi nó dừng lại. + + + 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. + Khi bạn nhấp OK, %1 sẽ bắt đầu tải xuống và xử lý toàn bộ blockchain %4 (%2 GB) bắt đầu từ các giao dịch sớm nhất trong %3 khi %4 được khởi chạy lần đầu. + + + 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. + Nếu bạn đã chọn giới hạn block chain lưu trữ (pruning),dữ liệu lịch sử vẫn phải được tải xuống và xử lý, nhưng sẽ bị xóa sau đó để giữ cho việc sử dụng đĩa của bạn ở mức usage thấp. + + + Use the default data directory + Sử dụng thư mục dữ liệu ngầm định + + + Use a custom data directory: + Sử dụng thư mục dữ liệu tuỳ chọn: + + + %n GB of space available + %n GB dung lượng khả dụng + + + (of %n GB needed) + (trong số %n GB cần thiết) + + + (%n GB needed for full chain) + (%n GB cần cho toàn bộ chuỗi) + + + At least %1 GB of data will be stored in this directory, and it will grow over time. + Ít nhất %1 GB data sẽ được trữ tại danh mục này, và nó sẽ lớn theo thời gian. + + + Approximately %1 GB of data will be stored in this directory. + Gần đúng %1 GB of data sẽ được lưu giữ trong danh mục này. + + + (sufficient to restore backups %n day(s) old) + Explanatory text on the capability of the current prune target. + (đủ để khôi phục bản sao lưu %n ngày tuổi) + + + %1 will download and store a copy of the Dash block chain. + %1 sẽ download và lưu trữ một bản copy của Dash block chain. + + + The wallet will also be stored in this directory. + Wallet sẽ cùng được lưu giữ trong danh mục này. + + + Error: Specified data directory "%1" cannot be created. + Lỗi: Thư mục bạn cọn "%1" không thể tạo được. Error Lỗi + + LoadWalletsActivity + + Loading wallets… + Đang tải ví… + + MasternodeList @@ -1024,6 +1516,10 @@ Service Dịch vụ + + Type + Loại + PoSe Score Điểm PoSe @@ -1159,7 +1655,15 @@ Hide Ẩn - + + %1 is currently syncing. It will download headers and blocks from peers and validate them until reaching the tip of the block chain. + %1 hiện đang đồng bộ hóa. Nó sẽ tải xuống header và block từ các peer và xác thực chúng cho đến khi đạt đến đỉnh của blockchain. + + + Unknown. Syncing Headers (%1, %2%)… + Không xác định. Đang đồng bộ Header (%1, %2%)… + + OpenURIDialog @@ -1170,10 +1674,37 @@ URI: URI: + + Paste address from clipboard + Tooltip text for button that allows you to paste an address that is in your clipboard. + Dán địa chỉ từ clipboard + OpenWalletActivity - + + Open wallet failed + Mở ví thất bại + + + Open wallet warning + Cảnh báo mở ví + + + default wallet + ví mặc định + + + Open Wallet + Title of window indicating the progress of opening of a wallet. + Mở Ví + + + Opening Wallet <b>%1</b>… + Descriptive text of the open wallet progress window which indicates to the user which wallet is currently being opened. + Đang mở Ví <b>%1</b>… + + OptionsDialog @@ -1204,6 +1735,78 @@ &Appearance &Giao diện + + Show the icon in the system tray. + Hiển thị biểu tượng trong khay hệ thống. + + + &Show tray icon + &Hiển thị biểu tượng khay + + + Prune &block storage to + Cắt bớt dung lượng &lưu trữ khối xuống + + + GB + GB + + + Reverting this setting requires re-downloading the entire blockchain. + Hoàn tác cài đặt này yêu cầu tải lại toàn bộ blockchain. + + + 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. + Tooltip text for Options window setting that sets the size of the database cache. Explains the corresponding effects of increasing/decreasing this value. + Kích thước bộ nhớ đệm cơ sở dữ liệu tối đa. Bộ nhớ đệm lớn hơn có thể giúp đồng bộ nhanh hơn, sau đó lợi ích ít rõ rệt hơn cho hầu hết trường hợp sử dụng. Giảm kích thước bộ nhớ đệm sẽ giảm mức sử dụng bộ nhớ. Bộ nhớ mempool chưa sử dụng được chia sẻ cho bộ nhớ đệm này. + + + MiB + MiB + + + Set the number of script verification threads. Negative values correspond to the number of cores you want to leave free to the system. + 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. + Đặt số lượng luồng xác minh script. Giá trị âm tương ứng với số lượng lõi bạn muốn để trống cho hệ thống. + + + This allows you or a third party tool to communicate with the node through command-line and JSON-RPC commands. + Tooltip text for Options window setting that enables the RPC server. + Điều này cho phép bạn hoặc công cụ của bên thứ ba giao tiếp với nút thông qua dòng lệnh và lệnh JSON-RPC. + + + Enable R&PC server + An Options window setting to enable the RPC server. + Bật máy chủ R&PC + + + Whether to set subtract fee from amount as default or not. + Tooltip text for Options window setting that sets subtracting the fee from a sending amount as default. + Có đặt trừ phí từ số tiền làm mặc định hay không. + + + Subtract &fee from amount by default + An Options window setting to set subtracting the fee from a sending amount as default. + Trừ &phí từ số tiền theo mặc định + + + Enable &PSBT controls + An options window setting to enable PSBT controls. + Bật điều khiển &PSBT + + + Whether to show PSBT controls. + Tooltip text for options window setting that enables PSBT controls. + Có hiển thị điều khiển PSBT hay không. + + + Whether to keep the specified custom change address or not. + Có giữ địa chỉ tiền lẻ tùy chỉnh đã chỉ định hay không. + + + Keep custom change &address + Giữ &địa chỉ tiền lẻ tùy chỉnh + Show additional tab listing all your masternodes in first sub-tab<br/>and all masternodes on the network in second sub-tab. Hiện thêm trang có danh sách tất cả các masternodes của bạn trong trang con thứ nhất <br/> và tất cả các masternode trên mạng trong trang con thứ hai. @@ -1212,14 +1815,106 @@ Show Masternodes Tab Hiển thị trang Masternodes + + Show additional tab listing governance proposals. + Hiển thị tab bổ sung liệt kê các đề xuất quản trị. + + + Show Governance Tab + Hiển thị Tab Quản trị + If you disable the spending of unconfirmed change, the change from a transaction<br/>cannot be used until that transaction has at least one confirmation.<br/>This also affects how your balance is computed. Nếu bạn vô hiệu hóa các chi tiêu của phần tiền lẻ chưa được xác nhận, phần tiền lẻ từ một giao dịch <br/>không thể được sử dụng đến khi giao dịch đó nhận được ít nhất một xác nhận. <br/>Điều này ảnh hưởng đến cách tính số dư của bạn. + + Show mixing interface on Overview screen and reveal an additional screen which allows to spend fully mixed coins only.<br/>A new tab with more settings will also appear in this dialog, please make sure to check them before mixing your coins. + Hiển thị giao diện trộn trên màn hình Tổng quan và hiển thị màn hình bổ sung cho phép chi tiêu chỉ các đồng coin đã trộn hoàn toàn.<br/>Tab mới với nhiều cài đặt hơn cũng sẽ xuất hiện trong hộp thoại này, vui lòng kiểm tra chúng trước khi trộn coin của bạn. + + + Show additional information and buttons on overview screen. + Hiển thị thông tin và nút bổ sung trên màn hình tổng quan. + + + Enable advanced interface + Bật giao diện nâng cao + + + Show system popups for mixing transactions<br/>just like for all other transaction types. + Hiển thị thông báo hệ thống cho giao dịch trộn<br/>giống như tất cả các loại giao dịch khác. + + + Show popups for mixing transactions + Hiển thị thông báo cho giao dịch trộn + + + Show warning dialog when the wallet has very low number of keys left. + Hiển thị hộp thoại cảnh báo khi ví còn rất ít khóa. + + + Warn if the wallet is running out of keys + Cảnh báo nếu ví sắp hết khóa + + + Whether to use experimental mode with multiple mixing sessions per block.<br/>Note: You must use this feature carefully.<br/>Make sure you always have recent wallet (auto)backup in a safe place! + Có sử dụng chế độ thử nghiệm với nhiều phiên trộn mỗi khối hay không.<br/>Lưu ý: Bạn phải sử dụng tính năng này một cách cẩn thận.<br/>Đảm bảo bạn luôn có bản sao lưu ví gần đây (tự động) ở nơi an toàn! + + + Enable &multi-session + Bật &đa phiên + + + Use this many separate masternodes in parallel to mix funds.<br/>Note: You must use this feature carefully.<br/>Make sure you always have recent wallet (auto)backup in a safe place! + Sử dụng nhiều masternode riêng biệt song song để trộn tiền.<br/>Lưu ý: Bạn phải sử dụng tính năng này một cách cẩn thận.<br/>Đảm bảo bạn luôn có bản sao lưu ví gần đây (tự động) ở nơi an toàn! + + + Parallel sessions + Phiên song song + + + Mixing rounds + Vòng trộn + + + This amount acts as a threshold to turn off mixing once it's reached. + Số tiền này đóng vai trò là ngưỡng để tắt trộn khi đạt được. + + + Target balance + Số dư mục tiêu + + + How many inputs of each denominated amount are created.<br/>Lower these numbers if you want fewer smaller denominations. + Có bao nhiêu đầu vào của mỗi mệnh giá được tạo ra.<br/>Giảm các số này nếu bạn muốn ít mệnh giá nhỏ hơn. + + + Inputs per denomination + Đầu vào mỗi mệnh giá + + + Try to create at least this many inputs for each denominated amount.<br/>Lower this number if you want fewer smaller denominations. + Cố gắng tạo ít nhất số lượng đầu vào này cho mỗi mệnh giá.<br/>Giảm số này nếu bạn muốn ít mệnh giá nhỏ hơn. + + + Target + Mục tiêu + + + Create up to this many inputs for each denominated amount.<br/>Lower this number if you want fewer smaller denominations. + Tạo tối đa số lượng đầu vào này cho mỗi mệnh giá.<br/>Giảm số này nếu bạn muốn ít mệnh giá nhỏ hơn. + + + Maximum + Tối đa + Automatically open the Dash Core client port on the router. This only works when your router supports UPnP and it is enabled. Tự động mở cổng cho phần mềm Dash Core trên rounter. Điều này chỉ hoạt động được khi rounter của bạn hỗ trợ UpnP và tính năng đó được bật lên. + + Map port using NA&T-PMP + Ánh xạ cổng bằng NA&T-PMP + Accept connections from outside. Chấp nhận các kết nối từ bên ngoài. @@ -1241,16 +1936,26 @@ Hiển thị nếu proxy SOCKS5 mặc định được cung cấp để dùng tiếp cận các thiết bị ngang hàng thông qua loại mạng này. - 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. - Thu nhỏ thay vì thoát khỏi ứng dụng khi cửa sổ được đóng lại. Khi tuỳ chọn này được bật, ứng dụng sẽ được đóng chỉ sau khi chọn chức năng Thoát trên menu. + Language missing or translation incomplete? Help contributing translations here: +https://explore.transifex.com/dash/dash/ + Thiếu ngôn ngữ hoặc bản dịch chưa hoàn chỉnh? Giúp đóng góp bản dịch tại đây: +https://explore.transifex.com/dash/dash/ + + + Third-party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items.<br/>%s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |. + URL của bên thứ ba (ví dụ: trình khám phá khối) xuất hiện trong tab giao dịch dưới dạng mục menu ngữ cảnh.<br/>%s trong URL được thay thế bằng hash giao dịch. Nhiều URL được phân tách bằng dấu gạch dọc |. + + + &Third-party transaction URLs + URL giao dịch của bên &thứ ba - Third party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items.<br/>%s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |. - Địa chỉ URL của bên thứ ba (ví dụ: một trang duyệt block) mà xuất hiện trong trang về các giao dịch giống như một mục trong menu ngữ cảnh.<br/>%s trong địa chỉ URL được thay thế bằng mã băm của giao dịch. Nhiều địa chỉ URL được phân cách với nhau bởi một đường thẳng dọc |. + Options set in this dialog are overridden by the command line or in the configuration file: + Các tùy chọn được đặt trong hộp thoại này bị ghi đè bởi dòng lệnh hoặc trong tệp cấu hình: - &Third party transaction URLs - URL của giao dịch bên &Thứ ba + 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. + Thu nhỏ thay vì thoát khỏi ứng dụng khi cửa sổ được đóng lại. Khi tuỳ chọn này được bật, ứng dụng sẽ được đóng chỉ sau khi chọn chức năng Thoát trên menu. Whether to show coin control features or not. @@ -1280,10 +1985,18 @@ &Network &Mạng + + 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. + Bật cắt tỉa giảm đáng kể dung lượng đĩa cần thiết để lưu trữ giao dịch. Tất cả các block vẫn được xác thực đầy đủ. Hoàn nguyên cài đặt này yêu cầu tải lại toàn bộ blockchain. + Map port using &UPnP Ánh xạ cổng sử dụng &UPnP + + Automatically open the Dash Core client port on the router. This only works when your router supports NAT-PMP and it is enabled. The external port could be random. + Tự động mở cổng ứng dụng Dash Core trên router. Điều này chỉ hoạt động khi router của bạn hỗ trợ NAT-PMP và được bật. Cổng ngoài có thể là ngẫu nhiên. + Proxy &IP: Proxy &IP: @@ -1332,6 +2045,14 @@ &Display &Hiển thị + + Connect to the Dash network through a separate SOCKS5 proxy for Tor onion services. + Kết nối với mạng Dash thông qua proxy SOCKS5 riêng cho dịch vụ Tor onion. + + + Use separate SOCKS&5 proxy to reach peers via Tor onion services: + Sử dụng proxy SOCKS&5 riêng để tiếp cận peer qua dịch vụ Tor onion: + User Interface &language: &Ngôn ngữ người dùng: @@ -1368,20 +2089,32 @@ &Cancel &Huỷ + + Enable %1 features + Bật tính năng %1 + default ngầm định Confirm options reset + Window title text of pop-up window shown when the user has chosen to reset options. Xác nhận tái lập tuỳ chọn Client restart required to activate changes. + Text explaining that the settings changed will not come into effect until the client is restarted. Cần phải khởi động phần mềm để kích hoạt các thay đổi. + + Current settings will be backed up at "%1". + 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. + Các cài đặt hiện tại sẽ được sao lưu tại "%1". + Client will be shut down. Do you want to proceed? + Text asking the user to confirm if they would like to proceed with a client shutdown. Phần mềm sẽ được tắt. Bạn có muốn xử lý? @@ -1515,6 +2248,14 @@ No inputs detected Phát hiện không có đầu vào + + %1 Balance + Số dư %1 + + + Discreet mode activated for the Overview tab. To unmask the values, uncheck Settings->Discreet mode. + Chế độ kín đáo đã được kích hoạt cho tab Tổng quan. Để bỏ ẩn các giá trị, bỏ chọn Cài đặt->Chế độ kín đáo. + %n Rounds %n Vòng @@ -1551,6 +2292,26 @@ keys left: %1 số khoá còn lại: %1 + + Start %1 + Bắt đầu %1 + + + If you don't want to see internal %1 fees/transactions select "Most Common" as Type on the "Transactions" tab. + Nếu bạn không muốn xem phí/giao dịch %1 nội bộ, hãy chọn "Phổ biến nhất" làm Loại trên tab "Giao dịch". + + + %1 requires at least %2 to use. + %1 yêu cầu ít nhất %2 để sử dụng. + + + Wallet is locked and user declined to unlock. Disabling %1. + Ví đã bị khoá và người dùng từ chối mở khoá. Đang tắt %1. + + + Stop %1 + Dừng %1 + Disabled Đã tắt @@ -1594,23 +2355,166 @@ PSBTOperationsDialog - - - PaymentServer - Payment request error - Yêu cầu thanh toán bị lỗi + Dialog + Hộp thoại - Cannot start dash: click-to-pay handler - Không thể khởi động dash: trình xử lý click-to-pay + Sign Tx + Ký Giao dịch - URI handling - xử lý URI + Broadcast Tx + Phát Giao dịch - URI cannot be parsed! This can be caused by an invalid Dash address or malformed URI parameters. + Copy to Clipboard + Sao chép vào Clipboard + + + Save… + Lưu… + + + Close + Đóng + + + Failed to load transaction: %1 + Không thể tải giao dịch: %1 + + + Failed to sign transaction: %1 + Không thể ký giao dịch: %1 + + + Cannot sign inputs while wallet is locked. + Không thể ký đầu vào khi ví bị khóa. + + + Could not sign any more inputs. + Không thể ký thêm đầu vào nào nữa. + + + Signed %1 inputs, but more signatures are still required. + Đã ký %1 đầu vào, nhưng vẫn cần thêm chữ ký. + + + Signed transaction successfully. Transaction is ready to broadcast. + Ký giao dịch thành công. Giao dịch đã sẵn sàng để phát. + + + Unknown error processing transaction. + Lỗi không xác định khi xử lý giao dịch. + + + Transaction broadcast successfully! Transaction ID: %1 + Phát giao dịch thành công! ID Giao dịch: %1 + + + Transaction broadcast failed: %1 + Phát giao dịch thất bại: %1 + + + PSBT copied to clipboard. + PSBT đã sao chép vào clipboard. + + + Save Transaction Data + Lưu Dữ liệu Giao dịch + + + Partially Signed Transaction (Binary) + Expanded name of the binary PSBT file format. See: BIP 174. + Giao dịch Đã Ký Một Phần (Nhị phân) + + + PSBT saved to disk. + PSBT đã lưu vào đĩa. + + + * Sends %1 to %2 + * Gửi %1 đến %2 + + + own address + địa chỉ riêng + + + Unable to calculate transaction fee or total transaction amount. + Không thể tính phí giao dịch hoặc tổng số tiền giao dịch. + + + Pays transaction fee: + Trả phí giao dịch: + + + Total Amount + Tổng số tiền + + + or + hoặc + + + Transaction has %1 unsigned inputs. + Giao dịch có %1 đầu vào chưa ký. + + + Transaction is missing some information about inputs. + Giao dịch thiếu một số thông tin về đầu vào. + + + Transaction still needs signature(s). + Giao dịch vẫn cần chữ ký. + + + (But no wallet is loaded.) + (Nhưng không có ví nào được tải.) + + + (But this wallet cannot sign transactions.) + (Nhưng ví này không thể ký giao dịch.) + + + (But this wallet does not have the right keys.) + (Nhưng ví này không có khoá đúng.) + + + Transaction is fully signed and ready for broadcast. + Giao dịch đã được ký đầy đủ và sẵn sàng để phát sóng. + + + Transaction status is unknown. + Trạng thái giao dịch không xác định. + + + + PaymentServer + + Payment request error + Yêu cầu thanh toán bị lỗi + + + Cannot start dash: click-to-pay handler + Không thể khởi động dash: trình xử lý click-to-pay + + + URI handling + xử lý URI + + + 'dash://' is not a valid URI. Use 'dash:' instead. + 'dash://' không phải là URI hợp lệ. Sử dụng 'dash:' thay thế. + + + Cannot process payment request as BIP70 is no longer supported. +Due to discontinued support, you should request the merchant to provide you with a BIP21 compatible URI or use a wallet that does continue to support BIP70. + Không thể xử lý yêu cầu thanh toán vì BIP70 không còn được hỗ trợ. +Do ngừng hỗ trợ, bạn nên yêu cầu người bán cung cấp cho bạn URI tương thích BIP21 hoặc sử dụng ví vẫn tiếp tục hỗ trợ BIP70. + + + URI cannot be parsed! This can be caused by an invalid Dash address or malformed URI parameters. URI không thể phân tích. Nó có thể bởi địa chỉ Dash không hợp lệ hoặc thông số URI dị hình. @@ -1630,6 +2534,26 @@ Title of Peers Table column which indicates the current latency of the connection with the peer. Ping + + Peer + Title of Peers Table column which contains a unique number used to identify a connection. + Peer + + + Age + Title of Peers Table column which indicates the duration (length of time) since the peer connection started. + Tuổi + + + Direction + Title of Peers Table column which indicates the direction the peer connection was initiated from. + Hướng + + + Type + Title of Peers Table column which describes the type of peer connection. The "type" describes why the connection exists. + Loại + Sent Title of Peers Table column which indicates the total amount of network information we have sent to the peer. @@ -1640,15 +2564,340 @@ Title of Peers Table column which indicates the total amount of network information we have received from the peer. Đã nhận - + + Address + Title of Peers Table column which contains the IP/Onion/I2P address of the connected peer. + Địa chỉ + + + Network + Title of Peers Table column which states the network the peer connected through. + Mạng + + + Inbound + An Inbound Connection from a Peer. + Vào + + + Outbound + An Outbound Connection to a Peer. + Ra + + Proposal - + + Passing +%1 + Đang vượt qua +%1 + + + Needs additional %1 votes + Cần thêm %1 phiếu bầu + + ProposalModel - + + Yes + + + + No + Không + + + Hash + Hash + + + Title + Tiêu đề + + + Start + Bắt đầu + + + End + Kết thúc + + + Amount + Số lượng + + + Active + Hoạt động + + + Status + Trạng thái + + + + ProposalWizard + + Create Governance Proposal + Tạo Đề xuất Quản trị + + + Enter proposal details + Nhập chi tiết đề xuất + + + A fee will be burned when you prepare the proposal. + Một khoản phí sẽ bị đốt khi bạn chuẩn bị đề xuất. + + + Proposal &name + &Tên đề xuất + + + &Description URL + URL &Mô tả + + + Payment &address + &Địa chỉ thanh toán + + + Payment &amount + &Số tiền thanh toán + + + The amount to request in a single payment + Số tiền yêu cầu trong một lần thanh toán + + + &First payment + Thanh toán &đầu tiên + + + Pa&yments + Các khoản thanh &toán + + + To&tal amount + Tổng &số tiền + + + Proposal &fee + &Phí đề xuất + + + Next + Tiếp theo + + + Review proposal JSON and validate. + Xem lại JSON đề xuất và xác thực. + + + Hex-encoded JSON + JSON mã hóa Hex + + + Back + Quay lại + + + Validate + Xác thực + + + Prepare (burn fee) and wait for confirmations. + Chuẩn bị (đốt phí) và đợi xác nhận. + + + Copy + Sao chép + + + At 1/6 confirmations: can be relayed and queued. At 6/6: accepted and processed. + Tại 1/6 xác nhận: có thể được chuyển tiếp và xếp hàng. Tại 6/6: được chấp nhận và xử lý. + + + Confirmations progress + Tiến trình xác nhận + + + Shows progress toward the required number of confirmations for the proposal fee transaction. + Hiển thị tiến trình hướng tới số lượng xác nhận cần thiết cho giao dịch phí đề xuất. + + + Estimated time remaining: - + Thời gian ước tính còn lại: - + + + Prepare Proposal + Chuẩn bị Đề xuất + + + You can submit after 1 confirmation. At 6 confirmations it is accepted and processed. + Bạn có thể gửi sau 1 xác nhận. Tại 6 xác nhận nó sẽ được chấp nhận và xử lý. + + + Proposal ID: + ID Đề xuất: + + + Submit Proposal + Gửi Đề xuất + + + Close + Đóng + + + Valid + Hợp lệ + + + Invalid: %1 + Không hợp lệ: %1 + + + Burn %1 + Đốt %1 + + + Burn %1 to create the fee transaction? + Đốt %1 để tạo giao dịch phí? + + + Prepare failed + Chuẩn bị thất bại + + + Confirmations: %1 / %2 required + Xác nhận: %1 / %2 yêu cầu + + + Estimated time remaining: Ready + Thời gian ước tính còn lại: Sẵn sàng + + + Estimated time remaining: %n minute(s) + Thời gian ước tính còn lại: %n phút + + + Your proposal was submitted successfully. + Đề xuất của bạn đã được gửi thành công. + + + Already submitted + Đã gửi + + + This proposal has already been submitted. + Đề xuất này đã được gửi rồi. + + + Submission failed + Gửi thất bại + + + Proposal submitted + Đề xuất đã gửi + + + A fee of %1 will be burned when you prepare the proposal. + Phí %1 sẽ bị đốt khi bạn chuẩn bị đề xuất. + + + Prepare (burn %1) and wait for %2 confirmations. + Chuẩn bị (đốt %1) và đợi %2 xác nhận. + + QObject + + Do you want to reset settings to default values, or to abort without making changes? + Explanatory text shown on startup when the settings file cannot be read. Prompts user to make a choice between resetting or aborting. + Bạn có muốn đặt lại cài đặt về giá trị mặc định, hay huỷ bỏ mà không thực hiện thay đổi? + + + A fatal error occurred. Check that settings file is writable, or try running with -nosettings. + 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. + Đã xảy ra lỗi nghiêm trọng. Kiểm tra rằng tệp cài đặt có thể ghi được, hoặc thử chạy với -nosettings. + + + Choose data directory on startup (default: %u) + Chọn thư mục dữ liệu khi khởi động (mặc định: %u) + + + Set the font family. Possible values: %1. (default: %2) + Đặt họ phông chữ. Các giá trị có thể: %1. (mặc định: %2) + + + Set a scale factor which gets applied to the base font size. Possible range %1 (smallest fonts) to %2 (largest fonts). (default: %3) + Đặt hệ số tỷ lệ được áp dụng cho kích thước phông chữ cơ sở. Phạm vi có thể %1 (phông chữ nhỏ nhất) đến %2 (phông chữ lớn nhất). (mặc định: %3) + + + Set the font weight for bold texts. Possible range %1 to %2 (default: %3) + Đặt độ đậm phông chữ cho văn bản in đậm. Phạm vi có thể %1 đến %2 (mặc định: %3) + + + Set the font weight for normal texts. Possible range %1 to %2 (default: %3) + Đặt độ đậm phông chữ cho văn bản thông thường. Phạm vi có thể %1 đến %2 (mặc định: %3) + + + Set language, for example "de_DE" (default: system locale) + Đặt ngôn ngữ, ví dụ "de_DE" (mặc định: ngôn ngữ hệ thống) + + + Start minimized + Bắt đầu ở dạng thu nhỏ + + + Reset all settings changed in the GUI + Đặt lại tất cả cài đặt đã thay đổi trong GUI + + + Show splash screen on startup (default: %u) + Hiển thị màn hình khởi động khi khởi động (mặc định: %u) + + + Error: Specified data directory "%1" does not exist. + Lỗi: Thư mục dữ liệu được chỉ định "%1" không tồn tại. + + + Error: Cannot parse configuration file: %1. + Lỗi: Không thể phân tích tệp cấu hình: %1. + + + Error: %1 + Lỗi: %1 + + + Error: Failed to load application fonts. + Lỗi: Không tải được phông chữ ứng dụng. + + + Error: Specified font-family invalid. Valid values: %1. + Lỗi: Họ phông chữ được chỉ định không hợp lệ. Giá trị hợp lệ: %1. + + + Error: Specified font-weight-normal invalid. Valid range %1 to %2. + Lỗi: Độ đậm phông chữ bình thường được chỉ định không hợp lệ. Phạm vi hợp lệ %1 đến %2. + + + Error: Specified font-weight-bold invalid. Valid range %1 to %2. + Lỗi: Độ đậm phông chữ in đậm được chỉ định không hợp lệ. Phạm vi hợp lệ %1 đến %2. + + + Error: Specified font-scale invalid. Valid range %1 to %2. + Lỗi: Tỷ lệ phông chữ được chỉ định không hợp lệ. Phạm vi hợp lệ %1 đến %2. + + + Error: Invalid -custom-css-dir path. + Lỗi: Đường dẫn -custom-css-dir không hợp lệ. + + + Error: %1 CSS file(s) missing in -custom-css-dir path. + Lỗi: %1 tệp CSS thiếu trong đường dẫn -custom-css-dir. + %1 didn't yet exit safely… %1 vẫn chưa thoát an toàn… @@ -1673,6 +2922,53 @@ This can also be adjusted later in the "Appearance" tab of the preferences. Cái này cũng có thể được điều chỉnh sau trong trang "Giao diện" của phần thiết lập tuỳ chọn. + + Ctrl+W + Ctrl+W + + + Unroutable + Không định tuyến được + + + Internal + Nội bộ + + + Inbound + An inbound connection from a peer. An inbound connection is a connection initiated by a peer. + Vào + + + Outbound + An outbound connection to a peer. An outbound connection is a connection initiated by us. + Ra + + + Full Relay + Peer connection type that relays all network information. + Chuyển tiếp đầy đủ + + + Block Relay + Peer connection type that relays network information about blocks and not transactions or addresses. + Chuyển tiếp Block + + + Manual + Peer connection type established manually through one of several methods. + Thủ công + + + Feeler + Short-lived peer connection type that tests the aliveness of known addresses. + Feeler + + + Address Fetch + Short-lived peer connection type that solicits known addresses from a peer. + Lấy địa chỉ + %1 d %1 giờ @@ -1734,8 +3030,8 @@ %1 B - %1 KB - %1 KB + %1 kB + %1 kB %1 MB @@ -1775,11 +3071,28 @@ &Copy Image &Sao chép ảnh + + Resulting URI too long, try to reduce the text for label / message. + URI kết quả quá dài, hãy thử giảm văn bản cho nhãn / thông điệp. + + + Error encoding URI into QR Code. + Lỗi mã hóa URI thành mã QR. + + + QR code support not available. + Hỗ trợ mã QR không khả dụng. + Save QR Code &Lưu mã QR - + + PNG Image + Expanded name of the PNG file format. See: https://en.wikipedia.org/wiki/Portable_Network_Graphics. + Ảnh PNG + + RPCConsole @@ -1870,6 +3183,10 @@ &Peers &Máy ngang cấp + + Wallet: + Ví: + Banned peers Các nút ngang hàng đã bị khoá @@ -1882,6 +3199,14 @@ Version Phiên bản + + High bandwidth BIP152 compact block relay: %1 + Chuyển tiếp khối nhỏ gọn BIP152 băng thông cao: %1 + + + High Bandwidth + Băng thông cao + Starting Block Khởi động khối @@ -1894,6 +3219,71 @@ Synced Blocks Các khối đã đồng bộ + + Elapsed time since a novel block passing initial validity checks was received from this peer. + Thời gian trôi qua kể từ khi một khối mới vượt qua kiểm tra tính hợp lệ ban đầu được nhận từ peer này. + + + Last Block + Khối cuối cùng + + + Elapsed time since a novel transaction accepted into our mempool was received from this peer. + Tooltip text for the Last Transaction field in the peer details area. + Thời gian trôi qua kể từ khi một giao dịch mới được chấp nhận vào mempool của chúng tôi được nhận từ peer này. + + + Last Transaction + Giao dịch cuối cùng + + + The mapped Autonomous System used for diversifying peer selection. + Hệ thống tự trị được ánh xạ được sử dụng để đa dạng hóa lựa chọn peer. + + + Mapped AS + AS được ánh xạ + + + Whether we relay addresses to this peer. + Tooltip text for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No). + Liệu chúng ta có chuyển tiếp địa chỉ đến peer này hay không. + + + Address Relay + Text title for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No). + Chuyển tiếp địa chỉ + + + Addresses Processed + 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). + Địa chỉ đã xử lý + + + Addresses Rate-Limited + 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. + Địa chỉ bị giới hạn tốc độ + + + Rescan blockchain files 1 + Quét lại các tệp blockchain 1 + + + Rescan blockchain files 2 + Quét lại các tệp blockchain 2 + + + The buttons below will restart the wallet with command-line options to repair the wallet, fix issues with corrupt blockchain files or missing/obsolete transactions. + Các nút bên dưới sẽ khởi động lại ví với các tùy chọn dòng lệnh để sửa chữa ví, khắc phục sự cố với các tệp blockchain bị hỏng hoặc các giao dịch bị thiếu/lỗi thời. + + + -rescan=1: Rescan the block chain for missing wallet transactions starting from wallet creation time. + -rescan=1: Quét lại blockchain để tìm các giao dịch ví bị thiếu bắt đầu từ thời điểm tạo ví. + + + -rescan=2: Rescan the block chain for missing wallet transactions starting from genesis block. + -rescan=2: Quét lại blockchain để tìm các giao dịch ví bị thiếu bắt đầu từ khối genesis. + User Agent User Agent @@ -1902,10 +3292,50 @@ Datadir Thư mục dữ liệu + + To specify a non-default location of the data directory use the '%1' option. + Để chỉ định vị trí không mặc định của thư mục dữ liệu, hãy sử dụng tùy chọn '%1'. + + + Blocksdir + Thư mục khối + + + To specify a non-default location of the blocks directory use the '%1' option. + Để chỉ định vị trí không mặc định của thư mục khối, hãy sử dụng tùy chọn '%1'. + + + Local Addresses + Địa chỉ cục bộ + + + Network addresses that your Dash node is currently using to communicate with other nodes. + Các địa chỉ mạng mà node Dash của bạn hiện đang sử dụng để giao tiếp với các node khác. + + + Number of regular Masternodes + Số lượng Masternode thông thường + + + Number of EvoNodes + Số lượng EvoNode + + + Current block height + Chiều cao khối hiện tại + Last block hash Mã băm khối cuối + + Latest ChainLocked block hash + Hash khối ChainLocked mới nhất + + + Latest ChainLocked block height + Chiều cao khối ChainLocked mới nhất + Open the %1 debug log file from the current data directory. This can take a few seconds for large log files. Mở cái %1 debug log file từ danh mục dữ liệu hiện tại. Điều này cần vài giây cho large log files. @@ -1914,6 +3344,10 @@ InstantSend locks Khoá InstantSend + + (none) + (không có) + Decrease font size Giảm cỡ chữ @@ -1926,10 +3360,58 @@ &Reset &Reset + + Node Type + Loại Node + + + PoSe Score + Điểm PoSe + + + The transport layer version: %1 + Phiên bản lớp truyền tải: %1 + + + Transport + Truyền tải + + + The BIP324 session ID string in hex. + Chuỗi ID phiên BIP324 ở dạng hex. + + + Session ID + ID phiên + + + The network protocol this peer is connected through: IPv4, IPv6, Onion, I2P, or CJDNS. + Giao thức mạng mà peer này được kết nối qua: IPv4, IPv6, Onion, I2P hoặc CJDNS. + + + Permissions + Quyền + + + The direction and type of peer connection: %1 + Hướng và loại kết nối peer: %1 + + + Direction/Type + Hướng/Loại + Services Dịch vụ + + Whether we relay transactions to this peer. + Liệu chúng ta có chuyển tiếp giao dịch đến peer này hay không. + + + Transaction Relay + Chuyển tiếp giao dịch + Connection Time Thời gian kết nối @@ -1947,114 +3429,277 @@ Thời gian phản hồi - The duration of a currently outstanding ping. - Khoảng thời gian để chờ cho một ping hiện thời. + The duration of a currently outstanding ping. + Khoảng thời gian để chờ cho một ping hiện thời. + + + Ping Wait + Đợi Ping + + + Min Ping + Ping tối thiểu + + + Time Offset + Time Offset + + + &Wallet Repair + Sửa &Ví + + + The total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting). + 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). + Tổng số địa chỉ nhận được từ peer này đã được xử lý (không bao gồm các địa chỉ bị loại bỏ do giới hạn tốc độ). + + + The total number of addresses received from this peer that were dropped (not processed) due to rate-limiting. + 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. + Tổng số địa chỉ nhận được từ peer này đã bị loại bỏ (không được xử lý) do giới hạn tốc độ. + + + Wallet repair options. + Các tuỳ chọn sửa ví. + + + Rebuild index + Lập lại chỉ mục + + + -reindex: Rebuild block chain index from current blk000??.dat files. + -reindex: Tái lập lại chỉ mục cho chuỗi khối từ tệp hiện tại blk000??.dat + + + Inbound: initiated by peer + Explanatory text for an inbound peer connection. + Vào: được khởi tạo bởi peer + + + Outbound Full Relay: default + Explanatory text for an outbound peer connection that relays all network information. This is the default behavior for outbound connections. + Ra Chuyển tiếp đầy đủ: mặc định + + + Outbound Block Relay: does not relay transactions or addresses + Explanatory text for an outbound peer connection that relays network information about blocks and not transactions or addresses. + Ra Chuyển tiếp Block: không chuyển tiếp giao dịch hoặc địa chỉ + + + Outbound Manual: added using RPC %1 or %2/%3 configuration options + 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. + Ra Thủ công: được thêm bằng cách sử dụng tùy chọn cấu hình RPC %1 hoặc %2/%3 + + + Outbound Feeler: short-lived, for testing addresses + Explanatory text for a short-lived outbound peer connection that is used to test the aliveness of known addresses. + Ra Feeler: tồn tại ngắn, để kiểm tra địa chỉ + + + Outbound Address Fetch: short-lived, for soliciting addresses + Explanatory text for a short-lived outbound peer connection that is used to request addresses from a peer. + Ra Lấy địa chỉ: tồn tại ngắn, để yêu cầu địa chỉ + + + To + Đến + + + we selected the peer for high bandwidth relay + chúng tôi đã chọn peer cho chuyển tiếp băng thông cao + + + From + Từ + + + the peer selected us for high bandwidth relay + peer đã chọn chúng tôi cho chuyển tiếp băng thông cao + + + No + Không đồng ý + + + no high bandwidth relay selected + không có chuyển tiếp băng thông cao được chọn + + + &Disconnect + &Ngắt kết nối + + + Ban for + Cấm + + + 1 &hour + 1 &giờ + + + 1 &week + 1 &tuần + + + 1 &year + 1 &năm + + + &Unban + &Bor + + + In: + Vào: + + + Out: + Ra: + + + Network activity disabled + Kết nối mạng bị tắt + + + None + Không có + + + Total: %1 (Enabled: %2) + Tổng số: %1 (Bật: %2) - Ping Wait - Đợi Ping + Executing command without any wallet + Thực thi lệnh mà không có ví nào - Min Ping - Ping tối thiểu + Ctrl++ + Main shortcut to increase the RPC console font size. + Ctrl++ - Time Offset - Time Offset + Ctrl+= + Secondary shortcut to increase the RPC console font size. + Ctrl+= - &Wallet Repair - Sửa &Ví + Ctrl+- + Main shortcut to decrease the RPC console font size. + Ctrl+- - Wallet repair options. - Các tuỳ chọn sửa ví. + Ctrl+_ + Secondary shortcut to decrease the RPC console font size. + Ctrl+_ - Rebuild index - Lập lại chỉ mục + Ctrl+Shift+I + Ctrl+Shift+I - -reindex: Rebuild block chain index from current blk000??.dat files. - -reindex: Tái lập lại chỉ mục cho chuỗi khối từ tệp hiện tại blk000??.dat + Ctrl+Shift+C + Ctrl+Shift+C - No - Không đồng ý + Ctrl+Shift+G + Ctrl+Shift+G - &Disconnect - &Ngắt kết nối + Ctrl+Shift+P + Ctrl+Shift+P - Ban for - Cấm + Ctrl+Shift+R + Ctrl+Shift+R - 1 &hour - 1 &giờ + Executing command using "%1" wallet + Thực thi lệnh bằng ví "%1" - 1 &day - 1 ngà&y + detecting: peer could be v1 or v2 + Explanatory text for "detecting" transport type. + đang phát hiện: peer có thể là v1 hoặc v2 - 1 &week - 1 &tuần + v1: unencrypted, plaintext transport protocol + Explanatory text for v1 transport type. + v1: giao thức truyền tải không mã hóa, văn bản rõ - 1 &year - 1 &năm + v2: BIP324 encrypted transport protocol + Explanatory text for v2 transport type. + v2: giao thức truyền tải mã hóa BIP324 - &Unban - &Bor + &Copy address + Context menu action to copy the address of a peer + &Sao chép địa chỉ - Welcome to the %1 RPC console. - Welcome to the %1 RPC console. + 1 d&ay + 1 ng&ày - Use up and down arrows to navigate history, and %1 to clear screen. - Sử dụng các mũi tên lên và xuống để duyệt lịch sử, và %1 để xoá màn hình. + &Copy IP/Netmask + 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 + &Sao chép IP/Netmask - Type %1 for an overview of available commands. - Hãy nhập %1 để xem tổng thể những câu lệnh có thể dùng. + 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 + 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. + Chào mừng đến với console RPC %1. +Sử dụng các mũi tên lên và xuống để điều hướng lịch sử, và %2 để xóa màn hình. +Sử dụng %3 và %4 để tăng hoặc giảm kích thước phông chữ. +Nhập %5 để xem tổng quan về các lệnh có sẵn. +Để biết thêm thông tin về việc sử dụng console này, hãy nhập %6. + +%7CẢNH BÁO: Kẻ lừa đảo đã hoạt động tích cực, yêu cầu người dùng nhập lệnh tại đây, đánh cắp nội dung ví của họ. Không sử dụng console này mà không hiểu rõ hậu quả của một lệnh.%8 - For more information on using this console type %1. - Để có thêm thông tin về việc sử dụng console này thì hãy nhập %1. + Executing… + A console message indicating an entered command is currently being executed. + Đang thực thi… - WARNING: Scammers have been active, telling users to type commands here, stealing their wallet contents. Do not use this console without fully understanding the ramifications of a command. - CẢNH BÁO: Những kẻ lừa đảo đã rất tích cực, xúi mọi người gõ các lệnh ở đây và đánh cắp nội dung ví của họ. Không nên sử dụng cửa sổ lệnh mà không hiểu đầy đủ các câu lệnh. + (peer: %1) + (peer: %1) - In: - Vào: + via %1 + theo %1 - Out: - Ra: + Regular + Thông thường - Network activity disabled - Kết nối mạng bị tắt + Masternode + Masternode - Total: %1 (Enabled: %2) - Tổng số: %1 (Bật: %2) + Verified Masternode + Masternode đã xác minh - via %1 - theo %1 + Yes + Unknown Không xác định - + + Never + Không bao giờ + + ReceiveCoinsDialog @@ -2073,6 +3718,10 @@ An optional message to attach to the payment request, which will be displayed when the request is opened.<br>Note: The message will not be sent with the payment over the Dash network. Một thông điệp tuỳ chọn để đính vào yêu cầu thanh toán, nó sẽ hiển thị khi yêu cầu được mở.<br>Chú ý: Thông điệp sẽ không được gửi thông qua mạng lưới Dash. + + 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. + Một nhãn tuỳ chọn để liên kết với địa chỉ nhận mới (được bạn sử dụng để xác định hóa đơn). Nó cũng được đính kèm vào yêu cầu thanh toán. + Use this form to request payments. All fields are <b>optional</b>. Sử dụng biểu mẫu này để yêu cầu thanh toán. Tất cả các trường đều là <b>không bắt buộc</b>. @@ -2089,6 +3738,10 @@ &Amount: &Số tiền: + + &Create new receiving address + &Tạo địa chỉ nhận mới + Clear all fields of the form. Xoá tất cả các ô. @@ -2126,24 +3779,60 @@ Hãy nhâpn một thông điệp để đính kèm với yêu cầu thanh toán - Copy URI - Copy URI + Copy &URI + Sao chép &URI - Copy label - Sao chép nhãn + &Copy address + &Sao chép địa chỉ - Copy message - Sao chép thông điệp + Copy &label + Sao chép &nhãn - Copy amount - Sao chép số tiền + Copy &message + Sao chép &thông điệp + + + Copy &amount + Sao chép &số tiền + + + Could not unlock wallet. + Không thể mở khoá ví. + + + Could not generate new address + Không thể tạo địa chỉ mới - + ReceiveRequestDialog + + Request payment to … + Yêu cầu thanh toán đến … + + + Address: + Địa chỉ: + + + Amount: + Số tiền: + + + Label: + Nhãn: + + + Message: + Thông điệp: + + + Wallet: + Ví: + Copy &URI Copy &URI @@ -2196,6 +3885,34 @@ Đã yêu cầu + + RestoreWalletActivity + + Restore Wallet + Title of progress window which is displayed when wallets are being restored. + Khôi phục Ví + + + Restoring Wallet <b>%1</b>… + Descriptive text of the restore wallets progress window which indicates to the user that wallets are currently being restored. + Đang khôi phục Ví <b>%1</b>… + + + Restore wallet failed + Title of message box which is displayed when the wallet could not be restored. + Khôi phục ví thất bại + + + Restore wallet warning + Title of message box which is displayed when the wallet is restored with some warning. + Cảnh báo khôi phục ví + + + Restore wallet message + Title of message box which is displayed when the wallet is successfully restored. + Thông điệp khôi phục ví + + SendCoinsDialog @@ -2230,10 +3947,6 @@ Fee: Phí: - - Dust: - Bụi - Inputs… Đầu vào… @@ -2258,6 +3971,14 @@ Transaction Fee: Phí giao dịch + + 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 dash transactions than the network can process. + Khi có ít giao dịch hơn không gian trong các khối, thợ đào cũng như các nút chuyển tiếp có thể áp dụng mức phí tối thiểu. Chỉ trả mức phí tối thiểu này là được, nhưng hãy lưu ý rằng điều này có thể dẫn đến giao dịch không bao giờ được xác nhận khi có nhiều nhu cầu giao dịch dash hơn mức mạng có thể xử lý. + + + A too low fee might result in a never confirming transaction (read the tooltip) + Phí quá thấp có thể dẫn đến giao dịch không bao giờ được xác nhận (đọc chú thích) + (Smart fee not initialized yet. This usually takes a few blocks…) (Phí khởi tạo thông minh chưa được khởi tạo. Thường thì sẽ mất vài block…) @@ -2286,6 +4007,10 @@ Note: Not enough data for fee estimation, using the fallback fee instead. Chú ý: Không đủ dữ liệu cho việc ước lượng chi phí, thay vào đó sử dụng mức phí dự phòng. + + Hide transaction fee settings + Ẩn cài đặt phí giao dịch + Hide Ẩn @@ -2346,10 +4071,6 @@ Copy bytes Sao chép bytes - - Copy dust - Sao chép bụi - Copy change Sao chép tiền trả lại @@ -2366,18 +4087,46 @@ %1 to %2 %1 đến %2 - - Are you sure you want to send? - Bạn có chắc mình muốn gửi? - <b>(%1 of %2 entries displayed)</b> <b>(%1 của %2 các thành phần được hiển thị)</b> + + S&end mixed funds + &Gửi tiền đã trộn + + + Confirm the %1 send action + Xác nhận hành động gửi %1 + + + Cr&eate Unsigned + &Tạo Chưa ký + + + from wallet '%1' + từ ví '%1' + + + %1 to '%2' + %1 đến '%2' + + + %1 funds only + Chỉ tiền %1 + any available funds bất kỳ nguồn cung nào còn + + Transaction fee + Phí giao dịch + + + (%1 transactions have higher fees usually due to no change output being allowed) + (Giao dịch %1 thường có phí cao hơn do không cho phép đầu ra tiền lẻ) + Transaction size: %1 Kích thước giao dịch: %1 @@ -2390,10 +4139,71 @@ This transaction will consume %n input(s) Giao dịch này sẽ dùng đến %n đầu vào + + Warning: Using %1 with %2 or more inputs can harm your privacy and is not recommended + Cảnh báo: Sử dụng %1 với %2 hoặc nhiều đầu vào hơn có thể làm tổn hại quyền riêng tư của bạn và không được khuyến nghị + + + Click to learn more + Nhấp để tìm hiểu thêm + + + Total Amount + Tổng số tiền + + + or + hoặc + Confirm send coins Xác nhận việc gửi tiền + + Save Transaction Data + Lưu Dữ liệu Giao dịch + + + PSBT saved + PSBT đã lưu + + + Watch-only balance: + Số dư chỉ xem: + + + Creates a Partially Signed Blockchain Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet. + Tạo Giao dịch Blockchain Được Ký Một Phần (PSBT) để sử dụng với ví %1 ngoại tuyến hoặc ví phần cứng tương thích PSBT. + + + Do you want to create this transaction? + 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. + Bạn có muốn tạo giao dịch này không? + + + Please, review your transaction proposal. This will produce a Partially Signed Blockchain Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet. + 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. + Vui lòng xem xét đề xuất giao dịch của bạn. Điều này sẽ tạo ra Giao dịch Blockchain Được Ký Một Phần (PSBT) mà bạn có thể lưu hoặc sao chép và sau đó ký bằng ví %1 ngoại tuyến hoặc ví phần cứng tương thích PSBT. + + + Please, review your transaction. You can create and send this transaction or create a Partially Signed Blockchain Transaction (PSBT), which you can save or copy and then sign with, e.g., an offline %1 wallet, or a PSBT-compatible hardware wallet. + 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. + Vui lòng xem xét giao dịch của bạn. Bạn có thể tạo và gửi giao dịch này hoặc tạo Giao dịch Blockchain Được Ký Một Phần (PSBT), mà bạn có thể lưu hoặc sao chép và sau đó ký bằng ví %1 ngoại tuyến hoặc ví phần cứng tương thích PSBT. + + + Please, review your transaction. + Text to prompt a user to review the details of the transaction they are attempting to send. + Vui lòng xem xét giao dịch của bạn. + + + To review recipient list click "Show Details…" + Để xem xét danh sách người nhận, nhấp vào "Hiển thị Chi tiết…" + + + Partially Signed Transaction (Binary) + Expanded name of the binary PSBT file format. See: BIP 174. + Giao dịch Được Ký Một Phần (Nhị phân) + The recipient address is not valid. Please recheck. Địa chỉ nhận không hợp lệ. Hãy kiểm tra lại xem. @@ -2489,6 +4299,10 @@ A&mount: &Số tiền: + + The amount to send in the selected unit + Số tiền gửi trong đơn vị đã chọn + The fee will be deducted from the amount being sent. The recipient will receive a lower amount of Dash than you enter in the amount field. If multiple recipients are selected, the fee is split equally. Phí sẽ được trừ trong khoản tiền mà bạn gửi. Bên nhận sẽ nhận được một khoản nhỏ hơn số Dash mà bạn nhập vào ở trong trường số lượng. Nếu có nhiều người nhận được chọn, phí được chia đều cho mọi người. @@ -2509,21 +4323,16 @@ A message that was attached to the dash: URI which will be stored with the transaction for your reference. Note: This message will not be sent over the Dash network. Một thông điệp được đính với dash: URI đó sẽ được lưu trữ với các giao dịch cho các bạn tham khảo. Lưu ý: Thông điệp này sẽ không được gửi qua mạng Dash. + + + SendConfirmationDialog - This is an unauthenticated payment request. - Đây là một yêu cầu thanh toán không được kiểm chứng. - - - This is an authenticated payment request. - Đây là một yêu cầu thanh toán đã được kiểm chứng. - - - Pay To: - Trả cho: + Send + Gửi - Memo: - Ghi nhớ: + Create Unsigned + Tạo chưa ký @@ -2611,6 +4420,14 @@ The Dash address the message was signed with Địa chỉ Dash mà thông điệp được ký bởi + + The signed message to verify + Thông điệp đã ký để xác minh + + + The signature given when the message was signed + Chữ ký được đưa ra khi thông điệp được ký + Verify the message to ensure it was signed with the specified Dash address Kiểm tra lại thông điệp để đảm bảo rằng nó được ký với địa chỉ Dash cụ thể @@ -2655,6 +4472,10 @@ Wallet unlock was cancelled. Mở khoá ví bị huỷ bỏ. + + No error + Không có lỗi + Private key for the entered address is not available. Khoá riêng cho địa chỉ vừa nhập không có. @@ -2688,11 +4509,26 @@ Thông điệp đã được xác thực. + + SplashScreen + + (press q to shutdown and continue later) + (nhấn q để tắt và tiếp tục sau) + + + press q to shutdown + nhấn q để tắt + + TrafficGraphWidget - KB/s - KB/s + kB/s + kB/s + + + Total + Tổng Received @@ -2705,20 +4541,9 @@ TransactionDesc - - Open for %n more block(s) - Mở cho %n khối nữa - - - Open until %1 - Mở đến khi %1 - - - conflicted - xung đột - 0/unconfirmed, %1 + 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. 0/chưa xác thực, %1 @@ -2731,22 +4556,32 @@ abandoned + 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. bị từ chối + + conflicted with a transaction with %1 confirmations + 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. + xung đột với giao dịch có %1 xác nhận + %1/unconfirmed + 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, and still not locked via ChainLocks. %1/chưa xác nhận %1 confirmations + 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 or locked via ChainLocks. %1 xác nhận locked via ChainLocks + 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 and has been locked by ChainLocks. được khoá với ChainLocks verified via InstantSend + 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 has been locked by InstantSend. đã được xác minh với InstantSend @@ -2765,6 +4600,10 @@ Generated Đã được sinh + + Platform Transfer + Chuyển nền tảng + From Từ @@ -2895,14 +4734,6 @@ Address / Label Địa chỉ / Nhãn - - Open for %n more block(s) - Mở cho %n khối nữa - - - Open until %1 - Mở đến khi %1 - Unconfirmed Chưa xác thực @@ -2947,6 +4778,10 @@ Received from Nhận từ + + Received via %1 + Đã nhận qua %1 + Sent to Gửi đến @@ -2959,6 +4794,30 @@ Mined Được đào + + Platform Transfer + Chuyển nền tảng + + + %1 Mixing + %1 Trộn + + + %1 Collateral Payment + %1 Thanh toán ký quỹ + + + %1 Make Collateral Inputs + %1 Tạo đầu vào ký quỹ + + + %1 Create Denominations + %1 Tạo mệnh giá + + + %1 Send + %1 Gửi + watch-only chỉ theo dõi @@ -3038,6 +4897,26 @@ Sent to Gửi đến + + %1 Send + %1 Gửi + + + %1 Make Collateral Inputs + %1 Tạo đầu vào ký quỹ + + + %1 Create Denominations + %1 Tạo mệnh giá + + + %1 Mixing + %1 Trộn + + + %1 Collateral Payment + %1 Thanh toán ký quỹ + To yourself Đến bản thân bạn @@ -3046,6 +4925,10 @@ Mined Được đào + + Platform Transfer + Chuyển nền tảng + Other Khác @@ -3059,45 +4942,63 @@ Số tiền tối thiểu - Abandon transaction - Từ bỏ giao dịch + &Copy address + &Sao chép địa chỉ - Copy address - Sao chép địa chỉ + Copy &label + Sao chép &nhãn - Copy label - Sao chép nhãn + Copy &amount + Sao chép &số tiền - Copy amount - Sao chép số tiền + Copy transaction &ID + Sao chép &ID giao dịch + + + Copy &raw transaction + Sao chép giao dịch &thô - Copy transaction ID - Sao chép mã giao dịch + Copy full transaction &details + Sao chép &chi tiết giao dịch đầy đủ - Copy raw transaction - Sao chép giao dịch thô + &Show transaction details + &Hiển thị chi tiết giao dịch - Copy full transaction details - Sao chép chi tiết đầy đủ về giao dịch + A&bandon transaction + &Bỏ giao dịch - Show transaction details - Xem chi tiết giao dịch + Rese&nd transaction + Gửi &lại giao dịch - Show address QR code - Hiển thị mã QR của địa chỉ + &Edit address label + &Chỉnh sửa nhãn địa chỉ + + + Show address &QR code + Hiển thị mã &QR địa chỉ + + + Show in %1 + 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. + Hiển thị trong %1 Export Transaction History Kết xuất Lịch sử Giao dịch + + Comma separated file + Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values. + Tập tin giá trị được phân cách bằng dấu phẩy + Confirmed Đã được xác nhận @@ -3164,17 +5065,77 @@ WalletController - + + Close wallet + Đóng ví + + + Are you sure you wish to close the wallet <i>%1</i>? + Bạn có chắc chắn muốn đóng ví <i>%1</i> không? + + + Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled. + Đóng ví quá lâu có thể dẫn đến phải đồng bộ lại toàn bộ chuỗi nếu cắt tỉa được bật. + + + Close all wallets + Đóng tất cả ví + + + Are you sure you wish to close all wallets? + Bạn có chắc chắn muốn đóng tất cả ví không? + + WalletFrame - + + No wallet has been loaded. +Go to File > Open Wallet to load a wallet. +- OR - + Chưa có ví nào được tải. +Vào File > Mở Ví để tải một ví. +- HOẶC - + + + Create a new wallet + Tạo một ví mới + + + Error + Lỗi + + + Unable to decode PSBT from clipboard (invalid base64) + Không thể giải mã PSBT từ clipboard (base64 không hợp lệ) + + + Load Transaction Data + Tải dữ liệu giao dịch + + + Partially Signed Transaction (*.psbt) + Giao dịch được ký một phần (*.psbt) + + + PSBT file must be smaller than 100 MiB + Tệp PSBT phải nhỏ hơn 100 MiB + + + Unable to decode PSBT + Không thể giải mã PSBT + + WalletModel Send Coins Gửi tiền - + + default wallet + ví mặc định + + WalletView @@ -3189,6 +5150,11 @@ Selected amount: Chọn số lượng: + + Wallet Data + Name of the wallet data file format. + Dữ liệu ví + Backup Wallet Sao lưu Ví @@ -3209,12 +5175,16 @@ The wallet data was successfully saved to %1. Dữ liệu ví đã được lưu thành công vào %1. - + + Cancel + Huỷ + + dash-core - Error: Listening for incoming connections failed (listen returned error %s) - Lỗi: Lắng nghe để nhận kết nối bị lỗi (lỗi trả về %s) + 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 + Lỗi này có thể xảy ra nếu ví không được tắt đúng cách và được tải lần cuối bằng phiên bản mới hơn của Berkeley DB. Nếu vậy, vui lòng sử dụng phần mềm đã tải ví này lần cuối This is a pre-release test build - use at your own risk - do not use for mining or merchant applications @@ -3269,16 +5239,20 @@ Lỗi đọc từ cơ sở dữ liệu, đang tắt phần mềm. - Failed to listen on any port. Use -listen=0 if you want this. - Không thành công khi lắng nghe trên các cổng. Sử dụng -listen=0 nếu bạn muốn nó. + Error: Missing checksum + Lỗi: Thiếu checksum + + + Error: Unable to parse version %u as a uint32_t + Lỗi: Không thể phân tích phiên bản %u dưới dạng uint32_t - -maxtxfee is set very high! Fees this large could be paid on a single transaction. - -maxtxfee được thiết lập rất cao! Mức phí cao này có thể được trả chỉ cho một giao dịch. + Error: Unable to write record to new wallet + Lỗi: Không thể ghi bản ghi vào ví mới - Cannot provide specific connections and have addrman find outgoing connections at the same. - Không thể cung cấp những kết nối cụ thể và nhờ addrman tìm những kết nối tại cùng một thời điểm. + Failed to listen on any port. Use -listen=0 if you want this. + Không thành công khi lắng nghe trên các cổng. Sử dụng -listen=0 nếu bạn muốn nó. Found unconfirmed denominated outputs, will wait till they confirm to continue. @@ -3289,13 +5263,17 @@ Thông số -socketevents ('%s') được chỉ định không hợp lệ. Chỉ có những chế độ được hỗ hỗ trợ sau: %s - Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions) - Số lượng không phù hợp cho -maxtxfee=<số lượng>: '%s' (phải bằng ít nhất mức phí chuyển tiếp tối thiểu %s để tránh tình trạng tắc các giao dịch) + SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is supported + SQLiteDatabase: Phiên bản lược đồ ví sqlite không xác định %d. Chỉ phiên bản %d được hỗ trợ Transaction index can't be disabled with governance validation enabled. Either start with -disablegovernance command line switch or enable transaction index. Chỉ mục giao dịch không thể tắt với tính năng xác thực quản trị đã được bật. Thay vào đó hãy khởi động với câu lệnh -disablegovernance hoặc bật chế độ chỉ mục giao dịch. + + Unsupported category-specific logging level -loglevel=%s. Expected -loglevel=<category>:<loglevel>. Valid categories: %s. Valid loglevels: %s. + Mức ghi nhật ký theo danh mục không được hỗ trợ -loglevel=%s. Mong đợi -loglevel=<category>:<loglevel>. Danh mục hợp lệ: %s. Mức ghi nhật ký hợp lệ: %s. + Can't mix: no compatible inputs found! Không thể trộn: không thấy đầu vào tương thích! @@ -3304,6 +5282,14 @@ Entry exceeds maximum size. Đầu vào vượt ngưỡng tối đa. + + Error upgrading evo database for EHF + Lỗi nâng cấp cơ sở dữ liệu evo cho EHF + + + Failed to commit Evo database + Không thể commit cơ sở dữ liệu Evo + Found enough users, signing ( waiting %s ) Đã tìm đủ người dùng, đang ký (vui lòng đợi %s) @@ -3328,18 +5314,14 @@ Insufficient funds. Không đủ tiền. - - Invalid amount for -discardfee=<amount>: '%s' - Số tiền không hợp lệ cho -discardfee=<amount>:'%s' - - - Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s) - Số tiền không hợp lệ cho -paytxfee=<số tiền>: '%s' (ít nhất phải bằng %s) - Invalid minimum number of spork signers specified with -minsporkkeys Số lượng người ký tối thiểu cho spork được chỉ bởi -minsporkkeys không hợp lệ + + Listening for incoming connections failed (listen returned error %s) + Lắng nghe kết nối đến thất bại (listen trả về lỗi %s) + Lock is already in place. Khoá đã sẵn sàng. @@ -3396,6 +5378,10 @@ Synchronizing governance objects… Đang đồng bộ các đối tượng quản trị… + + Transaction change output index out of range + Chỉ số đầu ra tiền lẻ giao dịch ngoài phạm vi + Unable to start HTTP server. See debug log for details. Không thể khởi động máy chủ HTTP. Hãy xem nhật ký lỗi để biết thêm chi tiết. @@ -3404,6 +5390,10 @@ Unknown response. Trả lời không xác định. + + Unsupported global logging level -loglevel=%s. Valid values: %s. + Mức ghi nhật ký toàn cục không được hỗ trợ -loglevel=%s. Giá trị hợp lệ: %s. + User Agent comment (%s) contains unsafe characters. Bình luận User Agent (%s) có chứa những ký tự không an toàn. @@ -3412,6 +5402,14 @@ Can't find random Masternode. Không tìm thấy Masternode ngẫu nhiên. + + %s can't be lower than %s + %s không thể thấp hơn %s + + + %s is idle. + %s đang rảnh. + Can't mix while sync in progress. Không thể trộn trong quá trình đồng bộ. @@ -3436,6 +5434,10 @@ Make sure to encrypt your wallet and delete all non-encrypted backups after you have verified that the wallet works! Hãy chắc chắn rằng bạn sẽ mã hoá ví của bạn và xoá đi tất cả các bản sao lưu của ví mà không có mã hoá sau kiểm tra ví đã hoạt động tốt! + + More than one onion bind address is provided. Using %s for the automatically created Tor onion service. + Nhiều hơn một địa chỉ gắn kết onion được cung cấp. Sử dụng %s cho dịch vụ Tor onion được tạo tự động. + Prune configured below the minimum of %d MiB. Please use a higher number. Cấu hình xén tỉa dưới mức tối thiểu của %d MiB. Hãy sử dụng một số lớn hơn. @@ -3464,14 +5466,14 @@ Wallet is locked, can't replenish keypool! Automatic backups and mixing are disabled, please unlock your wallet to replenish keypool. Ví đã được khoá, không thể bổ sung keypool! Tự động backups và trộn đã bị tắt, hãy mở khoá ví của bạn để bổ sung keypool. - - You need to rebuild the database using -reindex to change -timestampindex - Bạn cần phải tái lập lại cơ sở dữ liệu sử dụng tham số -reindex để thay đổi -timestampindex - You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain Bạn cần tái lập lại cơ sở dữ liệu sử dụng -reindex để quay trở lại chế độ không bị xén tỉa. Điều này sẽ làm tải lại toàn bộ blockchain + + %s failed + %s thất bại + -maxmempool must be at least %d MB -maxmempool phải ít nhất %d MB @@ -3480,21 +5482,57 @@ Automatic backups disabled Tự động backup đã bị tắt + + Cannot set -peerblockfilters without -blockfilterindex. + Không thể đặt -peerblockfilters mà không có -blockfilterindex. + + + Config setting for %s only applied on %s network when in [%s] section. + Cài đặt cấu hình cho %s chỉ được áp dụng trên mạng %s khi trong phần [%s]. + + + Could not find asmap file %s + Không tìm thấy file asmap %s + + + Could not parse asmap file %s + Không thể phân tích file asmap %s + ERROR! Failed to create automatic backup LỖI: Thất bại trong việc backup tự động - Error upgrading evo database - Lỗi nâng cấp cơ sở dữ liệu evo + Error loading %s: Private keys can only be disabled during creation + Lỗi tải %s: Khóa riêng chỉ có thể bị vô hiệu hóa trong quá trình tạo + + + Error: Couldn't create cursor into database + Lỗi: Không thể tạo con trỏ vào cơ sở dữ liệu + + + Error: Disk space is low for %s + Lỗi: Dung lượng đĩa thấp cho %s - Exceeded max tries. - Vượt quá số lần thử tối đa. + Error: Dumpfile checksum does not match. Computed %s, expected %s + Lỗi: Checksum file dump không khớp. Tính toán được %s, mong đợi %s - Failed to commit EvoDB - Không thể cập nhật vào EvoDB + Error: Got key that was not hex: %s + Lỗi: Nhận được khóa không phải hex: %s + + + Error: Got value that was not hex: %s + Lỗi: Nhận được giá trị không phải hex: %s + + + Error: Keypool ran out, please call keypoolrefill first + Lỗi: Keypool đã hết, vui lòng gọi keypoolrefill trước + + + Error: No addresses available. + Lỗi: Không có địa chỉ khả dụng. Failed to create backup %s! @@ -3512,13 +5550,29 @@ Failed to rescan the wallet during initialization Không thể quét lại ví trong quá trình khởi tạo + + Failed to verify database + Không thể xác minh cơ sở dữ liệu + + + Fee rate (%s) is lower than the minimum fee rate setting (%s) + Tỷ lệ phí (%s) thấp hơn cài đặt tỷ lệ phí tối thiểu (%s) + Found enough users, signing… Đã kiếm đủ người dùng, đang ký… - Invalid amount for -fallbackfee=<amount>: '%s' - Số lượng không hợp lệ cho -fallbackfee=<amount>: '%s' + Ignoring duplicate -wallet %s. + Bỏ qua -wallet %s trùng lặp. + + + Input not found or already spent + Không tìm thấy đầu vào hoặc đã chi tiêu + + + Invalid P2P permission: '%s' + Quyền P2P không hợp lệ: '%s' Invalid masternodeblsprivkey. Please see documentation. @@ -3540,6 +5594,10 @@ Mixing in progress… Đang trong quá trình trộn… + + No addresses available + Không có địa chỉ khả dụng + No errors detected. Không phát hiện ra các lỗi. @@ -3568,6 +5626,26 @@ Prune mode is incompatible with -txindex. Chế độ Xén-tỉa không tương thích với -txindex. + + SQLiteDatabase: Failed to execute statement to verify database: %s + SQLiteDatabase: Không thể thực thi câu lệnh để xác minh cơ sở dữ liệu: %s + + + SQLiteDatabase: Failed to prepare statement to verify database: %s + SQLiteDatabase: Không thể chuẩn bị câu lệnh để xác minh cơ sở dữ liệu: %s + + + SQLiteDatabase: Failed to read database verification error: %s + SQLiteDatabase: Không thể đọc lỗi xác minh cơ sở dữ liệu: %s + + + SQLiteDatabase: Unexpected application id. Expected %u, got %u + SQLiteDatabase: ID ứng dụng không mong đợi. Mong đợi %u, nhận được %u + + + Section [%s] is not recognized. + Phần [%s] không được nhận diện. + Specified -walletdir "%s" does not exist Thư mục được chỉ ra -walletdir "%s" không tồn tại @@ -3596,6 +5674,10 @@ This is the transaction fee you will pay if you send a transaction. Đây là transaction fee bạn sẽ pay nếu gửi transaction. + + Topping up keypool… + Đang nạp thêm keypool… + Transaction amounts must not be negative Transaction amounts phải không âm @@ -3616,13 +5698,25 @@ Unable to bind to %s on this computer. %s is probably already running. Unable to bind to %s on this computer. %s is probably already running. + + Unable to create the PID file '%s': %s + Không thể tạo tệp PID '%s': %s + Unable to generate initial keys Không thể sinh các khoá khởi tạo - Upgrading UTXO database - Upgrading UTXO database + Unable to open %s for writing + Không thể mở %s để ghi + + + Unknown -blockfilterindex value %s. + Giá trị -blockfilterindex không xác định %s. + + + Unknown new rules activated (versionbit %i) + Quy tắc mới không xác định đã được kích hoạt (versionbit %i) Verifying blocks… @@ -3641,16 +5735,12 @@ Không thể tạo được thư mục backup ví %s! - You can not start a masternode with wallet enabled. - Bạn không thể khởi động một masternode với ví được kích hoạt. - - - You need to rebuild the database using -reindex to change -addressindex - Bạn cần tái lập lại cơ sở dữ liệu sử dụng -reindex để thay đổi -addressindex + Wiping wallet transactions… + Đang xóa các giao dịch ví… - You need to rebuild the database using -reindex to change -spentindex - Bạn cần tái lập lại cơ sở dữ liệu sử dụng -reindex để thay đổi -spentindex + You can not start a masternode with wallet enabled. + Bạn không thể khởi động một masternode với ví được kích hoạt. no mixing available. @@ -3664,6 +5754,26 @@ The %s developers The %s developers + + %s uses exact denominated amounts to send funds, you might simply need to mix some more coins. + %s sử dụng các mệnh giá chính xác để gửi tiền, bạn có thể chỉ cần trộn thêm một số coin. + + + -reindex-chainstate option is not compatible with -blockfilterindex. Please temporarily disable blockfilterindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes. + Tùy chọn -reindex-chainstate không tương thích với -blockfilterindex. Vui lòng tạm thời vô hiệu hóa blockfilterindex khi sử dụng -reindex-chainstate, hoặc thay -reindex-chainstate bằng -reindex để xây dựng lại tất cả các chỉ mục. + + + -reindex-chainstate option is not compatible with -coinstatsindex. Please temporarily disable coinstatsindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes. + Tùy chọn -reindex-chainstate không tương thích với -coinstatsindex. Vui lòng tạm thời vô hiệu hóa coinstatsindex khi sử dụng -reindex-chainstate, hoặc thay -reindex-chainstate bằng -reindex để xây dựng lại tất cả các chỉ mục. + + + -reindex-chainstate option is not compatible with -txindex. Please temporarily disable txindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes. + Tùy chọn -reindex-chainstate không tương thích với -txindex. Vui lòng tạm thời vô hiệu hóa txindex khi sử dụng -reindex-chainstate, hoặc thay -reindex-chainstate bằng -reindex để xây dựng lại tất cả các chỉ mục. + + + Cannot downgrade wallet from version %i to version %i. Wallet version unchanged. + Không thể hạ cấp ví từ phiên bản %i xuống phiên bản %i. Phiên bản ví không thay đổi. + Cannot obtain a lock on data directory %s. %s is probably already running. Cannot obtain a lock on data directory %s. %s is probably already running. @@ -3676,14 +5786,82 @@ Error loading %s: You can't enable HD on an already existing non-HD wallet Lỗi khi tải %s: Bạn không thể bật HD trên một ví không HD + + 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 + Lỗi khi tải ví. Ví yêu cầu các khối được tải xuống, và phần mềm hiện tại không hỗ trợ tải ví trong khi các khối đang được tải xuống không theo thứ tự khi sử dụng assumeutxo snapshots. Ví sẽ có thể tải thành công sau khi node đồng bộ đạt chiều cao %s + Error reading %s! All keys read correctly, but transaction data or address book entries might be missing or incorrect. Error reading %s! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + + Error: Dumpfile format record is incorrect. Got "%s", expected "format". + Lỗi: Bản ghi định dạng dumpfile không chính xác. Nhận được "%s", mong đợi "format". + + + Error: Dumpfile identifier record is incorrect. Got "%s", expected "%s". + Lỗi: Bản ghi định danh dumpfile không chính xác. Nhận được "%s", mong đợi "%s". + + + Error: Dumpfile version is not supported. This version of bitcoin-wallet only supports version 1 dumpfiles. Got dumpfile with version %s + Lỗi: Phiên bản dumpfile không được hỗ trợ. Phiên bản bitcoin-wallet này chỉ hỗ trợ dumpfile phiên bản 1. Nhận được dumpfile với phiên bản %s + + + Failed to rename invalid peers.dat file. Please move or delete it and try again. + Không thể đổi tên tệp peers.dat không hợp lệ. Vui lòng di chuyển hoặc xóa nó và thử lại. + + + Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable %s. + Ước tính phí không thành công. Fallbackfee bị vô hiệu hóa. Đợi một vài khối hoặc bật %s. + + + File %s already exists. If you are sure this is what you want, move it out of the way first. + Tệp %s đã tồn tại. Nếu bạn chắc chắn đây là điều bạn muốn, hãy di chuyển nó ra khỏi đường dẫn trước. + + + Incompatible options: -dnsseed=1 was explicitly specified, but -onlynet forbids connections to IPv4/IPv6 + Tùy chọn không tương thích: -dnsseed=1 đã được chỉ định rõ ràng, nhưng -onlynet cấm các kết nối tới IPv4/IPv6 + Incorrect or no devnet genesis block found. Wrong datadir for devnet specified? Không chính xác hoặc không tìm thấy khối ban đầu của devnet. Thư mục dữ liệu devnet được cung cấp không chính xác? + + Invalid amount for %s=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions) + Số tiền không hợp lệ cho %s=<amount>: '%s' (phải ít nhất là phí minrelay %s để ngăn chặn giao dịch bị kẹt) + + + 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. + peers.dat không hợp lệ hoặc bị hỏng (%s). Nếu bạn tin đây là lỗi, vui lòng báo cáo cho %s. Để khắc phục, bạn có thể di chuyển tệp (%s) ra khỏi đường dẫn (đổi tên, di chuyển hoặc xóa) để tạo một tệp mới khi khởi động lại. + + + No dump file provided. To use createfromdump, -dumpfile=<filename> must be provided. + Không có tệp dump được cung cấp. Để sử dụng createfromdump, phải cung cấp -dumpfile=<filename>. + + + No dump file provided. To use dump, -dumpfile=<filename> must be provided. + Không có tệp dump được cung cấp. Để sử dụng dump, phải cung cấp -dumpfile=<filename>. + + + No wallet file format provided. To use createfromdump, -format=<format> must be provided. + Không có định dạng tệp ví được cung cấp. Để sử dụng createfromdump, phải cung cấp -format=<format>. + + + Outbound connections restricted to CJDNS (-onlynet=cjdns) but -cjdnsreachable is not provided + Kết nối ra ngoài bị giới hạn đối với CJDNS (-onlynet=cjdns) nhưng -cjdnsreachable không được cung cấp + + + Outbound connections restricted to Tor (-onlynet=onion) but the proxy for reaching the Tor network is explicitly forbidden: -onion=0 + Kết nối ra ngoài bị giới hạn đối với Tor (-onlynet=onion) nhưng proxy để truy cập mạng Tor bị cấm rõ ràng: -onion=0 + + + 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 + Kết nối ra ngoài bị giới hạn đối với Tor (-onlynet=onion) nhưng proxy để truy cập mạng Tor không được cung cấp: không có -proxy, -onion hoặc -listenonion được đưa ra + + + Outbound connections restricted to i2p (-onlynet=i2p) but -i2psam is not provided + Kết nối ra ngoài bị giới hạn đối với i2p (-onlynet=i2p) nhưng -i2psam không được cung cấp + Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly. Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly. @@ -3692,6 +5870,14 @@ Please contribute if you find %s useful. Visit %s for further information about the software. Please contribute if you find %s useful. Visit %s for further information about the software. + + Prune mode is incompatible with -reindex-chainstate. Use full -reindex instead. + Chế độ cắt tỉa không tương thích với -reindex-chainstate. Hãy sử dụng -reindex đầy đủ thay thế. + + + This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection. + Đây là phí giao dịch tối đa bạn trả (ngoài phí thông thường) để ưu tiên tránh chi tiêu một phần hơn lựa chọn coin thông thường. + This is the transaction fee you may discard if change is smaller than dust at this level Đây là phí giao dịch bạn có thể bỏ qua nếu phần trả lại nhỏ hơn bụi ở cấp độ này @@ -3700,10 +5886,38 @@ This is the transaction fee you may pay when fee estimates are not available. This is the transaction fee you may pay when fee estimates are not available. + + Transaction requires one destination of non-0 value, a non-0 feerate, or a pre-selected input + Giao dịch yêu cầu một đích có giá trị khác 0, tỷ lệ phí khác 0, hoặc một đầu vào đã được chọn trước + Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate. Không thể phát lại các khối. Bạn sẽ cần xây dựng lại cơ sở dữ liệu bằng cách sử dụng -reindex-chainstate. + + Unknown wallet file format "%s" provided. Please provide one of "bdb" or "sqlite". + Định dạng tệp ví không xác định "%s" được cung cấp. Vui lòng cung cấp một trong "bdb" hoặc "sqlite". + + + Unsupported chainstate database format found. Please restart with -reindex-chainstate. This will rebuild the chainstate database. + Đã tìm thấy định dạng cơ sở dữ liệu chainstate không được hỗ trợ. Vui lòng khởi động lại với -reindex-chainstate. Điều này sẽ xây dựng lại cơ sở dữ liệu chainstate. + + + Warning: Dumpfile wallet format "%s" does not match command line specified format "%s". + Cảnh báo: Định dạng ví dumpfile "%s" không khớp với định dạng được chỉ định trong dòng lệnh "%s". + + + Warning: Private keys detected in wallet {%s} with disabled private keys + Cảnh báo: Phát hiện khóa riêng trong ví {%s} với khóa riêng bị vô hiệu hóa + + + You need to rebuild the database using -reindex to enable -timestampindex + Bạn cần xây dựng lại cơ sở dữ liệu bằng cách sử dụng -reindex để bật -timestampindex + + + %s -- Incorrect seed, it should be a hex string + %s -- Seed không chính xác, nó phải là một chuỗi hex + %s is not a valid backup folder! %s không phải là thư mục sao lưu dự phòng hợp lệ! @@ -3712,6 +5926,10 @@ %s is set very high! %s is set very high! + + %s request incomplete: + Yêu cầu %s không đầy đủ: + -devnet can only be specified once -devnet chỉ có thể chỉ ra một lần duy nhất @@ -3724,18 +5942,54 @@ -rpcport must be specified when -devnet and -server are specified -rpcport phải được chỉ rõ khi -devnet và -server được sử dụng + + -statsbatchsize cannot be configured with a negative value. + -statsbatchsize không thể được cấu hình với giá trị âm. + + + -statsduration cannot be configured with a negative value. + -statsduration không thể được cấu hình với giá trị âm. + + + A fatal internal error occurred, see debug.log for details + Đã xảy ra lỗi nội bộ nghiêm trọng, xem debug.log để biết chi tiết + + + Cannot create socket (socket() returned error %s) + Không thể tạo socket (socket() trả về lỗi %s) + + + Cannot get socket address for %s + Không thể lấy địa chỉ socket cho %s + + + Cannot init Statsd client + Không thể khởi tạo Statsd client + Cannot resolve -%s address: '%s' Cannot resolve -%s address: '%s' - Change index out of range - Change index out of range + Cannot write to data directory '%s'; check permissions. + Không thể ghi vào thư mục dữ liệu '%s'; kiểm tra quyền truy cập. Copyright (C) Bản quyền (C) + + Disk space is too low! + Dung lượng đĩa quá thấp! + + + Dump file %s does not exist. + Tệp dump %s không tồn tại. + + + Error creating %s + Lỗi khi tạo %s + Error loading %s Error loading %s @@ -3753,8 +6007,8 @@ Lỗi tải %s: Bạn không thể tắt HD trên một ví đã có HD - Error upgrading chainstate database - Error upgrading chainstate database + Error reading next record from wallet database + Lỗi khi đọc bản ghi tiếp theo từ cơ sở dữ liệu ví Loading P2P addresses… @@ -3772,10 +6026,38 @@ Loading wallet… Đang tải ví… + + Failed to clear fulfilled requests cache at %s + Không thể xóa bộ nhớ đệm yêu cầu đã thực hiện tại %s + + + Failed to clear governance cache at %s + Không thể xóa bộ nhớ đệm quản trị tại %s + + + Failed to clear masternode cache at %s + Không thể xóa bộ nhớ đệm masternode tại %s + Failed to find mixing queue to join Không tìm thấy hàng đợi trộn để tham gia + + Failed to load fulfilled requests cache from %s + Không thể tải bộ nhớ đệm yêu cầu đã thực hiện từ %s + + + Failed to load governance cache from %s + Không thể tải bộ nhớ đệm quản trị từ %s + + + Failed to load masternode cache from %s + Không thể tải bộ nhớ đệm masternode từ %s + + + Failed to load sporks cache from %s + Không thể tải bộ nhớ đệm sporks từ %s + Failed to start a new mixing queue Không thể khởi động được một hàng đợi trộn mới @@ -3784,6 +6066,10 @@ Importing… Đang nạp… + + Incorrect -rescan mode, falling back to default value + Chế độ -rescan không chính xác, quay lại giá trị mặc định + Initialization sanity check failed. %s is shutting down. Initialization sanity check failed. %s is shutting down. @@ -3792,6 +6078,14 @@ Inputs vs outputs size mismatch. Kích thước của đầu vào với đầu ra không tương xứng. + + Invalid '%s'. Allowed values: 128, 160, 192, 224, 256. + '%s' không hợp lệ. Giá trị cho phép: 128, 160, 192, 224, 256. + + + Invalid -i2psam address or hostname: '%s' + Địa chỉ hoặc tên máy chủ -i2psam không hợp lệ: '%s' + Invalid -onion address or hostname: '%s' Invalid -onion address or hostname: '%s' @@ -3824,10 +6118,90 @@ Signing transaction failed Thất bại khi ký giao dịch + + Specified blocks directory "%s" does not exist. + Thư mục khối được chỉ định "%s" không tồn tại. + + + Last queue was created too recently. + Hàng đợi cuối cùng được tạo quá gần đây. + + + %s corrupt. Try using the wallet tool dash-wallet to salvage or restoring a backup. + %s bị hỏng. Hãy thử sử dụng công cụ ví dash-wallet để cứu hộ hoặc khôi phục từ bản sao lưu. + + + %s is set very high! Fees this large could be paid on a single transaction. + %s được đặt rất cao! Phí lớn như vậy có thể được trả cho một giao dịch duy nhất. + + + %s request to listen on port %u. This port is considered "bad" and thus it is unlikely that any Dash Core peers connect to it. See doc/p2p-bad-ports.md for details and a full list. + %s yêu cầu lắng nghe trên cổng %u. Cổng này được coi là "xấu" và do đó khó có khả năng bất kỳ peer Dash Core nào kết nối với nó. Xem doc/p2p-bad-ports.md để biết chi tiết và danh sách đầy đủ. + + + Cannot provide specific connections and have addrman find outgoing connections at the same time. + Không thể cung cấp các kết nối cụ thể và để addrman tìm các kết nối ra ngoài cùng một lúc. + + + Failed to upgrade Evo database + Không thể nâng cấp cơ sở dữ liệu Evo + + + Fee needed > fee paid + Phí cần thiết > phí đã trả + + + Host %s on unsupported network + Máy chủ %s trên mạng không được hỗ trợ + + + Invalid amount for %s=<amount>: '%s' (must be at least %s) + Số tiền không hợp lệ cho %s=<amount>: '%s' (phải ít nhất %s) + + + Invalid amount for %s=<amount>: '%s' + Số tiền không hợp lệ cho %s=<amount>: '%s' + + + Invalid port specified in %s: '%s' + Cổng không hợp lệ được chỉ định trong %s: '%s' + + + Last successful action was too recent. + Hành động thành công cuối cùng quá gần đây. + + + Missing solving data for estimating transaction size + Thiếu dữ liệu giải quyết để ước tính kích thước giao dịch + + + No host specified + Không có máy chủ được chỉ định + + + No host specified, malformed URL + Không có máy chủ được chỉ định, URL không đúng định dạng + + + No text before the scheme delimiter, malformed URL + Không có văn bản trước dấu phân cách scheme, URL không đúng định dạng + + + Port must be between %d and %d, supplied %d + Cổng phải nằm giữa %d và %d, đã cung cấp %d + + + Socket not initialized, cannot send message + Socket chưa được khởi tạo, không thể gửi tin nhắn + The source code is available from %s. The source code is available from %s. + + The specified config file %s does not exist + Tệp cấu hình được chỉ định %s không tồn tại + The transaction amount is too small to pay the fee Giá trị giao dịch quá nhỏ để trả phí @@ -3848,6 +6222,10 @@ Transaction fees are too high. Phí giao dịch quá cao. + + Transaction needs a change address, but we can't generate it. + Giao dịch cần một địa chỉ tiền thối, nhưng chúng tôi không thể tạo nó. + Transaction not valid. Giao dịch không hợp lệ. @@ -3860,6 +6238,26 @@ Unable to bind to %s on this computer (bind returned error %s) Không thể để ràng buộc vào %s trên máy tính này (bind trả lại lỗi %s) + + Unable to locate enough mixed funds for this transaction. + Không thể tìm đủ tiền đã trộn cho giao dịch này. + + + Unable to locate enough non-denominated funds for this transaction. + Không thể tìm đủ tiền chưa định mệnh giá cho giao dịch này. + + + Unable to lookup host %s + Không thể tra cứu máy chủ %s + + + Unable to parse -maxuploadtarget: '%s' + Không thể phân tích -maxuploadtarget: '%s' + + + Unable to send message to %s (::sendto() returned error %s) + Không thể gửi tin nhắn tới %s (::sendto() trả về lỗi %s) + Unable to sign spork message, wrong key? Không thể ký vào thông điệp phân nhánh, sai khoá? @@ -3872,6 +6270,10 @@ Unknown state: id = %u Trạng thái không xác định: id = %u + + Unsupported URL scheme, must begin with udp:// + Scheme URL không được hỗ trợ, phải bắt đầu bằng udp:// + Unsupported logging category %s=%s. Danh mục ghi nhật ký không được hỗ trợ %s=%s. @@ -3884,6 +6286,14 @@ Wallet is locked. Ví đã bị khoá. + + Warning: can't use %s and %s together, will prefer %s + Cảnh báo: không thể sử dụng %s và %s cùng nhau, sẽ ưu tiên %s + + + Warning: incorrect parameter %s, path must exist! Using default path. + Cảnh báo: tham số %s không chính xác, đường dẫn phải tồn tại! Sử dụng đường dẫn mặc định. + Will retry… Sẽ thử lại… @@ -3896,9 +6306,25 @@ You can not disable governance validation on a masternode. Bạn không thể tắt chế độ xác thực quản trị trên một masternode. + + You need to rebuild the database using -reindex to enable -addressindex + Bạn cần xây dựng lại cơ sở dữ liệu bằng cách sử dụng -reindex để bật -addressindex + + + You need to rebuild the database using -reindex to enable -spentindex + Bạn cần xây dựng lại cơ sở dữ liệu bằng cách sử dụng -reindex để bật -spentindex + Your entries added successfully. Các đầu vào của bạn đã được thêm vào một cách thành công. + + Settings file could not be read + Không thể đọc tệp cài đặt + + + Settings file could not be written + Không thể ghi tệp cài đặt + \ No newline at end of file diff --git a/src/qt/locale/dash_zh_CN.ts b/src/qt/locale/dash_zh_CN.ts index 076e9cc55e27..1c14e62cec94 100644 --- a/src/qt/locale/dash_zh_CN.ts +++ b/src/qt/locale/dash_zh_CN.ts @@ -65,14 +65,6 @@ C&hoose 选择(&H) - - Sending addresses - 正在发送地址 - - - Receiving addresses - 正在接收地址 - These are your Dash addresses for sending payments. Always check the amount and the receiving address before sending coins. 这些是您要付款过去的Dash地址。在付款之前,务必要检查金额和收款地址是否正确。 @@ -115,6 +107,14 @@ An error message. %1 is a stand-in argument for the name of the file we attempted to save to. 尝试保存地址列表至 %1 时发生错误. 请重新执行操作. + + Sending addresses - %1 + 发送地址 - %1 + + + Receiving addresses - %1 + 接收地址 - %1 + Exporting Failed 导出失败 @@ -284,10 +284,22 @@ The passphrase entered for the wallet decryption was incorrect. 用于解密钱包的密码不正确。 + + 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 23.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. + 用于解密钱包的密码不正确。其中包含空字符(即零字节)。如果密码是使用 23.0 之前版本的软件设置的,请仅使用第一个空字符之前(但不包括)的字符重试。如果成功,请设置新密码以避免将来出现此问题。 + Wallet passphrase was successfully changed. 修改钱包密码成功。 + + Passphrase change failed + 密码修改失败 + + + 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 23.0, please try again with only the characters up to — but not including — the first null character. + 用于解密钱包的旧密码不正确。其中包含空字符(即零字节)。如果密码是使用 23.0 之前版本的软件设置的,请仅使用第一个空字符之前(但不包括)的字符重试。 + Warning: The Caps Lock key is on! 警告:大写锁定键处于打开状态! @@ -392,10 +404,6 @@ &Load PSBT from file… &从文件读取 PSBT… - - Load PSBT from clipboard… - 从剪切板读取 PSBT... - &Sending addresses &发送地址 @@ -428,10 +436,6 @@ &Window &窗口 - - Minimize - 最小化 - Zoom 放大 @@ -484,14 +488,6 @@ Modify configuration options for %1 修改%1配置选项 - - &Show / Hide - 显示 / 隐藏(&S) - - - Show or hide the main Window - 显示或隐藏主窗口 - Encrypt the private keys that belong to your wallet 对钱包中的私钥加密 @@ -556,10 +552,6 @@ Show wallet repair options 显示钱包修复选项 - - Open Wallet &Configuration File - 打开钱包 &配置文件 - Open configuration file 打开配置文件 @@ -614,10 +606,18 @@ Show information about %1 显示有关%1的相关信息 + + Load PSBT from &clipboard… + 从剪贴板加载 PSBT… + Open debugging and diagnostic console 打开调试和诊断控制台 + + Open &wallet configuration file + 打开钱包配置文件(&W) + Open a dash: URI 打开一个dash: URI @@ -626,6 +626,16 @@ Create a new wallet 创建一个新钱包 + + Restore Wallet… + Name of the menu item that restores wallet from a backup file. + 恢复钱包… + + + Restore a wallet from a backup file + Status tip for Restore Wallet menu item + 从备份文件恢复钱包 + Close all wallets 关闭所有钱包 @@ -646,10 +656,34 @@ Mask the values in the Overview tab 遮盖总览选项卡中的数值 + + Wallet Data + Name of the wallet data file format. + 钱包数据 + + + Load Wallet Backup + The title for Restore Wallet File Windows + 加载钱包备份 + + + Restore Wallet + Title of pop-up window shown when the user is attempting to restore a wallet. + 恢复钱包 + + + Wallet Name + Label of the input field where the name of the wallet is entered. + 钱包名称 + &Settings 设置(&S) + + &Minimize + 最小化(&M) + &Help 帮助(&H) @@ -666,6 +700,14 @@ View Governance Proposals 查看治理提案 + + &Hide + 隐藏(&H) + + + S&how + 显示(&H) + %n active connection(s) to Dash network A substring of the tooltip. @@ -687,6 +729,14 @@ Close Wallet… 关闭钱包… + + Load Partially Signed Blockchain Transaction + 读取部分签名的区块链交易 + + + Load Partially Signed Blockchain Transaction from clipboard + 从剪贴板读取部分签名的区块链交易 + Create Wallet… 创建钱包… @@ -739,10 +789,6 @@ Processing blocks on disk… 正在处理硬盘中的区块… - - Reindexing blocks on disk… - 正在为硬盘中的区块重建索引… - Connecting to peers… 正在连接到节点…… @@ -896,10 +942,6 @@ Coin Selection 选择币 - - Dust: - 零散金额: - After Fee: 加上交易费用后: @@ -1000,10 +1042,6 @@ Copy bytes 复制字节 - - Copy dust - 复制零钱金额 - Copy change 复制零钱 @@ -1016,18 +1054,6 @@ (%1 locked) (%1 锁定) - - yes - - - - no - - - - This label turns red if any recipient receives an amount smaller than the current dust threshold. - 当任何一个收款金额小于目前的零散金额上限时,文字会变红色。 - Can vary +/- %1 duff(s) per input. 每笔输入可能会有 +/- %1个duff(s)的偏差. @@ -1241,18 +1267,102 @@ Filter proposal list 筛选提案列表 + + Masternode Count: + 主节点数量: + + + Number of masternodes this wallet can vote with (masternodes for which this wallet holds the voting key) + 此钱包可投票的主节点数量(此钱包持有投票密钥的主节点) + Proposal Count: 提案数量: + + Create Proposal + 创建提案 + Filter by Title 按标题筛选 + + Unavailable + 不可用 + + + A synced node and an unlocked wallet are required. + 需要已同步的节点和已解锁的钱包。 + + + Vote Yes + 投赞成票 + + + Vote No + 投反对票 + + + Vote Abstain + 投弃权票 + Proposal Info: %1 提案信息: %1 + + Voting Failed + 投票失败 + + + No wallet available. + 没有可用的钱包。 + + + No masternode voting keys found in wallet. + 在钱包中未找到主节点投票密钥。 + + + Please select a proposal to vote on. + 请选择要投票的提案。 + + + Unable to unlock wallet. + 无法解锁钱包。 + + + Unable to get masternode list. Please try again later. + 无法获取主节点列表。请稍后重试。 + + + Masternode %1 not found + 未找到主节点 %1 + + + Failed to sign vote for masternode %1 + 为主节点 %1 签署投票失败 + + + Masternode %1: %2 + 主节点 %1:%2 + + + Voted successfully %n time(s) + 成功投票 %n 次 + + + Failed to vote %n time(s) + 投票失败 %n 次 + + + Errors: + 错误: + + + Voting Results + 投票结果 + HelpMessageDialog @@ -1323,13 +1433,17 @@ Use a custom data directory: 使用自定义的数据目录: - - (of %1 GB needed) - (需要 %1 GB的空间) + + %n GB of space available + 可用空间 %n GB - - (%1 GB needed for full chain) - (完整区块链需要 %1 GB) + + (of %n GB needed) + (需要 %n GB) + + + (%n GB needed for full chain) + (完整区块链需要 %n GB) At least %1 GB of data will be stored in this directory, and it will grow over time. @@ -1361,6 +1475,13 @@ 错误 + + LoadWalletsActivity + + Loading wallets… + 正在加载钱包… + + MasternodeList @@ -1553,6 +1674,11 @@ URI: URI: + + Paste address from clipboard + Tooltip text for button that allows you to paste an address that is in your clipboard. + 从剪贴板粘贴地址 + OpenWalletActivity @@ -1663,6 +1789,16 @@ An Options window setting to set subtracting the fee from a sending amount as default. 默认从金额中扣除 &手续费 + + Enable &PSBT controls + An options window setting to enable PSBT controls. + 启用 PSBT 控件(&P) + + + Whether to show PSBT controls. + Tooltip text for options window setting that enables PSBT controls. + 是否显示 PSBT 控件。 + Whether to keep the specified custom change address or not. 是否保留指定的自定义找零地址. @@ -1806,20 +1942,20 @@ https://explore.transifex.com/dash/dash/ https://explore.transifex.com/dash/dash/ - Options set in this dialog are overridden by the command line or in the configuration file: - 此对话框中设置的选项被命令行或配置文件覆盖: + Third-party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items.<br/>%s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |. + 在交易选项卡中以上下文菜单项出现的第三方 URL(例如区块浏览器)。<br/>URL 中的 %s 将替换为交易哈希。多个 URL 用竖线 | 分隔。 - 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. - 窗口被关闭时最小化而不是退出应用程序。当此选项启用时,应用程序只会在菜单中选择退出时退出。 + &Third-party transaction URLs + 第三方交易 URL(&T) - Third party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items.<br/>%s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |. - 出现在交易的选项卡的上下文菜单项的第三方URL(例如,区块链查询网站)。<br/>URL中的 %s被替换为交易哈希。多个URL需用竖线 | 分隔。 + Options set in this dialog are overridden by the command line or in the configuration file: + 此对话框中设置的选项被命令行或配置文件覆盖: - &Third party transaction URLs - &第三方交易链接 + 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. + 窗口被关闭时最小化而不是退出应用程序。当此选项启用时,应用程序只会在菜单中选择退出时退出。 Whether to show coin control features or not. @@ -1963,14 +2099,22 @@ https://explore.transifex.com/dash/dash/ Confirm options reset + Window title text of pop-up window shown when the user has chosen to reset options. 确认恢复缺省设置 Client restart required to activate changes. + Text explaining that the settings changed will not come into effect until the client is restarted. 更改生效需要重启客户端。 + + Current settings will be backed up at "%1". + 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. + 当前设置将备份到"%1"。 + Client will be shut down. Do you want to proceed? + Text asking the user to confirm if they would like to proceed with a client shutdown. 客户端即将关闭,您想继续吗? @@ -2243,6 +2387,10 @@ https://explore.transifex.com/dash/dash/ Failed to sign transaction: %1 无法签名交易: %1 + + Cannot sign inputs while wallet is locked. + 钱包被锁定时无法签署输入。 + Could not sign any more inputs. 无法签名更多输入. @@ -2487,6 +2635,181 @@ Due to discontinued support, you should request the merchant to provide you with 状态 + + ProposalWizard + + Create Governance Proposal + 创建治理提案 + + + Enter proposal details + 输入提案详情 + + + A fee will be burned when you prepare the proposal. + 准备提案时将销毁一笔费用。 + + + Proposal &name + 提案名称(&N) + + + &Description URL + 描述 URL(&D) + + + Payment &address + 支付地址(&A) + + + Payment &amount + 支付金额(&A) + + + The amount to request in a single payment + 单次支付中请求的金额 + + + &First payment + 首次支付(&F) + + + Pa&yments + 支付次数(&Y) + + + To&tal amount + 总金额(&T) + + + Proposal &fee + 提案费用(&F) + + + Next + 下一步 + + + Review proposal JSON and validate. + 检查提案 JSON 并验证。 + + + Hex-encoded JSON + 十六进制编码的 JSON + + + Back + 返回 + + + Validate + 验证 + + + Prepare (burn fee) and wait for confirmations. + 准备(销毁费用)并等待确认。 + + + Copy + 复制 + + + At 1/6 confirmations: can be relayed and queued. At 6/6: accepted and processed. + 1/6 确认时:可以中继和排队。6/6 时:接受并处理。 + + + Confirmations progress + 确认进度 + + + Shows progress toward the required number of confirmations for the proposal fee transaction. + 显示提案费用交易所需确认数的进度。 + + + Estimated time remaining: - + 预计剩余时间:- + + + Prepare Proposal + 准备提案 + + + You can submit after 1 confirmation. At 6 confirmations it is accepted and processed. + 1 次确认后即可提交。6 次确认后将被接受并处理。 + + + Proposal ID: + 提案 ID: + + + Submit Proposal + 提交提案 + + + Close + 关闭 + + + Valid + 有效 + + + Invalid: %1 + 无效:%1 + + + Burn %1 + 销毁 %1 + + + Burn %1 to create the fee transaction? + 销毁 %1 以创建费用交易? + + + Prepare failed + 准备失败 + + + Confirmations: %1 / %2 required + 确认数:%1 / 需要 %2 + + + Estimated time remaining: Ready + 预计剩余时间:就绪 + + + Estimated time remaining: %n minute(s) + 预计剩余时间:%n 分钟 + + + Your proposal was submitted successfully. + 您的提案已成功提交。 + + + Already submitted + 已提交 + + + This proposal has already been submitted. + 此提案已经提交。 + + + Submission failed + 提交失败 + + + Proposal submitted + 提案已提交 + + + A fee of %1 will be burned when you prepare the proposal. + 准备提案时将销毁 %1 的费用。 + + + Prepare (burn %1) and wait for %2 confirmations. + 准备(销毁 %1)并等待 %2 次确认。 + + QObject @@ -2876,14 +3199,6 @@ Due to discontinued support, you should request the merchant to provide you with Version 版本 - - Whether the peer requested us to relay transactions. - 节点是否要求进行中继交易. - - - Wants Tx Relay - 想要交易中继 - High bandwidth BIP152 compact block relay: %1 高带宽 BIP152 紧凑区块中继: %1 @@ -2989,6 +3304,14 @@ Due to discontinued support, you should request the merchant to provide you with To specify a non-default location of the blocks directory use the '%1' option. 要指定的区块目录不是默认路径, 请使用 '%1' 选项. + + Local Addresses + 本地地址 + + + Network addresses that your Dash node is currently using to communicate with other nodes. + 您的 Dash 节点当前用于与其他节点通信的网络地址。 + Number of regular Masternodes 常规主节点数量 @@ -3081,6 +3404,14 @@ Due to discontinued support, you should request the merchant to provide you with Services 服务 + + Whether we relay transactions to this peer. + 是否向此对等节点中继交易。 + + + Transaction Relay + 交易中继 + Connection Time 连接时间 @@ -3229,6 +3560,10 @@ Due to discontinued support, you should request the merchant to provide you with Network activity disabled 网络活动已禁用 + + None + + Total: %1 (Enabled: %2) 总计: %1 (已激活的: %2) @@ -3550,6 +3885,34 @@ For more information on using this console, type %6. 总额 + + RestoreWalletActivity + + Restore Wallet + Title of progress window which is displayed when wallets are being restored. + 恢复钱包 + + + Restoring Wallet <b>%1</b>… + Descriptive text of the restore wallets progress window which indicates to the user that wallets are currently being restored. + 正在恢复钱包 <b>%1</b>… + + + Restore wallet failed + Title of message box which is displayed when the wallet could not be restored. + 恢复钱包失败 + + + Restore wallet warning + Title of message box which is displayed when the wallet is restored with some warning. + 恢复钱包警告 + + + Restore wallet message + Title of message box which is displayed when the wallet is successfully restored. + 恢复钱包消息 + + SendCoinsDialog @@ -3584,10 +3947,6 @@ For more information on using this console, type %6. Fee: 费用: - - Dust: - 零散金额: - Inputs… 输入… @@ -3712,10 +4071,6 @@ For more information on using this console, type %6. Copy bytes 复制字节 - - Copy dust - 复制零散金额 - Copy change 复制找零金额 @@ -3724,10 +4079,6 @@ For more information on using this console, type %6. %1 (%2 blocks) %1 (%2 区块) - - This will produce a Partially Signed Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet. - 它将生成一个部分签名交易 (PSBT), 您可以将其保存或复制, 然后使用例如离线的 %1 钱包, 或兼容 PSBT 的硬件钱包进行签名. - using 使用 @@ -3736,10 +4087,6 @@ For more information on using this console, type %6. %1 to %2 %1 到 %2 - - Are you sure you want to send? - 您确定要发出吗? - <b>(%1 of %2 entries displayed)</b> <b>(在%2中%1个项目显示出来)</b> @@ -3764,10 +4111,6 @@ For more information on using this console, type %6. %1 to '%2' %1 到 '%2' - - Do you want to draft this transaction? - 您想要起草这笔交易吗? - %1 funds only 仅支持%1资金 @@ -3816,14 +4159,6 @@ For more information on using this console, type %6. Confirm send coins 确认发送货币 - - Confirm transaction proposal - 确认交易提案 - - - Create Unsigned - 创建未签名的 - Save Transaction Data 保存交易数据 @@ -3837,8 +4172,28 @@ For more information on using this console, type %6. 仅可见余额: - Send - 发送 + Creates a Partially Signed Blockchain Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet. + 创建一个部分签名的区块链交易(PSBT),以与例如离线 %1 钱包或与PSBT兼容的硬件钱包。 + + + Do you want to create this transaction? + 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. + 您想创建这笔交易吗? + + + Please, review your transaction proposal. This will produce a Partially Signed Blockchain Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet. + 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. + 请检查您的交易提案。这将生成一个部分签名区块链交易(PSBT),您可以保存或复制它,然后使用例如离线 %1 钱包或兼容 PSBT 的硬件钱包进行签名。 + + + Please, review your transaction. You can create and send this transaction or create a Partially Signed Blockchain Transaction (PSBT), which you can save or copy and then sign with, e.g., an offline %1 wallet, or a PSBT-compatible hardware wallet. + 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. + 请检查您的交易。您可以创建并发送此交易,或创建一个部分签名区块链交易(PSBT),您可以保存或复制它,然后使用例如离线 %1 钱包或兼容 PSBT 的硬件钱包进行签名。 + + + Please, review your transaction. + Text to prompt a user to review the details of the transaction they are attempting to send. + 请检查您的交易。 To review recipient list click "Show Details…" @@ -3968,21 +4323,16 @@ For more information on using this console, type %6. A message that was attached to the dash: URI which will be stored with the transaction for your reference. Note: This message will not be sent over the Dash network. 附加在Dash付款协议URI中的信息,会和交易内容一并存储,可供您参考。提示:此信息不会发送到Dash网络上。 + + + SendConfirmationDialog - This is an unauthenticated payment request. - 这是一个未经验证的支付请求。 - - - This is an authenticated payment request. - 这是一个已经验证的支付请求。 - - - Pay To: - 支付给: + Send + 发送 - Memo: - 便条: + Create Unsigned + 创建未签名交易 @@ -4191,20 +4541,9 @@ For more information on using this console, type %6. TransactionDesc - - Open for %n more block(s) - 到下%n个区块产生前可修改 - - - Open until %1 - 至 %1 个区块时开启 - - - conflicted - 发现冲突 - 0/unconfirmed, %1 + 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. 0/未确认,%1 @@ -4217,22 +4556,32 @@ For more information on using this console, type %6. abandoned + 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. 已丢弃 + + conflicted with a transaction with %1 confirmations + 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. + 与有 %1 次确认的交易冲突 + %1/unconfirmed + 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, and still not locked via ChainLocks. %1/未确认 %1 confirmations + 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 or locked via ChainLocks. 确认%1次 locked via ChainLocks + 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 and has been locked by ChainLocks. 经链锁锁定 verified via InstantSend + 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 has been locked by InstantSend. 经即时支付验证 @@ -4385,14 +4734,6 @@ For more information on using this console, type %6. Address / Label 地址/标签 - - Open for %n more block(s) - 到下%n个区块产生前可修改 - - - Open until %1 - 至 %1 个区块时开启 - Unconfirmed 未确认的 @@ -4644,6 +4985,11 @@ For more information on using this console, type %6. Show address &QR code 显示地址 &二维码 + + Show in %1 + 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. + 在 %1 中显示 + Export Transaction History 导出交易历史 @@ -4836,10 +5182,6 @@ Go to File > Open Wallet to load a wallet. dash-core - - Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee. - 费用估算失败. 备用费用已禁用. 请等待几个区块或启用-fallbackfee。 - 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 如果此前包未完全关闭并且上次使用较新版本的Berkeley DB的构建加载, 则可能发生此错误. 如果是这样, 请使用上次加载此钱包的软件. @@ -4912,10 +5254,6 @@ Go to File > Open Wallet to load a wallet. Failed to listen on any port. Use -listen=0 if you want this. 监听端口失败。如果想使用此项,可设定-listen=0。 - - -maxtxfee is set very high! Fees this large could be paid on a single transaction. - -maxtxfee 设定了很高的金额!这是您一次交易就有可能付出的手续费。 - Found unconfirmed denominated outputs, will wait till they confirm to continue. 未确认的面额化输出,将等待他们确认后继续。 @@ -4924,10 +5262,6 @@ Go to File > Open Wallet to load a wallet. Invalid -socketevents ('%s') specified. Only these modes are supported: %s 指定的 -socketevents ('%s') 无效. 仅支持以下模式: %s - - Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions) - 设定 -maxtxfee=<金额> 的金额无效<amount>:'%s' (必须大于等于最低中继手续费%s 以避免交易无法被确认) - SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is supported SQLite数据库: 未知的sqlite钱包架构版本 %d. 仅支持 %d 版本 @@ -4936,6 +5270,10 @@ Go to File > Open Wallet to load a wallet. Transaction index can't be disabled with governance validation enabled. Either start with -disablegovernance command line switch or enable transaction index. 管理验证启动后不能禁用交易索引. 可以使用-disablegovernance命令行选项进行关闭, 或者启用交易索引. + + Unsupported category-specific logging level -loglevel=%s. Expected -loglevel=<category>:<loglevel>. Valid categories: %s. Valid loglevels: %s. + 未支撑的类别记录级别 -loglevel=%s. Expected -loglevel=<category>:<loglevel>. 有效的 类别: %s. 有效的记录级别: %s. + Can't mix: no compatible inputs found! 无法混合:没有找到兼容的输入! @@ -4944,6 +5282,14 @@ Go to File > Open Wallet to load a wallet. Entry exceeds maximum size. 条目超过最大值。 + + Error upgrading evo database for EHF + 升级EHF的 evo 数据库时出错 + + + Failed to commit Evo database + 无法提交资料到 Evo 数据库 + Found enough users, signing ( waiting %s ) 用户数已满足,开始签名 (等待 %s) @@ -4968,18 +5314,14 @@ Go to File > Open Wallet to load a wallet. Insufficient funds. 余额不足。 - - Invalid amount for -discardfee=<amount>: '%s' - 设定 -discardfee=<金额> 的金额无效:'%s' - - - Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s) - 设定 -paytxfee=<金额> 的金额无效:'%s' (至少要有%s) - Invalid minimum number of spork signers specified with -minsporkkeys 无效的最少数叉勺签名人以 -minsporkkeys 标识 + + Listening for incoming connections failed (listen returned error %s) + 监听外来连接失败(侦听返回错误%s) + Lock is already in place. 已锁定。 @@ -5036,6 +5378,10 @@ Go to File > Open Wallet to load a wallet. Synchronizing governance objects… 正在同步治理对象… + + Transaction change output index out of range + 交易变更输出索引超出范围 + Unable to start HTTP server. See debug log for details. 无法启动HTTP服务,查看日志获取更多信息。 @@ -5044,6 +5390,10 @@ Go to File > Open Wallet to load a wallet. Unknown response. 未知响应。 + + Unsupported global logging level -loglevel=%s. Valid values: %s. + 不支持的全局记录级别 -loglevel=%s. 有效值: %s. + User Agent comment (%s) contains unsafe characters. 用户代理评论(%s)包含不安全的字符。 @@ -5108,10 +5458,6 @@ Go to File > Open Wallet to load a wallet. Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments. 网络版本字符串的总长度 (%i) 超过最大长度 (%i) 了。请减少 uacomment 参数的数量或大小。 - - Transaction needs a change address, but we can't generate it. Please call keypoolrefill first. - 交易需要一个零钱地址, 但我们无法生成它. 请先联系 keypoolrefill. - WARNING! Failed to replenish keypool, please unlock your wallet to do so. 警告!无法补充公钥池,请解锁您的钱包。 @@ -5188,10 +5534,6 @@ Go to File > Open Wallet to load a wallet. Error: No addresses available. 错误: 没有可用地址. - - Exceeded max tries. - 超过最大尝试次数. - Failed to create backup %s! 无法创建备份%s! @@ -5232,10 +5574,6 @@ Go to File > Open Wallet to load a wallet. Invalid P2P permission: '%s' 无效的 P2P 权限: '%s' - - Invalid amount for -fallbackfee=<amount>: '%s' - 设定-fallbackfee=<amount>的金额无效:'%s' - Invalid masternodeblsprivkey. Please see documentation. 无效的 masternodeblsprivkey。请阅读文档。 @@ -5372,10 +5710,6 @@ Go to File > Open Wallet to load a wallet. Unable to open %s for writing 无法打开 %s 来写入 - - Unable to parse -maxuploadtarget: '%s' (possible integer overflow?) - 无法解析 -maxuploadtarget: '%s' (可能整数溢出?) - Unknown -blockfilterindex value %s. 未知 -blockfilterindex 值 %s. @@ -5384,10 +5718,6 @@ Go to File > Open Wallet to load a wallet. Unknown new rules activated (versionbit %i) 未知的新规则被激活(versionbit %i) - - Upgrading UTXO database - 升级UTXO数据库 - Verifying blocks… 验证区块中… @@ -5448,10 +5778,6 @@ Go to File > Open Wallet to load a wallet. Cannot obtain a lock on data directory %s. %s is probably already running. 无法锁定数据目录 %s。%s 可能已经在运行。 - - Cannot upgrade a non HD wallet from version %i to version %i which is non-HD wallet. Use upgradetohd RPC - 无法将非 HD 钱包从版本 %i 升级到版本 %i, 后者非 HD 钱包. 请使用 upgradetohd RPC - Distributed under the MIT software license, see the accompanying file %s or %s 在MIT协议下分发,参见附带的 %s 文件或 %s @@ -5484,6 +5810,10 @@ Go to File > Open Wallet to load a wallet. Failed to rename invalid peers.dat file. Please move or delete it and try again. 无法重命名无效的 peers.dat 文件. 请移动或删除它后再尝试. + + Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable %s. + 手续费估算失败。备用费用已禁用。请等待几个区块或启用 %s。 + File %s already exists. If you are sure this is what you want, move it out of the way first. 文件 %s 已经存在. 如果您确定这是您想要, 请先将其移走. @@ -5496,6 +5826,10 @@ Go to File > Open Wallet to load a wallet. Incorrect or no devnet genesis block found. Wrong datadir for devnet specified? devnet的创世区块错误或未找到. devnet的数据目录错误? + + Invalid amount for %s=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions) + %s=<amount> 的金额无效:'%s'(必须至少为最小中继费用 %s 以防止交易卡住) + 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. 无效或损坏的 peers.dat 文件 (%s). 如果您认为这是一个 bug, 请报告给 %s. 作为替代方法, 您可以将文件 (%s) 移走(重命名、移动或删除), 以便在下次启动时创建一个新的文件. @@ -5512,6 +5846,10 @@ Go to File > Open Wallet to load a wallet. No wallet file format provided. To use createfromdump, -format=<format> must be provided. 没有提供钱包文件格式. 要使用 createfromdump, 必须提供 -format=<format>. + + Outbound connections restricted to CJDNS (-onlynet=cjdns) but -cjdnsreachable is not provided + 出站连接限制为 CJDNS (-onlynet=cjdns),但未提供 -cjdnsreachable + Outbound connections restricted to Tor (-onlynet=onion) but the proxy for reaching the Tor network is explicitly forbidden: -onion=0 出站连接限制为 Tor 网络 (-onlynet=onion), 但用于访问 Tor 网络的代理被明确禁用: -onion=0. @@ -5520,6 +5858,10 @@ Go to File > Open Wallet to load a wallet. 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 出站连接限制为 Tor 网络 (-onlynet=onion), 但未提供访问 Tor 网络的代理: 没有指定 -proxy, -onion 或 -listenonion 参数 + + Outbound connections restricted to i2p (-onlynet=i2p) but -i2psam is not provided + 出站连接限制为 i2p (-onlynet=i2p),但未提供 -i2psam + Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly. 请检查电脑的日期时间设置是否正确!时间错误可能会导致 %s 运行异常。 @@ -5532,10 +5874,6 @@ Go to File > Open Wallet to load a wallet. Prune mode is incompatible with -reindex-chainstate. Use full -reindex instead. 修剪模式与 -reindex-chainstate 不兼容. 使用完整的 -reindex. - - The block index db contains a legacy 'txindex'. To clear the occupied disk space, run a full -reindex, otherwise ignore this error. This error message will not be displayed again. - 区块索引数据库包含一个遗留的 'txindex'. 要清理占用的磁盘空间, 请执行完整的 -reindex, 否则忽略此错误. 此错误信息将不会再显示. - This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection. 这是您能支付的最大交易手续费(除正常费用外), 用于避开部分交易优先处理, 而非常规的选择. @@ -5548,6 +5886,10 @@ Go to File > Open Wallet to load a wallet. This is the transaction fee you may pay when fee estimates are not available. 这是在费用估计不可用时您可能会支付的交易费。 + + Transaction requires one destination of non-0 value, a non-0 feerate, or a pre-selected input + 交易需要一个非零值的目标地址、非零的费率或预先选定的输入 + Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate. 无法重播区块. 您需要使用 -reindex-chainstate命令来重建数据库. @@ -5556,6 +5898,10 @@ Go to File > Open Wallet to load a wallet. Unknown wallet file format "%s" provided. Please provide one of "bdb" or "sqlite". 提供了未知的钱包文件格式 "%s". 请提供 "bdb" 或 "sqlite"中的一个. + + Unsupported chainstate database format found. Please restart with -reindex-chainstate. This will rebuild the chainstate database. + 发现不支持的链状态数据库格式。请使用 -reindex-chainstate 重启。这将重建链状态数据库。 + Warning: Dumpfile wallet format "%s" does not match command line specified format "%s". 警告: 转储文件钱包格式 "%s" 与命令行指定的格式 "%s" 不匹配. @@ -5596,10 +5942,30 @@ Go to File > Open Wallet to load a wallet. -rpcport must be specified when -devnet and -server are specified 当 -devnet 和 -server 被指定时, 必须指定 -rpcport + + -statsbatchsize cannot be configured with a negative value. + -statsbatchsize 不能配置为负值。 + + + -statsduration cannot be configured with a negative value. + -statsduration 不能配置为负值。 + A fatal internal error occurred, see debug.log for details 发生了严重的内部错误, 请参阅debug.log了解详细信息 + + Cannot create socket (socket() returned error %s) + 无法创建套接字(socket() 返回错误 %s) + + + Cannot get socket address for %s + 无法获取 %s 的套接字地址 + + + Cannot init Statsd client + 无法初始化 Statsd 客户端 + Cannot resolve -%s address: '%s' 无法解析 - %s 地址: '%s' @@ -5644,10 +6010,6 @@ Go to File > Open Wallet to load a wallet. Error reading next record from wallet database 从钱包数据库读取下个记录失败 - - Error upgrading chainstate database - 升级链状态数据库出错 - Loading P2P addresses… 正在加载P2P地址… @@ -5768,10 +6130,70 @@ Go to File > Open Wallet to load a wallet. %s corrupt. Try using the wallet tool dash-wallet to salvage or restoring a backup. %s 已损坏. 请尝试使用钱包工具 dash-wallet 来挽救或恢复备份. + + %s is set very high! Fees this large could be paid on a single transaction. + %s 设置得非常高!如此高的费用可能会在单笔交易中支付。 + + + %s request to listen on port %u. This port is considered "bad" and thus it is unlikely that any Dash Core peers connect to it. See doc/p2p-bad-ports.md for details and a full list. + %s 请求在端口上监听 %u. 该端口被认为是"不良",因此任何达世币核心程序的对等用户不太可能连接它。有关详细信息和完整列表,请参见 doc/p2p-bad-ports.md. + + + Cannot provide specific connections and have addrman find outgoing connections at the same time. + 无法提供特定的连接,并让Addrman同时查找传出连接。 + + + Failed to upgrade Evo database + 升级 Evo 数据库失败 + + + Fee needed > fee paid + 所需费用 > 已付费用 + + + Host %s on unsupported network + 主机 %s 在不支持的网络上 + + + Invalid amount for %s=<amount>: '%s' (must be at least %s) + %s=<amount> 的金额无效:'%s'(必须至少为 %s) + + + Invalid amount for %s=<amount>: '%s' + %s=<amount> 的金额无效:'%s' + + + Invalid port specified in %s: '%s' + 在 %s 中指定的端口无效:'%s' + Last successful action was too recent. 上一次成功操作才完成。 + + Missing solving data for estimating transaction size + 缺少用于估算交易大小的解决数据 + + + No host specified + 未指定主机 + + + No host specified, malformed URL + 未指定主机,格式错误的 URL + + + No text before the scheme delimiter, malformed URL + 方案分隔符之前没有文本,格式错误的 URL + + + Port must be between %d and %d, supplied %d + 端口必须在 %d 和 %d 之间,提供的是 %d + + + Socket not initialized, cannot send message + 套接字未初始化,无法发送消息 + The source code is available from %s. 源代码可以在 %s 获得。 @@ -5800,6 +6222,10 @@ Go to File > Open Wallet to load a wallet. Transaction fees are too high. 交易费用过高。 + + Transaction needs a change address, but we can't generate it. + 交易需要找零地址,但我们无法生成它。 + Transaction not valid. 交易无效。 @@ -5820,6 +6246,18 @@ Go to File > Open Wallet to load a wallet. Unable to locate enough non-denominated funds for this transaction. 无法找到足够的未面额化资金来完成本次交易. + + Unable to lookup host %s + 无法查找主机 %s + + + Unable to parse -maxuploadtarget: '%s' + 无法解析 -maxuploadtarget:'%s' + + + Unable to send message to %s (::sendto() returned error %s) + 无法向 %s 发送消息(::sendto() 返回错误 %s) + Unable to sign spork message, wrong key? 无法签署交叉信息,错误的密钥? @@ -5832,6 +6270,10 @@ Go to File > Open Wallet to load a wallet. Unknown state: id = %u 未知状态:id = %u + + Unsupported URL scheme, must begin with udp:// + 不支持的 URL 方案,必须以 udp:// 开头 + Unsupported logging category %s=%s. 不支持的日志记录类别 %s=%s. diff --git a/src/qt/locale/dash_zh_TW.ts b/src/qt/locale/dash_zh_TW.ts index 324b39a67aac..644c48f573e7 100644 --- a/src/qt/locale/dash_zh_TW.ts +++ b/src/qt/locale/dash_zh_TW.ts @@ -65,14 +65,6 @@ C&hoose 選取(&C) - - Sending addresses - 付款位址 - - - Receiving addresses - 收款位址 - These are your Dash addresses for sending payments. Always check the amount and the receiving address before sending coins. 這些是你要付款過去的達世幣位址。在付錢之前,務必要檢查金額和收款位址是否正確。 @@ -115,6 +107,14 @@ An error message. %1 is a stand-in argument for the name of the file we attempted to save to. 嘗試將位址清單儲存到 %1 時出錯,請重試。 + + Sending addresses - %1 + 發送地址 - %1 + + + Receiving addresses - %1 + 接收地址 - %1 + Exporting Failed 匯出失敗 @@ -284,10 +284,22 @@ The passphrase entered for the wallet decryption was incorrect. 輸入要用來解密錢包的密碼不對。 + + 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 23.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. + 輸入用於錢包解密的密碼不正確。其中包含空字元(即零位元組)。如果密碼是使用 23.0 之前版本的軟體設定的,請僅使用第一個空字元之前(但不包括)的字元重試。如果成功,請設定新密碼以避免將來出現此問題。 + Wallet passphrase was successfully changed. 成功更改錢包的密碼。 + + Passphrase change failed + 密碼變更失敗 + + + 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 23.0, please try again with only the characters up to — but not including — the first null character. + 輸入用於錢包解密的舊密碼不正確。其中包含空字元(即零位元組)。如果密碼是使用 23.0 之前版本的軟體設定的,請僅使用第一個空字元之前(但不包括)的字元重試。 + Warning: The Caps Lock key is on! 警告: 大寫字母鎖定作用中! @@ -392,10 +404,6 @@ &Load PSBT from file… &從檔案載入 PSBT… - - Load PSBT from clipboard… - 從剪貼簿載入 PSBT... - &Sending addresses 發送位址(&S) @@ -428,10 +436,6 @@ &Window 視窗(&W) - - Minimize - 最小化 - Zoom 放大 @@ -484,14 +488,6 @@ Modify configuration options for %1 修改 %1 的設定選項 - - &Show / Hide - 顯示或隱藏(&S) - - - Show or hide the main Window - 顯示或隱藏主視窗 - Encrypt the private keys that belong to your wallet 把錢包中的密鑰加密 @@ -556,10 +552,6 @@ Show wallet repair options 顯示修復錢包選項 - - Open Wallet &Configuration File - 開啟錢包配置文件(&C) - Open configuration file 開啟配置文件 @@ -614,10 +606,18 @@ Show information about %1 顯示有關%1 的相關信息 + + Load PSBT from &clipboard… + 從剪貼簿載入 PSBT… + Open debugging and diagnostic console 開啟偵錯和診斷控制台 + + Open &wallet configuration file + 開啟錢包設定檔(&W) + Open a dash: URI 打開達世幣: URI @@ -626,6 +626,16 @@ Create a new wallet 創建一個新錢包 + + Restore Wallet… + Name of the menu item that restores wallet from a backup file. + 還原錢包… + + + Restore a wallet from a backup file + Status tip for Restore Wallet menu item + 從備份檔還原錢包 + Close all wallets 關閉所有錢包 @@ -646,10 +656,34 @@ Mask the values in the Overview tab 屏蔽「概覽」標籤中的值 + + Wallet Data + Name of the wallet data file format. + 錢包資料 + + + Load Wallet Backup + The title for Restore Wallet File Windows + 載入錢包備份 + + + Restore Wallet + Title of pop-up window shown when the user is attempting to restore a wallet. + 還原錢包 + + + Wallet Name + Label of the input field where the name of the wallet is entered. + 錢包名稱 + &Settings 設定(&S) + + &Minimize + 最小化(&M) + &Help 說明(&H) @@ -666,6 +700,14 @@ View Governance Proposals 查看治理提案 + + &Hide + 隱藏(&H) + + + S&how + 顯示(&H) + %n active connection(s) to Dash network A substring of the tooltip. @@ -687,6 +729,14 @@ Close Wallet… 關閉錢包… + + Load Partially Signed Blockchain Transaction + 讀取部分簽名的區塊鏈交易 + + + Load Partially Signed Blockchain Transaction from clipboard + 從剪貼板中讀取部分簽名的區塊鏈交易 + Create Wallet… 創建錢包… @@ -739,10 +789,6 @@ Processing blocks on disk… 正在處理磁碟裡的區塊資料… - - Reindexing blocks on disk… - 正在為磁碟裡的區塊重建索引… - Connecting to peers… 正在連接其他對等用戶群… @@ -896,10 +942,6 @@ Coin Selection 選擇錢幣 - - Dust: - 零散錢: - After Fee: 計費後金額: @@ -1000,10 +1042,6 @@ Copy bytes 複製位元組數 - - Copy dust - 複製零散金額 - Copy change 複製找零金額 @@ -1016,18 +1054,6 @@ (%1 locked) (%1 鎖定) - - yes - - - - no - - - - This label turns red if any recipient receives an amount smaller than the current dust threshold. - 如果任何一個收款人收到的金額比當前零散錢的閾值還小的話,這個標籤將變為紅色。 - Can vary +/- %1 duff(s) per input. 每組輸入可能有 +/- %1 個 duff(s) 的誤差。 @@ -1241,18 +1267,102 @@ Filter proposal list 過濾提案列表 + + Masternode Count: + 主節點數量: + + + Number of masternodes this wallet can vote with (masternodes for which this wallet holds the voting key) + 此錢包可投票的主節點數量(此錢包持有投票金鑰的主節點) + Proposal Count: 提案數量: + + Create Proposal + 創建提案 + Filter by Title 按標題過濾 + + Unavailable + 不可用 + + + A synced node and an unlocked wallet are required. + 需要已同步的節點和已解鎖的錢包。 + + + Vote Yes + 投贊成票 + + + Vote No + 投反對票 + + + Vote Abstain + 投棄權票 + Proposal Info: %1 提案信息: %1 + + Voting Failed + 投票失敗 + + + No wallet available. + 沒有可用的錢包。 + + + No masternode voting keys found in wallet. + 在錢包中未找到主節點投票金鑰。 + + + Please select a proposal to vote on. + 請選擇要投票的提案。 + + + Unable to unlock wallet. + 無法解鎖錢包。 + + + Unable to get masternode list. Please try again later. + 無法取得主節點列表。請稍後重試。 + + + Masternode %1 not found + 未找到主節點 %1 + + + Failed to sign vote for masternode %1 + 為主節點 %1 簽署投票失敗 + + + Masternode %1: %2 + 主節點 %1:%2 + + + Voted successfully %n time(s) + 成功投票 %n 次 + + + Failed to vote %n time(s) + 投票失敗 %n 次 + + + Errors: + 錯誤: + + + Voting Results + 投票結果 + HelpMessageDialog @@ -1323,13 +1433,17 @@ Use a custom data directory: 使用自定的資料目錄: - - (of %1 GB needed) - (需要額外 %1 GB) + + %n GB of space available + 可用空間 %n GB - - (%1 GB needed for full chain) - (完整區塊鏈需要%1 GB) + + (of %n GB needed) + (需要 %n GB) + + + (%n GB needed for full chain) + (完整區塊鏈需要 %n GB) At least %1 GB of data will be stored in this directory, and it will grow over time. @@ -1361,6 +1475,13 @@ 錯誤 + + LoadWalletsActivity + + Loading wallets… + 正在載入錢包… + + MasternodeList @@ -1553,6 +1674,11 @@ URI: URI: + + Paste address from clipboard + Tooltip text for button that allows you to paste an address that is in your clipboard. + 從剪貼簿貼上地址 + OpenWalletActivity @@ -1663,6 +1789,16 @@ An Options window setting to set subtracting the fee from a sending amount as default. 預設把金額減去手續費(&F) + + Enable &PSBT controls + An options window setting to enable PSBT controls. + 啟用 PSBT 控制項(&P) + + + Whether to show PSBT controls. + Tooltip text for options window setting that enables PSBT controls. + 是否顯示 PSBT 控制項。 + Whether to keep the specified custom change address or not. 是否保留指定的自訂找零位址。 @@ -1806,20 +1942,20 @@ https://explore.transifex.com/dash/dash/ https://explore.transifex.com/dash/dash/ - Options set in this dialog are overridden by the command line or in the configuration file: - 此對話框中設置的選項被命令行或配置文件覆蓋: + Third-party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items.<br/>%s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |. + 在交易分頁中以內容選單項目出現的第三方 URL(例如區塊瀏覽器)。<br/>URL 中的 %s 將替換為交易雜湊。多個 URL 用豎線 | 分隔。 - 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. - 當視窗關閉時,把應用程式縮到最小,而不是結束。當勾選這個選項時,只能夠用選單中的結束來關掉應用程式。 + &Third-party transaction URLs + 第三方交易 URL(&T) - Third party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items.<br/>%s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |. - 在交易頁籤的情境選單出現的第三方(比如說區塊探索網站)網址連結。<br/>網址中的 %s 會被取代為交易的雜湊值。可以用直線符號 | 來分隔多個連結。 + Options set in this dialog are overridden by the command line or in the configuration file: + 此對話框中設置的選項被命令行或配置文件覆蓋: - &Third party transaction URLs - 第三方交易網址(&T) + 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. + 當視窗關閉時,把應用程式縮到最小,而不是結束。當勾選這個選項時,只能夠用選單中的結束來關掉應用程式。 Whether to show coin control features or not. @@ -1963,14 +2099,22 @@ https://explore.transifex.com/dash/dash/ Confirm options reset + Window title text of pop-up window shown when the user has chosen to reset options. 確認重設選項 Client restart required to activate changes. + Text explaining that the settings changed will not come into effect until the client is restarted. 需要重新啟動客戶端軟體來讓改變生效。 + + Current settings will be backed up at "%1". + 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. + 目前設定將備份至「%1」。 + Client will be shut down. Do you want to proceed? + Text asking the user to confirm if they would like to proceed with a client shutdown. 客戶端軟體將會關閉,確定要繼續嗎? @@ -2243,6 +2387,10 @@ https://explore.transifex.com/dash/dash/ Failed to sign transaction: %1 未能簽署交易: %1 + + Cannot sign inputs while wallet is locked. + 錢包被鎖定時無法簽署輸入。 + Could not sign any more inputs. 無法簽署更多輸入。 @@ -2487,6 +2635,181 @@ Due to discontinued support, you should request the merchant to provide you with 狀態 + + ProposalWizard + + Create Governance Proposal + 創建治理提案 + + + Enter proposal details + 輸入提案詳情 + + + A fee will be burned when you prepare the proposal. + 準備提案時將銷毀一筆費用。 + + + Proposal &name + 提案名稱(&N) + + + &Description URL + 描述 URL(&D) + + + Payment &address + 支付地址(&A) + + + Payment &amount + 支付金額(&A) + + + The amount to request in a single payment + 單次支付中請求的金額 + + + &First payment + 首次支付(&F) + + + Pa&yments + 支付次數(&Y) + + + To&tal amount + 總金額(&T) + + + Proposal &fee + 提案費用(&F) + + + Next + 下一步 + + + Review proposal JSON and validate. + 檢查提案 JSON 並驗證。 + + + Hex-encoded JSON + 十六進位編碼的 JSON + + + Back + 返回 + + + Validate + 驗證 + + + Prepare (burn fee) and wait for confirmations. + 準備(銷毀費用)並等待確認。 + + + Copy + 複製 + + + At 1/6 confirmations: can be relayed and queued. At 6/6: accepted and processed. + 1/6 確認時:可以中繼和排隊。6/6 時:接受並處理。 + + + Confirmations progress + 確認進度 + + + Shows progress toward the required number of confirmations for the proposal fee transaction. + 顯示提案費用交易所需確認數的進度。 + + + Estimated time remaining: - + 預計剩餘時間:- + + + Prepare Proposal + 準備提案 + + + You can submit after 1 confirmation. At 6 confirmations it is accepted and processed. + 1 次確認後即可提交。6 次確認後將被接受並處理。 + + + Proposal ID: + 提案 ID: + + + Submit Proposal + 提交提案 + + + Close + 關閉 + + + Valid + 有效 + + + Invalid: %1 + 無效:%1 + + + Burn %1 + 銷毀 %1 + + + Burn %1 to create the fee transaction? + 銷毀 %1 以創建費用交易? + + + Prepare failed + 準備失敗 + + + Confirmations: %1 / %2 required + 確認數:%1 / 需要 %2 + + + Estimated time remaining: Ready + 預計剩餘時間:就緒 + + + Estimated time remaining: %n minute(s) + 預計剩餘時間:%n 分鐘 + + + Your proposal was submitted successfully. + 您的提案已成功提交。 + + + Already submitted + 已提交 + + + This proposal has already been submitted. + 此提案已經提交。 + + + Submission failed + 提交失敗 + + + Proposal submitted + 提案已提交 + + + A fee of %1 will be burned when you prepare the proposal. + 準備提案時將銷毀 %1 的費用。 + + + Prepare (burn %1) and wait for %2 confirmations. + 準備(銷毀 %1)並等待 %2 次確認。 + + QObject @@ -2876,14 +3199,6 @@ Due to discontinued support, you should request the merchant to provide you with Version 版本 - - Whether the peer requested us to relay transactions. - 對方是否請求我們中繼交易。 - - - Wants Tx Relay - 想要交易中繼 - High bandwidth BIP152 compact block relay: %1 高頻寬 BIP152 緊湊區塊中繼器: %1 @@ -2989,6 +3304,14 @@ Due to discontinued support, you should request the merchant to provide you with To specify a non-default location of the blocks directory use the '%1' option. 要指定區塊目錄的非預設位置,請使用“%1”選項。 + + Local Addresses + 本機地址 + + + Network addresses that your Dash node is currently using to communicate with other nodes. + 您的 Dash 節點目前用於與其他節點通訊的網路地址。 + Number of regular Masternodes 常規主節點數量 @@ -3081,6 +3404,14 @@ Due to discontinued support, you should request the merchant to provide you with Services 服務 + + Whether we relay transactions to this peer. + 是否向此對等節點中繼交易。 + + + Transaction Relay + 交易中繼 + Connection Time 連線時間 @@ -3229,6 +3560,10 @@ Due to discontinued support, you should request the merchant to provide you with Network activity disabled 被禁用的網絡活動 + + None + + Total: %1 (Enabled: %2) 總計: %1 (已啟用: %2) @@ -3550,6 +3885,34 @@ For more information on using this console, type %6. 要求金額 + + RestoreWalletActivity + + Restore Wallet + Title of progress window which is displayed when wallets are being restored. + 還原錢包 + + + Restoring Wallet <b>%1</b>… + Descriptive text of the restore wallets progress window which indicates to the user that wallets are currently being restored. + 正在還原錢包 <b>%1</b>… + + + Restore wallet failed + Title of message box which is displayed when the wallet could not be restored. + 還原錢包失敗 + + + Restore wallet warning + Title of message box which is displayed when the wallet is restored with some warning. + 還原錢包警告 + + + Restore wallet message + Title of message box which is displayed when the wallet is successfully restored. + 還原錢包訊息 + + SendCoinsDialog @@ -3584,10 +3947,6 @@ For more information on using this console, type %6. Fee: 手續費: - - Dust: - 零散錢: - Inputs… 輸入… @@ -3712,10 +4071,6 @@ For more information on using this console, type %6. Copy bytes 複製位元組數 - - Copy dust - 複製零散錢 - Copy change 複製找零金額 @@ -3724,10 +4079,6 @@ For more information on using this console, type %6. %1 (%2 blocks) %1 (%2 個區塊) - - This will produce a Partially Signed Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet. - 這將產生一個部分簽名的交易(PSBT),您可以儲存或複製該交易,然後使用例如離線 %1 錢包,或 PSBT 相容的硬體錢包。 - using 使用 @@ -3736,10 +4087,6 @@ For more information on using this console, type %6. %1 to %2 %1 到 %2 - - Are you sure you want to send? - 你確定要付錢出去嗎? - <b>(%1 of %2 entries displayed)</b> <b>(在 %2 中 %1 個項目顯示出來)</b> @@ -3764,10 +4111,6 @@ For more information on using this console, type %6. %1 to '%2' %1 to '%2' - - Do you want to draft this transaction? - 您想起草這筆交易嗎? - %1 funds only 只限 %1 的資金 @@ -3816,14 +4159,6 @@ For more information on using this console, type %6. Confirm send coins 確認發送資金 - - Confirm transaction proposal - 確認交易提案 - - - Create Unsigned - 建立未簽名的 - Save Transaction Data 保存交易數據 @@ -3837,8 +4172,28 @@ For more information on using this console, type %6. 僅供查閱的餘額: - Send - 發送 + Creates a Partially Signed Blockchain Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet. + 創建一個部分簽名的區塊鏈交易(PSBT),以與例如離線 %1 錢包或與PSBT兼容的硬件錢包。 + + + Do you want to create this transaction? + 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. + 您想創建這筆交易嗎? + + + Please, review your transaction proposal. This will produce a Partially Signed Blockchain Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet. + 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. + 請檢查您的交易提案。這將生成一個部分簽名區塊鏈交易(PSBT),您可以儲存或複製它,然後使用例如離線 %1 錢包或相容 PSBT 的硬體錢包進行簽名。 + + + Please, review your transaction. You can create and send this transaction or create a Partially Signed Blockchain Transaction (PSBT), which you can save or copy and then sign with, e.g., an offline %1 wallet, or a PSBT-compatible hardware wallet. + 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. + 請檢查您的交易。您可以創建並發送此交易,或創建一個部分簽名區塊鏈交易(PSBT),您可以儲存或複製它,然後使用例如離線 %1 錢包或相容 PSBT 的硬體錢包進行簽名。 + + + Please, review your transaction. + Text to prompt a user to review the details of the transaction they are attempting to send. + 請檢查您的交易。 To review recipient list click "Show Details…" @@ -3968,21 +4323,16 @@ For more information on using this console, type %6. A message that was attached to the dash: URI which will be stored with the transaction for your reference. Note: This message will not be sent over the Dash network. 附加在達世幣付款協議 URI 中的訊息,會和交易內容一起存起來,給你自己做參考。注意: 這個訊息不會送到達世幣網路上。 + + + SendConfirmationDialog - This is an unauthenticated payment request. - 這是一個未認證的付款請求。 - - - This is an authenticated payment request. - 這是一個已認證的付款請求。 - - - Pay To: - 付給: + Send + 發送 - Memo: - 備註: + Create Unsigned + 創建未簽名交易 @@ -4191,20 +4541,9 @@ For more information on using this console, type %6. TransactionDesc - - Open for %n more block(s) - 到下 %n 個區塊產生前可修改 - - - Open until %1 - 至 %1 個數據塊時開啟 - - - conflicted - 發生衝突 - 0/unconfirmed, %1 + 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. 0 /未確認, %1 @@ -4217,22 +4556,32 @@ For more information on using this console, type %6. abandoned + 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. 放棄了 + + conflicted with a transaction with %1 confirmations + 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. + 與有 %1 次確認的交易衝突 + %1/unconfirmed + 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, and still not locked via ChainLocks. %1 次/未確認 %1 confirmations + 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 or locked via ChainLocks. 確認 %1 次 locked via ChainLocks + 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 and has been locked by ChainLocks. 通過 ChainLocks 鎖定的 verified via InstantSend + 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 has been locked by InstantSend. 經即時到帳系統核實 @@ -4385,14 +4734,6 @@ For more information on using this console, type %6. Address / Label 位址 / 標籤 - - Open for %n more block(s) - 到下 %n 個區塊產生前可修改 - - - Open until %1 - 至 %1 個數據塊時開啟 - Unconfirmed 未確認 @@ -4644,6 +4985,11 @@ For more information on using this console, type %6. Show address &QR code 顯示位址和二維碼(&Q) + + Show in %1 + 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. + 在 %1 中顯示 + Export Transaction History 匯出交易記錄 @@ -4836,10 +5182,6 @@ Go to File > Open Wallet to load a wallet. dash-core - - Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee. - 費用估算失敗。 後備費用已禁用。 請等待幾個區塊或啟用-fallbackfee。 - 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 如果此錢包未完全關閉並且上次使用具有較新版本的 Berkeley DB 的構建加載,則可能會發生此錯誤。 如果是這樣,請使用上次加載此錢包的軟件 @@ -4912,10 +5254,6 @@ Go to File > Open Wallet to load a wallet. Failed to listen on any port. Use -listen=0 if you want this. 在任意的通訊埠聽候失敗。如果你希望這樣的話,可以設定 -listen=0. - - -maxtxfee is set very high! Fees this large could be paid on a single transaction. - -maxtxfee設置得非常高! 這樣多的費用將在一筆交易中支付。 - Found unconfirmed denominated outputs, will wait till they confirm to continue. 找到未確認的己除名資金輸出,將等待,直到它們確認再繼續。 @@ -4924,10 +5262,6 @@ Go to File > Open Wallet to load a wallet. Invalid -socketevents ('%s') specified. Only these modes are supported: %s 指定的 -socketevents ('%s') 無效。僅支持以下模式: %s - - Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions) - -maxtxfee=<amount>: '%s' 的金額無效 (必須大於最低轉發手續費 %s 以避免交易無法確認) - SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is supported SQLiteDatabase:未知的 sqlite 錢包架構版本 %d。僅支援版本 %d @@ -4936,6 +5270,10 @@ Go to File > Open Wallet to load a wallet. Transaction index can't be disabled with governance validation enabled. Either start with -disablegovernance command line switch or enable transaction index. 無法在治理驗證啟用的情況下禁用事務索引。要麼使用-disablegovernance命令行選項,否則就啟用事務索引。 + + Unsupported category-specific logging level -loglevel=%s. Expected -loglevel=<category>:<loglevel>. Valid categories: %s. Valid loglevels: %s. + 未支援的類別記錄級別 -loglevel=%s. Expected -loglevel=<category>:<loglevel>. 有效的 類別: %s. 有效的記錄級別: %s. + Can't mix: no compatible inputs found! 無法開始混合:沒有找到相容的輸入! @@ -4944,6 +5282,14 @@ Go to File > Open Wallet to load a wallet. Entry exceeds maximum size. 條目超過最大大小。 + + Error upgrading evo database for EHF + 升級EHF的 evo 數據庫時出錯 + + + Failed to commit Evo database + 無法提交資料到 Evo 數據庫 + Found enough users, signing ( waiting %s ) 找到足夠多的用戶,簽署中 (等待 %s ) @@ -4968,18 +5314,14 @@ Go to File > Open Wallet to load a wallet. Insufficient funds. 餘額不足。 - - Invalid amount for -discardfee=<amount>: '%s' - 設定 -discardfee=<金額> 的金額無效: '%s' - - - Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s) - 設定 -paytxfee=<金額> 的金額無效: '%s' (至少要有 %s) - Invalid minimum number of spork signers specified with -minsporkkeys 使用-minsporkkeys 指定的最低叉勺簽名者數目無效 + + Listening for incoming connections failed (listen returned error %s) + 監聽外來連接失敗(偵聽返回錯誤%s) + Lock is already in place. 已經鎖定。 @@ -5036,6 +5378,10 @@ Go to File > Open Wallet to load a wallet. Synchronizing governance objects… 正在同步治理對象… + + Transaction change output index out of range + 交易變更輸出指數超出範圍 + Unable to start HTTP server. See debug log for details. 無法啟動HTTP服務器。 詳細信息請參閱debug.log。 @@ -5044,6 +5390,10 @@ Go to File > Open Wallet to load a wallet. Unknown response. 未知回應。 + + Unsupported global logging level -loglevel=%s. Valid values: %s. + 不支持的全局記錄級別 -loglevel=%s. 有效值: %s. + User Agent comment (%s) contains unsafe characters. 用戶代理註釋 (%s) 包含不安全的字符。 @@ -5108,10 +5458,6 @@ Go to File > Open Wallet to load a wallet. Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments. 網絡版本字符串的總長度 (%i) 超過最大長度 (%i)。減少uacomments參數的數量或大小。 - - Transaction needs a change address, but we can't generate it. Please call keypoolrefill first. - 交易需要找零地址,但我們無法產生。請先聯系 keypoolrefill。 - WARNING! Failed to replenish keypool, please unlock your wallet to do so. 警告! 無法補充公鑰池,請解鎖您的錢包。 @@ -5188,10 +5534,6 @@ Go to File > Open Wallet to load a wallet. Error: No addresses available. 錯誤:沒有可用的位址。 - - Exceeded max tries. - 超過最大嘗試的次數。 - Failed to create backup %s! 無法創建備份 %s! @@ -5232,10 +5574,6 @@ Go to File > Open Wallet to load a wallet. Invalid P2P permission: '%s' 無效的 P2P 權限: '%s' - - Invalid amount for -fallbackfee=<amount>: '%s' - 設定 -fallbackfee=<amount> 的金額無效: '%s' - Invalid masternodeblsprivkey. Please see documentation. 無效的masternodeblsprivkey。請參閱文檔。 @@ -5372,10 +5710,6 @@ Go to File > Open Wallet to load a wallet. Unable to open %s for writing 無法開啟 %s 進行寫入 - - Unable to parse -maxuploadtarget: '%s' (possible integer overflow?) - 無法解析-maxuploadtarget:「%s」(可能是整數溢出?) - Unknown -blockfilterindex value %s. 未知 -blockfilterindex 值 %s。 @@ -5384,10 +5718,6 @@ Go to File > Open Wallet to load a wallet. Unknown new rules activated (versionbit %i) 啟動未知的新規則(版本位 %i) - - Upgrading UTXO database - 正在升級 UTXO 資料庫 - Verifying blocks… 正在驗證區塊資料… @@ -5448,10 +5778,6 @@ Go to File > Open Wallet to load a wallet. Cannot obtain a lock on data directory %s. %s is probably already running. 沒辦法鎖定資料目錄 %s。%s 可能已經在執行了。 - - Cannot upgrade a non HD wallet from version %i to version %i which is non-HD wallet. Use upgradetohd RPC - 無法將非 HD 錢包從版本 %i 升級到版本 %i 。請使用upgradetohd RPC - Distributed under the MIT software license, see the accompanying file %s or %s 依據 MIT 軟體授權條款散布,詳情請見附帶的 %s 檔案或是 %s @@ -5484,6 +5810,10 @@ Go to File > Open Wallet to load a wallet. Failed to rename invalid peers.dat file. Please move or delete it and try again. 無法重新命名無效的peers.dat 文件,請移動或刪除它,然後重試。 + + Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable %s. + 手續費估計失敗。後備手續費已停用。請等待幾個區塊或啟用 %s。 + File %s already exists. If you are sure this is what you want, move it out of the way first. 文件 %s 已存在。如果您確定這就是您想要的,請先將其移開。 @@ -5496,6 +5826,10 @@ Go to File > Open Wallet to load a wallet. Incorrect or no devnet genesis block found. Wrong datadir for devnet specified? devnet 的創世區塊不正確或找不到。devnet 的資料目錄錯了嗎? + + Invalid amount for %s=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions) + %s=<amount> 的金額無效:「%s」(必須至少為 %s 的最小轉發費用以防止交易卡住) + 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. 無效或損壞的 peers.dat (%s) 如果您認為這是一個錯誤,請將其報告給 %s 作為解決方法,您可以將檔案 (%s) 移開(重新命名、移動或刪除)。以便在下次啟動時建立一個新的。 @@ -5512,6 +5846,10 @@ Go to File > Open Wallet to load a wallet. No wallet file format provided. To use createfromdump, -format=<format> must be provided. 未提供錢包文件格式。要使用 createfromdump,必須提供 -format=<format> + + Outbound connections restricted to CJDNS (-onlynet=cjdns) but -cjdnsreachable is not provided + 出站連線僅限於 CJDNS (-onlynet=cjdns),但未提供 -cjdnsreachable + Outbound connections restricted to Tor (-onlynet=onion) but the proxy for reaching the Tor network is explicitly forbidden: -onion=0 出站連線僅限於 Tor (-onlynet=onion),但明確禁止訪問 Tor 網路的代理:-onion=0 @@ -5520,6 +5858,10 @@ Go to File > Open Wallet to load a wallet. 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 出站連線僅限於 Tor (-onlynet=onion),但未提供用於訪問 Tor 網路的代理:未給出 -proxy、-onion 或 -listenonion 中的任何一個參數 + + Outbound connections restricted to i2p (-onlynet=i2p) but -i2psam is not provided + 出站連線僅限於 i2p (-onlynet=i2p),但未提供 -i2psam + Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly. 請檢查電腦日期和時間是否正確!%s 沒辦法在時鐘不準的情況下正常運作。 @@ -5532,10 +5874,6 @@ Go to File > Open Wallet to load a wallet. Prune mode is incompatible with -reindex-chainstate. Use full -reindex instead. 修剪模式與 -reindex-chainstate 不相容。請改用 full -reindex。 - - The block index db contains a legacy 'txindex'. To clear the occupied disk space, run a full -reindex, otherwise ignore this error. This error message will not be displayed again. - 區塊索引資料庫包含遺留的“txindex”。若要清除已佔用的磁碟空間,請執行 full -reindex,否則忽略此錯誤。該錯誤訊息將不會再次顯示。 - This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection. 這是您支付的最高交易費用(除了正常費用之外),以優先考慮避免部分支出而不是常規資金的選擇。 @@ -5548,6 +5886,10 @@ Go to File > Open Wallet to load a wallet. This is the transaction fee you may pay when fee estimates are not available. 這是當預估手續費還沒計算出來時,付款交易預設會付的手續費。 + + Transaction requires one destination of non-0 value, a non-0 feerate, or a pre-selected input + 交易需要一個非零值的目的地、非零費率或預先選擇的輸入 + Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate. 無法重播區塊。您將需要使用-reindex-chainstate來重建數據庫。 @@ -5556,6 +5898,10 @@ Go to File > Open Wallet to load a wallet. Unknown wallet file format "%s" provided. Please provide one of "bdb" or "sqlite". 提供了未知的錢包文件格式“%s”。請提供“bdb”或“sqlite”其中之一。 + + Unsupported chainstate database format found. Please restart with -reindex-chainstate. This will rebuild the chainstate database. + 發現不支援的鏈狀態資料庫格式。請使用 -reindex-chainstate 重新啟動。這將重建鏈狀態資料庫。 + Warning: Dumpfile wallet format "%s" does not match command line specified format "%s". 警告:轉儲檔案錢包格式「%s」與命令列指定的格式「%s」不符。 @@ -5596,10 +5942,30 @@ Go to File > Open Wallet to load a wallet. -rpcport must be specified when -devnet and -server are specified 當指定 -devnet 和 -server 時,必須指定 -rpcport + + -statsbatchsize cannot be configured with a negative value. + -statsbatchsize 不能配置為負值。 + + + -statsduration cannot be configured with a negative value. + -statsduration 不能配置為負值。 + A fatal internal error occurred, see debug.log for details 發生致命的內部錯誤,請參閱 debug.log 了解詳細信息 + + Cannot create socket (socket() returned error %s) + 無法創建 socket (socket() 回傳錯誤 %s) + + + Cannot get socket address for %s + 無法取得 %s 的 socket 位址 + + + Cannot init Statsd client + 無法初始化 Statsd 客戶端 + Cannot resolve -%s address: '%s' 沒辦法解析 -%s 參數指定的位址: '%s' @@ -5644,10 +6010,6 @@ Go to File > Open Wallet to load a wallet. Error reading next record from wallet database 從錢包資料庫讀取下一筆記錄時出錯 - - Error upgrading chainstate database - 升級區塊鏈狀態資料庫時發生錯誤 - Loading P2P addresses… 正在載入 P2P 位址資料… @@ -5768,10 +6130,70 @@ Go to File > Open Wallet to load a wallet. %s corrupt. Try using the wallet tool dash-wallet to salvage or restoring a backup. %s 已損壞。 請嘗試使用錢包工具 dash-wallet 來挽救或恢復備份。 + + %s is set very high! Fees this large could be paid on a single transaction. + %s 設定得非常高!如此高額的手續費可能在單筆交易中支付。 + + + %s request to listen on port %u. This port is considered "bad" and thus it is unlikely that any Dash Core peers connect to it. See doc/p2p-bad-ports.md for details and a full list. + %s在port%u上監聽。該端口被認為是“不良”,因此任何達世幣核心的對等用戶都不太可能連接到它。有關詳細信息和完整列表,請參見doc/p2p-bad-ports.md 。 + + + Cannot provide specific connections and have addrman find outgoing connections at the same time. + 無法提供特定的連接,並讓Addrman同時查找傳出連接。 + + + Failed to upgrade Evo database + 升級 Evo 資料庫失敗 + + + Fee needed > fee paid + 所需手續費 > 已支付手續費 + + + Host %s on unsupported network + 主機 %s 位於不支援的網路上 + + + Invalid amount for %s=<amount>: '%s' (must be at least %s) + %s=<amount> 的金額無效:「%s」(必須至少為 %s) + + + Invalid amount for %s=<amount>: '%s' + %s=<amount> 的金額無效:「%s」 + + + Invalid port specified in %s: '%s' + 在 %s 中指定的連接埠無效:「%s」 + Last successful action was too recent. 距離上一次成功執行的時間過短。 + + Missing solving data for estimating transaction size + 缺少估算交易大小的求解資料 + + + No host specified + 未指定主機 + + + No host specified, malformed URL + 未指定主機,URL 格式錯誤 + + + No text before the scheme delimiter, malformed URL + 協定分隔符號前無文字,URL 格式錯誤 + + + Port must be between %d and %d, supplied %d + 連接埠必須介於 %d 和 %d 之間,提供的是 %d + + + Socket not initialized, cannot send message + Socket 未初始化,無法發送訊息 + The source code is available from %s. 原始碼可以在 %s 取得。 @@ -5800,6 +6222,10 @@ Go to File > Open Wallet to load a wallet. Transaction fees are too high. 交易手續費過高。 + + Transaction needs a change address, but we can't generate it. + 交易需要找零地址,但我們無法生成。 + Transaction not valid. 交易無效。 @@ -5820,6 +6246,18 @@ Go to File > Open Wallet to load a wallet. Unable to locate enough non-denominated funds for this transaction. 無法為此交易找到足夠的未除名資金。 + + Unable to lookup host %s + 無法查詢主機 %s + + + Unable to parse -maxuploadtarget: '%s' + 無法解析 -maxuploadtarget:「%s」 + + + Unable to send message to %s (::sendto() returned error %s) + 無法發送訊息到 %s (::sendto() 回傳錯誤 %s) + Unable to sign spork message, wrong key? 無法簽署叉勺訊息訊息,錯誤的密鑰? @@ -5832,6 +6270,10 @@ Go to File > Open Wallet to load a wallet. Unknown state: id = %u 未知狀態: id = %u + + Unsupported URL scheme, must begin with udp:// + 不支援的 URL 協定,必須以 udp:// 開頭 + Unsupported logging category %s=%s. 不支持的日誌記錄類別 %s=%s. diff --git a/src/qt/mnemonicverificationdialog.cpp b/src/qt/mnemonicverificationdialog.cpp new file mode 100644 index 000000000000..365b8e6e5dc1 --- /dev/null +++ b/src/qt/mnemonicverificationdialog.cpp @@ -0,0 +1,502 @@ +// Copyright (c) 2024 The Dash Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#if defined(HAVE_CONFIG_H) +#include +#endif + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +MnemonicVerificationDialog::MnemonicVerificationDialog(const SecureString& mnemonic, QWidget *parent, bool viewOnly) : + QDialog(parent, GUIUtil::dialog_flags), + ui(new Ui::MnemonicVerificationDialog), + m_mnemonic(mnemonic), + m_mnemonic_revealed(false), + m_view_only(viewOnly) +{ + ui->setupUi(this); + + if (auto w = findChild("mnemonicGridWidget")) { + m_gridLayout = qobject_cast(w->layout()); + } + + // Keep minimum small so the page can compress when users scale down + setMinimumSize(QSize(550, 360)); + resize(minimumSize()); + + setWindowTitle(m_view_only ? tr("Your Recovery Phrase") : tr("Save Your Mnemonic")); + + // Words will be parsed on-demand to minimize exposure time in non-secure memory + // m_words is intentionally left empty initially + + // Trim outer paddings and inter-item spacing to avoid over-padded look + if (auto mainLayout = findChild("verticalLayout")) { + mainLayout->setContentsMargins(8, 4, 8, 6); + mainLayout->setSpacing(6); + } + if (auto s1 = findChild("verticalLayout_step1")) { + s1->setContentsMargins(8, 4, 8, 6); + s1->setSpacing(6); + } + if (auto s2 = findChild("verticalLayout_step2")) { + s2->setContentsMargins(8, 2, 8, 6); + s2->setSpacing(4); + s2->setAlignment(Qt::AlignTop); + } + if (ui->formLayout) { + ui->formLayout->setContentsMargins(0, 0, 0, 0); + ui->formLayout->setVerticalSpacing(3); + ui->formLayout->setHorizontalSpacing(8); + } + if (ui->buttonBox) { + ui->buttonBox->setContentsMargins(0, 0, 0, 0); + ui->buttonBox->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); + } + + // Prefer compact default; we will adjust per-step to sizeHint + ui->stackedWidget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); + // Ensure buttonBox is hidden initially (will be shown in step2) + ui->buttonBox->hide(); + setupStep1(); + adjustSize(); + m_defaultSize = size(); + + // Connections + connect(ui->showMnemonicButton, &QPushButton::clicked, this, &MnemonicVerificationDialog::onShowMnemonicClicked); + connect(ui->hideMnemonicButton, &QPushButton::clicked, this, &MnemonicVerificationDialog::onHideMnemonicClicked); + + if (!m_view_only) { + connect(ui->writtenDownCheckbox, &QCheckBox::toggled, this, [this](bool checked) { + if (checked && m_has_ever_revealed) setupStep2(); + }); + connect(ui->word1Edit, &QLineEdit::textChanged, this, &MnemonicVerificationDialog::onWord1Changed); + connect(ui->word2Edit, &QLineEdit::textChanged, this, &MnemonicVerificationDialog::onWord2Changed); + connect(ui->word3Edit, &QLineEdit::textChanged, this, &MnemonicVerificationDialog::onWord3Changed); + connect(ui->showMnemonicAgainButton, &QPushButton::clicked, this, &MnemonicVerificationDialog::onShowMnemonicAgainClicked); + } + + // Button box + ui->buttonBox->button(QDialogButtonBox::Ok)->setText(m_view_only ? tr("Close") : tr("Continue")); + connect(ui->buttonBox, &QDialogButtonBox::accepted, this, &MnemonicVerificationDialog::accept); + connect(ui->buttonBox, &QDialogButtonBox::rejected, this, &MnemonicVerificationDialog::reject); + + GUIUtil::handleCloseWindowShortcut(this); +} + +MnemonicVerificationDialog::~MnemonicVerificationDialog() +{ + clearWordsSecurely(); + clearMnemonic(); + delete ui; +} + +void MnemonicVerificationDialog::setupStep1() +{ + ui->stackedWidget->setCurrentIndex(0); + buildMnemonicGrid(false); + ui->hideMnemonicButton->hide(); + ui->showMnemonicButton->show(); + ui->writtenDownCheckbox->setEnabled(false); + ui->writtenDownCheckbox->setChecked(false); + m_mnemonic_revealed = false; + + // In view-only mode, hide the checkbox and show buttonBox immediately + if (m_view_only) { + ui->writtenDownCheckbox->hide(); + ui->buttonBox->show(); + // Hide Cancel button in view-only mode - only Close button is needed + if (QAbstractButton* cancelBtn = ui->buttonBox->button(QDialogButtonBox::Cancel)) { + cancelBtn->hide(); + } + } else { + ui->writtenDownCheckbox->show(); + ui->buttonBox->hide(); + } + + // Restore original minimum size (in case we came back from Step 2) + setMinimumSize(QSize(550, 360)); + + // Restore to default size if we have it (when coming back from Step 2) + if (m_defaultSize.isValid() && !m_defaultSize.isEmpty()) { + resize(m_defaultSize); + } else { + // Compact to content on first load + adjustSize(); + } + + // Set warning and instruction text with themed colors + // Font sizes and weights are defined in general.css + if (m_view_only) { + ui->warningLabel->setText( + tr("WARNING: Never share your recovery phrase with anyone. Store it securely offline.")); + ui->warningLabel->setStyleSheet(GUIUtil::getThemedStyleQString(GUIUtil::ThemedStyle::TS_ERROR)); + ui->instructionLabel->setText( + tr("These words can restore your wallet. Keep them safe and private.")); + } else { + ui->warningLabel->setText( + tr("WARNING: If you lose your mnemonic seed phrase, you will lose access to your wallet forever. Write it down in a safe place and never share it with anyone.")); + ui->warningLabel->setStyleSheet(GUIUtil::getThemedStyleQString(GUIUtil::ThemedStyle::TS_ERROR)); + ui->instructionLabel->setText( + tr("Please write down these words in order. You will need them to restore your wallet.")); + } + + // Reduce extra padding to avoid an over-padded look + if (auto outer = findChild("verticalLayout_step1")) { + outer->setContentsMargins(12, 6, 12, 6); + outer->setSpacing(6); + } + if (auto hb = findChild("horizontalLayout_buttons")) { + hb->setContentsMargins(0, 4, 0, 0); + hb->setSpacing(10); + } +} + +void MnemonicVerificationDialog::setupStep2() +{ + ui->stackedWidget->setCurrentIndex(1); + // Parse words for validation (needed in step 2) + parseWords(); + + // Validate mnemonic has at least 3 words before proceeding + const int wordCount = getWordCount(); + if (wordCount < 3) { + QMessageBox::critical(this, tr("Invalid Mnemonic"), + tr("Mnemonic phrase has fewer than 3 words (found %1). Verification cannot proceed.").arg(wordCount)); + reject(); + return; + } + + generateRandomPositions(); + + // Safety check: ensure positions were generated successfully + if (m_selected_positions.size() < 3) { + QMessageBox::critical(this, tr("Verification Error"), + tr("Failed to generate verification positions. Please try again.")); + reject(); + return; + } + + ui->word1Edit->clear(); + ui->word2Edit->clear(); + ui->word3Edit->clear(); + // Widget sizes are defined in general.css + + ui->word1Label->setText(tr("Word #%1:").arg(m_selected_positions[0])); + ui->word2Label->setText(tr("Word #%1:").arg(m_selected_positions[1])); + ui->word3Label->setText(tr("Word #%1:").arg(m_selected_positions[2])); + + ui->word1Status->clear(); + ui->word2Status->clear(); + ui->word3Status->clear(); + + ui->buttonBox->show(); + if (QAbstractButton* cancel = ui->buttonBox->button(QDialogButtonBox::Cancel)) { + cancel->show(); + cancel->setText(tr("Back")); + disconnect(cancel, nullptr, nullptr, nullptr); + connect(cancel, &QAbstractButton::clicked, this, &MnemonicVerificationDialog::onShowMnemonicAgainClicked); + } + if (QAbstractButton* cont = ui->buttonBox->button(QDialogButtonBox::Ok)) cont->setEnabled(false); + if (ui->showMnemonicAgainButton) ui->showMnemonicAgainButton->hide(); + + // Verification label styling is defined in general.css + + // Hide any existing title label if present + if (auto titleLabel = findChild("verifyTitleLabel")) { + titleLabel->hide(); + } + + // Align content toward top and remove any layout spacers expanding height FIRST + if (auto v = findChild("verticalLayout_step2")) { + v->setAlignment(Qt::AlignTop); + // Minimize top padding/margin to eliminate gap at top + QMargins m = v->contentsMargins(); + v->setContentsMargins(m.left(), 2, m.right(), m.bottom()); + for (int i = 0; i < v->count(); ++i) { + QLayoutItem* it = v->itemAt(i); + if (it && it->spacerItem()) it->spacerItem()->changeSize(0, 0, QSizePolicy::Fixed, QSizePolicy::Fixed); + } + // Force immediate layout update + v->invalidate(); + v->update(); + } + // Also ensure the main dialog layout has minimal top padding + if (auto mainLayout = findChild("verticalLayout")) { + QMargins m = mainLayout->contentsMargins(); + mainLayout->setContentsMargins(m.left(), 4, m.right(), m.bottom()); + mainLayout->invalidate(); + mainLayout->update(); + } + // Force widget to recalculate layout immediately + updateGeometry(); + + // Reduce minimums for verify; open exactly at the minimum size AFTER layout is fixed + setMinimumSize(QSize(460, 280)); + resize(minimumSize()); + adjustSize(); +} + +void MnemonicVerificationDialog::generateRandomPositions() +{ + m_selected_positions.clear(); + const int n = getWordCount(); + if (n < 3) { + // Unable to verify; bail out so the dialog can surface an error message upstream. + return; + } + QSet used; + QRandomGenerator* rng = QRandomGenerator::global(); + while (m_selected_positions.size() < 3) { + int pos = rng->bounded(1, n + 1); + if (!used.contains(pos)) { used.insert(pos); m_selected_positions.append(pos); } + } + std::sort(m_selected_positions.begin(), m_selected_positions.end()); +} + +void MnemonicVerificationDialog::onShowMnemonicClicked() +{ + buildMnemonicGrid(true); + ui->showMnemonicButton->hide(); + ui->hideMnemonicButton->show(); + if (!m_view_only) { + ui->writtenDownCheckbox->setEnabled(true); + } + m_mnemonic_revealed = true; + m_has_ever_revealed = true; +} + +void MnemonicVerificationDialog::onHideMnemonicClicked() +{ + buildMnemonicGrid(false); + ui->hideMnemonicButton->hide(); + ui->showMnemonicButton->show(); + m_mnemonic_revealed = false; + // Clear words from non-secure memory immediately when hiding + clearWordsSecurely(); +} + +void MnemonicVerificationDialog::onShowMnemonicAgainClicked() +{ + // Clear words when going back to step 1 (unless mnemonic is revealed) + if (!m_mnemonic_revealed) { + clearWordsSecurely(); + } + setupStep1(); +} + +void MnemonicVerificationDialog::onWord1Changed() { updateWordValidation(); } +void MnemonicVerificationDialog::onWord2Changed() { updateWordValidation(); } +void MnemonicVerificationDialog::onWord3Changed() { updateWordValidation(); } + +bool MnemonicVerificationDialog::validateWord(const QString& word, int position) +{ + // Parse words on-demand for validation (minimizes exposure time) + // Words are kept in memory during step 2 (verification) and step 1 (when revealed) + // They are only cleared when explicitly hiding in step 1 or on dialog destruction + std::vector words = parseWords(); + if (position < 1 || position > static_cast(words.size())) { + return false; + } + // Convert SecureString to QString temporarily for comparison + QString secureWord = QString::fromStdString(std::string(words[position - 1].begin(), words[position - 1].end())); + bool result = word == secureWord.toLower(); + // Clear temporary QString immediately + secureWord.fill(QChar(0)); + secureWord.clear(); + secureWord.squeeze(); + return result; +} + +void MnemonicVerificationDialog::updateWordValidation() +{ + const QString t1 = ui->word1Edit->text().trimmed().toLower(); + const QString t2 = ui->word2Edit->text().trimmed().toLower(); + const QString t3 = ui->word3Edit->text().trimmed().toLower(); + + const bool ok1 = !t1.isEmpty() && validateWord(t1, m_selected_positions[0]); + const bool ok2 = !t2.isEmpty() && validateWord(t2, m_selected_positions[1]); + const bool ok3 = !t3.isEmpty() && validateWord(t3, m_selected_positions[2]); + + // Status labels show checkmarks/X marks with themed colors + // Font weight is defined in general.css + auto setStatus = [](QLabel* lbl, bool filled, bool valid) { + if (!lbl) return; + if (!filled) { lbl->clear(); lbl->setStyleSheet(""); return; } + lbl->setText(valid ? "✓" : "✗"); + lbl->setStyleSheet(valid ? + GUIUtil::getThemedStyleQString(GUIUtil::ThemedStyle::TS_SUCCESS) : + GUIUtil::getThemedStyleQString(GUIUtil::ThemedStyle::TS_ERROR)); + }; + setStatus(ui->word1Status, !t1.isEmpty(), ok1); + setStatus(ui->word2Status, !t2.isEmpty(), ok2); + setStatus(ui->word3Status, !t3.isEmpty(), ok3); + if (ui->buttonBox && ui->stackedWidget->currentIndex() == 1) { + ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(ok1 && ok2 && ok3); + } +} + +void MnemonicVerificationDialog::accept() +{ + // In view-only mode, skip verification + if (!m_view_only) { + if (!validateWord(ui->word1Edit->text().trimmed().toLower(), m_selected_positions[0]) || + !validateWord(ui->word2Edit->text().trimmed().toLower(), m_selected_positions[1]) || + !validateWord(ui->word3Edit->text().trimmed().toLower(), m_selected_positions[2])) { + QMessageBox::warning(this, tr("Verification Failed"), tr("One or more words are incorrect. Please try again.")); + return; + } + } + QDialog::accept(); +} + +void MnemonicVerificationDialog::clearMnemonic() +{ + clearWordsSecurely(); + m_mnemonic.assign(m_mnemonic.size(), 0); +} + +std::vector MnemonicVerificationDialog::parseWords() +{ + // If words are already parsed, reuse them (for step 2 validation or step 1 display) + if (!m_words.empty()) { + return m_words; + } + + // Parse words from secure mnemonic string + QString mnemonicStr = QString::fromStdString(std::string(m_mnemonic.begin(), m_mnemonic.end())); + QStringList wordList = mnemonicStr.split(QRegularExpression("\\s+"), Qt::SkipEmptyParts); + + // Convert to SecureString vector for secure storage + m_words.clear(); + m_words.reserve(wordList.size()); + for (const QString& word : wordList) { + std::string wordStd = word.toStdString(); + SecureString secureWord; + secureWord.assign(std::string_view{wordStd}); + m_words.push_back(secureWord); + // Clear temporary std::string + wordStd.assign(wordStd.size(), 0); + } + + // Clear the temporary QString immediately after parsing + mnemonicStr.fill(QChar(0)); + mnemonicStr.clear(); + mnemonicStr.squeeze(); // Release memory + wordList.clear(); + + return m_words; +} + +void MnemonicVerificationDialog::clearWordsSecurely() +{ + // Securely clear each word string by overwriting before clearing + for (SecureString& word : m_words) { + // Overwrite with zeros before clearing + word.assign(word.size(), 0); + word.clear(); + } + m_words.clear(); +} + +int MnemonicVerificationDialog::getWordCount() const +{ + // Count words without parsing them into vector + // This avoids storing words in non-secure memory unnecessarily + if (m_words.empty()) { + QString mnemonicStr = QString::fromStdString(std::string(m_mnemonic.begin(), m_mnemonic.end())); + QStringList words = mnemonicStr.split(QRegularExpression("\\s+"), Qt::SkipEmptyParts); + int count = words.size(); + // Clear immediately + mnemonicStr.clear(); + mnemonicStr.squeeze(); + words.clear(); + return count; + } + return m_words.size(); +} + +void MnemonicVerificationDialog::buildMnemonicGrid(bool reveal) +{ + if (!m_gridLayout) return; + + QLayoutItem* child; + while ((child = m_gridLayout->takeAt(0)) != nullptr) { + if (child->widget()) child->widget()->deleteLater(); + delete child; + } + + // Parse words only when revealing (when needed for display) + std::vector words; + if (reveal) { + words = parseWords(); + } else { + // For hidden view, just get count without parsing words + const int n = getWordCount(); + const int columns = (n >= 24) ? 4 : 3; + const int rows = (n + columns - 1) / columns; + + // Font styling is defined in general.css + m_gridLayout->setContentsMargins(6, 2, 6, 8); + m_gridLayout->setHorizontalSpacing(32); + m_gridLayout->setVerticalSpacing(7); + + for (int r = 0; r < rows; ++r) { + for (int c = 0; c < columns; ++c) { + int idx = r * columns + c; if (idx >= n) break; + const QString text = QString("%1. •••••••").arg(idx + 1, 2); + QLabel* lbl = new QLabel(text); + lbl->setTextInteractionFlags(Qt::TextSelectableByMouse); + m_gridLayout->addWidget(lbl, r, c); + } + } + + m_gridLayout->setRowMinimumHeight(rows, 12); + return; + } + + // Revealed view - words are already parsed + const int n = words.size(); + const int columns = (n >= 24) ? 4 : 3; + const int rows = (n + columns - 1) / columns; + + // Font styling is defined in general.css + m_gridLayout->setContentsMargins(6, 2, 6, 8); + m_gridLayout->setHorizontalSpacing(32); + m_gridLayout->setVerticalSpacing(7); + + for (int r = 0; r < rows; ++r) { + for (int c = 0; c < columns; ++c) { + int idx = r * columns + c; if (idx >= n) break; + // Convert SecureString to QString temporarily for display + QString wordStr = QString::fromStdString(std::string(words[idx].begin(), words[idx].end())); + const QString text = QString("%1. %2").arg(idx + 1, 2).arg(wordStr); + QLabel* lbl = new QLabel(text); + lbl->setTextInteractionFlags(Qt::TextSelectableByMouse); + m_gridLayout->addWidget(lbl, r, c); + // Clear temporary QString immediately after use + wordStr.fill(QChar(0)); + wordStr.clear(); + wordStr.squeeze(); + } + } + + m_gridLayout->setRowMinimumHeight(rows, 12); +} + + diff --git a/src/qt/mnemonicverificationdialog.h b/src/qt/mnemonicverificationdialog.h new file mode 100644 index 000000000000..309912201c15 --- /dev/null +++ b/src/qt/mnemonicverificationdialog.h @@ -0,0 +1,61 @@ +// Copyright (c) 2024 The Dash Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_QT_MNEMONICVERIFICATIONDIALOG_H +#define BITCOIN_QT_MNEMONICVERIFICATIONDIALOG_H + +#include +#include + +#include +#include + +namespace Ui { + class MnemonicVerificationDialog; +} + +/** Dialog to verify mnemonic seed phrase by asking user to enter 3 random word positions */ +class MnemonicVerificationDialog : public QDialog +{ + Q_OBJECT + +public: + explicit MnemonicVerificationDialog(const SecureString& mnemonic, QWidget *parent = nullptr, bool viewOnly = false); + ~MnemonicVerificationDialog(); + + void accept() override; + +private Q_SLOTS: + void onShowMnemonicClicked(); + void onHideMnemonicClicked(); + void onWord1Changed(); + void onWord2Changed(); + void onWord3Changed(); + void onShowMnemonicAgainClicked(); + +private: + void setupStep1(); + void setupStep2(); + void generateRandomPositions(); + void updateWordValidation(); + bool validateWord(const QString& word, int position); + void clearMnemonic(); + void buildMnemonicGrid(bool reveal); + std::vector parseWords(); + void clearWordsSecurely(); + int getWordCount() const; + + Ui::MnemonicVerificationDialog *ui; + SecureString m_mnemonic; + std::vector m_words; + QList m_selected_positions; + bool m_mnemonic_revealed; + bool m_has_ever_revealed{false}; + bool m_view_only{false}; + class QGridLayout* m_gridLayout{nullptr}; + QSize m_defaultSize; +}; + +#endif // BITCOIN_QT_MNEMONICVERIFICATIONDIALOG_H + diff --git a/src/qt/notificator.cpp b/src/qt/notificator.cpp index 0d6d52e67e46..e9f666b506cc 100644 --- a/src/qt/notificator.cpp +++ b/src/qt/notificator.cpp @@ -70,7 +70,7 @@ Notificator::~Notificator() class FreedesktopImage { public: - FreedesktopImage() {} + FreedesktopImage() = default; explicit FreedesktopImage(const QImage &img); // Image to variant that can be marshalled over DBus diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index 0cd82261e3f5..da72b71b0675 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -23,11 +23,12 @@ #include #include // for -dbcache defaults #include +#include #include -#include #include +#include #include #include #include @@ -138,6 +139,11 @@ OptionsDialog::OptionsDialog(QWidget *parent, bool enableWallet) : showPage(0); +#ifndef ENABLE_EXTERNAL_SIGNER + //: "External signing" means using devices such as hardware wallets. + ui->externalSignerPath->setToolTip(tr("Compiled without external signing support (required for external signing)")); + ui->externalSignerPath->setEnabled(false); +#endif /* Display elements init */ /* Number of displayed decimal digits selector */ @@ -269,6 +275,7 @@ void OptionsDialog::setModel(OptionsModel *_model) connect(ui->prune, &QCheckBox::clicked, this, &OptionsDialog::togglePruneWarning); connect(ui->pruneSize, qOverload(&QSpinBox::valueChanged), this, &OptionsDialog::showRestartWarning); connect(ui->databaseCache, qOverload(&QSpinBox::valueChanged), this, &OptionsDialog::showRestartWarning); + connect(ui->externalSignerPath, &QLineEdit::textChanged, [this]{ showRestartWarning(); }); connect(ui->threadsScriptVerif, qOverload(&QSpinBox::valueChanged), this, &OptionsDialog::showRestartWarning); /* Wallet */ connect(ui->showMasternodesTab, &QCheckBox::clicked, this, &OptionsDialog::showRestartWarning); @@ -335,6 +342,7 @@ void OptionsDialog::setMapper() /* Wallet */ mapper->addMapping(ui->coinControlFeatures, OptionsModel::CoinControlFeatures); + mapper->addMapping(ui->externalSignerPath, OptionsModel::ExternalSignerPath); mapper->addMapping(ui->subFeeFromAmount, OptionsModel::SubFeeFromAmount); mapper->addMapping(ui->m_enable_psbt_controls, OptionsModel::EnablePSBTControls); mapper->addMapping(ui->keepChangeAddress, OptionsModel::KeepChangeAddress); diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index 719df0456b76..5fcf94edb9e7 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -223,6 +223,13 @@ void OptionsModel::Init(bool resetSettings) if (!gArgs.SoftSetBoolArg("-spendzeroconfchange", settings.value("bSpendZeroConfChange").toBool())) addOverriddenOption("-spendzeroconfchange"); + if (!settings.contains("external_signer_path")) + settings.setValue("external_signer_path", ""); + + if (!gArgs.SoftSetArg("-signer", settings.value("external_signer_path").toString().toStdString())) { + addOverriddenOption("-signer"); + } + if (!settings.contains("SubFeeFromAmount")) { settings.setValue("SubFeeFromAmount", false); } @@ -496,6 +503,8 @@ QVariant OptionsModel::data(const QModelIndex & index, int role) const #ifdef ENABLE_WALLET case SpendZeroConfChange: return settings.value("bSpendZeroConfChange"); + case ExternalSignerPath: + return settings.value("external_signer_path"); case SubFeeFromAmount: return m_sub_fee_from_amount; case ShowMasternodesTab: @@ -671,6 +680,12 @@ bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, in setRestartRequired(true); } break; + case ExternalSignerPath: + if (settings.value("external_signer_path") != value.toString()) { + settings.setValue("external_signer_path", value.toString()); + setRestartRequired(true); + } + break; case ShowMasternodesTab: if (settings.value("fShowMasternodesTab") != value) { settings.setValue("fShowMasternodesTab", value); diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h index 290ff3bd3dba..8d6d3c2c73f3 100644 --- a/src/qt/optionsmodel.h +++ b/src/qt/optionsmodel.h @@ -73,6 +73,7 @@ class OptionsModel : public QAbstractListModel Prune, // bool PruneSize, // int DatabaseCache, // int + ExternalSignerPath, // QString SpendZeroConfChange, // bool ShowMasternodesTab, // bool ShowGovernanceTab, // bool diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index eacf650e993a..80f399bd0328 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -43,7 +43,7 @@ class TxViewDelegate : public QAbstractItemDelegate Q_OBJECT public: explicit TxViewDelegate(QObject* parent = nullptr) - : QAbstractItemDelegate(parent), unit(BitcoinUnit::DASH) + : QAbstractItemDelegate(parent) { connect(this, &TxViewDelegate::width_changed, this, &TxViewDelegate::sizeHintChanged); } @@ -126,7 +126,7 @@ class TxViewDelegate : public QAbstractItemDelegate return {ITEM_HEIGHT + 8 + minimum_text_width, ITEM_HEIGHT}; } - BitcoinUnit unit; + BitcoinUnit unit{BitcoinUnit::DASH}; Q_SIGNALS: //! An intermediate signal for emitting from the `paint() const` member function. diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp index ecc92e12822e..6adf7fe4cc9b 100644 --- a/src/qt/paymentserver.cpp +++ b/src/qt/paymentserver.cpp @@ -157,9 +157,7 @@ PaymentServer::PaymentServer(QObject* parent, bool startLocalServer) : } } -PaymentServer::~PaymentServer() -{ -} +PaymentServer::~PaymentServer() = default; // // OSX-specific way of handling dash: URIs diff --git a/src/qt/peertablemodel.cpp b/src/qt/peertablemodel.cpp index 736dbf6f4fd8..370f40e9931e 100644 --- a/src/qt/peertablemodel.cpp +++ b/src/qt/peertablemodel.cpp @@ -27,10 +27,7 @@ PeerTableModel::PeerTableModel(interfaces::Node& node, QObject* parent) : refresh(); } -PeerTableModel::~PeerTableModel() -{ - // Intentionally left empty -} +PeerTableModel::~PeerTableModel() = default; void PeerTableModel::startAutoRefresh() { diff --git a/src/qt/proposalwizard.cpp b/src/qt/proposalwizard.cpp index b4cd0f06432c..7657ba2f826f 100644 --- a/src/qt/proposalwizard.cpp +++ b/src/qt/proposalwizard.cpp @@ -60,7 +60,7 @@ ProposalWizard::ProposalWizard(interfaces::Node& node, WalletModel* walletModel, // Initialize fields // Populate payments dropdown (mainnet 1..12 by default; adjust by network later if needed) for (int i = 1; i <= 12; ++i) { - m_ui->comboPayments->addItem(tr("%1").arg(i), i); + m_ui->comboPayments->addItem(QString().setNum(i), i); } m_ui->comboPayments->setCurrentIndex(0); @@ -90,7 +90,6 @@ ProposalWizard::ProposalWizard(interfaces::Node& node, WalletModel* walletModel, connect(m_ui->paymentAmount, &BitcoinAmountField::valueChanged, this, &ProposalWizard::updateLabels); connect(m_ui->btnNext1, &QPushButton::clicked, this, &ProposalWizard::onNextFromDetails); connect(m_ui->btnBack1, &QPushButton::clicked, this, &ProposalWizard::onBackToDetails); - connect(m_ui->btnValidate, &QPushButton::clicked, this, &ProposalWizard::onValidateJson); connect(m_ui->btnNext2, &QPushButton::clicked, this, &ProposalWizard::onNextFromReview); connect(m_ui->btnBack2, &QPushButton::clicked, this, &ProposalWizard::onBackToReview); connect(m_ui->btnPrepare, &QPushButton::clicked, this, &ProposalWizard::onPrepare); @@ -199,6 +198,7 @@ void ProposalWizard::onNextFromDetails() { buildJsonAndHex(); m_ui->stackedWidget->setCurrentIndex(1); + onValidateJson(); // Automatically validate when entering the review page } void ProposalWizard::onBackToDetails() { m_ui->stackedWidget->setCurrentIndex(0); } @@ -290,8 +290,8 @@ void ProposalWizard::onMaybeAdvanceAfterConfirmations() if (m_confirmTimer) m_confirmTimer->stop(); } else { const auto mins = (secs + 59) / 60; - m_ui->labelEta->setText(tr("Estimated time remaining: %1 min").arg(mins)); - m_ui->labelEta2->setText(tr("Estimated time remaining: %1 min").arg(mins)); + m_ui->labelEta->setText(tr("Estimated time remaining: %n minute(s)", "", mins)); + m_ui->labelEta2->setText(tr("Estimated time remaining: %n minute(s)", "", mins)); } } // Allow submitting (relay/postpone) at 1 confirmation and enable Next to proceed @@ -321,7 +321,8 @@ void ProposalWizard::onSubmit() const QString govId = QString::fromStdString(obj_hash); m_ui->editGovObjId->setText(govId); QMessageBox::information(this, tr("Proposal submitted"), - tr("Your proposal was submitted successfully.\nID: %1").arg(govId)); + tr("Your proposal was submitted successfully.") + + QString("\nID: %1").arg(govId)); m_submitted = true; m_ui->btnSubmit->setEnabled(false); // When 6 confs are reached show a final success message diff --git a/src/qt/receiverequestdialog.cpp b/src/qt/receiverequestdialog.cpp index 2961084f3714..bb1a90d45c26 100644 --- a/src/qt/receiverequestdialog.cpp +++ b/src/qt/receiverequestdialog.cpp @@ -93,6 +93,12 @@ void ReceiveRequestDialog::setInfo(const SendCoinsRecipient &_info) ui->wallet_tag->hide(); ui->wallet_content->hide(); } + + ui->btnVerify->setVisible(model->wallet().hasExternalSigner()); + + connect(ui->btnVerify, &QPushButton::clicked, [this] { + model->displayAddress(info.address.toStdString()); + }); } void ReceiveRequestDialog::updateDisplayUnit() diff --git a/src/qt/recentrequeststablemodel.cpp b/src/qt/recentrequeststablemodel.cpp index faab8f46ba55..2b86f7aa2ac4 100644 --- a/src/qt/recentrequeststablemodel.cpp +++ b/src/qt/recentrequeststablemodel.cpp @@ -34,10 +34,7 @@ RecentRequestsTableModel::RecentRequestsTableModel(WalletModel *parent) : connect(walletModel->getOptionsModel(), &OptionsModel::displayUnitChanged, this, &RecentRequestsTableModel::updateDisplayUnit); } -RecentRequestsTableModel::~RecentRequestsTableModel() -{ - /* Intentionally left empty */ -} +RecentRequestsTableModel::~RecentRequestsTableModel() = default; int RecentRequestsTableModel::rowCount(const QModelIndex &parent) const { diff --git a/src/qt/res/css/dark.css b/src/qt/res/css/dark.css index 0a534419fcff..9fe5b09762ed 100644 --- a/src/qt/res/css/dark.css +++ b/src/qt/res/css/dark.css @@ -1088,4 +1088,88 @@ QScrollBar:right-arrow:disabled { image: url(':/images/arrow_light_right_hover'); } +/** + * CreateWalletDialog (Dark Theme) + */ + +QDialog#CreateWalletDialog QLabel, +QDialog#CreateWalletDialog QCheckBox { + color: #bbbbbb; /* slightly lighter labels */ +} + +QDialog#CreateWalletDialog QToolButton#advanced_toggle_button { + color: #bdbdbd !important; /* lighter chevron/text */ +} + +QDialog#CreateWalletDialog QToolButton#advanced_toggle_button:hover { + color: #e0e0e0 !important; /* lighter on hover for better feedback */ +} + +QDialog#CreateWalletDialog QGroupBox#groupBox { + background-color: #2a2a2a; /* card background */ + border: 1px solid #3c3c3c; /* subtle outline */ + border-radius: 8px; + padding: 2px 12px 12px 12px; /* minimal top padding */ + margin-top: 0px; /* remove extra gap above card */ +} + +QDialog#CreateWalletDialog QGroupBox#groupBox::title { + padding: 0px; /* ensure no extra space for (empty) title */ +} + +QDialog#CreateWalletDialog QLineEdit:focus { + border-color: #4da3ff; /* subtle macOS-like blue */ +} + +/** + * MnemonicVerificationDialog (Dark Theme) + */ + +QDialog#MnemonicVerificationDialog QLabel { + color: #c7c7c7; /* light text for dark theme */ +} + +QDialog#MnemonicVerificationDialog QCheckBox { + color: #c7c7c7; /* light text for checkbox */ +} + +QDialog#MnemonicVerificationDialog QCheckBox#writtenDownCheckbox { + color: #c7c7c7; /* ensure checkbox text is visible */ +} + +QDialog#MnemonicVerificationDialog QScrollArea#mnemonicScroll { + background-color: #2d2d2e !important; /* dark background for scroll area */ + border: 1px solid #3c3c3c !important; /* subtle border */ + border-radius: 8px; +} + +QDialog#MnemonicVerificationDialog QScrollArea#mnemonicScroll QWidget#mnemonicGridWidget { + background-color: #2d2d2e !important; /* dark background matching scroll area */ +} + +QDialog#MnemonicVerificationDialog QWidget#mnemonicGridWidget { + background-color: #2d2d2e !important; /* dark background matching scroll area */ +} + +QDialog#MnemonicVerificationDialog QScrollArea#mnemonicScroll QWidget#mnemonicGridWidget QLabel { + color: #c7c7c7 !important; /* ensure grid labels are visible */ + background-color: transparent !important; +} + +QDialog#MnemonicVerificationDialog QLineEdit { + background-color: #2d2d2e; /* dark background for input fields */ + border-color: #00599a; + color: #c7c7c7; +} + +QDialog#MnemonicVerificationDialog QLineEdit:focus { + border-color: #4da3ff; /* subtle macOS-like blue */ +} + +QDialog#MnemonicVerificationDialog QLabel#word1Status, +QDialog#MnemonicVerificationDialog QLabel#word2Status, +QDialog#MnemonicVerificationDialog QLabel#word3Status { + color: #c7c7c7; /* ensure status labels are visible */ +} + diff --git a/src/qt/res/css/general.css b/src/qt/res/css/general.css index c0444986d362..a04af4d4d805 100644 --- a/src/qt/res/css/general.css +++ b/src/qt/res/css/general.css @@ -1985,3 +1985,54 @@ QDialog#HelpMessageDialog QScrollBar:horizontal { } + +/** + * CreateWalletDialog (Layout) + */ + +QDialog#CreateWalletDialog QGroupBox#groupBox { + border-radius: 8px; + padding: 2px 12px 12px 12px; + margin-top: 0px; +} + +QDialog#CreateWalletDialog QGroupBox#groupBox::title { + padding: 0px; +} + +/** + * MnemonicVerificationDialog (Layout) + */ + +QDialog#MnemonicVerificationDialog QLabel#warningLabel { + font-size: 17px; + font-weight: 700; +} + +QDialog#MnemonicVerificationDialog QLabel#instructionLabel { + font-size: 14px; +} + +QDialog#MnemonicVerificationDialog QLabel#verificationLabel { + margin-top: 0px; + margin-bottom: 4px; +} + +QDialog#MnemonicVerificationDialog QLabel#word1Status, +QDialog#MnemonicVerificationDialog QLabel#word2Status, +QDialog#MnemonicVerificationDialog QLabel#word3Status { + font-weight: 700; + min-width: 18px; +} + +QDialog#MnemonicVerificationDialog QScrollArea#mnemonicScroll QWidget#mnemonicGridWidget QLabel { + font-family: monospace; + font-size: 13pt; +} + +QDialog#MnemonicVerificationDialog QLineEdit#word1Edit, +QDialog#MnemonicVerificationDialog QLineEdit#word2Edit, +QDialog#MnemonicVerificationDialog QLineEdit#word3Edit { + max-width: 320px; +} + diff --git a/src/qt/res/css/light.css b/src/qt/res/css/light.css index 7d15950351bc..4657ff8e9902 100644 --- a/src/qt/res/css/light.css +++ b/src/qt/res/css/light.css @@ -1072,4 +1072,88 @@ QScrollBar:right-arrow:disabled { image: url(':/images/arrow_light_right_normal'); } +/** + * CreateWalletDialog (Light Theme) + */ + +QDialog#CreateWalletDialog QLabel, +QDialog#CreateWalletDialog QCheckBox { + color: #555; /* ensure contrast consistent with labels */ +} + +QDialog#CreateWalletDialog QToolButton#advanced_toggle_button { + color: #555 !important; /* ensure good contrast in light mode */ +} + +QDialog#CreateWalletDialog QToolButton#advanced_toggle_button:hover { + color: #333 !important; /* darker on hover for better feedback */ +} + +QDialog#CreateWalletDialog QGroupBox#groupBox { + background-color: #eaeaec; /* card background */ + border: 1px solid #dcdcdc; /* subtle outline */ + border-radius: 8px; + padding: 2px 12px 12px 12px; /* minimal top padding */ + margin-top: 0px; /* remove extra gap above card */ +} + +QDialog#CreateWalletDialog QGroupBox#groupBox::title { + padding: 0px; /* ensure no extra space for (empty) title */ +} + +QDialog#CreateWalletDialog QLineEdit:focus { + border-color: #4da3ff; /* macOS-like blue */ +} + +/** + * MnemonicVerificationDialog (Light Theme) + */ + +QDialog#MnemonicVerificationDialog QLabel { + color: #555; /* ensure good contrast for all labels */ +} + +QDialog#MnemonicVerificationDialog QCheckBox { + color: #555; /* ensure checkbox text is visible */ +} + +QDialog#MnemonicVerificationDialog QCheckBox#writtenDownCheckbox { + color: #555; /* ensure checkbox text has good contrast */ +} + +QDialog#MnemonicVerificationDialog QScrollArea#mnemonicScroll { + background-color: #eaeaec !important; /* light background for scroll area */ + border: 1px solid #dcdcdc !important; /* subtle border */ + border-radius: 8px; +} + +QDialog#MnemonicVerificationDialog QScrollArea#mnemonicScroll QWidget#mnemonicGridWidget { + background-color: #eaeaec !important; /* light background matching scroll area */ +} + +QDialog#MnemonicVerificationDialog QWidget#mnemonicGridWidget { + background-color: #eaeaec !important; /* light background matching scroll area */ +} + +QDialog#MnemonicVerificationDialog QScrollArea#mnemonicScroll QWidget#mnemonicGridWidget QLabel { + color: #555 !important; /* ensure grid labels are visible */ + background-color: transparent !important; +} + +QDialog#MnemonicVerificationDialog QLineEdit { + background-color: #ffffff; /* white background for input fields */ + border-color: #008de4; + color: #555; +} + +QDialog#MnemonicVerificationDialog QLineEdit:focus { + border-color: #4da3ff; /* macOS-like blue */ +} + +QDialog#MnemonicVerificationDialog QLabel#word1Status, +QDialog#MnemonicVerificationDialog QLabel#word2Status, +QDialog#MnemonicVerificationDialog QLabel#word3Status { + color: #555; /* ensure status labels are visible */ +} + diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index 4308740e5e88..a384301cdfa9 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -122,7 +122,7 @@ class QtRPCTimerBase: public QObject, public RPCTimerBase connect(&timer, &QTimer::timeout, [this]{ func(); }); timer.start(millis); } - ~QtRPCTimerBase() {} + ~QtRPCTimerBase() = default; private: QTimer timer; std::function func; @@ -131,7 +131,7 @@ class QtRPCTimerBase: public QObject, public RPCTimerBase class QtRPCTimerInterface: public RPCTimerInterface { public: - ~QtRPCTimerInterface() {} + ~QtRPCTimerInterface() = default; const char *Name() override { return "Qt"; } RPCTimerBase* NewTimer(std::function& func, int64_t millis) override { @@ -1174,8 +1174,9 @@ void RPCConsole::on_lineEdit_returnPressed() ui->lineEdit->clear(); + WalletModel* wallet_model{nullptr}; #ifdef ENABLE_WALLET - WalletModel* wallet_model = ui->WalletSelector->currentData().value(); + wallet_model = ui->WalletSelector->currentData().value(); if (m_last_wallet_model != wallet_model) { if (wallet_model) { @@ -1191,7 +1192,10 @@ void RPCConsole::on_lineEdit_returnPressed() //: A console message indicating an entered command is currently being executed. message(CMD_REPLY, tr("Executing…")); m_is_executing = true; - Q_EMIT cmdRequest(cmd, m_last_wallet_model); + + QMetaObject::invokeMethod(m_executor, [this, cmd, wallet_model] { + m_executor->request(cmd, wallet_model); + }); cmd = QString::fromStdString(strFilteredCmd); @@ -1233,11 +1237,11 @@ void RPCConsole::browseHistory(int offset) void RPCConsole::startExecutor() { - RPCExecutor *executor = new RPCExecutor(m_node); - executor->moveToThread(&thread); + m_executor = new RPCExecutor(m_node); + m_executor->moveToThread(&thread); // Replies from executor object must go to this object - connect(executor, &RPCExecutor::reply, this, [this](int category, const QString& command) { + connect(m_executor, &RPCExecutor::reply, this, [this](int category, const QString& command) { // Remove "Executing…" message. ui->messagesWidget->undo(); message(category, command); @@ -1245,16 +1249,13 @@ void RPCConsole::startExecutor() m_is_executing = false; }); - // Requests from this object must go to executor - connect(this, &RPCConsole::cmdRequest, executor, &RPCExecutor::request); - // Make sure executor object is deleted in its own thread - connect(&thread, &QThread::finished, executor, &RPCExecutor::deleteLater); + connect(&thread, &QThread::finished, m_executor, &RPCExecutor::deleteLater); // Default implementation of QThread::run() simply spins up an event loop in the thread, // which is what we want. thread.start(); - QTimer::singleShot(0, executor, []() { + QTimer::singleShot(0, m_executor, []() { util::ThreadRename("qt-rpcconsole"); }); } diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h index 9b825f4227e9..8bb1c1b9dfdd 100644 --- a/src/qt/rpcconsole.h +++ b/src/qt/rpcconsole.h @@ -5,6 +5,10 @@ #ifndef BITCOIN_QT_RPCCONSOLE_H #define BITCOIN_QT_RPCCONSOLE_H +#if defined(HAVE_CONFIG_H) +#include +#endif + #include #include #include @@ -18,6 +22,7 @@ #include class ClientModel; +class RPCExecutor; class RPCTimerInterface; class WalletModel; @@ -51,8 +56,11 @@ class RPCConsole: public QWidget } void setClientModel(ClientModel *model = nullptr, int bestblock_height = 0, int64_t bestblock_date = 0, uint256 bestblock_hash = uint256(), double verification_progress = 0.0); - void addWallet(WalletModel * const walletModel); + +#ifdef ENABLE_WALLET + void addWallet(WalletModel* const walletModel); void removeWallet(WalletModel* const walletModel); +#endif // ENABLE_WALLET enum MessageClass { MC_ERROR, @@ -149,8 +157,6 @@ public Q_SLOTS: #endif // ENABLE_WALLET Q_SIGNALS: - // For RPC command executor - void cmdRequest(const QString &command, const WalletModel* wallet_model); /** Get restart command-line parameters and handle restart */ void handleRestart(QStringList args); @@ -193,6 +199,7 @@ public Q_SLOTS: int consoleFontSize = 0; QCompleter *autoCompleter = nullptr; QThread thread; + RPCExecutor* m_executor{nullptr}; WalletModel* m_last_wallet_model{nullptr}; bool m_is_executing{false}; QByteArray m_peer_widget_header_state; diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index 8e5253b61ff2..146ed5cefe8c 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -226,7 +226,18 @@ void SendCoinsDialog::setModel(WalletModel *_model) updateFeeSectionControls(); updateSmartFeeLabel(); - if (model->wallet().privateKeysDisabled()) { + if (model->wallet().hasExternalSigner()) { + //: "device" usually means a hardware wallet + ui->sendButton->setText(tr("Sign on device")); + if (gArgs.GetArg("-signer", "") != "") { + ui->sendButton->setEnabled(true); + ui->sendButton->setToolTip(tr("Connect your hardware wallet first.")); + } else { + ui->sendButton->setEnabled(false); + //: "External signer" means using devices such as hardware wallets. + ui->sendButton->setToolTip(tr("Set external signer script path in Options -> Wallet")); + } + } else if (model->wallet().privateKeysDisabled()) { ui->sendButton->setText(tr("Cr&eate Unsigned")); ui->sendButton->setToolTip(tr("Creates a Partially Signed Blockchain Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.").arg(PACKAGE_NAME)); } @@ -362,27 +373,29 @@ bool SendCoinsDialog::send(const QList& recipients, QString& formatted_short.erase(formatted_short.begin() + MAX_SEND_POPUP_ENTRIES, formatted_short.end()); } + // Wrap the whole text in a global span to control its styling properly + question_string.append(""); + /*: 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. */ question_string.append(tr("Do you want to create this transaction?")); question_string.append("
    "); - // TODO: re-enable it when external signer will be backported - // if (model->wallet().privateKeysDisabled() && !model->wallet().hasExternalSigner()) { - const bool external_signer_available{false}; - if (external_signer_available) { + if (model->wallet().privateKeysDisabled() && !model->wallet().hasExternalSigner()) { + question_string.append(tr("Do you want to draft this transaction?")); /*: 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. */ - question_string.append(tr("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.").arg(PACKAGE_NAME)); + question_string.append(tr("Please, review your transaction proposal. This will produce a Partially Signed Blockchain Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.").arg(PACKAGE_NAME)); } else if (model->getOptionsModel()->getEnablePSBTControls()) { /*: 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. */ - question_string.append(tr("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.").arg(PACKAGE_NAME)); + question_string.append(tr("Please, review your transaction. You can create and send this transaction or create a Partially Signed Blockchain Transaction (PSBT), which you can save or copy and then sign with, e.g., an offline %1 wallet, or a PSBT-compatible hardware wallet.").arg(PACKAGE_NAME)); } else { /*: Text to prompt a user to review the details of the transaction they are attempting to send. */ question_string.append(tr("Please, review your transaction.")); } + question_string.append(""); question_string.append("

    "); question_string.append(formatted_short.join("
    ")); question_string.append("
    "); @@ -440,7 +453,7 @@ bool SendCoinsDialog::send(const QList& recipients, QString& question_string.append("
    "); question_string.append(""); question_string.append(tr("Warning: Using %1 with %2 or more inputs can harm your privacy and is not recommended").arg(strCoinJoinName).arg(10)); - question_string.append(""); + question_string.append(" "); question_string.append(tr("Click to learn more")); question_string.append(""); question_string.append(" "); @@ -462,6 +475,9 @@ bool SendCoinsDialog::send(const QList& recipients, QString& question_string.append(QString("
    (=%1)") .arg(alternativeUnits.join(" " + tr("or") + " "))); + // Close the global span we opened at the very beginning + question_string.append("
    "); + if (formatted.size() > 1) { informative_text = tr("To review recipient list click \"Show Details…\""); detailed_text = formatted.join("\n\n"); @@ -496,9 +512,52 @@ void SendCoinsDialog::sendButtonClicked([[maybe_unused]] bool checked) CMutableTransaction mtx = CMutableTransaction{*(m_current_transaction->getWtx())}; PartiallySignedTransaction psbtx(mtx); bool complete = false; - const TransactionError err = model->wallet().fillPSBT(SIGHASH_ALL, false /* sign */, true /* bip32derivs */, nullptr, psbtx, complete); + // 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, false /* sign */, true /* bip32derivs */, nullptr, psbtx, complete); assert(!complete); assert(err == TransactionError::OK); + if (model->wallet().hasExternalSigner()) { + try { + err = model->wallet().fillPSBT(SIGHASH_ALL, true /* sign */, true /* bip32derivs */, nullptr, psbtx, complete); + } catch (const std::runtime_error& e) { + QMessageBox::critical(nullptr, tr("Sign failed"), e.what()); + send_failure = true; + return; + } + if (err == TransactionError::EXTERNAL_SIGNER_NOT_FOUND) { + //: "External signer" means using devices such as hardware wallets. + QMessageBox::critical(nullptr, tr("External signer not found"), "External signer not found"); + send_failure = true; + return; + } + if (err == TransactionError::EXTERNAL_SIGNER_FAILED) { + //: "External signer" means using devices such as hardware wallets. + QMessageBox::critical(nullptr, tr("External signer failure"), "External signer failure"); + send_failure = true; + return; + } + if (err != TransactionError::OK) { + tfm::format(std::cerr, "Failed to sign PSBT"); + processSendCoinsReturn(WalletModel::TransactionCreationFailed); + send_failure = true; + return; + } + // fillPSBT does not always properly finalize + complete = FinalizeAndExtractPSBT(psbtx, mtx); + } + + // Broadcast transaction if complete (even with an external signer this + // is not always the case, e.g. in a multisig wallet). + if (complete) { + const CTransactionRef tx = MakeTransactionRef(mtx); + m_current_transaction->setWtx(tx); + model->sendCoins(*m_current_transaction, m_coin_control->IsUsingCoinJoin()); + return; + } + + // Copy PSBT to clipboard and offer to save + assert(!complete); // Serialize the PSBT CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); ssTx << psbtx; @@ -540,7 +599,7 @@ void SendCoinsDialog::sendButtonClicked([[maybe_unused]] bool checked) break; default: assert(false); - } + } // msgBox.exec() } else { assert(!model->wallet().privateKeysDisabled()); // now send the prepared transaction @@ -708,7 +767,9 @@ void SendCoinsDialog::setBalance(const interfaces::WalletBalances& balances) if(model && model->getOptionsModel()) { CAmount balance = 0; - if (model->wallet().privateKeysDisabled()) { + if (model->wallet().hasExternalSigner()) { + ui->labelBalanceName->setText(tr("External balance:")); + } else if (model->wallet().privateKeysDisabled()) { balance = balances.watch_only_balance; ui->labelBalanceName->setText(tr("Watch-only balance:")); } else if (m_coin_control->IsUsingCoinJoin()) { @@ -794,7 +855,7 @@ void SendCoinsDialog::on_buttonMinimizeFee_clicked() void SendCoinsDialog::useAvailableBalance(SendCoinsEntry* entry) { // Include watch-only for wallets without private key - m_coin_control->fAllowWatchOnly = model->wallet().privateKeysDisabled(); + m_coin_control->fAllowWatchOnly = model->wallet().privateKeysDisabled() && !model->wallet().hasExternalSigner(); // Calculate available amount to send. CAmount amount = model->wallet().getAvailableBalance(*m_coin_control); @@ -848,7 +909,7 @@ void SendCoinsDialog::updateCoinControlState() // Either custom fee will be used or if not selected, the confirmation target from dropdown box m_coin_control->m_confirm_target = getConfTargetForIndex(ui->confTargetSelector->currentIndex()); // Include watch-only for wallets without private key - m_coin_control->fAllowWatchOnly = model->wallet().privateKeysDisabled(); + m_coin_control->fAllowWatchOnly = model->wallet().privateKeysDisabled() && !model->wallet().hasExternalSigner(); } void SendCoinsDialog::updateNumberOfBlocks(int count, const QDateTime& blockDate, const QString& blockHash, double nVerificationProgress, bool header, SynchronizationState sync_state) { diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp index cb92b6d9e2f5..f82f71c2c264 100644 --- a/src/qt/splashscreen.cpp +++ b/src/qt/splashscreen.cpp @@ -55,7 +55,7 @@ SplashScreen::SplashScreen(const NetworkStyle *networkStyle) : // define text to place QString titleText = PACKAGE_NAME; QString versionText = QString::fromStdString(FormatFullVersion()).remove(0, 1); - QString titleAddText = networkStyle->getTitleAddText(); + const QString& titleAddText = networkStyle->getTitleAddText(); QFont fontNormal = GUIUtil::getFontNormal(); QFont fontBold = GUIUtil::getFontBold(); @@ -116,8 +116,7 @@ SplashScreen::SplashScreen(const NetworkStyle *networkStyle) : int titleAddTextWidth = GUIUtil::TextWidth(fm, titleAddText); // Draw the badge background with the network-specific color QRect badgeRect = QRect(width - titleAddTextWidth - 20, 5, width, fm.height() + 10); - QColor badgeColor = networkStyle->getBadgeColor(); - pixPaint.fillRect(badgeRect, badgeColor); + pixPaint.fillRect(badgeRect, networkStyle->getBadgeColor()); // Draw the text itself using white color, regardless of the current theme pixPaint.setPen(QColor(255, 255, 255)); pixPaint.drawText(width - titleAddTextWidth - 10, paddingTop + 10, titleAddText); diff --git a/src/qt/test/addressbooktests.cpp b/src/qt/test/addressbooktests.cpp index fb3c80f23c98..0701557b0ada 100644 --- a/src/qt/test/addressbooktests.cpp +++ b/src/qt/test/addressbooktests.cpp @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -98,11 +99,13 @@ void TestAddAddressesToSendBook(interfaces::Node& node) QString s_label("already here (s)"); // Define a new address (which should add to the address book successfully). - QString new_address; + QString new_address_a; + QString new_address_b; std::tie(r_key_dest, preexisting_r_address) = build_address(); std::tie(s_key_dest, preexisting_s_address) = build_address(); - std::tie(std::ignore, new_address) = build_address(); + std::tie(std::ignore, new_address_a) = build_address(); + std::tie(std::ignore, new_address_b) = build_address(); { LOCK(wallet->cs_wallet); @@ -154,9 +157,52 @@ void TestAddAddressesToSendBook(interfaces::Node& node) // Submit a new address which should add successfully - we expect the // warning message to be blank. EditAddressAndSubmit( - &editAddressDialog, QString("new"), new_address, QString("")); + &editAddressDialog, QString("io - new A"), new_address_a, QString("")); check_addbook_size(3); QCOMPARE(table_view->model()->rowCount(), 2); + + EditAddressAndSubmit( + &editAddressDialog, QString("io - new B"), new_address_b, QString("")); + check_addbook_size(4); + QCOMPARE(table_view->model()->rowCount(), 3); + + auto search_line = address_book.findChild("searchLineEdit"); + + search_line->setText(r_label); + QCOMPARE(table_view->model()->rowCount(), 0); + + search_line->setText(s_label); + QCOMPARE(table_view->model()->rowCount(), 1); + + search_line->setText("io"); + QCOMPARE(table_view->model()->rowCount(), 2); + + // Check wilcard "?". + search_line->setText("io?new"); + QCOMPARE(table_view->model()->rowCount(), 0); + search_line->setText("io???new"); + QCOMPARE(table_view->model()->rowCount(), 2); + + // Check wilcard "*". + search_line->setText("io*new"); + QCOMPARE(table_view->model()->rowCount(), 2); + search_line->setText("*"); + QCOMPARE(table_view->model()->rowCount(), 3); + + search_line->setText(preexisting_r_address); + QCOMPARE(table_view->model()->rowCount(), 0); + + search_line->setText(preexisting_s_address); + QCOMPARE(table_view->model()->rowCount(), 1); + + search_line->setText(new_address_a); + QCOMPARE(table_view->model()->rowCount(), 1); + + search_line->setText(new_address_b); + QCOMPARE(table_view->model()->rowCount(), 1); + + search_line->setText(""); + QCOMPARE(table_view->model()->rowCount(), 3); } } // namespace diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp index bb6ac6992289..a1c91b64bd56 100644 --- a/src/qt/transactiondesc.cpp +++ b/src/qt/transactiondesc.cpp @@ -35,25 +35,51 @@ using wallet::isminetype; QString TransactionDesc::FormatTxStatus(const interfaces::WalletTxStatus& status, bool inMempool) { int depth = status.depth_in_main_chain; - if (depth < 0) return tr("conflicted"); + if (depth < 0) { + /*: 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. */ + return tr("conflicted with a transaction with %1 confirmations").arg(-depth); + } QString strTxStatus; bool fChainLocked = status.is_chainlocked; if (depth == 0) { + /*: 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. */ const QString abandoned{status.is_abandoned ? QLatin1String(", ") + tr("abandoned") : QString()}; + /*: 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. */ strTxStatus = tr("0/unconfirmed, %1").arg((inMempool ? tr("in memory pool") : tr("not in memory pool"))) + abandoned; } else if (!fChainLocked && depth < 6) { + /*: 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, and still not locked via ChainLocks. */ strTxStatus = tr("%1/unconfirmed").arg(depth); } else { + /*: 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 + or locked via ChainLocks. */ strTxStatus = tr("%1 confirmations").arg(depth); if (fChainLocked) { + /*: 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 and has been locked by ChainLocks. */ strTxStatus += QLatin1String(", ") + tr("locked via ChainLocks"); return strTxStatus; } } if (status.is_islocked) { + /*: 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 has been locked by InstantSend. */ strTxStatus += QLatin1String(", ") + tr("verified via InstantSend"); } diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp index 0e550eb1bf9e..3814cd9c1999 100644 --- a/src/qt/transactionrecord.cpp +++ b/src/qt/transactionrecord.cpp @@ -13,7 +13,6 @@ #include -using wallet::ISMINE_ALL; using wallet::ISMINE_SPENDABLE; using wallet::ISMINE_WATCH_ONLY; using wallet::isminetype; diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp index c0e8d540fd92..d337057b2fb6 100644 --- a/src/qt/transactiontablemodel.cpp +++ b/src/qt/transactiontablemodel.cpp @@ -61,7 +61,7 @@ struct TxLessThan struct TransactionNotification { public: - TransactionNotification() {} + TransactionNotification() = default; TransactionNotification(uint256 _hash, ChangeType _status, bool _showTransaction): hash(_hash), status(_status), showTransaction(_showTransaction) {} diff --git a/src/qt/utilitydialog.cpp b/src/qt/utilitydialog.cpp index a57217e09e70..a6ae662d39c7 100644 --- a/src/qt/utilitydialog.cpp +++ b/src/qt/utilitydialog.cpp @@ -62,7 +62,8 @@ HelpMessageDialog::HelpMessageDialog(QWidget *parent, HelpMode helpMode) : ui->helpMessage->setVisible(false); } else if (helpMode == cmdline) { setWindowTitle(tr("Command-line options")); - QString header = "Usage: dash-qt [command-line options] \n"; + QString header = "Usage: dash-qt [command-line options] [URI]\n\n" + "Optional URI is a Dash address in BIP21 URI format.\n"; QTextCursor cursor(ui->helpMessage->document()); cursor.insertText(version); cursor.insertBlock(); diff --git a/src/qt/walletcontroller.cpp b/src/qt/walletcontroller.cpp index 935727806bc7..f694dbfde523 100644 --- a/src/qt/walletcontroller.cpp +++ b/src/qt/walletcontroller.cpp @@ -7,12 +7,14 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -34,6 +36,7 @@ using wallet::WALLET_FLAG_BLANK_WALLET; using wallet::WALLET_FLAG_DESCRIPTORS; +using wallet::WALLET_FLAG_EXTERNAL_SIGNER; using wallet::WALLET_FLAG_DISABLE_PRIVATE_KEYS; WalletController::WalletController(ClientModel& client_model, QObject* parent) @@ -78,14 +81,6 @@ std::map WalletController::listWalletDir() const 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); @@ -96,7 +91,10 @@ void WalletController::closeWallet(WalletModel* wallet_model, QWidget* parent) box.setDefaultButton(QMessageBox::Yes); if (box.exec() != QMessageBox::Yes) return; - removeWallet(wallet_model); + // First remove wallet from node. + wallet_model->wallet().remove(); + // Now release the model. + removeAndDeleteWallet(wallet_model); } void WalletController::closeAllWallets(QWidget* parent) @@ -109,8 +107,11 @@ void WalletController::closeAllWallets(QWidget* parent) QMutexLocker locker(&m_mutex); for (WalletModel* wallet_model : m_wallets) { - removeWallet(wallet_model); + wallet_model->wallet().remove(); + Q_EMIT walletRemoved(wallet_model); + delete wallet_model; } + m_wallets.clear(); } WalletModel* WalletController::getOrCreateWallet(std::unique_ptr wallet) @@ -259,6 +260,9 @@ void CreateWalletActivity::createWallet() if (m_create_wallet_dialog->isDescriptorWalletChecked()) { flags |= WALLET_FLAG_DESCRIPTORS; } + if (m_create_wallet_dialog->isExternalSignerChecked()) { + flags |= WALLET_FLAG_EXTERNAL_SIGNER; + } QTimer::singleShot(500ms, worker(), [this, name, flags] { auto wallet{node().walletLoader().createWallet(name, m_passphrase, flags, m_warning_message)}; @@ -281,7 +285,83 @@ void CreateWalletActivity::finish() QMessageBox::warning(m_parent_widget, tr("Create wallet warning"), QString::fromStdString(Join(m_warning_message, Untranslated("\n")).translated)); } - if (m_wallet_model) Q_EMIT created(m_wallet_model); + if (m_wallet_model) { + // Check if wallet is HD-enabled (has mnemonic) and requires verification + // Skip verification for blank wallets or wallets with disabled private keys + if (!m_wallet_model->wallet().hdEnabled() || + m_wallet_model->wallet().privateKeysDisabled() || + !m_wallet_model->wallet().canGetAddresses()) { + // Not an HD wallet - skip verification + Q_EMIT created(m_wallet_model); + Q_EMIT finished(); + return; + } + + // Unlock wallet if encrypted (needed to retrieve mnemonic) + // Note: Newly created wallet can only be locked (if encrypted) or unencrypted. + // Mixing-only unlock state is not possible at wallet creation time. + const bool was_locked = (m_wallet_model->getEncryptionStatus() == WalletModel::Locked); + if (was_locked) { + // Unlock to retrieve mnemonic using passphrase from wallet creation + if (!m_wallet_model->setWalletLocked(false, m_passphrase, false)) { + QMessageBox::warning(m_parent_widget, tr("Unlock failed"), + tr("Failed to unlock wallet for mnemonic verification. Wallet creation completed but verification skipped.")); + Q_EMIT created(m_wallet_model); + Q_EMIT finished(); + return; + } + } + + // Check if wallet has a mnemonic and requires verification + SecureString mnemonic; + SecureString mnemonic_passphrase; + bool has_mnemonic = m_wallet_model->wallet().getMnemonic(mnemonic, mnemonic_passphrase); + + if (!has_mnemonic || mnemonic.empty()) { + // No mnemonic found - log warning and skip verification + if (was_locked) { + m_wallet_model->setWalletLocked(true); + } + // Clear sensitive data before showing message + mnemonic.assign(mnemonic.size(), 0); + mnemonic_passphrase.assign(mnemonic_passphrase.size(), 0); + QMessageBox::warning(m_parent_widget, tr("Mnemonic retrieval failed"), + tr("Could not retrieve mnemonic phrase from wallet. Wallet creation completed but verification skipped.")); + Q_EMIT created(m_wallet_model); + Q_EMIT finished(); + return; + } + + // Wallet has mnemonic - show verification dialog + MnemonicVerificationDialog verify_dialog(mnemonic, m_parent_widget); + verify_dialog.setWindowModality(Qt::ApplicationModal); + + // Clear mnemonic from local variables after dialog has copied it + // The dialog will manage its own copy securely + const size_t mnemonic_size = mnemonic.size(); + const size_t passphrase_size = mnemonic_passphrase.size(); + mnemonic.assign(mnemonic_size, 0); + mnemonic_passphrase.assign(passphrase_size, 0); + + if (verify_dialog.exec() == QDialog::Accepted) { + // Verification successful + if (was_locked) { + m_wallet_model->setWalletLocked(true); + } + Q_EMIT created(m_wallet_model); + } else { + // User cancelled verification + if (was_locked) { + m_wallet_model->setWalletLocked(true); + } + QMessageBox::warning(m_parent_widget, tr("Verification cancelled"), + tr("You cancelled mnemonic verification. Please make sure you have saved your mnemonic phrase safely.")); + Q_EMIT created(m_wallet_model); + } + } else { + // Wallet creation failed - no wallet model + // Already showed error message above + } Q_EMIT finished(); } @@ -289,6 +369,19 @@ void CreateWalletActivity::finish() void CreateWalletActivity::create() { m_create_wallet_dialog = new CreateWalletDialog(m_parent_widget); + + std::vector> signers; + try { + signers = node().listExternalSigners(); + } catch (const std::runtime_error& e) { + QMessageBox::critical(nullptr, tr("Can't list signers"), e.what()); + } + if (signers.size() > 1) { + QMessageBox::critical(nullptr, tr("Too many external signers found"), QString::fromStdString("More than one external signer found. Please connect only one at a time.")); + signers.clear(); + } + m_create_wallet_dialog->setSigners(signers); + m_create_wallet_dialog->setWindowModality(Qt::ApplicationModal); m_create_wallet_dialog->show(); diff --git a/src/qt/walletcontroller.h b/src/qt/walletcontroller.h index 0546c7f9ebd1..ccb7dbc62d51 100644 --- a/src/qt/walletcontroller.h +++ b/src/qt/walletcontroller.h @@ -79,9 +79,6 @@ class WalletController : public QObject std::unique_ptr m_handler_load_wallet; friend class WalletControllerActivity; - - //! Starts the wallet closure procedure - void removeWallet(WalletModel* wallet_model); }; class WalletControllerActivity : public QObject diff --git a/src/qt/walletframe.cpp b/src/qt/walletframe.cpp index 3a64e3327d26..417847a6fe68 100644 --- a/src/qt/walletframe.cpp +++ b/src/qt/walletframe.cpp @@ -62,9 +62,7 @@ WalletFrame::WalletFrame(QWidget* parent) walletStack->addWidget(governanceListPage); } -WalletFrame::~WalletFrame() -{ -} +WalletFrame::~WalletFrame() = default; void WalletFrame::setClientModel(ClientModel *_clientModel) { @@ -312,6 +310,13 @@ void WalletFrame::changePassphrase() walletView->changePassphrase(); } +void WalletFrame::showMnemonic() +{ + WalletView *walletView = currentWalletView(); + if (walletView) + walletView->showMnemonic(); +} + void WalletFrame::unlockWallet() { WalletView *walletView = currentWalletView(); diff --git a/src/qt/walletframe.h b/src/qt/walletframe.h index f95000d68d2d..f2820c7dd410 100644 --- a/src/qt/walletframe.h +++ b/src/qt/walletframe.h @@ -100,6 +100,8 @@ public Q_SLOTS: void backupWallet(); /** Change encrypted wallet passphrase */ void changePassphrase(); + /** Show wallet mnemonic/recovery phrase */ + void showMnemonic(); /** Ask for passphrase to unlock wallet temporarily */ void unlockWallet(); /** Lock wallet */ diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 0d448689c297..9b03c9cf9d5c 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -35,6 +35,7 @@ #include #include +#include #include #include @@ -578,6 +579,18 @@ WalletModel::UnlockContext::~UnlockContext() } } +bool WalletModel::displayAddress(std::string sAddress) +{ + CTxDestination dest = DecodeDestination(sAddress); + bool res = false; + try { + res = m_wallet->displayAddress(dest); + } catch (const std::runtime_error& e) { + QMessageBox::critical(nullptr, tr("Can't display address"), e.what()); + } + return res; +} + bool WalletModel::isWalletEnabled() { return !gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET); diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index 523c07ad91b9..b33e74a43ada 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -141,6 +141,8 @@ class WalletModel : public QObject UnlockContext requestUnlock(bool fForMixingOnly = false); + bool displayAddress(std::string sAddress); + static bool isWalletEnabled(); int getNumISLocks() const; diff --git a/src/qt/walletmodeltransaction.cpp b/src/qt/walletmodeltransaction.cpp index aed16d919262..c3dc38fa27c9 100644 --- a/src/qt/walletmodeltransaction.cpp +++ b/src/qt/walletmodeltransaction.cpp @@ -26,6 +26,11 @@ CTransactionRef& WalletModelTransaction::getWtx() return wtx; } +void WalletModelTransaction::setWtx(const CTransactionRef& newTx) +{ + wtx = newTx; +} + unsigned int WalletModelTransaction::getTransactionSize() { return wtx != nullptr ? ::GetSerializeSize(*wtx, PROTOCOL_VERSION) : 0; diff --git a/src/qt/walletmodeltransaction.h b/src/qt/walletmodeltransaction.h index 05973f621e34..67effb8e2908 100644 --- a/src/qt/walletmodeltransaction.h +++ b/src/qt/walletmodeltransaction.h @@ -27,6 +27,8 @@ class WalletModelTransaction QList getRecipients() const; CTransactionRef& getWtx(); + void setWtx(const CTransactionRef&); + unsigned int getTransactionSize(); void setTransactionFee(const CAmount& newFee); diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp index 38535b920d21..89433046bb54 100644 --- a/src/qt/walletview.cpp +++ b/src/qt/walletview.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -27,6 +28,7 @@ #include #include +#include #include #include #include @@ -153,9 +155,7 @@ WalletView::WalletView(WalletModel* wallet_model, QWidget* parent) GUIUtil::disableMacFocusRect(this); } -WalletView::~WalletView() -{ -} +WalletView::~WalletView() = default; void WalletView::setClientModel(ClientModel *_clientModel) { @@ -327,6 +327,54 @@ void WalletView::changePassphrase() GUIUtil::ShowModalDialogAsynchronously(dlg); } +void WalletView::showMnemonic() +{ + // Check if wallet supports mnemonic retrieval + if (walletModel->wallet().privateKeysDisabled()) { + QMessageBox::warning(this, tr("No Recovery Phrase"), + tr("This wallet does not have private keys and therefore has no recovery phrase.")); + return; + } + + if (!walletModel->wallet().hdEnabled()) { + QMessageBox::warning(this, tr("No Recovery Phrase"), + tr("This wallet was not created with HD (Hierarchical Deterministic) mode and does not have a recovery phrase.")); + return; + } + + // Request unlock if needed - UnlockContext will restore lock state on destruction + WalletModel::UnlockContext ctx(walletModel->requestUnlock()); + if (!ctx.isValid()) { + // User cancelled unlock + return; + } + + // Retrieve mnemonic + SecureString mnemonic; + SecureString mnemonic_passphrase; + bool has_mnemonic = walletModel->wallet().getMnemonic(mnemonic, mnemonic_passphrase); + + if (!has_mnemonic || mnemonic.empty()) { + QMessageBox::warning(this, tr("Mnemonic Retrieval Failed"), + tr("Could not retrieve the recovery phrase from this wallet.")); + return; + } + + // Show mnemonic verification dialog in view-only mode (no verification required) + MnemonicVerificationDialog verify_dialog(mnemonic, this, true); + verify_dialog.setWindowModality(Qt::ApplicationModal); + + // Clear mnemonic from local variables after dialog has copied it + const size_t mnemonic_size = mnemonic.size(); + const size_t passphrase_size = mnemonic_passphrase.size(); + mnemonic.assign(mnemonic_size, 0); + mnemonic_passphrase.assign(passphrase_size, 0); + + verify_dialog.exec(); + + // UnlockContext destructor will automatically restore the wallet lock state +} + void WalletView::unlockWallet(bool fForMixingOnly) { // Unlock wallet when requested by wallet model diff --git a/src/qt/walletview.h b/src/qt/walletview.h index 4ff82cbf4b8c..328b42821d06 100644 --- a/src/qt/walletview.h +++ b/src/qt/walletview.h @@ -107,6 +107,8 @@ public Q_SLOTS: void backupWallet(); /** Change encrypted wallet passphrase */ void changePassphrase(); + /** Show wallet mnemonic/recovery phrase */ + void showMnemonic(); /** Ask for passphrase to unlock wallet temporarily */ void unlockWallet(bool fAnonymizeOnly=false); /** Lock wallet */ diff --git a/src/random.cpp b/src/random.cpp index 362499abefb1..8f565000d9d6 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -295,14 +295,14 @@ static void SeedHardwareSlow(CSHA512& hasher) noexcept { } /** Use repeated SHA512 to strengthen the randomness in seed32, and feed into hasher. */ -static void Strengthen(const unsigned char (&seed)[32], int microseconds, CSHA512& hasher) noexcept +static void Strengthen(const unsigned char (&seed)[32], SteadyClock::duration dur, CSHA512& hasher) noexcept { CSHA512 inner_hasher; inner_hasher.Write(seed, sizeof(seed)); // Hash loop unsigned char buffer[64]; - int64_t stop = GetTimeMicros() + microseconds; + const auto stop{SteadyClock::now() + dur}; do { for (int i = 0; i < 1000; ++i) { inner_hasher.Finalize(buffer); @@ -312,7 +312,7 @@ static void Strengthen(const unsigned char (&seed)[32], int microseconds, CSHA51 // Benchmark operation and feed it into outer hasher. int64_t perf = GetPerformanceCounter(); hasher.Write((const unsigned char*)&perf, sizeof(perf)); - } while (GetTimeMicros() < stop); + } while (SteadyClock::now() < stop); // Produce output from inner state and feed it to outer hasher. inner_hasher.Finalize(buffer); @@ -443,9 +443,7 @@ class RNGState { InitHardwareRand(); } - ~RNGState() - { - } + ~RNGState() = default; void AddEvent(uint32_t event_info) noexcept EXCLUSIVE_LOCKS_REQUIRED(!m_events_mutex) { @@ -568,13 +566,13 @@ static void SeedSlow(CSHA512& hasher, RNGState& rng) noexcept } /** Extract entropy from rng, strengthen it, and feed it into hasher. */ -static void SeedStrengthen(CSHA512& hasher, RNGState& rng, int microseconds) noexcept +static void SeedStrengthen(CSHA512& hasher, RNGState& rng, SteadyClock::duration dur) noexcept { // Generate 32 bytes of entropy from the RNG, and a copy of the entropy already in hasher. unsigned char strengthen_seed[32]; rng.MixExtract(strengthen_seed, sizeof(strengthen_seed), CSHA512(hasher), false); // Strengthen the seed, and feed it into hasher. - Strengthen(strengthen_seed, microseconds, hasher); + Strengthen(strengthen_seed, dur, hasher); } static void SeedPeriodic(CSHA512& hasher, RNGState& rng) noexcept @@ -594,7 +592,7 @@ static void SeedPeriodic(CSHA512& hasher, RNGState& rng) noexcept LogPrint(BCLog::RANDOM, "Feeding %i bytes of dynamic environment data into RNG\n", hasher.Size() - old_size); // Strengthen for 10 ms - SeedStrengthen(hasher, rng, 10000); + SeedStrengthen(hasher, rng, 10ms); } static void SeedStartup(CSHA512& hasher, RNGState& rng) noexcept @@ -614,7 +612,7 @@ static void SeedStartup(CSHA512& hasher, RNGState& rng) noexcept LogPrint(BCLog::RANDOM, "Feeding %i bytes of environment data into RNG\n", hasher.Size() - old_size); // Strengthen for 100 ms - SeedStrengthen(hasher, rng, 100000); + SeedStrengthen(hasher, rng, 100ms); } enum class RNGLevel { diff --git a/src/rest.cpp b/src/rest.cpp index e58a650689f6..110c08476b48 100644 --- a/src/rest.cpp +++ b/src/rest.cpp @@ -223,7 +223,11 @@ static bool rest_headers(const CoreContext& context, } else if (path.size() == 1) { // new path with query parameter: /rest/headers/?count= hashStr = path[0]; - raw_count = req->GetQueryParameter("count").value_or("5"); + try { + raw_count = req->GetQueryParameter("count").value_or("5"); + } catch (const std::runtime_error& e) { + return RESTERR(req, HTTP_BAD_REQUEST, e.what()); + } } else { return RESTERR(req, HTTP_BAD_REQUEST, "Invalid URI format. Expected /rest/headers/.?count="); } @@ -399,7 +403,11 @@ static bool rest_filter_header(const CoreContext& context, HTTPRequest* req, con } else if (uri_parts.size() == 2) { // new path with query parameter: /rest/blockfilterheaders//?count= raw_blockhash = uri_parts[1]; - raw_count = req->GetQueryParameter("count").value_or("5"); + try { + raw_count = req->GetQueryParameter("count").value_or("5"); + } catch (const std::runtime_error& e) { + return RESTERR(req, HTTP_BAD_REQUEST, e.what()); + } } else { return RESTERR(req, HTTP_BAD_REQUEST, "Invalid URI format. Expected /rest/blockfilterheaders//.?count="); } @@ -620,51 +628,34 @@ static bool rest_chaininfo(const CoreContext& context, HTTPRequest* req, const s } } -static bool rest_mempool_info(const CoreContext& context, HTTPRequest* req, const std::string& strURIPart) +static bool rest_mempool(const CoreContext& context, HTTPRequest* req, const std::string& str_uri_part) { if (!CheckWarmup(req)) return false; - const CTxMemPool* mempool = GetMemPool(context, req); - if (!mempool) return false; - std::string param; - const RESTResponseFormat rf = ParseDataFormat(param, strURIPart); - switch (rf) { - case RESTResponseFormat::JSON: { - const LLMQContext* llmq_ctx = GetLLMQContext(context, req); - if (!llmq_ctx) return false; - - UniValue mempoolInfoObject = MempoolInfoToJSON(*mempool, *llmq_ctx->isman); - - std::string strJSON = mempoolInfoObject.write() + "\n"; - req->WriteHeader("Content-Type", "application/json"); - req->WriteReply(HTTP_OK, strJSON); - return true; - } - default: { - return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: json)"); - } + std::string param; + const RESTResponseFormat rf = ParseDataFormat(param, str_uri_part); + if (param != "contents" && param != "info") { + return RESTERR(req, HTTP_BAD_REQUEST, "Invalid URI format. Expected /rest/mempool/.json"); } -} -static bool rest_mempool_contents(const CoreContext& context, HTTPRequest* req, const std::string& strURIPart) -{ - if (!CheckWarmup(req)) return false; const CTxMemPool* mempool = GetMemPool(context, req); if (!mempool) return false; - std::string param; - const RESTResponseFormat rf = ParseDataFormat(param, strURIPart); switch (rf) { case RESTResponseFormat::JSON: { const LLMQContext* llmq_ctx = GetLLMQContext(context, req); if (!llmq_ctx) return false; - UniValue mempoolObject = MempoolToJSON(*mempool, llmq_ctx->isman.get(), true); + std::string str_json; + if (param == "contents") { + str_json = MempoolToJSON(*mempool, llmq_ctx->isman.get(), true).write() + "\n"; + } else { + str_json = MempoolInfoToJSON(*mempool, *llmq_ctx->isman).write() + "\n"; + } - std::string strJSON = mempoolObject.write() + "\n"; req->WriteHeader("Content-Type", "application/json"); - req->WriteReply(HTTP_OK, strJSON); + req->WriteReply(HTTP_OK, str_json); return true; } default: { @@ -691,7 +682,7 @@ static bool rest_tx(const CoreContext& context, HTTPRequest* req, const std::str 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, Params().GetConsensus(), hashBlock); + const CTransactionRef tx = GetTransaction(/*block_index=*/nullptr, node->mempool.get(), hash, Params().GetConsensus(), hashBlock); if (!tx) { return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found"); } @@ -982,8 +973,7 @@ static const struct { {"/rest/blockfilter/", rest_block_filter}, {"/rest/blockfilterheaders/", rest_filter_header}, {"/rest/chaininfo", rest_chaininfo}, - {"/rest/mempool/info", rest_mempool_info}, - {"/rest/mempool/contents", rest_mempool_contents}, + {"/rest/mempool/", rest_mempool}, {"/rest/headers/", rest_headers}, {"/rest/getutxos", rest_getutxos}, {"/rest/blockhashbyheight/", rest_blockhash_by_height}, diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 89b4ae290df7..8401e186c750 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -20,9 +20,9 @@ #include #include #include +#include #include #include -#include #include #include #include @@ -63,9 +63,10 @@ #include #include +using kernel::CCoinsStats; +using kernel::CoinStatsHashType; + using node::BlockManager; -using node::CCoinsStats; -using node::CoinStatsHashType; using node::NodeContext; using node::ReadBlockFromDisk; using node::SnapshotMetadata; @@ -77,7 +78,7 @@ struct CUpdatedBlock int height; }; -static Mutex cs_blockchange; +static GlobalMutex cs_blockchange; static std::condition_variable cond_blockchange; static CUpdatedBlock latestblock GUARDED_BY(cs_blockchange); @@ -451,7 +452,7 @@ static RPCHelpMan syncwithvalidationinterfacequeue() [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { SyncWithValidationInterfaceQueue(); - return NullUniValue; + return UniValue::VNULL; }, }; } @@ -483,7 +484,9 @@ static RPCHelpMan getblockfrompeer() "getblockfrompeer", "Attempt to fetch block from a given peer.\n\n" "We must have the header for this block, e.g. using submitheader.\n" - "Subsequent calls for the same block and a new peer will cause the response from the previous peer to be ignored.\n\n" + "Subsequent calls for the same block and a new peer will cause the response from the previous peer to be ignored.\n" + "Peers generally ignore requests for a stale block that they never fully verified, or one that is more than a month old.\n" + "When a peer does not respond with a block, we will disconnect.\n\n" "Returns an empty JSON object if the request was successfully scheduled.", { {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The block hash to try to fetch"}, @@ -886,6 +889,30 @@ static RPCHelpMan getmerkleblocks() }; } +const RPCResult getblock_vin{ + RPCResult::Type::ARR, "vin", "", + { + {RPCResult::Type::OBJ, "", "", + { + {RPCResult::Type::ELISION, "", "The same output as verbosity = 2"}, + {RPCResult::Type::OBJ, "prevout", "(Only if undo information is available)", + { + {RPCResult::Type::BOOL, "generated", "Coinbase or not"}, + {RPCResult::Type::NUM, "height", "The height of the prevout"}, + {RPCResult::Type::STR_AMOUNT, "value", "The value in " + CURRENCY_UNIT}, + {RPCResult::Type::OBJ, "scriptPubKey", "", + { + {RPCResult::Type::STR, "asm", "Disassembly of the public key script"}, + {RPCResult::Type::STR, "desc", "Inferred descriptor for the output"}, + {RPCResult::Type::STR_HEX, "hex", "The raw public key script bytes, hex-encoded"}, + {RPCResult::Type::STR, "address", /*optional=*/true, "The Dash address (only if a well-defined address exists)"}, + {RPCResult::Type::STR, "type", "The type, eg 'pubkeyhash'"}, + }}, + }}, + }}, + } +}; + static RPCHelpMan getblock() { return RPCHelpMan{"getblock", @@ -922,13 +949,7 @@ static RPCHelpMan getblock() {RPCResult::Type::NUM, "size", "The block size"}, {RPCResult::Type::ARR, "tx", "The transaction ids", {{RPCResult::Type::STR_HEX, "", "The transaction id"}}}, - {RPCResult::Type::OBJ, "cbTx", "The coinbase special transaction", - { - {RPCResult::Type::NUM, "version", "The coinbase special transaction version"}, - {RPCResult::Type::NUM, "height", "The block height"}, - {RPCResult::Type::STR_HEX, "merkleRootMNList", "The merkle root of the masternode list"}, - {RPCResult::Type::STR_HEX, "merkleRootQuorums", "The merkle root of the quorum list"}, - }}, + CCbTx::GetJsonHelp(/*key=*/"cbTx", /*optional=*/true), }}, RPCResult{"for verbosity = 2", RPCResult::Type::OBJ, "", "", @@ -951,26 +972,7 @@ static RPCHelpMan getblock() { {RPCResult::Type::OBJ, "", "", { - {RPCResult::Type::ARR, "vin", "", - { - {RPCResult::Type::OBJ, "", "", - { - {RPCResult::Type::ELISION, "", "The same output as verbosity = 2"}, - {RPCResult::Type::OBJ, "prevout", "(Only if undo information is available)", - { - {RPCResult::Type::BOOL, "generated", "Coinbase or not"}, - {RPCResult::Type::NUM, "height", "The height of the prevout"}, - {RPCResult::Type::NUM, "value", "The value in " + CURRENCY_UNIT}, - {RPCResult::Type::OBJ, "scriptPubKey", "", - { - {RPCResult::Type::STR, "asm", "The asm"}, - {RPCResult::Type::STR, "hex", "The hex"}, - {RPCResult::Type::STR, "address", /*optional=*/true, "The Dash address (only if a well-defined address exists)"}, - {RPCResult::Type::STR, "type", "The type, eg 'pubkeyhash'"}, - }}, - }}, - }}, - }}, + getblock_vin, }}, }}, }}, @@ -1104,6 +1106,31 @@ CoinStatsHashType ParseHashType(const std::string& hash_type_input) } } +std::optional GetUTXOStats(CCoinsView* view, node::BlockManager& blockman, + kernel::CoinStatsHashType hash_type, + const std::function& interruption_point, + const CBlockIndex* pindex, + bool index_requested) +{ + // Use CoinStatsIndex if it is requested and available and a hash_type of Muhash or None was requested + if ((hash_type == kernel::CoinStatsHashType::MUHASH || hash_type == kernel::CoinStatsHashType::NONE) && g_coin_stats_index && index_requested) { + if (pindex) { + return g_coin_stats_index->LookUpStats(pindex); + } else { + CBlockIndex* block_index = WITH_LOCK(::cs_main, return blockman.LookupBlockIndex(view->GetBestBlock())); + return g_coin_stats_index->LookUpStats(block_index); + } + } + + // If the coinstats index isn't requested or is otherwise not usable, the + // pindex should either be null or equal to the view's best block. This is + // because without the coinstats index we can only get coinstats about the + // best block. + CHECK_NONFATAL(!pindex || pindex->GetBlockHash() == view->GetBestBlock()); + + return kernel::ComputeUTXOStats(hash_type, view, blockman, interruption_point); +} + static RPCHelpMan gettxoutsetinfo() { return RPCHelpMan{"gettxoutsetinfo", @@ -1159,8 +1186,7 @@ static RPCHelpMan gettxoutsetinfo() const CBlockIndex* pindex{nullptr}; const CoinStatsHashType hash_type{request.params[0].isNull() ? CoinStatsHashType::HASH_SERIALIZED : ParseHashType(request.params[0].get_str())}; - CCoinsStats stats{hash_type}; - stats.index_requested = request.params[2].isNull() || request.params[2].get_bool(); + bool index_requested = request.params[2].isNull() || request.params[2].get_bool(); const NodeContext& node = EnsureAnyNodeContext(request.context); ChainstateManager& chainman = EnsureChainman(node); @@ -1181,17 +1207,17 @@ static RPCHelpMan gettxoutsetinfo() throw JSONRPCError(RPC_INVALID_PARAMETER, "Querying specific block heights requires coinstatsindex"); } - if (stats.m_hash_type == CoinStatsHashType::HASH_SERIALIZED) { + if (hash_type == CoinStatsHashType::HASH_SERIALIZED) { throw JSONRPCError(RPC_INVALID_PARAMETER, "hash_serialized_2 hash type cannot be queried for a specific block"); } - if (!stats.index_requested) { + if (!index_requested) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot set use_index to false when querying for a specific block"); } pindex = ParseHashOrHeight(request.params[1], chainman); } - if (stats.index_requested && g_coin_stats_index) { + if (index_requested && g_coin_stats_index) { if (!g_coin_stats_index->BlockUntilSyncedToCurrentChain()) { const IndexSummary summary{g_coin_stats_index->GetSummary()}; @@ -1203,7 +1229,9 @@ static RPCHelpMan gettxoutsetinfo() } } - if (GetUTXOStats(coins_view, *blockman, stats, node.rpc_interruption_point, pindex)) { + const std::optional maybe_stats = GetUTXOStats(coins_view, *blockman, hash_type, node.rpc_interruption_point, pindex, index_requested); + if (maybe_stats.has_value()) { + const CCoinsStats& stats = maybe_stats.value(); ret.pushKV("height", (int64_t)stats.nHeight); ret.pushKV("bestblock", stats.hashBlock.GetHex()); ret.pushKV("txouts", (int64_t)stats.nTransactionOutputs); @@ -1222,10 +1250,13 @@ static RPCHelpMan gettxoutsetinfo() } else { ret.pushKV("total_unspendable_amount", ValueFromAmount(stats.total_unspendable_amount)); - CCoinsStats prev_stats{hash_type}; - + CCoinsStats prev_stats{}; if (pindex->nHeight > 0) { - GetUTXOStats(coins_view, *blockman, prev_stats, node.rpc_interruption_point, pindex->pprev); + const std::optional maybe_prev_stats = GetUTXOStats(coins_view, *blockman, hash_type, node.rpc_interruption_point, pindex->pprev, index_requested); + if (!maybe_prev_stats) { + throw JSONRPCError(RPC_INTERNAL_ERROR, "Unable to read UTXO set"); + } + prev_stats = maybe_prev_stats.value(); } UniValue block_info(UniValue::VOBJ); @@ -1268,9 +1299,9 @@ static RPCHelpMan gettxout() {RPCResult::Type::STR_AMOUNT, "value", "The transaction value in " + CURRENCY_UNIT}, {RPCResult::Type::OBJ, "scriptPubKey", "", { - {RPCResult::Type::STR, "asm", ""}, + {RPCResult::Type::STR, "asm", "Disassembly of the public key script"}, {RPCResult::Type::STR, "desc", "Inferred descriptor for the output"}, - {RPCResult::Type::STR_HEX, "hex", ""}, + {RPCResult::Type::STR_HEX, "hex", "The raw public key script bytes, hex-encoded"}, {RPCResult::Type::STR_HEX, "type", "The type, eg pubkeyhash"}, {RPCResult::Type::STR, "address", /*optional=*/ true, "Dash address (only if a well-defined address exists)"}, }}, @@ -1298,8 +1329,7 @@ static RPCHelpMan gettxout() UniValue ret(UniValue::VOBJ); uint256 hash(ParseHashV(request.params[0], "txid")); - int n = request.params[1].getInt(); - COutPoint out(hash, n); + COutPoint out{hash, request.params[1].getInt()}; bool fMempool = true; if (!request.params[2].isNull()) fMempool = request.params[2].get_bool(); @@ -1312,11 +1342,11 @@ static RPCHelpMan gettxout() LOCK(mempool.cs); CCoinsViewMemPool view(coins_view, mempool); if (!view.GetCoin(out, coin) || mempool.isSpent(out)) { - return NullUniValue; + return UniValue::VNULL; } } else { if (!coins_view->GetCoin(out, coin)) { - return NullUniValue; + return UniValue::VNULL; } } @@ -1464,31 +1494,34 @@ RPCHelpMan getblockchaininfo() {RPCResult::Type::NUM, "pruneheight", /*optional=*/true, "height of the last block pruned, plus one (only present if pruning is enabled)"}, {RPCResult::Type::BOOL, "automatic_pruning", /*optional=*/true, "whether automatic pruning is enabled (only present if pruning is enabled)"}, {RPCResult::Type::NUM, "prune_target_size", /*optional=*/true, "the target size used by pruning (only present if automatic pruning is enabled)"}, - {RPCResult::Type::OBJ, "softforks", "status of softforks in progress", + {RPCResult::Type::OBJ_DYN, "softforks", "status of softforks in progress", { - {RPCResult::Type::STR, "type", "one of \"buried\", \"bip9\""}, - {RPCResult::Type::OBJ, "bip9", /*optional=*/true, "status of bip9 softforks (only for \"bip9\" type)", + {RPCResult::Type::OBJ, "xxxx", "name of the softfork", { - {RPCResult::Type::STR, "status", "one of \"defined\", \"started\", \"locked_in\", \"active\", \"failed\""}, - {RPCResult::Type::NUM, "bit", /*optional=*/true, "the bit (0-28) in the block version field used to signal this softfork (only for \"started\" and \"locked_in\" status)"}, - {RPCResult::Type::NUM_TIME, "start_time", "the minimum median time past of a block at which the bit gains its meaning"}, - {RPCResult::Type::NUM_TIME, "timeout", "the median time past of a block at which the deployment is considered failed if not yet locked in"}, - {RPCResult::Type::BOOL, "ehf", "returns true for EHF activated forks"}, - {RPCResult::Type::NUM, "ehf_height", /*optional=*/true, "the minimum height when miner's signals for the deployment matter. Below this height miner signaling cannot trigger hard fork lock-in. Not specified for non-EHF forks"}, - {RPCResult::Type::NUM, "since", "height of the first block to which the status applies"}, - {RPCResult::Type::NUM, "activation_height", "expected activation height for this softfork (only for \"locked_in\" status)"}, - {RPCResult::Type::NUM, "min_activation_height", "minimum height of blocks for which the rules may be enforced"}, - {RPCResult::Type::OBJ, "statistics", /*optional=*/true, "numeric statistics about signalling for a softfork (only for \"started\" and \"locked_in\" status)", + {RPCResult::Type::STR, "type", "one of \"buried\", \"bip9\""}, + {RPCResult::Type::OBJ, "bip9", /*optional=*/true, "status of bip9 softforks (only for \"bip9\" type)", { - {RPCResult::Type::NUM, "period", "the length in blocks of the signalling period"}, - {RPCResult::Type::NUM, "threshold", /*optional=*/true, "the number of blocks with the version bit set required to activate the feature (only for \"started\" status)"}, - {RPCResult::Type::NUM, "elapsed", "the number of blocks elapsed since the beginning of the current period"}, - {RPCResult::Type::NUM, "count", "the number of blocks with the version bit set in the current period"}, - {RPCResult::Type::BOOL, "possible", /*optional=*/true, "returns false if there are not enough blocks left in this period to pass activation threshold (only for \"started\" status)"}, + {RPCResult::Type::STR, "status", "one of \"defined\", \"started\", \"locked_in\", \"active\", \"failed\""}, + {RPCResult::Type::NUM, "bit", /*optional=*/true, "the bit (0-28) in the block version field used to signal this softfork (only for \"started\" and \"locked_in\" status)"}, + {RPCResult::Type::NUM_TIME, "start_time", "the minimum median time past of a block at which the bit gains its meaning"}, + {RPCResult::Type::NUM_TIME, "timeout", "the median time past of a block at which the deployment is considered failed if not yet locked in"}, + {RPCResult::Type::BOOL, "ehf", "returns true for EHF activated forks"}, + {RPCResult::Type::NUM, "ehf_height", /*optional=*/true, "the minimum height when miner's signals for the deployment matter. Below this height miner signaling cannot trigger hard fork lock-in. Not specified for non-EHF forks"}, + {RPCResult::Type::NUM, "since", "height of the first block to which the status applies"}, + {RPCResult::Type::NUM, "activation_height", "expected activation height for this softfork (only for \"locked_in\" status)"}, + {RPCResult::Type::NUM, "min_activation_height", "minimum height of blocks for which the rules may be enforced"}, + {RPCResult::Type::OBJ, "statistics", /*optional=*/true, "numeric statistics about signalling for a softfork (only for \"started\" and \"locked_in\" status)", + { + {RPCResult::Type::NUM, "period", "the length in blocks of the signalling period"}, + {RPCResult::Type::NUM, "threshold", /*optional=*/true, "the number of blocks with the version bit set required to activate the feature (only for \"started\" status)"}, + {RPCResult::Type::NUM, "elapsed", "the number of blocks elapsed since the beginning of the current period"}, + {RPCResult::Type::NUM, "count", "the number of blocks with the version bit set in the current period"}, + {RPCResult::Type::BOOL, "possible", /*optional=*/true, "returns false if there are not enough blocks left in this period to pass activation threshold (only for \"started\" status)"}, + }}, }}, + {RPCResult::Type::NUM, "height", /*optional=*/true, "height of the first block which the rules are or will be enforced (only for \"buried\" type, or \"bip9\" type with \"active\" status)"}, + {RPCResult::Type::BOOL, "active", "true if the rules are enforced for the mempool and the next block"}, }}, - {RPCResult::Type::NUM, "height", /*optional=*/true, "height of the first block which the rules are or will be enforced (only for \"buried\" type, or \"bip9\" type with \"active\" status)"}, - {RPCResult::Type::BOOL, "active", "true if the rules are enforced for the mempool and the next block"}, }}, {RPCResult::Type::STR, "warnings", "any network and blockchain warnings"}, }}, @@ -1561,7 +1594,7 @@ RPCHelpMan getblockchaininfo() SoftForkDescPushBack(&tip, softforks, consensusParams, deploy); } for (auto ehf_deploy : { /* sorted by activation block */ - Consensus::DEPLOYMENT_V23, + Consensus::DEPLOYMENT_V24, Consensus::DEPLOYMENT_TESTDUMMY }) { SoftForkDescPushBack(&tip, ehfSignals, softforks, consensusParams, ehf_deploy); } @@ -1743,7 +1776,7 @@ static RPCHelpMan preciousblock() throw JSONRPCError(RPC_DATABASE_ERROR, state.ToString()); } - return NullUniValue; + return UniValue::VNULL; }, }; } @@ -1786,7 +1819,7 @@ static RPCHelpMan invalidateblock() throw JSONRPCError(RPC_DATABASE_ERROR, state.ToString()); } - return NullUniValue; + return UniValue::VNULL; }, }; } @@ -1830,7 +1863,7 @@ static RPCHelpMan reconsiderblock() throw JSONRPCError(RPC_DATABASE_ERROR, state.ToString()); } - return NullUniValue; + return UniValue::VNULL; }, }; } @@ -2360,9 +2393,9 @@ static std::atomic g_should_abort_scan; class CoinsViewScanReserver { private: - bool m_could_reserve; + bool m_could_reserve{false}; public: - explicit CoinsViewScanReserver() : m_could_reserve(false) {} + explicit CoinsViewScanReserver() = default; bool reserve() { CHECK_NONFATAL(!m_could_reserve); @@ -2463,7 +2496,7 @@ static RPCHelpMan scantxoutset() CoinsViewScanReserver reserver; if (reserver.reserve()) { // no scan in progress - return NullUniValue; + return UniValue::VNULL; } result.pushKV("progress", g_scan_progress.load()); return result; @@ -2494,7 +2527,7 @@ static RPCHelpMan scantxoutset() for (const UniValue& scanobject : request.params[1].get_array().getValues()) { FlatSigningProvider provider; auto scripts = EvalDescriptorStringOrObject(scanobject, provider); - for (const auto& script : scripts) { + for (CScript& script : scripts) { std::string inferred = InferDescriptor(script, provider)->ToString(); needles.emplace(script); descriptors.emplace(std::move(script), std::move(inferred)); @@ -2674,7 +2707,7 @@ static RPCHelpMan dumptxoutset() } FILE* file{fsbridge::fopen(temppath, "wb")}; - CAutoFile afile{file, SER_DISK, CLIENT_VERSION}; + AutoFile afile{file}; if (afile.IsNull()) { throw JSONRPCError( RPC_INVALID_PARAMETER, @@ -2695,12 +2728,12 @@ static RPCHelpMan dumptxoutset() UniValue CreateUTXOSnapshot( NodeContext& node, CChainState& chainstate, - CAutoFile& afile, + AutoFile& afile, const fs::path& path, const fs::path& temppath) { std::unique_ptr pcursor; - CCoinsStats stats{CoinStatsHashType::HASH_SERIALIZED}; + std::optional maybe_stats; const CBlockIndex* tip; { @@ -2720,19 +2753,20 @@ UniValue CreateUTXOSnapshot( chainstate.ForceFlushStateToDisk(); - if (!GetUTXOStats(&chainstate.CoinsDB(), chainstate.m_blockman, stats, node.rpc_interruption_point)) { + maybe_stats = GetUTXOStats(&chainstate.CoinsDB(), chainstate.m_blockman, CoinStatsHashType::HASH_SERIALIZED, node.rpc_interruption_point); + if (!maybe_stats) { throw JSONRPCError(RPC_INTERNAL_ERROR, "Unable to read UTXO set"); } pcursor = chainstate.CoinsDB().Cursor(); - tip = CHECK_NONFATAL(chainstate.m_blockman.LookupBlockIndex(stats.hashBlock)); + tip = CHECK_NONFATAL(chainstate.m_blockman.LookupBlockIndex(maybe_stats->hashBlock)); } 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{tip->GetBlockHash(), stats.coins_count, tip->nChainTx}; + SnapshotMetadata metadata{tip->GetBlockHash(), maybe_stats->coins_count, tip->nChainTx}; afile << metadata; @@ -2754,59 +2788,51 @@ UniValue CreateUTXOSnapshot( afile.fclose(); UniValue result(UniValue::VOBJ); - result.pushKV("coins_written", stats.coins_count); + result.pushKV("coins_written", maybe_stats->coins_count); result.pushKV("base_hash", tip->GetBlockHash().ToString()); result.pushKV("base_height", tip->nHeight); result.pushKV("path", path.utf8string()); - result.pushKV("txoutset_hash", stats.hashSerialized.ToString()); + result.pushKV("txoutset_hash", maybe_stats->hashSerialized.ToString()); // Cast required because univalue doesn't have serialization specified for // `unsigned int`, nChainTx's type. result.pushKV("nchaintx", uint64_t{tip->nChainTx}); return result; } - -void RegisterBlockchainRPCCommands(CRPCTable &t) -{ -// clang-format off -static const CRPCCommand commands[] = -{ // category actor (function) - // --------------------- ------------------------ - { "blockchain", &getblockchaininfo, }, - { "blockchain", &getchaintxstats, }, - { "blockchain", &getblockstats, }, - { "blockchain", &getbestblockhash, }, - { "blockchain", &getbestchainlock, }, - { "blockchain", &getblockcount, }, - { "blockchain", &getblock, }, - { "blockchain", &getblockfrompeer, }, - { "blockchain", &getblockhashes, }, - { "blockchain", &getblockhash, }, - { "blockchain", &getblockheader, }, - { "blockchain", &getblockheaders, }, - { "blockchain", &getmerkleblocks, }, - { "blockchain", &getchaintips, }, - { "blockchain", &getdifficulty, }, - { "blockchain", &getspecialtxes, }, - { "blockchain", &gettxout, }, - { "blockchain", &gettxoutsetinfo, }, - { "blockchain", &pruneblockchain, }, - { "blockchain", &verifychain, }, - - { "blockchain", &preciousblock, }, - { "blockchain", &scantxoutset, }, - { "blockchain", &getblockfilter, }, - - /* Not shown in help */ - { "hidden", &invalidateblock, }, - { "hidden", &reconsiderblock, }, - { "hidden", &waitfornewblock, }, - { "hidden", &waitforblock, }, - { "hidden", &waitforblockheight, }, - { "hidden", &syncwithvalidationinterfacequeue, }, - { "hidden", &dumptxoutset, }, -}; -// clang-format on +void RegisterBlockchainRPCCommands(CRPCTable& t) +{ + static const CRPCCommand commands[]{ + {"blockchain", &getblockchaininfo}, + {"blockchain", &getchaintxstats}, + {"blockchain", &getblockstats}, + {"blockchain", &getbestblockhash}, + {"blockchain", &getbestchainlock}, + {"blockchain", &getblockcount}, + {"blockchain", &getblock}, + {"blockchain", &getblockfrompeer}, + {"blockchain", &getblockhashes}, + {"blockchain", &getblockhash}, + {"blockchain", &getblockheader}, + {"blockchain", &getblockheaders}, + {"blockchain", &getmerkleblocks}, + {"blockchain", &getchaintips}, + {"blockchain", &getdifficulty}, + {"blockchain", &getspecialtxes}, + {"blockchain", &gettxout}, + {"blockchain", &gettxoutsetinfo}, + {"blockchain", &pruneblockchain}, + {"blockchain", &verifychain}, + {"blockchain", &preciousblock}, + {"blockchain", &scantxoutset}, + {"blockchain", &getblockfilter}, + {"hidden", &invalidateblock}, + {"hidden", &reconsiderblock}, + {"hidden", &waitfornewblock}, + {"hidden", &waitforblock}, + {"hidden", &waitforblockheight}, + {"hidden", &syncwithvalidationinterfacequeue}, + {"hidden", &dumptxoutset}, + }; for (const auto& c : commands) { t.appendCommand(c.name, &c); } diff --git a/src/rpc/blockchain.h b/src/rpc/blockchain.h index 6438cfcf6a02..0ef7c2bd30e6 100644 --- a/src/rpc/blockchain.h +++ b/src/rpc/blockchain.h @@ -8,10 +8,13 @@ #include #include #include +#include #include #include -#include +#include +#include +#include #include extern RecursiveMutex cs_main; @@ -19,7 +22,10 @@ extern RecursiveMutex cs_main; class CBlock; class CBlockIndex; class CChainState; -class UniValue; +class CCoinsView; +namespace kernel { +enum class CoinStatsHashType : uint8_t; +} namespace llmq { class CChainLocksHandler; class CInstantSendManager; @@ -29,6 +35,8 @@ class BlockManager; struct NodeContext; } // namespace node +class UniValue; + static constexpr int NUM_GETBLOCKSTATS_PERCENTILES = 5; /** @@ -58,8 +66,19 @@ void CalculatePercentilesBySize(CAmount result[NUM_GETBLOCKSTATS_PERCENTILES], s UniValue CreateUTXOSnapshot( node::NodeContext& node, CChainState& chainstate, - CAutoFile& afile, + AutoFile& afile, const fs::path& path, const fs::path& tmppath); +/** + * Calculate statistics about the unspent transaction output set + * + * @param[in] index_requested Signals if the coinstatsindex should be used (when available). + */ +std::optional GetUTXOStats(CCoinsView* view, node::BlockManager& blockman, + kernel::CoinStatsHashType hash_type, + const std::function& interruption_point = {}, + const CBlockIndex* pindex = nullptr, + bool index_requested = true); + #endif // BITCOIN_RPC_BLOCKCHAIN_H diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index eeb75eba835d..636ca29d6163 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -8,16 +8,17 @@ #include #include -#include +#include #include #include class CRPCConvertParam { public: - std::string methodName; //!< method whose params want conversion - int paramIdx; //!< 0-based idx of param to convert - std::string paramName; //!< parameter name + std::string methodName; //!< method whose params want conversion + int paramIdx; //!< 0-based idx of param to convert + std::string paramName; //!< parameter name + bool preserve_str{false}; //!< only parse if array or object }; // clang-format off @@ -199,6 +200,7 @@ static const CRPCConvertParam vRPCConvertParams[] = { "setwalletflag", 1, "value" }, { "getmempoolancestors", 1, "verbose" }, { "getmempooldescendants", 1, "verbose" }, + { "gettxspendingprevout", 0, "outputs" }, { "logging", 0, "include" }, { "logging", 1, "exclude" }, { "sporkupdate", 1, "value" }, @@ -237,6 +239,7 @@ static const CRPCConvertParam vRPCConvertParams[] = { "createwallet", 4, "avoid_reuse"}, { "createwallet", 5, "descriptors"}, { "createwallet", 6, "load_on_startup"}, + { "createwallet", 7, "external_signer"}, { "restorewallet", 2, "load_on_startup"}, { "loadwallet", 1, "load_on_startup"}, { "unloadwallet", 1, "load_on_startup"}, @@ -252,14 +255,47 @@ static const CRPCConvertParam vRPCConvertParams[] = { "verifyislock", 3, "maxHeight" }, { "submitchainlock", 2, "blockHeight" }, { "mnauth", 0, "nodeId" }, + { "protx register", 3, "coreP2PAddrs", true }, + { "protx register_legacy", 3, "coreP2PAddrs", true }, + { "protx register_evo", 3, "coreP2PAddrs", true }, + { "protx register_evo", 10, "platformP2PAddrs", true }, + { "protx register_evo", 11, "platformHTTPSAddrs", true }, + { "protx register_fund", 2, "coreP2PAddrs", true }, + { "protx register_fund_legacy", 2, "coreP2PAddrs", true }, + { "protx register_fund_evo", 2, "coreP2PAddrs", true }, + { "protx register_fund_evo", 9, "platformP2PAddrs", true }, + { "protx register_fund_evo", 10, "platformHTTPSAddrs", true }, + { "protx register_prepare", 3, "coreP2PAddrs", true }, + { "protx register_prepare_legacy", 3, "coreP2PAddrs", true }, + { "protx register_prepare_evo", 3, "coreP2PAddrs", true }, + { "protx register_prepare_evo", 10, "platformP2PAddrs", true }, + { "protx register_prepare_evo", 11, "platformHTTPSAddrs", true }, + { "protx update_service", 2, "coreP2PAddrs", true }, + { "protx update_service_evo", 2, "coreP2PAddrs", true }, + { "protx update_service_evo", 5, "platformP2PAddrs", true }, + { "protx update_service_evo", 6, "platformHTTPSAddrs", true }, }; // clang-format on class CRPCConvertTable { private: - std::set> members; - std::set> membersByName; + std::map, bool> members; + std::map, bool> membersByName; + + std::string_view MaybeUnquoteString(std::string_view arg_value) + { + if (arg_value.size() >= 2 && ((arg_value.front() == '\'' && arg_value.back() == '\'') || (arg_value.front() == '\"' && arg_value.back() == '\"'))) { + return arg_value.substr(1, arg_value.size() - 2); + } + return arg_value; + } + + bool LikelyJSONType(std::string_view arg_value) + { + arg_value = MaybeUnquoteString(arg_value); + return arg_value.size() >= 2 && ((arg_value.front() == '[' && arg_value.back() == ']') || (arg_value.front() == '{' && arg_value.back() == '}')); + } public: CRPCConvertTable(); @@ -267,21 +303,35 @@ class CRPCConvertTable /** Return arg_value as UniValue, and first parse it if it is a non-string parameter */ UniValue ArgToUniValue(std::string_view arg_value, const std::string& method, int param_idx) { - return members.count({method, param_idx}) > 0 ? ParseNonRFCJSONValue(arg_value) : arg_value; + if (const auto it = members.find({method, param_idx}); it != members.end() && (!it->second || (it->second && LikelyJSONType(arg_value)))) { + return ParseNonRFCJSONValue(MaybeUnquoteString(arg_value)); + } + return arg_value; } /** Return arg_value as UniValue, and first parse it if it is a non-string parameter */ UniValue ArgToUniValue(std::string_view arg_value, const std::string& method, const std::string& param_name) { - return membersByName.count({method, param_name}) > 0 ? ParseNonRFCJSONValue(arg_value) : arg_value; + if (const auto it = membersByName.find({method, param_name}); it != membersByName.end() && (!it->second || (it->second && LikelyJSONType(arg_value)))) { + return ParseNonRFCJSONValue(MaybeUnquoteString(arg_value)); + } + return arg_value; + } + + /** Check if we have any conversion rules for this method */ + bool IsDefined(const std::string& method, bool named) const + { + return named ? + std::find_if(membersByName.begin(), membersByName.end(), [&method](const auto& kv) { return kv.first.first == method; }) != membersByName.end() + : std::find_if(members.begin(), members.end(), [&method](const auto& kv) { return kv.first.first == method; }) != members.end(); } }; CRPCConvertTable::CRPCConvertTable() { for (const auto& cp : vRPCConvertParams) { - members.emplace(cp.methodName, cp.paramIdx); - membersByName.emplace(cp.methodName, cp.paramName); + members.try_emplace({cp.methodName, cp.paramIdx}, cp.preserve_str); + membersByName.try_emplace({cp.methodName, cp.paramName}, cp.preserve_str); } } @@ -297,10 +347,19 @@ UniValue ParseNonRFCJSONValue(std::string_view raw) return parsed; } -UniValue RPCConvertValues(const std::string &strMethod, const std::vector &strParams) +UniValue RPCConvertValues(std::string strMethod, const std::vector &strParams) { UniValue params(UniValue::VARR); + // If we are using a subcommand that is in the table, update the method name + strMethod = [&strMethod, &strParams]() { + if (!strParams.empty() && strMethod.find(' ') == std::string::npos) { + std::string candidate{strMethod + " " + strParams[0]}; + return rpcCvtTable.IsDefined(candidate, /*named=*/false) ? candidate : strMethod; + } + return strMethod; + }(); + for (unsigned int idx = 0; idx < strParams.size(); idx++) { std::string_view value{strParams[idx]}; params.push_back(rpcCvtTable.ArgToUniValue(value, strMethod, idx)); @@ -309,11 +368,20 @@ UniValue RPCConvertValues(const std::string &strMethod, const std::vector &strParams) +UniValue RPCConvertNamedValues(std::string strMethod, const std::vector &strParams) { UniValue params(UniValue::VOBJ); UniValue positional_args{UniValue::VARR}; + // If we are using a subcommand that is in the table, update the method name + strMethod = [&strMethod, &strParams]() { + if (strMethod.find(' ') == std::string::npos && !strParams.empty() && strParams[0].find('=') == std::string::npos) { + std::string candidate{strMethod + " " + strParams[0]}; + return rpcCvtTable.IsDefined(candidate, /*named=*/true) ? candidate : strMethod; + } + return strMethod; + }(); + for (std::string_view s: strParams) { size_t pos = s.find('='); if (pos == std::string::npos) { diff --git a/src/rpc/client.h b/src/rpc/client.h index a99d8611109d..60e118de084c 100644 --- a/src/rpc/client.h +++ b/src/rpc/client.h @@ -12,10 +12,10 @@ #include /** Convert positional arguments to command-specific RPC representation */ -UniValue RPCConvertValues(const std::string& strMethod, const std::vector& strParams); +UniValue RPCConvertValues(std::string strMethod, const std::vector& strParams); /** Convert named arguments to command-specific RPC representation */ -UniValue RPCConvertNamedValues(const std::string& strMethod, const std::vector& strParams); +UniValue RPCConvertNamedValues(std::string strMethod, const std::vector& strParams); /** Non-RFC4627 JSON parser, accepts internal values (such as numbers, true, false, null) * as well as objects and arrays. diff --git a/src/rpc/coinjoin.cpp b/src/rpc/coinjoin.cpp index e0367734467a..d3dd399dd35d 100644 --- a/src/rpc/coinjoin.cpp +++ b/src/rpc/coinjoin.cpp @@ -2,8 +2,8 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include #include +#include #include #include #include @@ -15,7 +15,6 @@ #include #ifdef ENABLE_WALLET -#include #include #include #endif // ENABLE_WALLET @@ -59,7 +58,7 @@ static RPCHelpMan coinjoin() { {"command", RPCArg::Type::STR, RPCArg::Optional::NO, "The command to execute"}, }, - RPCResults{}, + RPCResult{RPCResult::Type::NONE, "", ""}, RPCExamples{""}, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { @@ -83,7 +82,7 @@ static RPCHelpMan coinjoin_reset() [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { const std::shared_ptr wallet = GetWalletForJSONRPCRequest(request); - if (!wallet) return NullUniValue; + if (!wallet) return UniValue::VNULL; const NodeContext& node = EnsureAnyNodeContext(request.context); @@ -117,7 +116,7 @@ static RPCHelpMan coinjoin_start() [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { const std::shared_ptr wallet = GetWalletForJSONRPCRequest(request); - if (!wallet) return NullUniValue; + if (!wallet) return UniValue::VNULL; const NodeContext& node = EnsureAnyNodeContext(request.context); @@ -158,7 +157,7 @@ static RPCHelpMan coinjoin_status() [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { const std::shared_ptr wallet = GetWalletForJSONRPCRequest(request); - if (!wallet) return NullUniValue; + if (!wallet) return UniValue::VNULL; const NodeContext& node = EnsureAnyNodeContext(request.context); @@ -174,7 +173,7 @@ static RPCHelpMan coinjoin_status() } UniValue ret(UniValue::VARR); - for (auto str_status : cj_clientman->getSessionStatuses()) { + for (const auto& str_status : cj_clientman->getSessionStatuses()) { ret.push_back(str_status); } return ret; @@ -197,7 +196,7 @@ static RPCHelpMan coinjoin_stop() [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { const std::shared_ptr wallet = GetWalletForJSONRPCRequest(request); - if (!wallet) return NullUniValue; + if (!wallet) return UniValue::VNULL; const NodeContext& node = EnsureAnyNodeContext(request.context); @@ -231,7 +230,7 @@ static RPCHelpMan coinjoinsalt() { {"command", RPCArg::Type::STR, RPCArg::Optional::NO, "The command to execute"}, }, - RPCResults{}, + RPCResult{RPCResult::Type::NONE, "", ""}, RPCExamples{""}, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { @@ -258,7 +257,7 @@ static RPCHelpMan coinjoinsalt_generate() [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { std::shared_ptr const wallet = GetWalletForJSONRPCRequest(request); - if (!wallet) return NullUniValue; + if (!wallet) return UniValue::VNULL; const auto str_wallet = wallet->GetName(); if (wallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) { @@ -322,7 +321,7 @@ static RPCHelpMan coinjoinsalt_get() [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { std::shared_ptr const wallet = GetWalletForJSONRPCRequest(request); - if (!wallet) return NullUniValue; + if (!wallet) return UniValue::VNULL; const auto str_wallet = wallet->GetName(); if (wallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) { @@ -360,7 +359,7 @@ static RPCHelpMan coinjoinsalt_set() [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { std::shared_ptr const wallet = GetWalletForJSONRPCRequest(request); - if (!wallet) return NullUniValue; + if (!wallet) return UniValue::VNULL; const auto salt{ParseHashV(request.params[0], "salt")}; if (salt == uint256::ZERO) { @@ -473,8 +472,10 @@ static RPCHelpMan getcoinjoininfo() #ifdef ENABLE_WALLET CCoinJoinClientOptions::GetJsonInfo(obj); - if (node.cj_ctx->queueman) { - obj.pushKV("queue_size", node.cj_ctx->queueman->GetQueueSize()); + if (node.cj_walletman) { + if (auto queue_size = node.cj_walletman->getQueueSize()) { + obj.pushKV("queue_size", queue_size.value()); + } } const std::shared_ptr wallet = GetWalletForJSONRPCRequest(request); @@ -503,35 +504,27 @@ static RPCHelpMan getcoinjoininfo() #ifdef ENABLE_WALLET Span GetWalletCoinJoinRPCCommands() { -// clang-format off -static const CRPCCommand commands[] = -{ // category actor (function) - // --------------------- ----------------------- - { "dash", &coinjoin, }, - { "dash", &coinjoin_reset, }, - { "dash", &coinjoin_start, }, - { "dash", &coinjoin_status, }, - { "dash", &coinjoin_stop, }, - { "dash", &coinjoinsalt, }, - { "dash", &coinjoinsalt_generate, }, - { "dash", &coinjoinsalt_get, }, - { "dash", &coinjoinsalt_set, }, - { "dash", &getcoinjoininfo, }, -}; -// clang-format on + static const CRPCCommand commands[]{ + {"dash", &coinjoin}, + {"dash", &coinjoin_reset}, + {"dash", &coinjoin_start}, + {"dash", &coinjoin_status}, + {"dash", &coinjoin_stop}, + {"dash", &coinjoinsalt}, + {"dash", &coinjoinsalt_generate}, + {"dash", &coinjoinsalt_get}, + {"dash", &coinjoinsalt_set}, + {"dash", &getcoinjoininfo}, + }; return commands; } #endif // ENABLE_WALLET void RegisterCoinJoinRPCCommands(CRPCTable& t) { -// clang-format off -static const CRPCCommand commands_wallet[] = -{ // category actor (function) - // --------------------- ----------------------- - { "dash", &getcoinjoininfo, }, -}; -// clang-format on + static const CRPCCommand commands_wallet[]{ + {"dash", &getcoinjoininfo}, + }; // If we aren't compiling with wallet support, we still need to register RPCs that are // capable of working without wallet support. We have to do this even if wallet support // is compiled in but is disabled at runtime because runtime disablement prohibits diff --git a/src/rpc/evo.cpp b/src/rpc/evo.cpp index cc7052b453c3..44c6f4fda664 100644 --- a/src/rpc/evo.cpp +++ b/src/rpc/evo.cpp @@ -50,8 +50,6 @@ using node::NodeContext; using wallet::CWallet; #ifdef ENABLE_WALLET using wallet::CCoinControl; -using wallet::CoinType; -using wallet::COutput; using wallet::CRecipient; using wallet::DEFAULT_DISABLE_WALLET; using wallet::GetWalletForJSONRPCRequest; @@ -683,7 +681,7 @@ static UniValue protx_register_common_wrapper(const JSONRPCRequest& request, const bool isEvoRequested = mnType == MnType::Evo; std::shared_ptr const pwallet = GetWalletForJSONRPCRequest(request); - if (!pwallet) return NullUniValue; + if (!pwallet) return UniValue::VNULL; if (action == ProTxRegisterAction::External || action == ProTxRegisterAction::Fund) { EnsureWalletIsUnlocked(*pwallet); @@ -888,7 +886,7 @@ static RPCHelpMan protx_register_submit() CChainstateHelper& chain_helper = *CHECK_NONFATAL(node.chain_helper); const std::shared_ptr wallet = GetWalletForJSONRPCRequest(request); - if (!wallet) return NullUniValue; + if (!wallet) return UniValue::VNULL; EnsureWalletIsUnlocked(*wallet); @@ -997,7 +995,7 @@ static UniValue protx_update_service_common_wrapper(const JSONRPCRequest& reques const bool isEvoRequested = mnType == MnType::Evo; std::shared_ptr const wallet = GetWalletForJSONRPCRequest(request); - if (!wallet) return NullUniValue; + if (!wallet) return UniValue::VNULL; EnsureWalletIsUnlocked(*wallet); @@ -1131,7 +1129,7 @@ static RPCHelpMan protx_update_registrar_wrapper(const bool specific_legacy_bls_ CChainstateHelper& chain_helper = *CHECK_NONFATAL(node.chain_helper); std::shared_ptr const wallet = GetWalletForJSONRPCRequest(request); - if (!wallet) return NullUniValue; + if (!wallet) return UniValue::VNULL; EnsureWalletIsUnlocked(*wallet); @@ -1251,7 +1249,7 @@ static RPCHelpMan protx_revoke() CChainstateHelper& chain_helper = *CHECK_NONFATAL(node.chain_helper); std::shared_ptr const pwallet = GetWalletForJSONRPCRequest(request); - if (!pwallet) return NullUniValue; + if (!pwallet) return UniValue::VNULL; EnsureWalletIsUnlocked(*pwallet); @@ -1379,8 +1377,7 @@ static UniValue BuildDMNListEntry(const CWallet* const pwallet, const CDetermini } #endif - const auto metaInfo = mn_metaman.GetMetaInfo(dmn.proTxHash); - o.pushKV("metaInfo", metaInfo->ToJson()); + o.pushKV("metaInfo", mn_metaman.GetInfo(dmn.proTxHash).ToJson()); return o; } @@ -1404,7 +1401,16 @@ static RPCHelpMan protx_list() {"detailed", RPCArg::Type::BOOL, RPCArg::Default{false}, "If not specified, only the hashes of the ProTx will be returned."}, {"height", RPCArg::Type::NUM, RPCArg::DefaultHint{"current chain-tip"}, ""}, }, - RPCResults{}, + RPCResult{ + RPCResult::Type::ARR, "", "List of masternodes", + { + RPCResult{"when detailed=false", RPCResult::Type::STR, "", "ProTx hash"}, + RPCResult{"when detailed=true", RPCResult::Type::OBJ, "", "", + { + // TODO: document fields of the detailed entry + {RPCResult::Type::ELISION, "", ""} + }}, + }}, RPCExamples{""}, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { @@ -1511,6 +1517,7 @@ static RPCHelpMan protx_info() RPCResult{ RPCResult::Type::OBJ, "", "Details about a specific deterministic masternode", { + // TODO: implement proper doc for protx info {RPCResult::Type::ELISION, "", ""} } }, @@ -1586,7 +1593,7 @@ static RPCHelpMan protx_diff() {"block", RPCArg::Type::NUM, RPCArg::Optional::NO, "The ending block height."}, {"extended", RPCArg::Type::BOOL, RPCArg::Optional::OMITTED, "Show additional fields."}, }, - RPCResults{}, + CSimplifiedMNListDiff::GetJsonHelp(/*key=*/"", /*optional=*/false), RPCExamples{""}, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { @@ -1644,8 +1651,40 @@ static RPCHelpMan protx_listdiff() {"baseBlock", RPCArg::Type::NUM, RPCArg::Optional::NO, "The starting block height."}, {"block", RPCArg::Type::NUM, RPCArg::Optional::NO, "The ending block height."}, }, - RPCResults{}, - RPCExamples{""}, + RPCResult { + RPCResult::Type::OBJ, "", "", + { + {RPCResult::Type::NUM, "baseHeight", "Height of base (starting) block"}, + {RPCResult::Type::NUM, "blockHeight", "Height of target (ending) block"}, + {RPCResult::Type::ARR, "addedMNs", "Added masternodes", + { + {RPCResult::Type::OBJ, "", "", + { + // TODO: list fields of output for RPC help instead ELISION + {RPCResult::Type::ELISION, "", ""} + }}, + }, + }, + {RPCResult::Type::ARR, "removedMns", "Removed masternodes", + { + {RPCResult::Type::STR_HEX, "protx", "ProTx of removed masternode"}, + }, + }, + {RPCResult::Type::ARR, "updatedMNs", "Updated masternodes", + { + {RPCResult::Type::OBJ, "", "", + { + {RPCResult::Type::OBJ, "protx", "ProTx of updated masternode", + { + // TODO: list fields of output for RPC help instead ELISION + {RPCResult::Type::ELISION, "", ""} + }}, + }}, + }, + }, + }, + }, + RPCExamples{""}, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { const NodeContext& node = EnsureAnyNodeContext(request.context); @@ -1679,6 +1718,7 @@ static RPCHelpMan protx_listdiff() for(const auto& mn : mnDiff.addedMNs) { jaddedMNs.push_back(mn->ToJson()); } + // TODO: Use CDeterministicMN::GetJsonHelp() for mn ret.pushKV("addedMNs", jaddedMNs); UniValue jremovedMNs(UniValue::VARR); @@ -1701,6 +1741,7 @@ static RPCHelpMan protx_listdiff() obj.pushKV(dmn->proTxHash.ToString(), stateDiff.ToJson(dmn->nType)); jupdatedMNs.push_back(obj); } + // TODO: Use CDeterministicMNStateDiff::GetJsonHelp() for stateDiff ret.pushKV("updatedMNs", jupdatedMNs); return ret; @@ -1708,6 +1749,175 @@ static RPCHelpMan protx_listdiff() }; } +// Helper function for evodb verify/repair commands +static UniValue evodb_verify_or_repair_impl(const JSONRPCRequest& request, bool repair) +{ + const NodeContext& node = EnsureAnyNodeContext(request.context); + ChainstateManager& chainman = EnsureChainman(node); + CDeterministicMNManager& dmnman = *CHECK_NONFATAL(node.dmnman); + CChainstateHelper& chain_helper = *CHECK_NONFATAL(node.chain_helper); + + const CBlockIndex* start_index; + const CBlockIndex* stop_index; + + { + LOCK(::cs_main); + // Default to DIP0003 activation height if startBlock not specified + if (request.params[0].isNull()) { + const auto& consensus_params = Params().GetConsensus(); + start_index = chainman.ActiveChain()[consensus_params.DIP0003Height]; + if (!start_index) { + throw JSONRPCError(RPC_INTERNAL_ERROR, "Cannot find DIP0003 activation block"); + } + } else { + uint256 start_block_hash = ParseBlock(request.params[0], chainman, "startBlock"); + start_index = chainman.m_blockman.LookupBlockIndex(start_block_hash); + if (!start_index) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Start block not found"); + } + } + + // Default to chain tip if stopBlock not specified + if (request.params[1].isNull()) { + stop_index = chainman.ActiveChain().Tip(); + if (!stop_index) { + throw JSONRPCError(RPC_INTERNAL_ERROR, "Cannot find chain tip"); + } + } else { + uint256 stop_block_hash = ParseBlock(request.params[1], chainman, "stopBlock"); + stop_index = chainman.m_blockman.LookupBlockIndex(stop_block_hash); + if (!stop_index) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Stop block not found"); + } + } + } + + int start_height = start_index->nHeight; + int stop_height = stop_index->nHeight; + + // Validation + if (stop_height < start_height) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "stopBlock must be >= startBlock"); + } + + // Create a callback that wraps CSpecialTxProcessor::RebuildListFromBlock + auto build_list_func = [&chain_helper](const CBlock& block, gsl::not_null pindexPrev, + const CDeterministicMNList& prevList, const CCoinsViewCache& view, + bool debugLogs, BlockValidationState& state, + CDeterministicMNList& mnListRet) -> bool { + return chain_helper.special_tx->RebuildListFromBlock(block, pindexPrev, prevList, view, debugLogs, state, mnListRet); + }; + + // Call the dmnman method to do the work + auto recalc_result = dmnman.RecalculateAndRepairDiffs(start_index, stop_index, chainman, build_list_func, repair); + + // Convert result to UniValue + UniValue result(UniValue::VOBJ); + UniValue verification_errors(UniValue::VARR); + + for (const auto& error : recalc_result.verification_errors) { + verification_errors.push_back(error); + } + + result.pushKV("startHeight", recalc_result.start_height); + result.pushKV("stopHeight", recalc_result.stop_height); + result.pushKV("diffsRecalculated", recalc_result.diffs_recalculated); + result.pushKV("snapshotsVerified", recalc_result.snapshots_verified); + result.pushKV("verificationErrors", verification_errors); + + // Only include repair errors if we're in repair mode + if (repair) { + UniValue repair_errors(UniValue::VARR); + for (const auto& error : recalc_result.repair_errors) { + repair_errors.push_back(error); + } + result.pushKV("repairErrors", repair_errors); + } + + return result; +} + +static RPCHelpMan evodb_verify() +{ + return RPCHelpMan{"evodb verify", + "\nVerifies evodb diff records between specified block heights.\n" + "Checks that all diffs applied between snapshots in the range match the saved snapshots in evodb.\n" + "This is a read-only operation that does not modify the database.\n" + "If no heights are specified, defaults to the full range from DIP0003 activation to chain tip.\n", + { + {"startBlock", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "The starting block height (defaults to DIP0003 activation height)."}, + {"stopBlock", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "The ending block height (defaults to current chain tip)."}, + }, + RPCResult{ + RPCResult::Type::OBJ, "", "", + { + {RPCResult::Type::NUM, "startHeight", "Actual starting block height (may differ from input if clamped to DIP0003 activation)"}, + {RPCResult::Type::NUM, "stopHeight", "Ending block height"}, + {RPCResult::Type::NUM, "diffsRecalculated", "Number of diffs recalculated (always 0 for verify-only mode)"}, + {RPCResult::Type::NUM, "snapshotsVerified", "Number of snapshot pairs that passed verification"}, + {RPCResult::Type::ARR, "verificationErrors", "List of verification errors (empty if verification passed)", + { + {RPCResult::Type::STR, "", "Error message"}, + } + }, + } + }, + RPCExamples{ + HelpExampleCli("evodb verify", "") + + HelpExampleCli("evodb verify", "1000 2000") + + HelpExampleRpc("evodb", "\"verify\"") + + HelpExampleRpc("evodb", "\"verify\", 1000, 2000") + }, + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ + return evodb_verify_or_repair_impl(request, false); +}, + }; +} + +static RPCHelpMan evodb_repair() +{ + return RPCHelpMan{"evodb repair", + "\nRepairs corrupted evodb diff records between specified block heights.\n" + "First verifies all diffs applied between snapshots in the range.\n" + "If verification fails, recalculates diffs from blockchain data and replaces corrupted records.\n" + "If no heights are specified, defaults to the full range from DIP0003 activation to chain tip.\n", + { + {"startBlock", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "The starting block height (defaults to DIP0003 activation height)."}, + {"stopBlock", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "The ending block height (defaults to current chain tip)."}, + }, + RPCResult{ + RPCResult::Type::OBJ, "", "", + { + {RPCResult::Type::NUM, "startHeight", "Actual starting block height (may differ from input if clamped to DIP0003 activation)"}, + {RPCResult::Type::NUM, "stopHeight", "Ending block height"}, + {RPCResult::Type::NUM, "diffsRecalculated", "Number of diffs successfully recalculated and written to database"}, + {RPCResult::Type::NUM, "snapshotsVerified", "Number of snapshot pairs that passed verification"}, + {RPCResult::Type::ARR, "verificationErrors", "Errors encountered during verification phase (empty if verification passed)", + { + {RPCResult::Type::STR, "", "Error message"}, + } + }, + {RPCResult::Type::ARR, "repairErrors", "Critical errors encountered during repair phase (non-empty means full reindex required)", + { + {RPCResult::Type::STR, "", "Error message"}, + } + }, + } + }, + RPCExamples{ + HelpExampleCli("evodb repair", "") + + HelpExampleCli("evodb repair", "1000 2000") + + HelpExampleRpc("evodb", "\"repair\"") + + HelpExampleRpc("evodb", "\"repair\", 1000, 2000") + }, + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ + return evodb_verify_or_repair_impl(request, true); +}, + }; +} + static RPCHelpMan protx_help() { return RPCHelpMan{ @@ -1741,7 +1951,7 @@ static RPCHelpMan protx_help() { {"command", RPCArg::Type::STR, RPCArg::Optional::NO, "The command to execute"}, }, - RPCResults{}, + RPCResult{RPCResult::Type::NONE, "", ""}, RPCExamples{""}, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { @@ -1831,7 +2041,7 @@ static RPCHelpMan bls_help() { {"command", RPCArg::Type::STR, RPCArg::Optional::NO, "The command to execute"}, }, - RPCResults{}, + RPCResult{RPCResult::Type::NONE, "", ""}, RPCExamples{""}, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { @@ -1843,52 +2053,45 @@ static RPCHelpMan bls_help() #ifdef ENABLE_WALLET Span GetWalletEvoRPCCommands() { -// clang-format off -static const CRPCCommand commands[] = -{ // category actor (function) - // --------------------- ----------------------- - { "evo", &protx_list, }, - { "evo", &protx_info, }, - { "evo", &protx_register, }, - { "evo", &protx_register_evo, }, - { "evo", &protx_register_fund, }, - { "evo", &protx_register_fund_evo, }, - { "evo", &protx_register_prepare, }, - { "evo", &protx_register_prepare_evo, }, - { "evo", &protx_update_service, }, - { "evo", &protx_update_service_evo, }, - { "evo", &protx_register_submit, }, - { "evo", &protx_update_registrar, }, - { "evo", &protx_revoke, }, - { "hidden", &protx_register_legacy, }, - { "hidden", &protx_register_fund_legacy, }, - { "hidden", &protx_register_prepare_legacy, }, - { "hidden", &protx_update_registrar_legacy, }, -}; -// clang-format on + static const CRPCCommand commands[]{ + {"evo", &protx_list}, + {"evo", &protx_info}, + {"evo", &protx_register}, + {"evo", &protx_register_evo}, + {"evo", &protx_register_fund}, + {"evo", &protx_register_fund_evo}, + {"evo", &protx_register_prepare}, + {"evo", &protx_register_prepare_evo}, + {"evo", &protx_update_service}, + {"evo", &protx_update_service_evo}, + {"evo", &protx_register_submit}, + {"evo", &protx_update_registrar}, + {"evo", &protx_revoke}, + {"hidden", &protx_register_legacy}, + {"hidden", &protx_register_fund_legacy}, + {"hidden", &protx_register_prepare_legacy}, + {"hidden", &protx_update_registrar_legacy}, + }; return commands; } #endif // ENABLE_WALLET void RegisterEvoRPCCommands(CRPCTable& tableRPC) { -// clang-format off -static const CRPCCommand commands[] = -{ // category actor (function) - // --------------------- ----------------------- - { "evo", &bls_help, }, - { "evo", &bls_generate, }, - { "evo", &bls_fromsecret, }, - { "evo", &protx_help, }, - { "evo", &protx_diff, }, - { "evo", &protx_listdiff, }, -}; -static const CRPCCommand commands_wallet[] = -{ - { "evo", &protx_list, }, - { "evo", &protx_info, }, -}; -// clang-format on + static const CRPCCommand commands[]{ + {"evo", &bls_help}, + {"evo", &bls_generate}, + {"evo", &bls_fromsecret}, + {"evo", &protx_help}, + {"evo", &protx_diff}, + {"evo", &protx_listdiff}, + {"hidden", &evodb_verify}, + {"hidden", &evodb_repair}, + }; + static const CRPCCommand commands_wallet[]{ + {"evo", &protx_list}, + {"evo", &protx_info}, + }; for (const auto& command : commands) { tableRPC.appendCommand(command.name, &command); } diff --git a/src/rpc/external_signer.cpp b/src/rpc/external_signer.cpp new file mode 100644 index 000000000000..91a21f4e4d5b --- /dev/null +++ b/src/rpc/external_signer.cpp @@ -0,0 +1,71 @@ +// Copyright (c) 2018-2021 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include +#include +#include +#include +#include + +#include +#include + +#ifdef ENABLE_EXTERNAL_SIGNER + +static RPCHelpMan enumeratesigners() +{ + return RPCHelpMan{"enumeratesigners", + "Returns a list of external signers from -signer.", + {}, + RPCResult{ + RPCResult::Type::OBJ, "", "", + { + {RPCResult::Type::ARR, "signers", /*optional=*/false, "", + { + {RPCResult::Type::STR_HEX, "masterkeyfingerprint", "Master key fingerprint"}, + {RPCResult::Type::STR, "name", "Device name"}, + }, + } + } + }, + RPCExamples{ + HelpExampleCli("enumeratesigners", "") + + HelpExampleRpc("enumeratesigners", "") + }, + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue + { + const std::string command = gArgs.GetArg("-signer", ""); + if (command == "") throw JSONRPCError(RPC_MISC_ERROR, "Error: restart dashd with -signer="); + const std::string chain = gArgs.GetChainName(); + UniValue signers_res = UniValue::VARR; + try { + std::vector signers; + ExternalSigner::Enumerate(command, signers, chain); + for (const ExternalSigner& signer : signers) { + UniValue signer_res = UniValue::VOBJ; + signer_res.pushKV("fingerprint", signer.m_fingerprint); + signer_res.pushKV("name", signer.m_name); + signers_res.push_back(signer_res); + } + } catch (const std::exception& e) { + throw JSONRPCError(RPC_MISC_ERROR, e.what()); + } + UniValue result(UniValue::VOBJ); + result.pushKV("signers", signers_res); + return result; + } + }; +} + +void RegisterSignerRPCCommands(CRPCTable& t) +{ + static const CRPCCommand commands[]{ + {"signer", &enumeratesigners}, + }; + for (const auto& c : commands) { + t.appendCommand(c.name, &c); + } +} + +#endif // ENABLE_EXTERNAL_SIGNER diff --git a/src/rpc/governance.cpp b/src/rpc/governance.cpp index ea66057b457c..985a43818eba 100644 --- a/src/rpc/governance.cpp +++ b/src/rpc/governance.cpp @@ -43,7 +43,20 @@ static RPCHelpMan gobject_count() { {"mode", RPCArg::Type::STR, RPCArg::DefaultHint{"json"}, "Output format: json (\"json\") or string in free form (\"all\")"}, }, - RPCResults{}, + { + RPCResult{"for mode = json", + RPCResult::Type::OBJ, "", "", + { + {RPCResult::Type::NUM, "objects_total", "Total number of all governance objects"}, + {RPCResult::Type::NUM, "proposals", "Number of governance proposals"}, + {RPCResult::Type::NUM, "triggers", "Number of triggers"}, + {RPCResult::Type::NUM, "other", "Total number of unknown governance objects"}, + {RPCResult::Type::NUM, "erased", "Number of removed (expired) objects"}, + {RPCResult::Type::NUM, "votes", "Total number of votes"}, + } + }, + RPCResult{"for mode = all", RPCResult::Type::STR, "", "Human-friendly summary string for proposals and votes"}, + }, RPCExamples{""}, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { @@ -71,7 +84,7 @@ static RPCHelpMan gobject_deserialize() { {"hex_data", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "data in hex string form"}, }, - RPCResults{}, + RPCResult{RPCResult::Type::STR, "", "JSON string of the deserialized governance object"}, RPCExamples{""}, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { @@ -96,7 +109,12 @@ static RPCHelpMan gobject_check() { {"hex_data", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "data in hex string format"}, }, - RPCResults{}, + RPCResult{"if object is valid", + RPCResult::Type::OBJ, "", "", + { + {RPCResult::Type::STR, "Object status", "OK"}, + } + }, RPCExamples{""}, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { @@ -145,12 +163,12 @@ static RPCHelpMan gobject_prepare() {"outputHash", RPCArg::Type::STR_HEX, RPCArg::Default{""}, "the single output to submit the proposal fee from"}, {"outputIndex", RPCArg::Type::NUM, RPCArg::Default{0}, "The output index."}, }, - RPCResults{}, + {RPCResult{"if object valid", RPCResult::Type::STR_HEX, "", "The collateral transaction id (txid)"}}, RPCExamples{""}, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { std::shared_ptr const wallet = GetWalletForJSONRPCRequest(request); - if (!wallet) return NullUniValue; + if (!wallet) return UniValue::VNULL; EnsureWalletIsUnlocked(*wallet); @@ -254,12 +272,21 @@ static RPCHelpMan gobject_list_prepared() { {"count", RPCArg::Type::NUM, RPCArg::Default{10}, "Maximum number of objects to return."}, }, - RPCResults{}, + RPCResult{ + RPCResult::Type::ARR, "", "list of governance objects", + { + {RPCResult::Type::OBJ, "", "", + { + // TODO: list fields of output for RPC help instead ELISION + {RPCResult::Type::ELISION, "", ""} + }}, + } + }, RPCExamples{""}, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { std::shared_ptr const wallet = GetWalletForJSONRPCRequest(request); - if (!wallet) return NullUniValue; + if (!wallet) return UniValue::VNULL; EnsureWalletIsUnlocked(*wallet); int64_t nCount = request.params.empty() ? 10 : ParseInt64V(request.params[0], "count"); @@ -303,7 +330,7 @@ static RPCHelpMan gobject_submit() {"data-hex", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "data in hex string form"}, {"fee-txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "txid of the corresponding proposal fee transaction"}, }, - RPCResults{}, + RPCResult{RPCResult::Type::STR_HEX, "hash", "Hash of the submitted governance object"}, RPCExamples{""}, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { @@ -393,12 +420,11 @@ static RPCHelpMan gobject_submit() LogPrintf("gobject(submit) -- Adding locally created governance object - %s\n", strHash); - PeerManager& peerman = EnsurePeerman(node); if (fMissingConfirmations) { node.govman->AddPostponedObject(govobj); - govobj.Relay(peerman, *CHECK_NONFATAL(node.mn_sync)); + node.govman->RelayObject(govobj); } else { - node.govman->AddGovernanceObject(govobj, peerman); + node.govman->AddGovernanceObject(govobj); } return govobj.GetHash().ToString(); @@ -415,8 +441,7 @@ static UniValue VoteWithMasternodes(const JSONRPCRequest& request, const CWallet const NodeContext& node = EnsureAnyNodeContext(request.context); CHECK_NONFATAL(node.govman); { - LOCK(node.govman->cs); - const CGovernanceObject *pGovObj = node.govman->FindConstGovernanceObject(hash); + auto pGovObj = node.govman->FindConstGovernanceObject(hash); if (!pGovObj) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Governance object not found"); } @@ -429,10 +454,7 @@ static UniValue VoteWithMasternodes(const JSONRPCRequest& request, const CWallet UniValue resultsObj(UniValue::VOBJ); - for (const auto& p : votingKeys) { - const auto& proTxHash = p.first; - const auto& keyID = p.second; - + for (const auto& [proTxHash, keyID] : votingKeys) { UniValue statusObj(UniValue::VOBJ); auto dmn = mnList.GetValidMN(proTxHash); @@ -456,8 +478,7 @@ static UniValue VoteWithMasternodes(const JSONRPCRequest& request, const CWallet CGovernanceException exception; CConnman& connman = EnsureConnman(node); - PeerManager& peerman = EnsurePeerman(node); - if (node.govman->ProcessVoteAndRelay(vote, exception, connman, peerman)) { + if (node.govman->ProcessVoteAndRelay(vote, exception, connman)) { nSuccessful++; statusObj.pushKV("result", "success"); } else { @@ -484,6 +505,23 @@ static bool CheckWalletOwnsKey(const CWallet& wallet, const CKeyID& keyid) return wallet.IsMine(script) == isminetype::ISMINE_SPENDABLE; } +namespace { +const RPCResult vote_results{ + RPCResult::Type::OBJ, "", "", + { + {RPCResult::Type::STR, "overall", "Total number of successful and failed votes"}, + {RPCResult::Type::OBJ, "detail", "Detailed information for each vote", + { + {RPCResult::Type::OBJ, "protx", "ProTx of masternode for voting", + { + {RPCResult::Type::STR, "result", "Result of voting: {success|failed}"}, + {RPCResult::Type::STR, "errorMessage", /*optional=*/true, "Error message if failed"}, + }}, + }}, + }, +}; +} // anonymous namespace + static RPCHelpMan gobject_vote_many() { return RPCHelpMan{"gobject vote-many", @@ -494,12 +532,12 @@ static RPCHelpMan gobject_vote_many() {"vote", RPCArg::Type::STR, RPCArg::Optional::NO, "vote, possible values: [funding|valid|delete|endorsed]"}, {"vote-outcome", RPCArg::Type::STR, RPCArg::Optional::NO, "vote outcome, possible values: [yes|no|abstain]"}, }, - RPCResults{}, + vote_results, RPCExamples{""}, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { const std::shared_ptr wallet = GetWalletForJSONRPCRequest(request); - if (!wallet) return NullUniValue; + if (!wallet) return UniValue::VNULL; const NodeContext& node = EnsureAnyNodeContext(request.context); @@ -547,12 +585,12 @@ static RPCHelpMan gobject_vote_alias() {"vote-outcome", RPCArg::Type::STR, RPCArg::Optional::NO, "vote outcome, possible values: [yes|no|abstain]"}, {"protx-hash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "masternode's proTxHash"}, }, - RPCResults{}, + vote_results, RPCExamples{""}, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { const std::shared_ptr wallet = GetWalletForJSONRPCRequest(request); - if (!wallet) return NullUniValue; + if (!wallet) return UniValue::VNULL; const NodeContext& node = EnsureAnyNodeContext(request.context); @@ -606,7 +644,7 @@ static UniValue ListObjects(CGovernanceManager& govman, const CDeterministicMNLi g_txindex->BlockUntilSyncedToCurrentChain(); } - LOCK2(cs_main, govman.cs); + LOCK(cs_main); std::vector objs; govman.GetAllNewerThan(objs, nStartTime); @@ -669,7 +707,18 @@ static RPCHelpMan gobject_list_helper(const bool make_a_diff) {"signal", RPCArg::Type::STR, RPCArg::Default{"valid"}, "cached signal, possible values: [valid|funding|delete|endorsed|all]"}, {"type", RPCArg::Type::STR, RPCArg::Default{"all"}, "object type, possible values: [proposals|triggers|all]"}, }, - RPCResults{}, + { + RPCResult{"If request is valid", + RPCResult::Type::OBJ, "hash", "Object details", + { + // TODO: list fields of output for RPC help instead ELISION + {RPCResult::Type::ELISION, "", ""} + }, + }, + RPCResult{"If request is invalid", + RPCResult::Type::STR, "", "Error string" + }, + }, RPCExamples{""}, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { @@ -715,7 +764,15 @@ static RPCHelpMan gobject_get() { {"governance-hash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "object id"}, }, - RPCResults{}, + { + RPCResult{ + RPCResult::Type::OBJ, "", "", + { + // TODO: list fields of output for RPC help instead ELISION + {RPCResult::Type::ELISION, "", ""} + } + }, + }, RPCExamples{""}, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { @@ -731,8 +788,8 @@ static RPCHelpMan gobject_get() const ChainstateManager& chainman = EnsureChainman(node); CHECK_NONFATAL(node.govman); - LOCK2(cs_main, node.govman->cs); - const CGovernanceObject* pGovObj = node.govman->FindConstGovernanceObject(hash); + LOCK(cs_main); + auto pGovObj = node.govman->FindConstGovernanceObject(hash); if (pGovObj == nullptr) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Unknown governance object"); @@ -811,7 +868,12 @@ static RPCHelpMan gobject_getcurrentvotes() {"txid", RPCArg::Type::STR_HEX, RPCArg::Default{""}, "masternode collateral txid"}, {"vout", RPCArg::Type::STR, RPCArg::Default{""}, "masternode collateral output index, required if present"}, }, - RPCResults{}, + RPCResult{ + RPCResult::Type::OBJ_DYN, "", "Keys are hashes of vote, values are votes", + { + {RPCResult::Type::STR, "votes", "Human-friendly presentation of vote"}, + }, + }, RPCExamples{""}, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { @@ -830,8 +892,7 @@ static RPCHelpMan gobject_getcurrentvotes() const NodeContext& node = EnsureAnyNodeContext(request.context); CHECK_NONFATAL(node.govman); - LOCK(node.govman->cs); - const CGovernanceObject* pGovObj = node.govman->FindConstGovernanceObject(hash); + auto pGovObj = node.govman->FindConstGovernanceObject(hash); if (pGovObj == nullptr) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Unknown governance-hash"); @@ -877,7 +938,7 @@ static RPCHelpMan gobject() { {"command", RPCArg::Type::STR, RPCArg::Optional::NO, "The command to execute"}, }, - RPCResults{}, + RPCResult{RPCResult::Type::NONE, "", ""}, RPCExamples{""}, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { @@ -899,7 +960,7 @@ static RPCHelpMan voteraw() {"time", RPCArg::Type::NUM, RPCArg::Optional::NO, ""}, {"vote-sig", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, ""}, }, - RPCResults{}, + RPCResult{RPCResult::Type::STR, "", "Result of voting"}, RPCExamples{""}, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { @@ -926,8 +987,7 @@ static RPCHelpMan voteraw() const NodeContext& node = EnsureAnyNodeContext(request.context); CHECK_NONFATAL(node.govman); GovernanceObject govObjType = [&]() { - LOCK(node.govman->cs); - const CGovernanceObject *pGovObj = node.govman->FindConstGovernanceObject(hashGovObj); + auto pGovObj = node.govman->FindConstGovernanceObject(hashGovObj); if (!pGovObj) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Governance object not found"); } @@ -961,10 +1021,9 @@ static RPCHelpMan voteraw() } CConnman& connman = EnsureConnman(node); - PeerManager& peerman = EnsurePeerman(node); CGovernanceException exception; - if (node.govman->ProcessVoteAndRelay(vote, exception, connman, peerman)) { + if (node.govman->ProcessVoteAndRelay(vote, exception, connman)) { return "Voted successfully"; } else { throw JSONRPCError(RPC_INTERNAL_ERROR, "Error voting : " + exception.GetMessage()); @@ -1052,41 +1111,32 @@ static RPCHelpMan getsuperblockbudget() #ifdef ENABLE_WALLET Span GetWalletGovernanceRPCCommands() { -// clang-format off -static const CRPCCommand commands[] = -{ // category actor (function) - // --------------------- ----------------------- - { "dash", &gobject_prepare, }, - { "dash", &gobject_list_prepared, }, - { "dash", &gobject_vote_many, }, - { "dash", &gobject_vote_alias, }, -}; -// clang-format on + static const CRPCCommand commands[]{ + {"dash", &gobject_prepare}, + {"dash", &gobject_list_prepared}, + {"dash", &gobject_vote_many}, + {"dash", &gobject_vote_alias}, + }; return commands; } #endif // ENABLE_WALLET void RegisterGovernanceRPCCommands(CRPCTable &t) { -// clang-format off -static const CRPCCommand commands[] = -{ // category actor (function) - // --------------------- ----------------------- - /* Dash features */ - { "dash", &getgovernanceinfo, }, - { "dash", &getsuperblockbudget, }, - { "dash", &gobject, }, - { "dash", &gobject_count, }, - { "dash", &gobject_deserialize, }, - { "dash", &gobject_check, }, - { "dash", &gobject_submit, }, - { "dash", &gobject_list, }, - { "dash", &gobject_diff, }, - { "dash", &gobject_get, }, - { "dash", &gobject_getcurrentvotes, }, - { "dash", &voteraw, }, -}; -// clang-format on + static const CRPCCommand commands[]{ + {"dash", &getgovernanceinfo}, + {"dash", &getsuperblockbudget}, + {"dash", &gobject}, + {"dash", &gobject_count}, + {"dash", &gobject_deserialize}, + {"dash", &gobject_check}, + {"dash", &gobject_submit}, + {"dash", &gobject_list}, + {"dash", &gobject_diff}, + {"dash", &gobject_get}, + {"dash", &gobject_getcurrentvotes}, + {"dash", &voteraw}, + }; for (const auto& command : commands) { t.appendCommand(command.name, &command); } diff --git a/src/rpc/masternode.cpp b/src/rpc/masternode.cpp index b87670e3766c..7a8537da3356 100644 --- a/src/rpc/masternode.cpp +++ b/src/rpc/masternode.cpp @@ -36,7 +36,6 @@ using node::ReadBlockFromDisk; #ifdef ENABLE_WALLET using wallet::CCoinControl; using wallet::CoinType; -using wallet::COutput; using wallet::CWallet; using wallet::GetWalletForJSONRPCRequest; #endif // ENABLE_WALLET @@ -49,7 +48,9 @@ static RPCHelpMan masternode_connect() {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The address of the masternode to connect"}, {"v2transport", RPCArg::Type::BOOL, RPCArg::DefaultHint{"set by -v2transport"}, "Attempt to connect using BIP324 v2 transport protocol"}, }, - RPCResults{}, + RPCResult{ + RPCResult::Type::STR, "status", "Returns 'successfully connected' if successful" + }, RPCExamples{""}, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { @@ -85,7 +86,28 @@ static RPCHelpMan masternode_count() return RPCHelpMan{"masternode count", "Get information about number of masternodes.\n", {}, - RPCResults{}, + RPCResult{ + RPCResult::Type::OBJ, "", "", + { + {RPCResult::Type::NUM, "total", "Total number of Masternodes"}, + {RPCResult::Type::NUM, "enabled", "Number of enabled Masternodes"}, + {RPCResult::Type::OBJ, "details", "Breakdown of masternodes by type", + {{RPCResult::Type::OBJ, "", "", + { + {RPCResult::Type::OBJ, "regular", "Details for regular masternodes", + { + {RPCResult::Type::NUM, "total", "Total number of regular Masternodes"}, + {RPCResult::Type::NUM, "enabled", "Number of enabled regular Masternodes"} + }}, + {RPCResult::Type::OBJ, "evo", "Details for Evo nodes", + { + {RPCResult::Type::NUM, "total", "Total number of Evo nodes"}, + {RPCResult::Type::NUM, "enabled", "Number of enabled Evo nodes"} + }}, + }}, + }} + } + }, RPCExamples{""}, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { @@ -135,7 +157,7 @@ static RPCHelpMan masternode_outputs() [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { const std::shared_ptr wallet = GetWalletForJSONRPCRequest(request); - if (!wallet) return NullUniValue; + if (!wallet) return UniValue::VNULL; // Find possible candidates CCoinControl coin_control(CoinType::ONLY_MASTERNODE_COLLATERAL); @@ -157,7 +179,13 @@ static RPCHelpMan masternode_status() return RPCHelpMan{"masternode status", "Print masternode status information\n", {}, - RPCResults{}, + RPCResult{ + RPCResult::Type::OBJ, "", "", + { + // TODO: implement proper type validator instead ELISION + {RPCResult::Type::ELISION, "", ""} + } + }, RPCExamples{""}, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { @@ -177,6 +205,7 @@ static RPCHelpMan masternode_status() mnObj.pushKV("type", std::string(GetMnType(dmn->nType).description)); mnObj.pushKV("collateralHash", dmn->collateralOutpoint.hash.ToString()); mnObj.pushKV("collateralIndex", dmn->collateralOutpoint.n); + // TODO: Use CDeterministicMNState::GetJsonHelp() for dmnState mnObj.pushKV("dmnState", dmn->pdmnState->ToJson(dmn->nType)); } mnObj.pushKV("state", node.mn_activeman->GetStateString()); @@ -231,7 +260,12 @@ static RPCHelpMan masternode_winners() {"count", RPCArg::Type::NUM, RPCArg::Default{10}, "number of last winners to return"}, {"filter", RPCArg::Type::STR, RPCArg::Default{""}, "filter for returned winners"}, }, - RPCResults{}, + RPCResult{ + RPCResult::Type::OBJ_DYN, "", "Keys are block heights (as strings); values describe the payees for that height", + { + {RPCResult::Type::STR, "payee", "Payee for the height"} + } + }, RPCExamples{""}, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { @@ -241,7 +275,7 @@ static RPCHelpMan masternode_winners() { LOCK(::cs_main); pindexTip = chainman.ActiveChain().Tip(); - if (!pindexTip) return NullUniValue; + if (!pindexTip) return UniValue::VNULL; } int nCount = 10; @@ -453,7 +487,7 @@ static RPCHelpMan masternode_help() { {"command", RPCArg::Type::STR, RPCArg::Optional::NO, "The command to execute"}, }, - RPCResults{}, + RPCResult{RPCResult::Type::NONE, "", ""}, RPCExamples{""}, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { @@ -490,7 +524,13 @@ static RPCHelpMan masternodelist_helper(bool is_composite) {"mode", RPCArg::Type::STR, RPCArg::DefaultHint{"json"}, "The mode to run list in"}, {"filter", RPCArg::Type::STR, RPCArg::Default{""}, "Filter results. Partial match by outpoint by default in all modes, additional matches in some modes are also available"}, }, - RPCResults{}, + RPCResult{ + RPCResult::Type::OBJ, "", "", + { + // TODO: implement proper type validator instead ELISION + {RPCResult::Type::ELISION, "", ""} + } + }, RPCExamples{""}, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { @@ -678,33 +718,25 @@ static RPCHelpMan masternodelist_composite() #ifdef ENABLE_WALLET Span GetWalletMasternodeRPCCommands() { -// clang-format off -static const CRPCCommand commands[] = -{ // category actor (function) - // --------------------- ----------------------- - { "dash", &masternode_outputs, }, -}; -// clang-format on + static const CRPCCommand commands[]{ + {"dash", &masternode_outputs}, + }; return commands; } #endif // ENABLE_WALLET void RegisterMasternodeRPCCommands(CRPCTable &t) { -// clang-format off -static const CRPCCommand commands[] = -{ // category actor (function) - // --------------------- ----------------------- - { "dash", &masternode_help, }, - { "dash", &masternodelist_composite, }, - { "dash", &masternodelist, }, - { "dash", &masternode_connect, }, - { "dash", &masternode_count, }, - { "dash", &masternode_status, }, - { "dash", &masternode_payments, }, - { "dash", &masternode_winners, }, -}; -// clang-format on + static const CRPCCommand commands[]{ + {"dash", &masternode_help}, + {"dash", &masternodelist_composite}, + {"dash", &masternodelist}, + {"dash", &masternode_connect}, + {"dash", &masternode_count}, + {"dash", &masternode_status}, + {"dash", &masternode_payments}, + {"dash", &masternode_winners}, + }; for (const auto& command : commands) { t.appendCommand(command.name, &command); } diff --git a/src/rpc/mempool.cpp b/src/rpc/mempool.cpp index ab527f39f824..ea184dd89ea2 100644 --- a/src/rpc/mempool.cpp +++ b/src/rpc/mempool.cpp @@ -14,14 +14,228 @@ #include #include #include +#include #include +#include +#include #include #include +using node::DEFAULT_MAX_RAW_TX_FEE_RATE; using node::NodeContext; -static std::vector MempoolEntryDescription() { return { +RPCHelpMan sendrawtransaction() +{ + return RPCHelpMan{"sendrawtransaction", + "\nSubmit a raw transaction (serialized, hex-encoded) to local node and network.\n" + "\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" + "\nRelated RPCs: createrawtransaction, signrawtransactionwithkey\n", + { + {"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hex string of the raw transaction"}, + {"maxfeerate", RPCArg::Type::AMOUNT, RPCArg::Default{FormatMoney(DEFAULT_MAX_RAW_TX_FEE_RATE.GetFeePerK())}, + "Reject transactions whose fee rate is higher than the specified value, expressed in " + CURRENCY_UNIT + + "/kB.\nSet to 0 to accept any fee rate.\n"}, + {"instantsend", RPCArg::Type::BOOL, RPCArg::Optional::OMITTED, "Deprecated and ignored"}, + {"bypasslimits", RPCArg::Type::BOOL, RPCArg::Default{false}, "Bypass transaction policy limits"}, + }, + RPCResult{ + RPCResult::Type::STR_HEX, "", "The transaction hash in hex" + }, + RPCExamples{ + "\nCreate a transaction\n" + + HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\" : \\\"mytxid\\\",\\\"vout\\\":0}]\" \"{\\\"myaddress\\\":0.01}\"") + + "Sign the transaction, and get back the hex\n" + + HelpExampleCli("signrawtransactionwithwallet", "\"myhex\"") + + "\nSend the transaction (signed hex)\n" + + HelpExampleCli("sendrawtransaction", "\"signedhex\"") + + "\nAs a JSON-RPC call\n" + + HelpExampleRpc("sendrawtransaction", "\"signedhex\"") + }, + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue + { + RPCTypeCheck(request.params, { + UniValue::VSTR, + UniValueType(), // VNUM or VSTR, checked inside AmountFromValue() + UniValue::VBOOL, + UniValue::VBOOL, + }); + + CMutableTransaction mtx; + if (!DecodeHexTx(mtx, request.params[0].get_str())) { + throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed. Make sure the tx has at least one input."); + } + CTransactionRef tx(MakeTransactionRef(std::move(mtx))); + + const CFeeRate max_raw_tx_fee_rate = request.params[1].isNull() ? + DEFAULT_MAX_RAW_TX_FEE_RATE : + CFeeRate(AmountFromValue(request.params[1])); + + int64_t virtual_size = GetVirtualTransactionSize(*tx); + CAmount max_raw_tx_fee = max_raw_tx_fee_rate.GetFee(virtual_size); + + bool bypass_limits = false; + if (!request.params[3].isNull()) bypass_limits = request.params[3].get_bool(); + bilingual_str err_string; + AssertLockNotHeld(cs_main); + NodeContext& node = EnsureAnyNodeContext(request.context); + const TransactionError err = BroadcastTransaction(node, tx, err_string, max_raw_tx_fee, /*relay=*/true, /*wait_callback=*/true, bypass_limits); + if (TransactionError::OK != err) { + throw JSONRPCTransactionError(err, err_string.original); + } + + return tx->GetHash().GetHex(); + }, + }; +} + +static RPCHelpMan testmempoolaccept() +{ + return RPCHelpMan{"testmempoolaccept", + "\nReturns result of mempool acceptance tests indicating if raw transaction (serialized, hex-encoded) would be accepted by mempool.\n" + "\nIf multiple transactions are passed in, parents must come before children and package policies apply: the transactions cannot conflict with any mempool transactions or each other.\n" + "\nIf one transaction fails, other transactions may not be fully validated (the 'allowed' key will be blank).\n" + "\nThe maximum number of transactions allowed is " + ToString(MAX_PACKAGE_COUNT) + ".\n" + "\nThis checks if transactions violate the consensus or policy rules.\n" + "\nSee sendrawtransaction call.\n", + { + {"rawtxs", RPCArg::Type::ARR, RPCArg::Optional::NO, "An array of hex strings of raw transactions.", + { + {"rawtx", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, ""}, + }, + }, + {"maxfeerate", RPCArg::Type::AMOUNT, RPCArg::Default{FormatMoney(DEFAULT_MAX_RAW_TX_FEE_RATE.GetFeePerK())}, + "Reject transactions whose fee rate is higher than the specified value, expressed in " + CURRENCY_UNIT + "/kB\n"}, + }, + RPCResult{ + RPCResult::Type::ARR, "", "The result of the mempool acceptance test for each raw transaction in the input array.\n" + "Returns results for each transaction in the same order they were passed in.\n" + "Transactions that cannot be fully validated due to failures in other transactions will not contain an 'allowed' result.\n", + { + {RPCResult::Type::OBJ, "", "", + { + {RPCResult::Type::STR_HEX, "txid", "The transaction hash in hex"}, + {RPCResult::Type::STR, "package-error", /*optional=*/true, "Package validation error, if any (only possible if rawtxs had more than 1 transaction)."}, + {RPCResult::Type::BOOL, "allowed", /*optional=*/true, "Whether this tx would be accepted to the mempool and pass client-specified maxfeerate. " + "If not present, the tx was not fully validated due to a failure in another tx in the list."}, + {RPCResult::Type::NUM, "vsize", /*optional=*/true, "Transaction size."}, + {RPCResult::Type::OBJ, "fees", /*optional=*/true, "Transaction fees (only present if 'allowed' is true)", + { + {RPCResult::Type::STR_AMOUNT, "base", "transaction fee in " + CURRENCY_UNIT}, + }}, + {RPCResult::Type::STR, "reject-reason", /*optional=*/true, "Rejection string (only present when 'allowed' is false)"}, + }}, + } + }, + RPCExamples{ + "\nCreate a transaction\n" + + HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\" : \\\"mytxid\\\",\\\"vout\\\":0}]\" \"{\\\"myaddress\\\":0.01}\"") + + "Sign the transaction, and get back the hex\n" + + HelpExampleCli("signrawtransactionwithwallet", "\"myhex\"") + + "\nTest acceptance of the transaction (signed hex)\n" + + HelpExampleCli("testmempoolaccept", R"('["signedhex"]')") + + "\nAs a JSON-RPC call\n" + + HelpExampleRpc("testmempoolaccept", "[\"signedhex\"]") + }, + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue + { + RPCTypeCheck(request.params, { + UniValue::VARR, + UniValueType(), // VNUM or VSTR, checked inside AmountFromValue() + }); + const UniValue raw_transactions = request.params[0].get_array(); + if (raw_transactions.size() < 1 || raw_transactions.size() > MAX_PACKAGE_COUNT) { + throw JSONRPCError(RPC_INVALID_PARAMETER, + "Array must contain between 1 and " + ToString(MAX_PACKAGE_COUNT) + " transactions."); + } + + const CFeeRate max_raw_tx_fee_rate = request.params[1].isNull() ? + DEFAULT_MAX_RAW_TX_FEE_RATE : + CFeeRate(AmountFromValue(request.params[1])); + + std::vector txns; + txns.reserve(raw_transactions.size()); + for (const auto& rawtx : raw_transactions.getValues()) { + CMutableTransaction mtx; + if (!DecodeHexTx(mtx, rawtx.get_str())) { + throw JSONRPCError(RPC_DESERIALIZATION_ERROR, + "TX decode failed: " + rawtx.get_str() + " Make sure the tx has at least one input."); + } + txns.emplace_back(MakeTransactionRef(std::move(mtx))); + } + + NodeContext& node = EnsureAnyNodeContext(request.context); + CTxMemPool& mempool = EnsureMemPool(node); + ChainstateManager& chainman = EnsureChainman(node); + CChainState& chainstate = chainman.ActiveChainstate(); + const PackageMempoolAcceptResult package_result = [&] { + LOCK(::cs_main); + if (txns.size() > 1) return ProcessNewPackage(chainstate, mempool, txns, /*test_accept=*/true); + return PackageMempoolAcceptResult(txns[0]->GetHash(), + chainman.ProcessTransaction(txns[0], /*test_accept=*/true)); + }(); + + UniValue rpc_result(UniValue::VARR); + // We will check transaction fees while we iterate through txns in order. If any transaction fee + // exceeds maxfeerate, we will leave the rest of the validation results blank, because it + // doesn't make sense to return a validation result for a transaction if its ancestor(s) would + // not be submitted. + bool exit_early{false}; + for (const auto& tx : txns) { + UniValue result_inner(UniValue::VOBJ); + result_inner.pushKV("txid", tx->GetHash().GetHex()); + if (package_result.m_state.GetResult() == PackageValidationResult::PCKG_POLICY) { + result_inner.pushKV("package-error", package_result.m_state.GetRejectReason()); + } + auto it = package_result.m_tx_results.find(tx->GetHash()); + if (exit_early || it == package_result.m_tx_results.end()) { + // Validation unfinished. Just return the txid. + rpc_result.push_back(result_inner); + continue; + } + const auto& tx_result = it->second; + // Package testmempoolaccept doesn't allow transactions to already be in the mempool. + CHECK_NONFATAL(tx_result.m_result_type != MempoolAcceptResult::ResultType::MEMPOOL_ENTRY); + if (tx_result.m_result_type == MempoolAcceptResult::ResultType::VALID) { + const CAmount fee = tx_result.m_base_fees.value(); + // Check that fee does not exceed maximum fee + const int64_t virtual_size = tx_result.m_vsize.value(); + const CAmount max_raw_tx_fee = max_raw_tx_fee_rate.GetFee(virtual_size); + if (max_raw_tx_fee && fee > max_raw_tx_fee) { + result_inner.pushKV("allowed", false); + result_inner.pushKV("reject-reason", "max-fee-exceeded"); + exit_early = true; + } else { + // Only return the fee and vsize if the transaction would pass ATMP. + // These can be used to calculate the feerate. + result_inner.pushKV("allowed", true); + result_inner.pushKV("vsize", virtual_size); + UniValue fees(UniValue::VOBJ); + fees.pushKV("base", ValueFromAmount(fee)); + result_inner.pushKV("fees", fees); + } + } else { + result_inner.pushKV("allowed", false); + const TxValidationState state = tx_result.m_state; + if (state.GetResult() == TxValidationResult::TX_MISSING_INPUTS) { + result_inner.pushKV("reject-reason", "missing-inputs"); + } else { + result_inner.pushKV("reject-reason", state.GetRejectReason()); + } + } + rpc_result.push_back(result_inner); + } + return rpc_result; + }, + }; +} + +static std::vector MempoolEntryDescription() +{ + return { RPCResult{RPCResult::Type::NUM, "vsize", "virtual transaction size. This can be different from actual serialized size for high-sigop transactions."}, RPCResult{RPCResult::Type::STR_AMOUNT, "fee", /*optional=*/true, "transaction fee, denominated in " + CURRENCY_UNIT + " (DEPRECATED, returned only if config option -deprecatedrpc=fees is passed)"}, @@ -53,7 +267,8 @@ static std::vector MempoolEntryDescription() { return { {RPCResult{RPCResult::Type::STR_HEX, "transactionid", "child transaction id"}}}, RPCResult{RPCResult::Type::BOOL, "instantsend", "True if this transaction was locked via InstantSend"}, RPCResult{RPCResult::Type::BOOL, "unbroadcast", "Whether this transaction is currently unbroadcast (initial broadcast not yet acknowledged by any peers)"} -};} + }; +} static void entryToJSON(const CTxMemPool& pool, UniValue& info, const CTxMemPoolEntry& e, const llmq::CInstantSendManager* isman) EXCLUSIVE_LOCKS_REQUIRED(pool.cs) { @@ -155,7 +370,7 @@ UniValue MempoolToJSON(const CTxMemPool& pool, const llmq::CInstantSendManager* } } -RPCHelpMan getrawmempool() +static RPCHelpMan getrawmempool() { return RPCHelpMan{"getrawmempool", "\nReturns all transaction ids in memory pool as a json array of string transaction ids.\n" @@ -209,7 +424,7 @@ RPCHelpMan getrawmempool() }; } -RPCHelpMan getmempoolancestors() +static RPCHelpMan getmempoolancestors() { return RPCHelpMan{"getmempoolancestors", "\nIf txid is in the mempool, returns all in-mempool ancestors.\n", @@ -276,7 +491,7 @@ RPCHelpMan getmempoolancestors() }; } -RPCHelpMan getmempooldescendants() +static RPCHelpMan getmempooldescendants() { return RPCHelpMan{"getmempooldescendants", "\nIf txid is in the mempool, returns all in-mempool descendants.\n", @@ -344,7 +559,7 @@ RPCHelpMan getmempooldescendants() }; } -RPCHelpMan getmempoolentry() +static RPCHelpMan getmempoolentry() { return RPCHelpMan{"getmempoolentry", "\nReturns mempool data for given transaction\n", @@ -381,6 +596,89 @@ RPCHelpMan getmempoolentry() }; } +static RPCHelpMan gettxspendingprevout() +{ + return RPCHelpMan{"gettxspendingprevout", + "Scans the mempool to find transactions spending any of the given outputs", + { + {"outputs", RPCArg::Type::ARR, RPCArg::Optional::NO, "The transaction outputs that we want to check, and within each, the txid (string) vout (numeric).", + { + {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "", + { + {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"}, + {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"}, + }, + }, + }, + }, + }, + RPCResult{ + RPCResult::Type::ARR, "", "", + { + {RPCResult::Type::OBJ, "", "", + { + {RPCResult::Type::STR_HEX, "txid", "the transaction id of the checked output"}, + {RPCResult::Type::NUM, "vout", "the vout value of the checked output"}, + {RPCResult::Type::STR_HEX, "spendingtxid", /*optional=*/true, "the transaction id of the mempool transaction spending this output (omitted if unspent)"}, + }}, + } + }, + RPCExamples{ + HelpExampleCli("gettxspendingprevout", "\"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":3}]\"") + + HelpExampleRpc("gettxspendingprevout", "\"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":3}]\"") + }, + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue + { + RPCTypeCheckArgument(request.params[0], UniValue::VARR); + const UniValue& output_params = request.params[0]; + if (output_params.empty()) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, outputs are missing"); + } + + std::vector prevouts; + prevouts.reserve(output_params.size()); + + for (unsigned int idx = 0; idx < output_params.size(); idx++) { + const UniValue& o = output_params[idx].get_obj(); + + RPCTypeCheckObj(o, + { + {"txid", UniValueType(UniValue::VSTR)}, + {"vout", UniValueType(UniValue::VNUM)}, + }, /*fAllowNull=*/false, /*fStrict=*/true); + + const uint256 txid(ParseHashO(o, "txid")); + const int nOutput{o.find_value("vout").getInt()}; + if (nOutput < 0) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout cannot be negative"); + } + + prevouts.emplace_back(txid, nOutput); + } + + const CTxMemPool& mempool = EnsureAnyMemPool(request.context); + LOCK(mempool.cs); + + UniValue result{UniValue::VARR}; + + for (const COutPoint& prevout : prevouts) { + UniValue o(UniValue::VOBJ); + o.pushKV("txid", prevout.hash.ToString()); + o.pushKV("vout", (uint64_t)prevout.n); + + const CTransaction* spendingTx = mempool.GetConflictTx(prevout); + if (spendingTx != nullptr) { + o.pushKV("spendingtxid", spendingTx->GetHash().ToString()); + } + + result.push_back(o); + } + + return result; + }, + }; +} + UniValue MempoolInfoToJSON(const CTxMemPool& pool, const llmq::CInstantSendManager& isman) { // Make sure this call is atomic in the pool. @@ -400,7 +698,7 @@ UniValue MempoolInfoToJSON(const CTxMemPool& pool, const llmq::CInstantSendManag return ret; } -RPCHelpMan getmempoolinfo() +static RPCHelpMan getmempoolinfo() { return RPCHelpMan{"getmempoolinfo", "\nReturns details on the active state of the TX memory pool.\n", @@ -433,7 +731,7 @@ RPCHelpMan getmempoolinfo() }; } -RPCHelpMan savemempool() +static RPCHelpMan savemempool() { return RPCHelpMan{"savemempool", "\nDumps the mempool to disk. It will fail until the previous dump is fully loaded.\n", @@ -471,11 +769,12 @@ RPCHelpMan savemempool() void RegisterMempoolRPCCommands(CRPCTable& t) { static const CRPCCommand commands[]{ - // category actor (function) - // -------- ---------------- + {"rawtransactions", &sendrawtransaction}, + {"rawtransactions", &testmempoolaccept}, {"blockchain", &getmempoolancestors}, {"blockchain", &getmempooldescendants}, {"blockchain", &getmempoolentry}, + {"blockchain", &gettxspendingprevout}, {"blockchain", &getmempoolinfo}, {"blockchain", &getrawmempool}, {"blockchain", &savemempool}, diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index d055d17d7bfd..6e372c75cea0 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -131,7 +131,7 @@ static bool GenerateBlock(ChainstateManager& chainman, CBlock& block, uint64_t& block_hash.SetNull(); block.hashMerkleRoot = BlockMerkleRoot(block); - CChainParams chainparams(Params()); + const CChainParams& chainparams(Params()); while (max_tries > 0 && block.nNonce < std::numeric_limits::max() && !CheckProofOfWork(block.GetHash(), block.nBits, chainparams.GetConsensus()) && !ShutdownRequested()) { ++block.nNonce; @@ -356,7 +356,7 @@ static RPCHelpMan generateblock() } } - CChainParams chainparams(Params()); + const CChainParams& chainparams(Params()); const LLMQContext& llmq_ctx = EnsureLLMQContext(node); ChainstateManager& chainman = EnsureChainman(node); @@ -516,7 +516,7 @@ static RPCHelpMan prioritisetransaction() static UniValue BIP22ValidationResult(const BlockValidationState& state) { if (state.IsValid()) - return NullUniValue; + return UniValue::VNULL; if (state.IsError()) throw JSONRPCError(RPC_VERIFY_ERROR, state.ToString()); @@ -755,7 +755,7 @@ static RPCHelpMan getblocktemplate() if (lpval.isStr()) { // Format: - std::string lpstr = lpval.get_str(); + const std::string& lpstr = lpval.get_str(); hashWatchedChain = ParseHashV(lpstr.substr(0, 64), "longpollid"); nTransactionsUpdatedLastLP = LocaleIndependentAtoi(lpstr.substr(64)); @@ -978,10 +978,10 @@ class submitblock_StateCatcher final : public CValidationInterface { public: uint256 hash; - bool found; + bool found{false}; BlockValidationState state; - explicit submitblock_StateCatcher(const uint256 &hashIn) : hash(hashIn), found(false), state() {} + explicit submitblock_StateCatcher(const uint256 &hashIn) : hash(hashIn), state() {} protected: void BlockChecked(const CBlock& block, const BlockValidationState& stateIn) override { @@ -1083,7 +1083,7 @@ static RPCHelpMan submitheader() BlockValidationState state; chainman.ProcessNewBlockHeaders({h}, state, Params()); - if (state.IsValid()) return NullUniValue; + if (state.IsValid()) return UniValue::VNULL; if (state.IsError()) { throw JSONRPCError(RPC_VERIFY_ERROR, state.ToString()); } @@ -1094,24 +1094,18 @@ static RPCHelpMan submitheader() void RegisterMiningRPCCommands(CRPCTable& t) { -// clang-format off -static const CRPCCommand commands[] = -{ // category actor (function) - // --------------------- ----------------------- - { "mining", &getnetworkhashps, }, - { "mining", &getmininginfo, }, - { "mining", &prioritisetransaction, }, - { "mining", &getblocktemplate, }, - { "mining", &submitblock, }, - { "mining", &submitheader, }, - - { "hidden", &generatetoaddress, }, - { "hidden", &generatetodescriptor, }, - { "hidden", &generateblock, }, - - { "hidden", &generate, }, -}; -// clang-format on + static const CRPCCommand commands[]{ + {"mining", &getnetworkhashps}, + {"mining", &getmininginfo}, + {"mining", &prioritisetransaction}, + {"mining", &getblocktemplate}, + {"mining", &submitblock}, + {"mining", &submitheader}, + {"hidden", &generatetoaddress}, + {"hidden", &generatetodescriptor}, + {"hidden", &generateblock}, + {"hidden", &generate}, + }; for (const auto& c : commands) { t.appendCommand(c.name, &c); } diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index 866c5c858c76..266fc27672ca 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -90,7 +90,7 @@ static RPCHelpMan ping() // Request that each node send a ping during next message processing pass peerman.SendPings(); - return NullUniValue; + return UniValue::VNULL; }, }; } @@ -99,7 +99,7 @@ static RPCHelpMan getpeerinfo() { return RPCHelpMan{ "getpeerinfo", - "\nReturns data about each connected network node as a json array of objects.\n", + "Returns data about each connected network peer as a json array of objects.", {}, RPCResult{ RPCResult::Type::ARR, "", "", @@ -124,7 +124,7 @@ static RPCHelpMan getpeerinfo() {RPCResult::Type::STR_HEX, "verified_pubkey_hash", "Only present when the peer is a masternode and successfully " "authenticated via MNAUTH. In this case, this field contains the " "hash of the masternode's operator public key"}, - {RPCResult::Type::BOOL, "relaytxes", "Whether peer has asked us to relay transactions to it"}, + {RPCResult::Type::BOOL, "relaytxes", /*optional=*/true, "Whether peer has asked us to relay transactions to it"}, {RPCResult::Type::NUM_TIME, "lastsend", "The " + UNIX_EPOCH_TIME + " of the last send"}, {RPCResult::Type::NUM_TIME, "lastrecv", "The " + UNIX_EPOCH_TIME + " of the last receive"}, {RPCResult::Type::NUM_TIME, "last_transaction", "The " + UNIX_EPOCH_TIME + " of the last valid transaction received from this peer"}, @@ -340,7 +340,7 @@ static RPCHelpMan addnode() { CAddress addr; connman.OpenNetworkConnection(addr, /*fCountFailure=*/false, /*grant_outbound=*/{}, node_arg.c_str(), ConnectionType::MANUAL, use_v2transport); - return NullUniValue; + return UniValue::VNULL; } if (command == "add") @@ -356,7 +356,7 @@ static RPCHelpMan addnode() } } - return NullUniValue; + return UniValue::VNULL; }, }; } @@ -466,7 +466,7 @@ static RPCHelpMan disconnectnode() throw JSONRPCError(RPC_CLIENT_NODE_NOT_CONNECTED, "Node not found in connected nodes"); } - return NullUniValue; + return UniValue::VNULL; }, }; } @@ -804,7 +804,7 @@ static RPCHelpMan setban() throw JSONRPCError(RPC_CLIENT_INVALID_IP_OR_SUBNET, "Error: Unban failed. Requested address/subnet was not previously manually banned."); } } - return NullUniValue; + return UniValue::VNULL; }, }; } @@ -872,7 +872,7 @@ static RPCHelpMan clearbanned() banman.ClearBanned(); - return NullUniValue; + return UniValue::VNULL; }, }; } @@ -893,7 +893,7 @@ static RPCHelpMan cleardiscouraged() banman.ClearDiscouraged(); - return NullUniValue; + return UniValue::VNULL; }, }; } @@ -1079,7 +1079,7 @@ static RPCHelpMan sendmsgtopeer() throw JSONRPCError(RPC_MISC_ERROR, "Error: Could not send message to peer"); } - return NullUniValue; + return UniValue::VNULL; }, }; } @@ -1112,31 +1112,26 @@ static RPCHelpMan setmnthreadactive() void RegisterNetRPCCommands(CRPCTable &t) { -// clang-format off -static const CRPCCommand commands[] = -{ // category actor - // --------------------- ----------------------- - { "network", &getconnectioncount, }, - { "network", &ping, }, - { "network", &getpeerinfo, }, - { "network", &addnode, }, - { "network", &disconnectnode, }, - { "network", &getaddednodeinfo, }, - { "network", &getnettotals, }, - { "network", &getnetworkinfo, }, - { "network", &setban, }, - { "network", &listbanned, }, - { "network", &clearbanned, }, - { "network", &setnetworkactive, }, - { "network", &getnodeaddresses, }, - - { "hidden", &cleardiscouraged, }, - { "hidden", &addconnection, }, - { "hidden", &addpeeraddress, }, - { "hidden", &sendmsgtopeer }, - { "hidden", &setmnthreadactive }, -}; -// clang-format on + static const CRPCCommand commands[]{ + {"network", &getconnectioncount}, + {"network", &ping}, + {"network", &getpeerinfo}, + {"network", &addnode}, + {"network", &disconnectnode}, + {"network", &getaddednodeinfo}, + {"network", &getnettotals}, + {"network", &getnetworkinfo}, + {"network", &setban}, + {"network", &listbanned}, + {"network", &clearbanned}, + {"network", &setnetworkactive}, + {"network", &getnodeaddresses}, + {"hidden", &cleardiscouraged}, + {"hidden", &addconnection}, + {"hidden", &addpeeraddress}, + {"hidden", &sendmsgtopeer}, + {"hidden", &setmnthreadactive}, + }; for (const auto& c : commands) { t.appendCommand(c.name, &c); } diff --git a/src/rpc/node.cpp b/src/rpc/node.cpp index 97d6188828b9..4f573566525f 100644 --- a/src/rpc/node.cpp +++ b/src/rpc/node.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -190,7 +191,7 @@ static RPCHelpMan spork() return ret; } - return NullUniValue; + return UniValue::VNULL; }, }; } @@ -220,18 +221,19 @@ static RPCHelpMan sporkupdate() } const NodeContext& node = EnsureAnyNodeContext(request.context); - PeerManager& peerman = EnsurePeerman(node); CHECK_NONFATAL(node.sporkman); // SPORK VALUE int64_t nValue = request.params[1].getInt(); - // broadcast new spork - if (node.sporkman->UpdateSpork(peerman, nSporkID, nValue)) { + auto inv{node.sporkman->UpdateSpork(nSporkID, nValue)}; + if (inv.has_value()) { + PeerManager& peerman = EnsurePeerman(node); + peerman.RelayInv(inv.value()); return "success"; } - return NullUniValue; + return UniValue::VNULL; }, }; } @@ -272,7 +274,7 @@ static RPCHelpMan setmocktime() } } - return NullUniValue; + return UniValue::VNULL; }, }; } @@ -825,7 +827,7 @@ static RPCHelpMan mockscheduler() { {"delta_time", RPCArg::Type::NUM, RPCArg::Optional::NO, "Number of seconds to forward the scheduler into the future." }, }, - RPCResults{}, + RPCResult{RPCResult::Type::NONE, "", ""}, RPCExamples{""}, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { @@ -845,7 +847,7 @@ static RPCHelpMan mockscheduler() CHECK_NONFATAL(node_context->scheduler); node_context->scheduler->MockForward(std::chrono::seconds(delta_seconds)); - return NullUniValue; + return UniValue::VNULL; }, }; } diff --git a/src/rpc/output_script.cpp b/src/rpc/output_script.cpp index 2e238ecfbab9..ca5beef1d0f7 100644 --- a/src/rpc/output_script.cpp +++ b/src/rpc/output_script.cpp @@ -23,11 +23,6 @@ #include #include -namespace node { -struct NodeContext; -} -using node::NodeContext; - static RPCHelpMan validateaddress() { return RPCHelpMan{ @@ -40,10 +35,10 @@ static RPCHelpMan validateaddress() RPCResult::Type::OBJ, "", "", { {RPCResult::Type::BOOL, "isvalid", "If the address is valid or not"}, - {RPCResult::Type::STR, "address", /* optional */ true, "The Dash address validated"}, - {RPCResult::Type::STR_HEX, "scriptPubKey", /* optional */ true, "The hex-encoded scriptPubKey generated by the address"}, - {RPCResult::Type::BOOL, "isscript", /* optional */ true, "If the key is a script"}, - {RPCResult::Type::STR, "error", /* optional */ true, "Error message, if any"}, + {RPCResult::Type::STR, "address", /*optional=*/true, "The Dash address validated"}, + {RPCResult::Type::STR_HEX, "scriptPubKey", /*optional=*/true, "The hex-encoded scriptPubKey generated by the address"}, + {RPCResult::Type::BOOL, "isscript", /*optional=*/true, "If the key is a script"}, + {RPCResult::Type::STR, "error", /*optional=*/true, "Error message, if any"}, } }, RPCExamples{ diff --git a/src/rpc/quorums.cpp b/src/rpc/quorums.cpp index d4776d97e745..fbac23cd76dc 100644 --- a/src/rpc/quorums.cpp +++ b/src/rpc/quorums.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -179,20 +180,20 @@ static RPCHelpMan quorum_list_extended() } static UniValue BuildQuorumInfo(const llmq::CQuorumBlockProcessor& quorum_block_processor, - const llmq::CQuorumCPtr& quorum, bool includeMembers, bool includeSkShare) + const llmq::CQuorum& quorum, bool includeMembers, bool includeSkShare) { UniValue ret(UniValue::VOBJ); - ret.pushKV("height", quorum->m_quorum_base_block_index->nHeight); - ret.pushKV("type", std::string(quorum->params.name)); - ret.pushKV("quorumHash", quorum->qc->quorumHash.ToString()); - ret.pushKV("quorumIndex", quorum->qc->quorumIndex); - ret.pushKV("minedBlock", quorum->minedBlockHash.ToString()); + ret.pushKV("height", quorum.m_quorum_base_block_index->nHeight); + ret.pushKV("type", std::string(quorum.params.name)); + ret.pushKV("quorumHash", quorum.qc->quorumHash.ToString()); + ret.pushKV("quorumIndex", quorum.qc->quorumIndex); + ret.pushKV("minedBlock", quorum.minedBlockHash.ToString()); - if (quorum->params.useRotation) { - auto previousActiveCommitment = quorum_block_processor.GetLastMinedCommitmentsByQuorumIndexUntilBlock(quorum->params.type, quorum->m_quorum_base_block_index, quorum->qc->quorumIndex, 0); + if (quorum.params.useRotation) { + auto previousActiveCommitment = quorum_block_processor.GetLastMinedCommitmentsByQuorumIndexUntilBlock(quorum.params.type, quorum.m_quorum_base_block_index, quorum.qc->quorumIndex, 0); if (previousActiveCommitment.has_value()) { - int previousConsecutiveDKGFailures = (quorum->m_quorum_base_block_index->nHeight - previousActiveCommitment.value()->nHeight) / quorum->params.dkgInterval - 1; + int previousConsecutiveDKGFailures = (quorum.m_quorum_base_block_index->nHeight - previousActiveCommitment.value()->nHeight) / quorum.params.dkgInterval - 1; ret.pushKV("previousConsecutiveDKGFailures", previousConsecutiveDKGFailures); } else { @@ -202,19 +203,19 @@ static UniValue BuildQuorumInfo(const llmq::CQuorumBlockProcessor& quorum_block_ if (includeMembers) { UniValue membersArr(UniValue::VARR); - for (size_t i = 0; i < quorum->members.size(); i++) { - const auto& dmn = quorum->members[i]; + for (size_t i = 0; i < quorum.members.size(); i++) { + const auto& dmn = quorum.members[i]; UniValue mo(UniValue::VOBJ); mo.pushKV("proTxHash", dmn->proTxHash.ToString()); mo.pushKV("service", dmn->pdmnState->netInfo->GetPrimary().ToStringAddrPort()); mo.pushKV("addresses", GetNetInfoWithLegacyFields(*dmn->pdmnState, dmn->nType)); mo.pushKV("pubKeyOperator", dmn->pdmnState->pubKeyOperator.ToString()); - mo.pushKV("valid", static_cast(quorum->qc->validMembers[i])); - if (quorum->qc->validMembers[i]) { - if (quorum->params.size == 1) { + mo.pushKV("valid", static_cast(quorum.qc->validMembers[i])); + if (quorum.qc->validMembers[i]) { + if (quorum.params.is_single_member()) { mo.pushKV("pubKeyShare", dmn->pdmnState->pubKeyOperator.ToString()); } else { - CBLSPublicKey pubKey = quorum->GetPubKeyShare(i); + CBLSPublicKey pubKey = quorum.GetPubKeyShare(i); if (pubKey.IsValid()) { mo.pushKV("pubKeyShare", pubKey.ToString()); } @@ -225,8 +226,8 @@ static UniValue BuildQuorumInfo(const llmq::CQuorumBlockProcessor& quorum_block_ ret.pushKV("members", membersArr); } - ret.pushKV("quorumPublicKey", quorum->qc->quorumPublicKey.ToString()); - const CBLSSecretKey& skShare = quorum->GetSkShare(); + ret.pushKV("quorumPublicKey", quorum.qc->quorumPublicKey.ToString()); + const CBLSSecretKey& skShare = quorum.GetSkShare(); if (includeSkShare && skShare.IsValid()) { ret.pushKV("secretKeyShare", skShare.ToString()); } @@ -242,7 +243,30 @@ static RPCHelpMan quorum_info() {"quorumHash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "Block hash of quorum."}, {"includeSkShare", RPCArg::Type::BOOL, RPCArg::Default{false}, "Include secret key share in output."}, }, - RPCResults{}, + RPCResult{ + RPCResult::Type::OBJ, "", "", + { + {RPCResult::Type::NUM, "height", "Quorum Height"}, + {RPCResult::Type::STR, "type", "Quorum type"}, + GetRpcResult("quorumHash"), + GetRpcResult("quorumIndex"), + {RPCResult::Type::STR_HEX, "minedBlock", "Blockhash where the commitment was mined."}, + {RPCResult::Type::NUM, "previousConsecutiveDKGFailures", "Number of previous consecutive DKG failures. Only present for rotation-enabled quorums."}, + {RPCResult::Type::ARR, "members", "Members of quorum", + { + {RPCResult::Type::OBJ, "", "", + { + GetRpcResult("proTxHash"), + GetRpcResult("service"), + GetRpcResult("addresses"), + GetRpcResult("pubKeyOperator"), + {RPCResult::Type::BOOL, "valid", "True if member is valid for this DKG"}, + {RPCResult::Type::STR_HEX, "pubKeyShare", /*optional=*/true, "Share of BLS public key of the member. Only present if member is valid."} + }}, + }, + }, + }, + }, RPCExamples{""}, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { @@ -265,7 +289,7 @@ static RPCHelpMan quorum_info() throw JSONRPCError(RPC_INVALID_PARAMETER, "quorum not found"); } - return BuildQuorumInfo(*llmq_ctx.quorum_block_processor, quorum, true, includeSkShare); + return BuildQuorumInfo(*llmq_ctx.quorum_block_processor, *quorum, true, includeSkShare); }, }; } @@ -280,7 +304,35 @@ static RPCHelpMan quorum_dkgstatus() "Detail level of output.\n" "0=Only show counts. 1=Show member indexes. 2=Show member's ProTxHashes."}, }, - RPCResults{}, + RPCResult{ + RPCResult::Type::OBJ, "", "", + { + {RPCResult::Type::NUM, "time", "Adjusted time for the last update, timestamp"}, + {RPCResult::Type::STR, "timeStr", "Adjusted time for the last update, human friendly"}, + {RPCResult::Type::ARR, "session", "", + { + {RPCResult::Type::OBJ, "", "", + { + {RPCResult::Type::NUM, "llmqType", "Name of quorum"}, + GetRpcResult("quorumIndex"), + {RPCResult::Type::OBJ, "status", "", + { + // TODO: list fields of output for RPC help instead ELISION + {RPCResult::Type::ELISION, "", ""}, + }}, + }}, + }, + }, + {RPCResult::Type::ARR, "quorumConnections", "", + // TODO: list fields of output for RPC help instead ELISION + {{RPCResult::Type::ELISION, "", ""}}, + }, + {RPCResult::Type::ARR, "minableCommitments", "", + // TODO: list fields of output for RPC help instead ELISION + {{RPCResult::Type::ELISION, "", ""}}, + }, + }, + }, RPCExamples{""}, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { @@ -365,6 +417,7 @@ static RPCHelpMan quorum_dkgstatus() std::optional> vfqc = llmq_ctx.quorum_block_processor->GetMineableCommitments(llmq_params, tipHeight); if (vfqc.has_value()) { for (const auto& fqc : vfqc.value()) { + // TODO: Use CFinalCommitment::GetJsonHelp() for fqc minableCommitments.push_back(fqc.ToJson()); } } @@ -387,7 +440,17 @@ static RPCHelpMan quorum_memberof() "Can be CPU/disk heavy when the value is larger than the number of active quorums." }, }, - RPCResults{}, + RPCResult{ + RPCResult::Type::ARR, "quorums", "", + { + {RPCResult::Type::OBJ, "", "Quorum Info", + { + {RPCResult::Type::ELISION, "", "See `help quorum info` for details"}, + {RPCResult::Type::BOOL, "isValidMember", ""}, + {RPCResult::Type::NUM, "memberIndex", ""}, + }}, + }, + }, RPCExamples{""}, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { @@ -422,7 +485,7 @@ static RPCHelpMan quorum_memberof() auto quorums = llmq_ctx.qman->ScanQuorums(llmq_params_opt->type, count); for (auto& quorum : quorums) { if (quorum->IsMember(dmn->proTxHash)) { - auto json = BuildQuorumInfo(*llmq_ctx.quorum_block_processor, quorum, false, false); + auto json = BuildQuorumInfo(*llmq_ctx.quorum_block_processor, *quorum, false, false); json.pushKV("isValidMember", quorum->IsValidMember(dmn->proTxHash)); json.pushKV("memberIndex", quorum->GetMemberIndex(dmn->proTxHash)); result.push_back(json); @@ -438,6 +501,10 @@ static RPCHelpMan quorum_memberof() static UniValue quorum_sign_helper(const JSONRPCRequest& request, Consensus::LLMQType llmqType) { const NodeContext& node = EnsureAnyNodeContext(request.context); + if (!node.mn_activeman) { + throw JSONRPCError(RPC_INTERNAL_ERROR, "Only available in masternode mode."); + } + const ChainstateManager& chainman = EnsureChainman(node); const LLMQContext& llmq_ctx = EnsureLLMQContext(node); @@ -458,7 +525,7 @@ static UniValue quorum_sign_helper(const JSONRPCRequest& request, Consensus::LLM fSubmit = ParseBoolV(request.params[3], "submit"); } if (fSubmit) { - return llmq_ctx.sigman->AsyncSignIfMember(llmqType, *llmq_ctx.shareman, id, msgHash, quorumHash); + return CHECK_NONFATAL(node.active_ctx)->shareman->AsyncSignIfMember(llmqType, *llmq_ctx.sigman, id, msgHash, quorumHash); } else { const auto pQuorum = [&]() { if (quorumHash.IsNull()) { @@ -472,7 +539,7 @@ static UniValue quorum_sign_helper(const JSONRPCRequest& request, Consensus::LLM throw JSONRPCError(RPC_INVALID_PARAMETER, "quorum not found"); } - auto sigShare = llmq_ctx.shareman->CreateSigShare(pQuorum, id, msgHash); + auto sigShare = CHECK_NONFATAL(node.active_ctx)->shareman->CreateSigShare(*pQuorum, id, msgHash); if (!sigShare.has_value() || !sigShare->sigShare.Get().IsValid()) { throw JSONRPCError(RPC_INVALID_PARAMETER, "failed to create sigShare"); @@ -491,6 +558,23 @@ static UniValue quorum_sign_helper(const JSONRPCRequest& request, Consensus::LLM } } +namespace { +const RPCResults quorum_sign_result{ + RPCResult{"if submit is set to true", RPCResult::Type::BOOL, "result", "result of signing, true if success"}, + RPCResult{"if submit is not set or set to false", RPCResult::Type::OBJ, "", "", + { + {RPCResult::Type::NUM, "llmqType", "Quorum type"}, + {RPCResult::Type::STR_HEX, "quorumHash", "Quorum Hash"}, + {RPCResult::Type::NUM, "quorumMember", "Number of quorum member"}, + {RPCResult::Type::STR_HEX, "id", "Request ID"}, + {RPCResult::Type::STR_HEX, "msgHash", "Hash of message"}, + {RPCResult::Type::STR_HEX, "signHash", "Hash of signature"}, + {RPCResult::Type::STR_HEX, "signature", "Hex encoded signature"}, + }, + }, +}; +} // anonymous namespace + static RPCHelpMan quorum_sign() { return RPCHelpMan{"quorum sign", @@ -503,7 +587,7 @@ static RPCHelpMan quorum_sign() {"submit", RPCArg::Type::BOOL, RPCArg::Default{true}, "Submits the signature share to the network if this is true. " "Returns an object containing the signature share if this is false."}, }, - RPCResults{}, + quorum_sign_result, RPCExamples{""}, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { @@ -530,7 +614,7 @@ static RPCHelpMan quorum_platformsign() {"submit", RPCArg::Type::BOOL, RPCArg::Default{true}, "Submits the signature share to the network if this is true. " "Returns an object containing the signature share if this is false."}, }, - RPCResults{}, + quorum_sign_result, RPCExamples{""}, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { @@ -568,7 +652,7 @@ static RPCHelpMan quorum_verify() "The height at which the message was signed.\n" "Only works when quorumHash is \"\"."}, }, - RPCResults{}, + RPCResult{RPCResult::Type::BOOL, "", "Returns true if the signature is valid"}, RPCExamples{""}, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { @@ -622,7 +706,7 @@ static RPCHelpMan quorum_hasrecsig() {"id", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "Request id."}, {"msgHash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "Message hash."}, }, - RPCResults{}, + RPCResult{RPCResult::Type::BOOL, "", "Returns true if node has this recovered signature"}, RPCExamples{""}, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { @@ -651,7 +735,7 @@ static RPCHelpMan quorum_getrecsig() {"id", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "Request id."}, {"msgHash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "Message hash."}, }, - RPCResults{}, + llmq::CRecoveredSig::GetJsonHelp(/*key=*/"", /*optional=*/false), RPCExamples{""}, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { @@ -687,7 +771,7 @@ static RPCHelpMan quorum_isconflicting() {"id", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "Request id."}, {"msgHash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "Message hash."}, }, - RPCResults{}, + RPCResult{RPCResult::Type::BOOL, "", "Returns true if this msgHash is conflicting with previous signing sessions"}, RPCExamples{""}, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { @@ -715,7 +799,15 @@ static RPCHelpMan quorum_selectquorum() {"llmqType", RPCArg::Type::NUM, RPCArg::Optional::NO, "LLMQ type."}, {"id", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "Request id."}, }, - RPCResults{}, + RPCResult{ + RPCResult::Type::OBJ, "", "", + { + {RPCResult::Type::STR_HEX, "quorumHash", "Hash of chosen quorum"}, + {RPCResult::Type::ARR, "recoveryMembers", "List of members to use for signature recovery", + {{RPCResult::Type::STR_HEX, "hash", "ProTxHash of member"}} + }, + } + }, RPCExamples{""}, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { @@ -741,7 +833,7 @@ static RPCHelpMan quorum_selectquorum() UniValue recoveryMembers(UniValue::VARR); for (int i = 0; i < quorum->params.recoveryMembers; ++i) { - auto dmn = llmq_ctx.shareman->SelectMemberForRecovery(quorum, id, i); + auto dmn = llmq::CSigSharesManager::SelectMemberForRecovery(*quorum, id, i); recoveryMembers.push_back(dmn->proTxHash.ToString()); } ret.pushKV("recoveryMembers", recoveryMembers); @@ -760,7 +852,7 @@ static RPCHelpMan quorum_dkgsimerror() {"type", RPCArg::Type::STR, RPCArg::Optional::NO, "Error type."}, {"rate", RPCArg::Type::NUM, RPCArg::Optional::NO, "Rate at which to simulate this error type (between 0 and 100)."}, }, - RPCResults{}, + RPCResult{RPCResult::Type::NONE, "", ""}, RPCExamples{""}, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { @@ -776,7 +868,7 @@ static RPCHelpMan quorum_dkgsimerror() throw JSONRPCError(RPC_INVALID_PARAMETER, "invalid type. See DKGError class implementation"); } else { llmq::SetSimulatedDKGErrorRate(type, static_cast(rate) / 100); - return UniValue(); + return NullUniValue; } }, }; @@ -797,7 +889,7 @@ static RPCHelpMan quorum_getdata() "3 - Request both, 1 and 2"}, {"proTxHash", RPCArg::Type::STR_HEX, RPCArg::Default{""}, "The proTxHash the contributions will be requested for. Must be member of the specified LLMQ."}, }, - RPCResults{}, + RPCResult{RPCResult::Type::BOOL, "", "Returns true if the message QGETDATA has been successfully sent"}, RPCExamples{""}, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { @@ -828,7 +920,7 @@ static RPCHelpMan quorum_getdata() throw JSONRPCError(RPC_INVALID_PARAMETER, "quorum not found"); } return connman.ForNode(nodeId, [&](CNode* pNode) { - return llmq_ctx.qman->RequestQuorumData(pNode, connman, quorum, nDataMask, proTxHash); + return llmq_ctx.qman->RequestQuorumData(pNode, connman, *quorum, nDataMask, proTxHash); }); }, }; @@ -847,7 +939,7 @@ static RPCHelpMan quorum_rotationinfo() {"baseBlockHash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The block hash"}, }}, }, - RPCResults{}, + llmq::CQuorumRotationInfo::GetJsonHelp(/*key=*/"", /*optional=*/false), RPCExamples{""}, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { @@ -959,7 +1051,7 @@ static RPCHelpMan quorum_help() { {"command", RPCArg::Type::STR, RPCArg::Optional::NO, "The command to execute"}, }, - RPCResults{}, + RPCResult{RPCResult::Type::NONE, "", ""}, RPCExamples{""}, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { @@ -977,7 +1069,7 @@ static RPCHelpMan verifychainlock() {"signature", RPCArg::Type::STR, RPCArg::Optional::NO, "The signature of the ChainLock."}, {"blockHeight", RPCArg::Type::NUM, RPCArg::DefaultHint{"There will be an internal lookup of \"blockHash\" if this is not provided."}, "The height of the ChainLock."}, }, - RPCResults{}, + RPCResult{RPCResult::Type::BOOL, "", "Returns true if the chainlock is valid"}, RPCExamples{""}, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { @@ -1036,7 +1128,7 @@ static RPCHelpMan verifyislock() {"signature", RPCArg::Type::STR, RPCArg::Optional::NO, "The InstantSend Lock signature to verify."}, {"maxHeight", RPCArg::Type::NUM, RPCArg::Default{-1}, "The maximum height to search quorums from."}, }, - RPCResults{}, + RPCResult{RPCResult::Type::BOOL, "", "Returns true if the instantsend lock is valid"}, RPCExamples{""}, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { @@ -1154,32 +1246,28 @@ static RPCHelpMan submitchainlock() void RegisterQuorumsRPCCommands(CRPCTable &tableRPC) { -// clang-format off -static const CRPCCommand commands[] = -{ // category actor (function) - // --------------------- ----------------------- - { "evo", &quorum_help, }, - { "evo", &quorum_list, }, - { "evo", &quorum_list_extended, }, - { "evo", &quorum_info, }, - { "evo", &quorum_dkginfo, }, - { "evo", &quorum_dkgstatus, }, - { "evo", &quorum_memberof, }, - { "evo", &quorum_sign, }, - { "evo", &quorum_platformsign, }, - { "evo", &quorum_verify, }, - { "evo", &quorum_hasrecsig, }, - { "evo", &quorum_getrecsig, }, - { "evo", &quorum_isconflicting, }, - { "evo", &quorum_selectquorum, }, - { "evo", &quorum_dkgsimerror, }, - { "evo", &quorum_getdata, }, - { "evo", &quorum_rotationinfo, }, - { "evo", &submitchainlock, }, - { "evo", &verifychainlock, }, - { "evo", &verifyislock, }, -}; -// clang-format on + static const CRPCCommand commands[]{ + {"evo", &quorum_help}, + {"evo", &quorum_list}, + {"evo", &quorum_list_extended}, + {"evo", &quorum_info}, + {"evo", &quorum_dkginfo}, + {"evo", &quorum_dkgstatus}, + {"evo", &quorum_memberof}, + {"evo", &quorum_sign}, + {"evo", &quorum_platformsign}, + {"evo", &quorum_verify}, + {"evo", &quorum_hasrecsig}, + {"evo", &quorum_getrecsig}, + {"evo", &quorum_isconflicting}, + {"evo", &quorum_selectquorum}, + {"evo", &quorum_dkgsimerror}, + {"evo", &quorum_getdata}, + {"evo", &quorum_rotationinfo}, + {"evo", &submitchainlock}, + {"evo", &verifychainlock}, + {"evo", &verifyislock}, + }; for (const auto& command : commands) { tableRPC.appendCommand(command.name, &command); } diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 151e48a162e9..c06a297ea3c5 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -27,7 +26,6 @@ #include #include #include -#include #include #include #include @@ -40,29 +38,33 @@ #include #include #include -#include #include #include #include #include #include #include -#include #include +#include #include +#include +#include +#include #include -#include #include +#include +#include #include +#include +#include +#include #include -#include #include using node::AnalyzePSBT; -using node::DEFAULT_MAX_RAW_TX_FEE_RATE; using node::GetTransaction; using node::NodeContext; using node::PSBTAnalysis; @@ -146,8 +148,8 @@ static std::vector DecodeTxDoc(const std::string& txid_field_doc) {RPCResult::Type::NUM, "vout", /*optional=*/true, "The output number (if not coinbase transaction)"}, {RPCResult::Type::OBJ, "scriptSig", /*optional=*/true, "The script (if not coinbase transaction)", { - {RPCResult::Type::STR, "asm", "asm"}, - {RPCResult::Type::STR_HEX, "hex", "hex"}, + {RPCResult::Type::STR, "asm", "Disassembly of the signature script"}, + {RPCResult::Type::STR_HEX, "hex", "The raw signature script bytes, hex-encoded"}, }}, {RPCResult::Type::NUM, "sequence", "The script sequence number"}, }}, @@ -160,9 +162,9 @@ static std::vector DecodeTxDoc(const std::string& txid_field_doc) {RPCResult::Type::NUM, "n", "index"}, {RPCResult::Type::OBJ, "scriptPubKey", "", { - {RPCResult::Type::STR, "asm", "the asm"}, + {RPCResult::Type::STR, "asm", "Disassembly of the public key script"}, {RPCResult::Type::STR, "desc", "Inferred descriptor for the output"}, - {RPCResult::Type::STR_HEX, "hex", "the hex"}, + {RPCResult::Type::STR_HEX, "hex", "The raw public key script bytes, hex-encoded"}, {RPCResult::Type::STR, "type", "The type, eg 'pubkeyhash'"}, {RPCResult::Type::STR, "address", /*optional=*/true, "The Dash address (only if a well-defined address exists)"}, }}, @@ -170,6 +172,15 @@ static std::vector DecodeTxDoc(const std::string& txid_field_doc) }}, {RPCResult::Type::NUM, "extraPayloadSize", /*optional=*/true, "Size of DIP2 extra payload. Only present if it's a special TX"}, {RPCResult::Type::STR_HEX, "extraPayload", /*optional=*/true, "Hex-encoded DIP2 extra payload data. Only present if it's a special TX"}, + CProRegTx::GetJsonHelp(/*key=*/"proRegTx", /*optional=*/true), + CProUpServTx::GetJsonHelp(/*key=*/"proUpServTx", /*optional=*/true), + CProUpRegTx::GetJsonHelp(/*key=*/"proUpRegTx", /*optional=*/true), + CProUpRevTx::GetJsonHelp(/*key=*/"proUpRevTx", /*optional=*/true), + CCbTx::GetJsonHelp(/*key=*/"cbTx", /*optional=*/true), + llmq::CFinalCommitmentTxPayload::GetJsonHelp(/*key=*/"qcTx", /*optional=*/true), + MNHFTxPayload::GetJsonHelp(/*key=*/"mnhfTx", /*optional=*/true), + CAssetLockPayload::GetJsonHelp(/*key=*/"assetLockTx", /*optional=*/true), + CAssetUnlockPayload::GetJsonHelp(/*key=*/"assetUnlockTx", /*optional=*/true), }; } @@ -347,8 +358,19 @@ static RPCHelpMan getrawtransactionmulti() { {"verbose", RPCArg::Type::BOOL, RPCArg::Default{false}, "If false, return a string, otherwise return a json object"}, }, - // TODO: replace RPCResults to proper annotation - RPCResults{}, + RPCResult{ + RPCResult::Type::OBJ, "", "", + { + {"If verbose is not set or set to false", + RPCResult::Type::STR_HEX, "txid", "The serialized, hex-encoded data for 'txid'"}, + {"if verbose is set to true", + RPCResult::Type::OBJ, "txid", "The decoded network-serialized transaction.", + { + {RPCResult::Type::ELISION, "", "The layout is the same as the output of getrawtransaction."}, + }}, + {"If tx is unknown", RPCResult::Type::STR, "txid", "None"}, + }, + }, RPCExamples{ HelpExampleCli("getrawtransactionmulti", R"('{"blockhash1":["txid1","txid2"], "0":["txid3"]}')") @@ -645,8 +667,9 @@ static RPCHelpMan getassetunlockstatuses() } else { const auto pBlockIndexBestCL = [&]() -> const CBlockIndex* { - if (!llmq_ctx.clhandler->GetBestChainLock().IsNull()) { - return pTipBlockIndex->GetAncestor(llmq_ctx.clhandler->GetBestChainLock().getHeight()); + const auto best_clsig = llmq_ctx.clhandler->GetBestChainLock(); + if (!best_clsig.IsNull()) { + return pTipBlockIndex->GetAncestor(best_clsig.getHeight()); } // If no CL info is available, try to use CbTx CL information if (const auto cbtx_best_cl = GetNonNullCoinbaseChainlock(pTipBlockIndex)) { @@ -899,7 +922,7 @@ static RPCHelpMan combinerawtransaction() sigdata.MergeSignatureData(DataFromTransaction(txv, i, coin.out)); } } - ProduceSignature(DUMMY_SIGNING_PROVIDER, MutableTransactionSignatureCreator(&mergedTx, i, coin.out.nValue, 1), coin.out.scriptPubKey, sigdata); + ProduceSignature(DUMMY_SIGNING_PROVIDER, MutableTransactionSignatureCreator(mergedTx, i, coin.out.nValue, 1), coin.out.scriptPubKey, sigdata); UpdateInput(txin, sigdata); } @@ -1006,211 +1029,111 @@ static RPCHelpMan signrawtransactionwithkey() }; } -RPCHelpMan sendrawtransaction() -{ - return RPCHelpMan{"sendrawtransaction", "\nSubmit a raw transaction (serialized, hex-encoded) to local node and network.\n" - "\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" - "\nRelated RPCs: createrawtransaction, signrawtransactionwithkey\n", +const RPCResult decodepsbt_inputs{ + RPCResult::Type::ARR, "inputs", "", + { + {RPCResult::Type::OBJ, "", "", + { + {RPCResult::Type::OBJ, "non_witness_utxo", /*optional=*/true, "Decoded network transaction for non-witness UTXOs", + { + {RPCResult::Type::ELISION, "",""}, + }}, + {RPCResult::Type::OBJ_DYN, "partial_signatures", /*optional=*/true, "", + { + {RPCResult::Type::STR, "pubkey", "The public key and signature that corresponds to it."}, + }}, + {RPCResult::Type::STR, "sighash", /*optional=*/true, "The sighash type to be used"}, + {RPCResult::Type::OBJ, "redeem_script", /*optional=*/true, "", + { + {RPCResult::Type::STR, "asm", "Disassembly of the redeem script"}, + {RPCResult::Type::STR_HEX, "hex", "The raw redeem script bytes, hex-encoded"}, + {RPCResult::Type::STR, "type", "The type, eg 'pubkeyhash'"}, + }}, + {RPCResult::Type::ARR, "bip32_derivs", /*optional=*/true, "", + { + {RPCResult::Type::OBJ, "", "", { - {"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hex string of the raw transaction"}, - {"maxfeerate", RPCArg::Type::AMOUNT, RPCArg::Default{FormatMoney(DEFAULT_MAX_RAW_TX_FEE_RATE.GetFeePerK())}, - "Reject transactions whose fee rate is higher than the specified value, expressed in " + CURRENCY_UNIT + - "/kB.\nSet to 0 to accept any fee rate.\n"}, - {"instantsend", RPCArg::Type::BOOL, RPCArg::Optional::OMITTED, "Deprecated and ignored"}, - {"bypasslimits", RPCArg::Type::BOOL, RPCArg::Default{false}, "Bypass transaction policy limits"}, - }, - RPCResult{ - RPCResult::Type::STR_HEX, "", "The transaction hash in hex" - }, - RPCExamples{ - "\nCreate a transaction\n" - + HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\" : \\\"mytxid\\\",\\\"vout\\\":0}]\" \"{\\\"myaddress\\\":0.01}\"") + - "Sign the transaction, and get back the hex\n" - + HelpExampleCli("signrawtransactionwithwallet", "\"myhex\"") + - "\nSend the transaction (signed hex)\n" - + HelpExampleCli("sendrawtransaction", "\"signedhex\"") + - "\nAs a JSON-RPC call\n" - + HelpExampleRpc("sendrawtransaction", "\"signedhex\"") - }, - [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue -{ - RPCTypeCheck(request.params, { - UniValue::VSTR, - UniValueType(), // VNUM or VSTR, checked inside AmountFromValue() - UniValue::VBOOL - }); - - CMutableTransaction mtx; - if (!DecodeHexTx(mtx, request.params[0].get_str())) { - throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed. Make sure the tx has at least one input."); - } - CTransactionRef tx(MakeTransactionRef(std::move(mtx))); - - const CFeeRate max_raw_tx_fee_rate = request.params[1].isNull() ? - DEFAULT_MAX_RAW_TX_FEE_RATE : - CFeeRate(AmountFromValue(request.params[1])); - - int64_t virtual_size = GetVirtualTransactionSize(*tx); - CAmount max_raw_tx_fee = max_raw_tx_fee_rate.GetFee(virtual_size); - - bool bypass_limits = false; - if (!request.params[3].isNull()) bypass_limits = request.params[3].get_bool(); - bilingual_str err_string; - AssertLockNotHeld(cs_main); - NodeContext& node = EnsureAnyNodeContext(request.context); - const TransactionError err = BroadcastTransaction(node, tx, err_string, max_raw_tx_fee, /*relay=*/true, /*wait_callback=*/true, bypass_limits); - if (TransactionError::OK != err) { - throw JSONRPCTransactionError(err, err_string.original); - } - - return tx->GetHash().GetHex(); -}, - }; -} - -static RPCHelpMan testmempoolaccept() -{ - return RPCHelpMan{"testmempoolaccept", - "\nReturns result of mempool acceptance tests indicating if raw transaction (serialized, hex-encoded) would be accepted by mempool.\n" - "\nIf multiple transactions are passed in, parents must come before children and package policies apply: the transactions cannot conflict with any mempool transactions or each other.\n" - "\nIf one transaction fails, other transactions may not be fully validated (the 'allowed' key will be blank).\n" - "\nThe maximum number of transactions allowed is " + ToString(MAX_PACKAGE_COUNT) + ".\n" - "\nThis checks if transactions violate the consensus or policy rules.\n" - "\nSee sendrawtransaction call.\n", + {RPCResult::Type::STR, "pubkey", "The public key with the derivation path as the value."}, + {RPCResult::Type::STR, "master_fingerprint", "The fingerprint of the master key"}, + {RPCResult::Type::STR, "path", "The path"}, + }}, + }}, + {RPCResult::Type::OBJ, "final_scriptSig", /*optional=*/true, "", + { + {RPCResult::Type::STR, "asm", "Disassembly of the final signature script"}, + {RPCResult::Type::STR_HEX, "hex", "The raw final signature script bytes, hex-encoded"}, + }}, + {RPCResult::Type::OBJ_DYN, "ripemd160_preimages", /*optional=*/true, "", + { + {RPCResult::Type::STR, "hash", "The hash and preimage that corresponds to it."}, + }}, + {RPCResult::Type::OBJ_DYN, "sha256_preimages", /*optional=*/true, "", + { + {RPCResult::Type::STR, "hash", "The hash and preimage that corresponds to it."}, + }}, + {RPCResult::Type::OBJ_DYN, "hash160_preimages", /*optional=*/true, "", + { + {RPCResult::Type::STR, "hash", "The hash and preimage that corresponds to it."}, + }}, + {RPCResult::Type::OBJ_DYN, "hash256_preimages", /*optional=*/true, "", + { + {RPCResult::Type::STR, "hash", "The hash and preimage that corresponds to it."}, + }}, + {RPCResult::Type::OBJ_DYN, "unknown", /*optional=*/true, "The unknown input fields", + { + {RPCResult::Type::STR_HEX, "key", "(key-value pair) An unknown key-value pair"}, + }}, + {RPCResult::Type::ARR, "proprietary", /*optional=*/true, "The input proprietary map", + { + {RPCResult::Type::OBJ, "", "", { - {"rawtxs", RPCArg::Type::ARR, RPCArg::Optional::NO, "An array of hex strings of raw transactions.", - { - {"rawtx", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, ""}, - }, - }, - {"maxfeerate", RPCArg::Type::AMOUNT, RPCArg::Default{FormatMoney(DEFAULT_MAX_RAW_TX_FEE_RATE.GetFeePerK())}, - "Reject transactions whose fee rate is higher than the specified value, expressed in " + CURRENCY_UNIT + "/kB\n"}, - }, - RPCResult{ - RPCResult::Type::ARR, "", "The result of the mempool acceptance test for each raw transaction in the input array.\n" - "Returns results for each transaction in the same order they were passed in.\n" - "Transactions that cannot be fully validated due to failures in other transactions will not contain an 'allowed' result.\n", - { - {RPCResult::Type::OBJ, "", "", - { - {RPCResult::Type::STR_HEX, "txid", "The transaction hash in hex"}, - {RPCResult::Type::STR, "package-error", /*optional=*/true, "Package validation error, if any (only possible if rawtxs had more than 1 transaction)."}, - {RPCResult::Type::BOOL, "allowed", /*optional=*/true, "Whether this tx would be accepted to the mempool and pass client-specified maxfeerate. " - "If not present, the tx was not fully validated due to a failure in another tx in the list."}, - {RPCResult::Type::NUM, "vsize", /*optional=*/true, "Transaction size."}, - {RPCResult::Type::OBJ, "fees", /*optional=*/true, "Transaction fees (only present if 'allowed' is true)", - { - {RPCResult::Type::STR_AMOUNT, "base", "transaction fee in " + CURRENCY_UNIT}, - }}, - {RPCResult::Type::STR, "reject-reason", /*optional=*/true, "Rejection string (only present when 'allowed' is false)"}, - }}, - } - }, - RPCExamples{ - "\nCreate a transaction\n" - + HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\" : \\\"mytxid\\\",\\\"vout\\\":0}]\" \"{\\\"myaddress\\\":0.01}\"") + - "Sign the transaction, and get back the hex\n" - + HelpExampleCli("signrawtransactionwithwallet", "\"myhex\"") + - "\nTest acceptance of the transaction (signed hex)\n" - + HelpExampleCli("testmempoolaccept", R"('["signedhex"]')") + - "\nAs a JSON-RPC call\n" - + HelpExampleRpc("testmempoolaccept", "[\"signedhex\"]") - }, - [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue -{ - RPCTypeCheck(request.params, { - UniValue::VARR, - UniValueType(), // VNUM or VSTR, checked inside AmountFromValue() - }); - const UniValue raw_transactions = request.params[0].get_array(); - if (raw_transactions.size() < 1 || raw_transactions.size() > MAX_PACKAGE_COUNT) { - throw JSONRPCError(RPC_INVALID_PARAMETER, - "Array must contain between 1 and " + ToString(MAX_PACKAGE_COUNT) + " transactions."); - } - - const CFeeRate max_raw_tx_fee_rate = request.params[1].isNull() ? - DEFAULT_MAX_RAW_TX_FEE_RATE : - CFeeRate(AmountFromValue(request.params[1])); - - std::vector txns; - txns.reserve(raw_transactions.size()); - for (const auto& rawtx : raw_transactions.getValues()) { - CMutableTransaction mtx; - if (!DecodeHexTx(mtx, rawtx.get_str())) { - throw JSONRPCError(RPC_DESERIALIZATION_ERROR, - "TX decode failed: " + rawtx.get_str() + " Make sure the tx has at least one input."); - } - txns.emplace_back(MakeTransactionRef(std::move(mtx))); + {RPCResult::Type::STR_HEX, "identifier", "The hex string for the proprietary identifier"}, + {RPCResult::Type::NUM, "subtype", "The number for the subtype"}, + {RPCResult::Type::STR_HEX, "key", "The hex for the key"}, + {RPCResult::Type::STR_HEX, "value", "The hex for the value"}, + }}, + }}, + }}, } +}; - NodeContext& node = EnsureAnyNodeContext(request.context); - CTxMemPool& mempool = EnsureMemPool(node); - ChainstateManager& chainman = EnsureChainman(node); - CChainState& chainstate = chainman.ActiveChainstate(); - const PackageMempoolAcceptResult package_result = [&] { - LOCK(::cs_main); - if (txns.size() > 1) return ProcessNewPackage(chainstate, mempool, txns, /*test_accept=*/true); - return PackageMempoolAcceptResult(txns[0]->GetHash(), - chainman.ProcessTransaction(txns[0], /*test_accept=*/true)); - }(); - - UniValue rpc_result(UniValue::VARR); - // We will check transaction fees while we iterate through txns in order. If any transaction fee - // exceeds maxfeerate, we will leave the rest of the validation results blank, because it - // doesn't make sense to return a validation result for a transaction if its ancestor(s) would - // not be submitted. - bool exit_early{false}; - for (const auto& tx : txns) { - UniValue result_inner(UniValue::VOBJ); - result_inner.pushKV("txid", tx->GetHash().GetHex()); - if (package_result.m_state.GetResult() == PackageValidationResult::PCKG_POLICY) { - result_inner.pushKV("package-error", package_result.m_state.GetRejectReason()); - } - auto it = package_result.m_tx_results.find(tx->GetHash()); - if (exit_early || it == package_result.m_tx_results.end()) { - // Validation unfinished. Just return the txid. - rpc_result.push_back(result_inner); - continue; - } - const auto& tx_result = it->second; - // Package testmempoolaccept doesn't allow transactions to already be in the mempool. - CHECK_NONFATAL(tx_result.m_result_type != MempoolAcceptResult::ResultType::MEMPOOL_ENTRY); - if (tx_result.m_result_type == MempoolAcceptResult::ResultType::VALID) { - const CAmount fee = tx_result.m_base_fees.value(); - // Check that fee does not exceed maximum fee - const int64_t virtual_size = tx_result.m_vsize.value(); - const CAmount max_raw_tx_fee = max_raw_tx_fee_rate.GetFee(virtual_size); - if (max_raw_tx_fee && fee > max_raw_tx_fee) { - result_inner.pushKV("allowed", false); - result_inner.pushKV("reject-reason", "max-fee-exceeded"); - exit_early = true; - } else { - // Only return the fee and vsize if the transaction would pass ATMP. - // These can be used to calculate the feerate. - result_inner.pushKV("allowed", true); - result_inner.pushKV("vsize", virtual_size); - UniValue fees(UniValue::VOBJ); - fees.pushKV("base", ValueFromAmount(fee)); - result_inner.pushKV("fees", fees); - } - } else { - result_inner.pushKV("allowed", false); - const TxValidationState state = tx_result.m_state; - if (state.GetResult() == TxValidationResult::TX_MISSING_INPUTS) { - result_inner.pushKV("reject-reason", "missing-inputs"); - } else { - result_inner.pushKV("reject-reason", state.GetRejectReason()); - } - } - rpc_result.push_back(result_inner); +const RPCResult decodepsbt_outputs{ + RPCResult::Type::ARR, "outputs", "", + { + {RPCResult::Type::OBJ, "", "", + { + {RPCResult::Type::OBJ, "redeem_script", /*optional=*/true, "", + { + {RPCResult::Type::STR, "asm", "Disassembly of the redeem script"}, + {RPCResult::Type::STR_HEX, "hex", "The raw redeem script bytes, hex-encoded"}, + {RPCResult::Type::STR, "type", "The type, eg 'pubkeyhash'"}, + }}, + {RPCResult::Type::ARR, "bip32_derivs", /*optional=*/true, "", + { + {RPCResult::Type::OBJ, "", "", + { + {RPCResult::Type::STR, "pubkey", "The public key this path corresponds to"}, + {RPCResult::Type::STR, "master_fingerprint", "The fingerprint of the master key"}, + {RPCResult::Type::STR, "path", "The path"}, + }}, + }}, + {RPCResult::Type::OBJ_DYN, "unknown", /*optional=*/true, "The unknown global fields", + { + {RPCResult::Type::STR_HEX, "key", "(key-value pair) An unknown key-value pair"}, + }}, + {RPCResult::Type::ARR, "proprietary", /*optional=*/true, "The output proprietary map", + { + {RPCResult::Type::OBJ, "", "", + { + {RPCResult::Type::STR_HEX, "identifier", "The hex string for the proprietary identifier"}, + {RPCResult::Type::NUM, "subtype", "The number for the subtype"}, + {RPCResult::Type::STR_HEX, "key", "The hex for the key"}, + {RPCResult::Type::STR_HEX, "value", "The hex for the value"}, + }}, + }}, + }}, } - return rpc_result; -}, - }; -} +}; static RPCHelpMan decodepsbt() { @@ -1251,106 +1174,8 @@ static RPCHelpMan decodepsbt() { {RPCResult::Type::STR_HEX, "key", "(key-value pair) An unknown key-value pair"}, }}, - {RPCResult::Type::ARR, "inputs", "", - { - {RPCResult::Type::OBJ, "", "", - { - {RPCResult::Type::OBJ, "non_witness_utxo", /*optional=*/true, "Decoded network transaction for non-witness UTXOs", - { - {RPCResult::Type::ELISION, "",""}, - }}, - {RPCResult::Type::OBJ_DYN, "partial_signatures", /*optional=*/true, "", - { - {RPCResult::Type::STR, "pubkey", "The public key and signature that corresponds to it."}, - }}, - {RPCResult::Type::STR, "sighash", /*optional=*/true, "The sighash type to be used"}, - {RPCResult::Type::OBJ, "redeem_script", /*optional=*/true, "", - { - {RPCResult::Type::STR, "asm", "The asm"}, - {RPCResult::Type::STR_HEX, "hex", "The hex"}, - {RPCResult::Type::STR, "type", "The type, eg 'pubkeyhash'"}, - }}, - {RPCResult::Type::ARR, "bip32_derivs", /*optional=*/true, "", - { - {RPCResult::Type::OBJ, "", "", - { - {RPCResult::Type::STR, "pubkey", "The public key with the derivation path as the value."}, - {RPCResult::Type::STR, "master_fingerprint", "The fingerprint of the master key"}, - {RPCResult::Type::STR, "path", "The path"}, - }}, - }}, - {RPCResult::Type::OBJ, "final_scriptSig", /*optional=*/true, "", - { - {RPCResult::Type::STR, "asm", "The asm"}, - {RPCResult::Type::STR, "hex", "The hex"}, - }}, - {RPCResult::Type::OBJ_DYN, "ripemd160_preimages", /*optional=*/ true, "", - { - {RPCResult::Type::STR, "hash", "The hash and preimage that corresponds to it."}, - }}, - {RPCResult::Type::OBJ_DYN, "sha256_preimages", /*optional=*/ true, "", - { - {RPCResult::Type::STR, "hash", "The hash and preimage that corresponds to it."}, - }}, - {RPCResult::Type::OBJ_DYN, "hash160_preimages", /*optional=*/ true, "", - { - {RPCResult::Type::STR, "hash", "The hash and preimage that corresponds to it."}, - }}, - {RPCResult::Type::OBJ_DYN, "hash256_preimages", /*optional=*/ true, "", - { - {RPCResult::Type::STR, "hash", "The hash and preimage that corresponds to it."}, - }}, - {RPCResult::Type::OBJ_DYN, "unknown", /*optional=*/ true, "The unknown input fields", - { - {RPCResult::Type::STR_HEX, "key", "(key-value pair) An unknown key-value pair"}, - }}, - {RPCResult::Type::ARR, "proprietary", /*optional=*/ true, "The input proprietary map", - { - {RPCResult::Type::OBJ, "", "", - { - {RPCResult::Type::STR_HEX, "identifier", "The hex string for the proprietary identifier"}, - {RPCResult::Type::NUM, "subtype", "The number for the subtype"}, - {RPCResult::Type::STR_HEX, "key", "The hex for the key"}, - {RPCResult::Type::STR_HEX, "value", "The hex for the value"}, - }}, - }}, - }}, - }}, - {RPCResult::Type::ARR, "outputs", "", - { - {RPCResult::Type::OBJ, "", "", - { - {RPCResult::Type::OBJ, "redeem_script", /*optional=*/true, "", - { - {RPCResult::Type::STR, "asm", "The asm"}, - {RPCResult::Type::STR_HEX, "hex", "The hex"}, - {RPCResult::Type::STR, "type", "The type, eg 'pubkeyhash'"}, - }}, - {RPCResult::Type::ARR, "bip32_derivs", /*optional=*/true, "", - { - {RPCResult::Type::OBJ, "", "", - { - {RPCResult::Type::STR, "pubkey", "The public key this path corresponds to"}, - {RPCResult::Type::STR, "master_fingerprint", "The fingerprint of the master key"}, - {RPCResult::Type::STR, "path", "The path"}, - }}, - }}, - {RPCResult::Type::OBJ_DYN, "unknown", /*optional=*/true, "The unknown global fields", - { - {RPCResult::Type::STR_HEX, "key", "(key-value pair) An unknown key-value pair"}, - }}, - {RPCResult::Type::ARR, "proprietary", /*optional=*/true, "The output proprietary map", - { - {RPCResult::Type::OBJ, "", "", - { - {RPCResult::Type::STR_HEX, "identifier", "The hex string for the proprietary identifier"}, - {RPCResult::Type::NUM, "subtype", "The number for the subtype"}, - {RPCResult::Type::STR_HEX, "key", "The hex for the key"}, - {RPCResult::Type::STR_HEX, "value", "The hex for the value"}, - }}, - }}, - }}, - }}, + decodepsbt_inputs, + decodepsbt_outputs, {RPCResult::Type::STR_AMOUNT, "fee", /*optional=*/true, "The transaction fee paid if all UTXOs slots in the PSBT have been filled."}, } }, @@ -2104,34 +1929,28 @@ static RPCHelpMan analyzepsbt() }; } -void RegisterRawTransactionRPCCommands(CRPCTable &t) +void RegisterRawTransactionRPCCommands(CRPCTable& t) { -// clang-format off -static const CRPCCommand commands[] = -{ // category actor (function) - // --------------------- ----------------------- - { "rawtransactions", &getassetunlockstatuses, }, - { "rawtransactions", &getrawtransaction, }, - { "rawtransactions", &getrawtransactionmulti, }, - { "rawtransactions", &getislocks, }, - { "rawtransactions", &gettxchainlocks, }, - { "rawtransactions", &createrawtransaction, }, - { "rawtransactions", &decoderawtransaction, }, - { "rawtransactions", &decodescript, }, - { "rawtransactions", &sendrawtransaction, }, - { "rawtransactions", &combinerawtransaction, }, - { "rawtransactions", &signrawtransactionwithkey, }, - { "rawtransactions", &testmempoolaccept, }, - { "rawtransactions", &decodepsbt, }, - { "rawtransactions", &combinepsbt, }, - { "rawtransactions", &finalizepsbt, }, - { "rawtransactions", &createpsbt, }, - { "rawtransactions", &converttopsbt, }, - { "rawtransactions", &utxoupdatepsbt, }, - { "rawtransactions", &joinpsbts, }, - { "rawtransactions", &analyzepsbt, }, -}; -// clang-format on + static const CRPCCommand commands[]{ + {"rawtransactions", &getassetunlockstatuses}, + {"rawtransactions", &getrawtransaction}, + {"rawtransactions", &getrawtransactionmulti}, + {"rawtransactions", &getislocks}, + {"rawtransactions", &gettxchainlocks}, + {"rawtransactions", &createrawtransaction}, + {"rawtransactions", &decoderawtransaction}, + {"rawtransactions", &decodescript}, + {"rawtransactions", &combinerawtransaction}, + {"rawtransactions", &signrawtransactionwithkey}, + {"rawtransactions", &decodepsbt}, + {"rawtransactions", &combinepsbt}, + {"rawtransactions", &finalizepsbt}, + {"rawtransactions", &createpsbt}, + {"rawtransactions", &converttopsbt}, + {"rawtransactions", &utxoupdatepsbt}, + {"rawtransactions", &joinpsbts}, + {"rawtransactions", &analyzepsbt}, + }; for (const auto& c : commands) { t.appendCommand(c.name, &c); } diff --git a/src/rpc/rawtransaction_util.cpp b/src/rpc/rawtransaction_util.cpp index e66a5b2d3aa9..8ab727004650 100644 --- a/src/rpc/rawtransaction_util.cpp +++ b/src/rpc/rawtransaction_util.cpp @@ -146,14 +146,14 @@ static void TxInErrorToJSON(const CTxIn& txin, UniValue& vErrorsRet, const std:: void ParsePrevouts(const UniValue& prevTxsUnival, FillableSigningProvider* keystore, std::map& coins) { if (!prevTxsUnival.isNull()) { - UniValue prevTxs = prevTxsUnival.get_array(); + const UniValue& prevTxs = prevTxsUnival.get_array(); for (unsigned int idx = 0; idx < prevTxs.size(); ++idx) { const UniValue& p = prevTxs[idx]; if (!p.isObject()) { throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "expected object with {\"txid'\",\"vout\",\"scriptPubKey\"}"); } - UniValue prevOut = p.get_obj(); + const UniValue& prevOut = p.get_obj(); RPCTypeCheckObj(prevOut, { diff --git a/src/rpc/register.h b/src/rpc/register.h index f6bbd57a7c60..04aede8e16b2 100644 --- a/src/rpc/register.h +++ b/src/rpc/register.h @@ -22,6 +22,8 @@ void RegisterNetRPCCommands(CRPCTable&); void RegisterOutputScriptRPCCommands(CRPCTable&); void RegisterRawTransactionRPCCommands(CRPCTable &tableRPC); void RegisterSignMessageRPCCommands(CRPCTable&); +/** Register raw transaction RPC commands */ +void RegisterSignerRPCCommands(CRPCTable &tableRPC); void RegisterTxoutProofRPCCommands(CRPCTable&); void RegisterMasternodeRPCCommands(CRPCTable &tableRPC); void RegisterCoinJoinRPCCommands(CRPCTable &tableRPC); @@ -48,6 +50,9 @@ static inline void RegisterAllCoreRPCCommands(CRPCTable &t) RegisterOutputScriptRPCCommands(t); RegisterRawTransactionRPCCommands(t); RegisterSignMessageRPCCommands(t); +#ifdef ENABLE_EXTERNAL_SIGNER + RegisterSignerRPCCommands(t); +#endif // ENABLE_EXTERNAL_SIGNER RegisterTxoutProofRPCCommands(t); RegisterMasternodeRPCCommands(t); RegisterCoinJoinRPCCommands(t); diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index 80e07ad9b1d5..c4b49e2a4a1c 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -23,14 +23,14 @@ #include #include -static Mutex g_rpc_warmup_mutex; +static GlobalMutex g_rpc_warmup_mutex; static std::atomic g_rpc_running{false}; static bool fRPCInWarmup GUARDED_BY(g_rpc_warmup_mutex) = true; static std::string rpcWarmupStatus GUARDED_BY(g_rpc_warmup_mutex) = "RPC server started"; /* Timer-creating functions */ static RPCTimerInterface* timerInterface = nullptr; /* Map of name to timer. */ -static Mutex g_deadline_timers_mutex; +static GlobalMutex g_deadline_timers_mutex; static std::map > deadlineTimers GUARDED_BY(g_deadline_timers_mutex); static bool ExecuteCommand(const CRPCCommand& command, const JSONRPCRequest& request, UniValue& result, bool last_handler); @@ -266,17 +266,14 @@ static RPCHelpMan getrpcinfo() } }; } -// clang-format off -static const CRPCCommand vRPCCommands[] = -{ // category actor (function) - // --------------------- ----------------------- + +static const CRPCCommand vRPCCommands[]{ /* Overall control/query calls */ - { "control", &getrpcinfo, }, - { "control", &help, }, - { "control", &stop, }, - { "control", &uptime, }, + {"control", &getrpcinfo}, + {"control", &help}, + {"control", &stop}, + {"control", &uptime}, }; -// clang-format on CRPCTable::CRPCTable() { diff --git a/src/rpc/txoutproof.cpp b/src/rpc/txoutproof.cpp index 45de1e39d2c0..168a47cb1a87 100644 --- a/src/rpc/txoutproof.cpp +++ b/src/rpc/txoutproof.cpp @@ -177,8 +177,6 @@ static RPCHelpMan verifytxoutproof() void RegisterTxoutProofRPCCommands(CRPCTable& t) { static const CRPCCommand commands[]{ - // category actor (function) - // -------- ---------------- {"blockchain", &gettxoutproof}, {"blockchain", &verifytxoutproof}, }; diff --git a/src/rpc/util.cpp b/src/rpc/util.cpp index 482caccec770..3f3b852422f1 100644 --- a/src/rpc/util.cpp +++ b/src/rpc/util.cpp @@ -12,9 +12,9 @@ #include