diff options
276 files changed, 19021 insertions, 3535 deletions
diff --git a/.appveyor.yml b/.appveyor.yml index 249d0b8df9..ac39fe235b 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -7,18 +7,19 @@ clone_depth: 5 environment: APPVEYOR_SAVE_CACHE_ON_ERROR: true CLCACHE_SERVER: 1 - PACKAGES: boost-filesystem boost-signals2 boost-test libevent openssl zeromq berkeleydb secp256k1 leveldb + PACKAGES: berkeleydb boost-filesystem boost-signals2 boost-test libevent openssl rapidcheck zeromq PATH: 'C:\Python37-x64;C:\Python37-x64\Scripts;%PATH%' PYTHONUTF8: 1 cache: -- C:\tools\vcpkg\installed -- C:\Users\appveyor\clcache +- C:\tools\vcpkg\installed -> .appveyor.yml +- C:\Users\appveyor\clcache -> .appveyor.yml, build_msvc\**, **\Makefile.am, **\*.vcxproj.in install: - cmd: pip install --quiet git+https://github.com/frerich/clcache.git@v4.2.0 # Disable zmq test for now since python zmq library on Windows would cause Access violation sometimes. # - cmd: pip install zmq +- cmd: echo set(VCPKG_BUILD_TYPE release) >> C:\tools\vcpkg\triplets\%PLATFORM%-windows-static.cmake +- cmd: vcpkg remove --outdated --recurse - cmd: vcpkg install --triplet %PLATFORM%-windows-static %PACKAGES% > NUL -- cmd: del /s /q C:\Tools\vcpkg\installed\%PLATFORM%-windows-static\debug # Remove unused debug library before_build: - ps: clcache -M 536870912 - cmd: python build_msvc\msvc-autogen.py @@ -27,7 +28,6 @@ before_build: ${content} = (Get-Content ${files}[${i}]); ${content} = ${content}.Replace("</RuntimeLibrary>", "</RuntimeLibrary><DebugInformationFormat>None</DebugInformationFormat>"); ${content} = ${content}.Replace("<WholeProgramOptimization>true", "<WholeProgramOptimization>false"); - ${content} = ${content}.Replace("NDEBUG;", ""); Set-Content ${files}[${i}] ${content}; } - ps: Start-Process clcache-server @@ -54,5 +54,5 @@ test_script: - cmd: src\bench_bitcoin.exe -evals=1 -scaling=0 > NUL - ps: python test\util\bitcoin-util-test.py - cmd: python test\util\rpcauth-test.py -- cmd: python test\functional\test_runner.py --ci --force --quiet --combinedlogslen=4000 --failfast +- cmd: python test\functional\test_runner.py --ci --quiet --combinedlogslen=4000 --failfast deploy: off diff --git a/.travis.yml b/.travis.yml index 8bfe39ed8f..0ede31b4a6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,6 +15,7 @@ env: - MAKEJOBS=-j3 - RUN_UNIT_TESTS=true - RUN_FUNCTIONAL_TESTS=true + - RUN_FUZZ_TESTS=false - DOCKER_NAME_TAG=ubuntu:18.04 - BOOST_TEST_RANDOM=1$TRAVIS_BUILD_ID - CCACHE_SIZE=100M @@ -32,7 +33,8 @@ install: before_script: - set -o errexit; source .travis/test_05_before_script.sh script: - - if [ $SECONDS -gt 1200 ]; then set +o errexit; echo "Travis early exit to cache current state"; false; else set -o errexit; source .travis/test_06_script.sh; fi + - if [ $SECONDS -gt 1200 ]; then set +o errexit; echo "Travis early exit to cache current state"; false; else set -o errexit; source .travis/test_06_script_a.sh; fi + - if [ $SECONDS -gt 1800 ]; then set +o errexit; echo "Travis early exit to cache current state"; false; else set -o errexit; source .travis/test_06_script_b.sh; fi after_script: - echo $TRAVIS_COMMIT_RANGE - echo $TRAVIS_COMMIT_LOG @@ -65,29 +67,31 @@ jobs: BITCOIN_CONFIG="--enable-glibc-back-compat --enable-reduce-exports CXXFLAGS=-Wno-psabi" - stage: test - name: 'Win32 [GOAL: deploy] [no gui tests]' + name: 'Win32 [GOAL: deploy] [no gui or functional tests]' env: >- HOST=i686-w64-mingw32 DPKG_ADD_ARCH="i386" PACKAGES="python3 nsis g++-mingw-w64-i686 wine-binfmt wine32" + RUN_FUNCTIONAL_TESTS=false GOAL="deploy" BITCOIN_CONFIG="--enable-reduce-exports --disable-gui-tests" - stage: test - name: 'Win64 [GOAL: deploy] [no gui tests]' + name: 'Win64 [GOAL: deploy] [no gui or functional tests]' env: >- HOST=x86_64-w64-mingw32 PACKAGES="python3 nsis g++-mingw-w64-x86-64 wine-binfmt wine64" + RUN_FUNCTIONAL_TESTS=false GOAL="deploy" BITCOIN_CONFIG="--enable-reduce-exports --disable-gui-tests" - stage: test - name: '32-bit + dash [GOAL: install]' + name: '32-bit + dash [GOAL: install] [GUI: no BIP70]' env: >- HOST=i686-pc-linux-gnu PACKAGES="g++-multilib python3-zmq" GOAL="install" - BITCOIN_CONFIG="--enable-zmq --enable-glibc-back-compat --enable-reduce-exports LDFLAGS=-static-libstdc++" + BITCOIN_CONFIG="--enable-zmq --with-gui=qt5 --disable-bip70 --enable-glibc-back-compat --enable-reduce-exports LDFLAGS=-static-libstdc++" CONFIG_SHELL="/bin/dash" - stage: test @@ -97,14 +101,15 @@ jobs: PACKAGES="python3-zmq qtbase5-dev qttools5-dev-tools protobuf-compiler libdbus-1-dev libharfbuzz-dev libprotobuf-dev" DEP_OPTS="NO_QT=1 NO_UPNP=1 DEBUG=1 ALLOW_HOST_PACKAGES=1" GOAL="install" - BITCOIN_CONFIG="--enable-zmq --with-gui=qt5 --enable-fuzz --enable-glibc-back-compat --enable-reduce-exports --enable-debug CXXFLAGS=\"-g0 -O2\"" + BITCOIN_CONFIG="--enable-zmq --with-gui=qt5 --enable-glibc-back-compat --enable-reduce-exports --enable-debug CXXFLAGS=\"-g0 -O2\"" - stage: test - name: 'x86_64 Linux [GOAL: install] [trusty] [depends for now]' + name: 'x86_64 Linux [GOAL: install] [trusty] [no functional tests, no depends, only system libs]' env: >- HOST=x86_64-unknown-linux-gnu DOCKER_NAME_TAG=ubuntu:14.04 PACKAGES="python3-zmq qtbase5-dev qttools5-dev-tools libicu-dev libpng-dev libssl-dev libevent-dev bsdmainutils libboost-system-dev libboost-filesystem-dev libboost-chrono-dev libboost-test-dev libboost-thread-dev libdb5.1++-dev libminiupnpc-dev libzmq3-dev libprotobuf-dev protobuf-compiler libqrencode-dev" + NO_DEPENDS=1 RUN_FUNCTIONAL_TESTS=false GOAL="install" BITCOIN_CONFIG="--enable-zmq --with-incompatible-bdb --with-gui=no" @@ -125,11 +130,22 @@ jobs: HOST=x86_64-unknown-linux-gnu PACKAGES="clang llvm python3-zmq qtbase5-dev qttools5-dev-tools libssl1.0-dev libevent-dev bsdmainutils libboost-system-dev libboost-filesystem-dev libboost-chrono-dev libboost-test-dev libboost-thread-dev libdb5.3++-dev libminiupnpc-dev libzmq3-dev libprotobuf-dev protobuf-compiler libqrencode-dev" NO_DEPENDS=1 - FUNCTIONAL_TESTS_CONFIG="--exclude wallet_multiwallet.py" # Temporarily suppress ASan heap-use-after-free (see issue #14163) GOAL="install" BITCOIN_CONFIG="--enable-zmq --with-incompatible-bdb --with-gui=qt5 CPPFLAGS=-DDEBUG_LOCKORDER --with-sanitizers=address,integer,undefined CC=clang CXX=clang++" - stage: test + name: 'x86_64 Linux [GOAL: install] [bionic] [no depends, only system libs, sanitizers: fuzzer,address]' + env: >- + HOST=x86_64-unknown-linux-gnu + PACKAGES="clang llvm python3 libssl1.0-dev libevent-dev bsdmainutils libboost-system-dev libboost-filesystem-dev libboost-chrono-dev libboost-test-dev libboost-thread-dev" + NO_DEPENDS=1 + RUN_UNIT_TESTS=false + RUN_FUNCTIONAL_TESTS=false + RUN_FUZZ_TESTS=true + GOAL="install" + BITCOIN_CONFIG="--disable-wallet --disable-bench --with-utils=no --with-daemon=no --with-libs=no --with-gui=no --enable-fuzz --with-sanitizers=fuzzer,address CC=clang CXX=clang++" + + - stage: test name: 'x86_64 Linux [GOAL: install] [bionic] [no wallet]' env: >- HOST=x86_64-unknown-linux-gnu @@ -139,7 +155,7 @@ jobs: BITCOIN_CONFIG="--enable-glibc-back-compat --enable-reduce-exports" - stage: test - name: 'macOS 10.10 [GOAL: deploy]' + name: 'macOS 10.10 [GOAL: deploy] [no functional tests]' env: >- HOST=x86_64-apple-darwin14 PACKAGES="cmake imagemagick libcap-dev librsvg2-bin libz-dev libbz2-dev libtiff-tools python-dev python3-setuptools-git" diff --git a/.travis/test_04_install.sh b/.travis/test_04_install.sh index a111387f10..8055bbdd19 100755 --- a/.travis/test_04_install.sh +++ b/.travis/test_04_install.sh @@ -7,6 +7,11 @@ export LC_ALL=C.UTF-8 travis_retry docker pull "$DOCKER_NAME_TAG" + +export DIR_FUZZ_IN=${TRAVIS_BUILD_DIR}/qa-assets +git clone https://github.com/bitcoin-core/qa-assets ${DIR_FUZZ_IN} +export DIR_FUZZ_IN=${DIR_FUZZ_IN}/fuzz_seed_corpus/ + mkdir -p "${TRAVIS_BUILD_DIR}/sanitizer-output/" export ASAN_OPTIONS="" export LSAN_OPTIONS="suppressions=${TRAVIS_BUILD_DIR}/test/sanitizer_suppressions/lsan" diff --git a/.travis/test_06_script.sh b/.travis/test_06_script_a.sh index 618aa2c3b6..8cc593f936 100755 --- a/.travis/test_06_script.sh +++ b/.travis/test_06_script_a.sh @@ -47,18 +47,4 @@ BEGIN_FOLD build DOCKER_EXEC make $MAKEJOBS $GOAL || ( echo "Build failure. Verbose build follows." && DOCKER_EXEC make $GOAL V=1 ; false ) END_FOLD -if [ "$RUN_UNIT_TESTS" = "true" ]; then - BEGIN_FOLD unit-tests - DOCKER_EXEC LD_LIBRARY_PATH=$TRAVIS_BUILD_DIR/depends/$HOST/lib make $MAKEJOBS check VERBOSE=1 - END_FOLD -fi - -if [ "$TRAVIS_EVENT_TYPE" = "cron" ]; then - extended="--extended --exclude feature_pruning" -fi - -if [ "$RUN_FUNCTIONAL_TESTS" = "true" ]; then - BEGIN_FOLD functional-tests - DOCKER_EXEC test/functional/test_runner.py --ci --combinedlogslen=4000 --coverage --quiet --failfast ${extended} ${FUNCTIONAL_TESTS_CONFIG} - END_FOLD -fi +cd ${TRAVIS_BUILD_DIR} || (echo "could not enter travis build dir $TRAVIS_BUILD_DIR"; exit 1) diff --git a/.travis/test_06_script_b.sh b/.travis/test_06_script_b.sh new file mode 100755 index 0000000000..e13abfd52f --- /dev/null +++ b/.travis/test_06_script_b.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2018 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +export LC_ALL=C.UTF-8 + +cd "build/bitcoin-$HOST" || (echo "could not enter distdir build/bitcoin-$HOST"; exit 1) + +if [ "$RUN_UNIT_TESTS" = "true" ]; then + BEGIN_FOLD unit-tests + DOCKER_EXEC LD_LIBRARY_PATH=$TRAVIS_BUILD_DIR/depends/$HOST/lib make $MAKEJOBS check VERBOSE=1 + END_FOLD +fi + +if [ "$RUN_FUNCTIONAL_TESTS" = "true" ]; then + BEGIN_FOLD functional-tests + DOCKER_EXEC test/functional/test_runner.py --ci --combinedlogslen=4000 --coverage --quiet --failfast + END_FOLD +fi + +if [ "$RUN_FUZZ_TESTS" = "true" ]; then + BEGIN_FOLD fuzz-tests + DOCKER_EXEC test/fuzz/test_runner.py -l DEBUG ${DIR_FUZZ_IN} + END_FOLD +fi diff --git a/.tx/config b/.tx/config index c0931c0f34..743510a7f2 100644 --- a/.tx/config +++ b/.tx/config @@ -1,7 +1,7 @@ [main] host = https://www.transifex.com -[bitcoin.qt-translation-017x] +[bitcoin.qt-translation-018x] file_filter = src/qt/locale/bitcoin_<lang>.ts source_file = src/qt/locale/bitcoin_en.ts source_lang = en diff --git a/Makefile.am b/Makefile.am index 9a6e15f0dd..85674f819a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -20,6 +20,7 @@ BITCOIND_BIN=$(top_builddir)/src/$(BITCOIN_DAEMON_NAME)$(EXEEXT) BITCOIN_QT_BIN=$(top_builddir)/src/qt/$(BITCOIN_GUI_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) BITCOIN_WIN_INSTALLER=$(PACKAGE)-$(PACKAGE_VERSION)-win$(WINDOWS_BITS)-setup$(EXEEXT) empty := @@ -76,6 +77,7 @@ $(BITCOIN_WIN_INSTALLER): all-recursive STRIPPROG="$(STRIP)" $(INSTALL_STRIP_PROGRAM) $(BITCOIN_QT_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 @test -f $(MAKENSIS) && $(MAKENSIS) -V2 $(top_builddir)/share/setup.nsi || \ echo error: could not build $@ @echo built $@ @@ -172,6 +174,9 @@ $(BITCOIN_CLI_BIN): FORCE $(BITCOIN_TX_BIN): FORCE $(MAKE) -C src $(@F) +$(BITCOIN_WALLET_BIN): FORCE + $(MAKE) -C src $(@F) + if USE_LCOV LCOV_FILTER_PATTERN=-p "/usr/include/" -p "/usr/lib/" -p "src/leveldb/" -p "src/bench/" -p "src/univalue" -p "src/crypto/ctaes" -p "src/secp256k1" @@ -220,7 +225,11 @@ endif dist_noinst_SCRIPTS = autogen.sh -EXTRA_DIST = $(DIST_SHARE) test/functional/test_runner.py test/functional $(DIST_CONTRIB) $(DIST_DOCS) $(WINDOWS_PACKAGING) $(OSX_PACKAGING) $(BIN_CHECKS) +EXTRA_DIST = $(DIST_SHARE) $(DIST_CONTRIB) $(DIST_DOCS) $(WINDOWS_PACKAGING) $(OSX_PACKAGING) $(BIN_CHECKS) + +EXTRA_DIST += \ + test/functional \ + test/fuzz EXTRA_DIST += \ test/util/bitcoin-util-test.py \ diff --git a/build-aux/m4/bitcoin_qt.m4 b/build-aux/m4/bitcoin_qt.m4 index 90a2cd9875..1a7c5d5f7d 100644 --- a/build-aux/m4/bitcoin_qt.m4 +++ b/build-aux/m4/bitcoin_qt.m4 @@ -116,24 +116,6 @@ AC_DEFUN([BITCOIN_QT_CONFIGURE],[ if test "x$bitcoin_cv_static_qt" = xyes; then _BITCOIN_QT_FIND_STATIC_PLUGINS AC_DEFINE(QT_STATICPLUGIN, 1, [Define this symbol if qt plugins are static]) - AC_CACHE_CHECK(for Qt < 5.4, bitcoin_cv_need_acc_widget,[ - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ - #include <QtCore/qconfig.h> - #ifndef QT_VERSION - # include <QtCore/qglobal.h> - #endif - ]], - [[ - #if QT_VERSION >= 0x050400 - choke - #endif - ]])], - [bitcoin_cv_need_acc_widget=yes], - [bitcoin_cv_need_acc_widget=no]) - ]) - if test "x$bitcoin_cv_need_acc_widget" = xyes; then - _BITCOIN_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(AccessibleFactory)], [-lqtaccessiblewidgets]) - fi _BITCOIN_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(QMinimalIntegrationPlugin)],[-lqminimal]) AC_DEFINE(QT_QPA_PLATFORM_MINIMAL, 1, [Define this symbol if the minimal qt platform exists]) if test "x$TARGET_OS" = xwindows; then @@ -264,7 +246,7 @@ dnl All macros below are internal and should _not_ be used from the main dnl configure.ac. dnl ---- -dnl Internal. Check if the included version of Qt is Qt5. +dnl Internal. Check included version of Qt against minimum specified in doc/dependencies.md dnl Requires: INCLUDES must be populated as necessary. dnl Output: bitcoin_cv_qt5=yes|no AC_DEFUN([_BITCOIN_QT_CHECK_QT5],[ @@ -276,7 +258,7 @@ AC_DEFUN([_BITCOIN_QT_CHECK_QT5],[ #endif ]], [[ - #if QT_VERSION < 0x050200 || QT_VERSION_MAJOR < 5 + #if QT_VERSION < 0x050501 choke #endif ]])], @@ -374,9 +356,7 @@ AC_DEFUN([_BITCOIN_QT_FIND_STATIC_PLUGINS],[ fi if test "x$TARGET_OS" = xlinux; then PKG_CHECK_MODULES([X11XCB], [x11-xcb], [QT_LIBS="$X11XCB_LIBS $QT_LIBS"]) - if ${PKG_CONFIG} --exists "Qt5Core >= 5.5" 2>/dev/null; then - PKG_CHECK_MODULES([QTXCBQPA], [Qt5XcbQpa], [QT_LIBS="$QTXCBQPA_LIBS $QT_LIBS"]) - fi + PKG_CHECK_MODULES([QTXCBQPA], [Qt5XcbQpa], [QT_LIBS="$QTXCBQPA_LIBS $QT_LIBS"]) elif test "x$TARGET_OS" = xdarwin; then PKG_CHECK_MODULES([QTCLIPBOARD], [Qt5ClipboardSupport], [QT_LIBS="-lQt5ClipboardSupport $QT_LIBS"]) PKG_CHECK_MODULES([QTGRAPHICS], [Qt5GraphicsSupport], [QT_LIBS="-lQt5GraphicsSupport $QT_LIBS"]) @@ -527,4 +507,3 @@ AC_DEFUN([_BITCOIN_QT_FIND_LIBS_WITHOUT_PKGCONFIG],[ CXXFLAGS="$TEMP_CXXFLAGS" LIBS="$TEMP_LIBS" ]) - diff --git a/build_msvc/bench_bitcoin/bench_bitcoin.vcxproj b/build_msvc/bench_bitcoin/bench_bitcoin.vcxproj index b987a337c0..368fe7ead5 100644 --- a/build_msvc/bench_bitcoin/bench_bitcoin.vcxproj +++ b/build_msvc/bench_bitcoin/bench_bitcoin.vcxproj @@ -61,6 +61,12 @@ <ProjectReference Include="..\libunivalue\libunivalue.vcxproj"> <Project>{5724ba7d-a09a-4ba8-800b-c4c1561b3d69}</Project> </ProjectReference> + <ProjectReference Include="..\libsecp256k1\libsecp256k1.vcxproj"> + <Project>{bb493552-3b8c-4a8c-bf69-a6e7a51d2ea6}</Project> + </ProjectReference> + <ProjectReference Include="..\libleveldb\libleveldb.vcxproj"> + <Project>{18430fef-6b61-4c53-b396-718e02850f1b}</Project> + </ProjectReference> </ItemGroup> <PropertyGroup Label="Globals"> <VCProjectVersion>15.0</VCProjectVersion> @@ -140,7 +146,6 @@ <IntrinsicFunctions>true</IntrinsicFunctions> <PreprocessorDefinitions>NOMINMAX;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;WIN32;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\..\src;</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> </ClCompile> <Link> @@ -158,7 +163,6 @@ <Optimization>Disabled</Optimization> <PreprocessorDefinitions>NOMINMAX;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\..\src;</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> </ClCompile> <Link> @@ -174,7 +178,6 @@ <Optimization>Disabled</Optimization> <PreprocessorDefinitions>NOMINMAX;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\..\src;</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> </ClCompile> <Link> @@ -192,7 +195,6 @@ <IntrinsicFunctions>true</IntrinsicFunctions> <PreprocessorDefinitions>NOMINMAX;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;WIN32;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\..\src;</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> </ClCompile> <Link> diff --git a/build_msvc/bitcoin-cli/bitcoin-cli.vcxproj b/build_msvc/bitcoin-cli/bitcoin-cli.vcxproj index 32f0354fad..6b668054a3 100644 --- a/build_msvc/bitcoin-cli/bitcoin-cli.vcxproj +++ b/build_msvc/bitcoin-cli/bitcoin-cli.vcxproj @@ -111,9 +111,8 @@ <Optimization>MaxSpeed</Optimization> <FunctionLevelLinking>true</FunctionLevelLinking> <IntrinsicFunctions>true</IntrinsicFunctions> - <PreprocessorDefinitions>HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions>HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;WIN32;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> </ClCompile> <Link> @@ -131,7 +130,6 @@ <Optimization>Disabled</Optimization> <PreprocessorDefinitions>HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> </ClCompile> <Link> @@ -147,7 +145,6 @@ <Optimization>Disabled</Optimization> <PreprocessorDefinitions>HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> </ClCompile> <Link> @@ -163,9 +160,8 @@ <Optimization>MaxSpeed</Optimization> <FunctionLevelLinking>true</FunctionLevelLinking> <IntrinsicFunctions>true</IntrinsicFunctions> - <PreprocessorDefinitions>HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions>HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;WIN32;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> </ClCompile> <Link> diff --git a/build_msvc/bitcoin-tx/bitcoin-tx.vcxproj b/build_msvc/bitcoin-tx/bitcoin-tx.vcxproj index a9fae6b739..1d0174e319 100644 --- a/build_msvc/bitcoin-tx/bitcoin-tx.vcxproj +++ b/build_msvc/bitcoin-tx/bitcoin-tx.vcxproj @@ -38,6 +38,9 @@ <ProjectReference Include="..\libunivalue\libunivalue.vcxproj"> <Project>{5724ba7d-a09a-4ba8-800b-c4c1561b3d69}</Project> </ProjectReference> + <ProjectReference Include="..\libsecp256k1\libsecp256k1.vcxproj"> + <Project>{bb493552-3b8c-4a8c-bf69-a6e7a51d2ea6}</Project> + </ProjectReference> </ItemGroup> <PropertyGroup Label="Globals"> <VCProjectVersion>15.0</VCProjectVersion> @@ -111,9 +114,8 @@ <Optimization>MaxSpeed</Optimization> <FunctionLevelLinking>true</FunctionLevelLinking> <IntrinsicFunctions>true</IntrinsicFunctions> - <PreprocessorDefinitions>HAVE_CONFIG_H;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions>HAVE_CONFIG_H;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;WIN32;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> </ClCompile> <Link> @@ -131,7 +133,6 @@ <Optimization>Disabled</Optimization> <PreprocessorDefinitions>HAVE_CONFIG_H;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> </ClCompile> <Link> @@ -147,7 +148,6 @@ <Optimization>Disabled</Optimization> <PreprocessorDefinitions>HAVE_CONFIG_H;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> </ClCompile> <Link> @@ -163,9 +163,8 @@ <Optimization>MaxSpeed</Optimization> <FunctionLevelLinking>true</FunctionLevelLinking> <IntrinsicFunctions>true</IntrinsicFunctions> - <PreprocessorDefinitions>HAVE_CONFIG_H;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions>HAVE_CONFIG_H;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;WIN32;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> </ClCompile> <Link> diff --git a/build_msvc/bitcoin-wallet/bitcoin-wallet.vcxproj b/build_msvc/bitcoin-wallet/bitcoin-wallet.vcxproj index b618aca817..fa86da7bae 100644 --- a/build_msvc/bitcoin-wallet/bitcoin-wallet.vcxproj +++ b/build_msvc/bitcoin-wallet/bitcoin-wallet.vcxproj @@ -53,6 +53,12 @@ <ProjectReference Include="..\libbitcoin_wallet_tool\libbitcoin_wallet_tool.vcxproj"> <Project>{f91ac55e-6f5e-4c58-9ac5-b40db7deef93}</Project> </ProjectReference> + <ProjectReference Include="..\libsecp256k1\libsecp256k1.vcxproj"> + <Project>{bb493552-3b8c-4a8c-bf69-a6e7a51d2ea6}</Project> + </ProjectReference> + <ProjectReference Include="..\libleveldb\libleveldb.vcxproj"> + <Project>{18430fef-6b61-4c53-b396-718e02850f1b}</Project> + </ProjectReference> </ItemGroup> <PropertyGroup Label="Globals"> <VCProjectVersion>15.0</VCProjectVersion> @@ -126,9 +132,8 @@ <Optimization>MaxSpeed</Optimization> <FunctionLevelLinking>true</FunctionLevelLinking> <IntrinsicFunctions>true</IntrinsicFunctions> - <PreprocessorDefinitions>HAVE_CONFIG_H;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions>HAVE_CONFIG_H;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;WIN32;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> </ClCompile> <Link> @@ -146,7 +151,6 @@ <Optimization>Disabled</Optimization> <PreprocessorDefinitions>HAVE_CONFIG_H;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> </ClCompile> <Link> @@ -162,7 +166,6 @@ <Optimization>Disabled</Optimization> <PreprocessorDefinitions>HAVE_CONFIG_H;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> </ClCompile> <Link> @@ -178,9 +181,8 @@ <Optimization>MaxSpeed</Optimization> <FunctionLevelLinking>true</FunctionLevelLinking> <IntrinsicFunctions>true</IntrinsicFunctions> - <PreprocessorDefinitions>HAVE_CONFIG_H;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions>HAVE_CONFIG_H;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;WIN32;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> </ClCompile> <Link> diff --git a/build_msvc/bitcoin.sln b/build_msvc/bitcoin.sln index b84a525afa..45bc934d77 100644 --- a/build_msvc/bitcoin.sln +++ b/build_msvc/bitcoin.sln @@ -1,4 +1,4 @@ -Microsoft Visual Studio Solution File, Format Version 12.00 +Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 VisualStudioVersion = 15.0.27130.2027 MinimumVisualStudioVersion = 10.0.40219.1 @@ -36,6 +36,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bitcoin-wallet", "bitcoin-w EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libbitcoin_wallet_tool", "libbitcoin_wallet_tool\libbitcoin_wallet_tool.vcxproj", "{F91AC55E-6F5E-4C58-9AC5-B40DB7DEEF93}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libsecp256k1", "libsecp256k1\libsecp256k1.vcxproj", "{BB493552-3B8C-4A8C-BF69-A6E7A51D2EA6}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libleveldb", "libleveldb\libleveldb.vcxproj", "{18430FEF-6B61-4C53-B396-718E02850F1B}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -180,6 +184,22 @@ Global {F91AC55E-6F5E-4C58-9AC5-B40DB7DEEF93}.Release|x64.Build.0 = Release|x64 {F91AC55E-6F5E-4C58-9AC5-B40DB7DEEF93}.Release|x86.ActiveCfg = Release|Win32 {F91AC55E-6F5E-4C58-9AC5-B40DB7DEEF93}.Release|x86.Build.0 = Release|Win32 + {BB493552-3B8C-4A8C-BF69-A6E7A51D2EA6}.Debug|x64.ActiveCfg = Debug|x64 + {BB493552-3B8C-4A8C-BF69-A6E7A51D2EA6}.Debug|x64.Build.0 = Debug|x64 + {BB493552-3B8C-4A8C-BF69-A6E7A51D2EA6}.Debug|x86.ActiveCfg = Debug|Win32 + {BB493552-3B8C-4A8C-BF69-A6E7A51D2EA6}.Debug|x86.Build.0 = Debug|Win32 + {BB493552-3B8C-4A8C-BF69-A6E7A51D2EA6}.Release|x64.ActiveCfg = Release|x64 + {BB493552-3B8C-4A8C-BF69-A6E7A51D2EA6}.Release|x64.Build.0 = Release|x64 + {BB493552-3B8C-4A8C-BF69-A6E7A51D2EA6}.Release|x86.ActiveCfg = Release|Win32 + {BB493552-3B8C-4A8C-BF69-A6E7A51D2EA6}.Release|x86.Build.0 = Release|Win32 + {18430FEF-6B61-4C53-B396-718E02850F1B}.Debug|x64.ActiveCfg = Debug|x64 + {18430FEF-6B61-4C53-B396-718E02850F1B}.Debug|x64.Build.0 = Debug|x64 + {18430FEF-6B61-4C53-B396-718E02850F1B}.Debug|x86.ActiveCfg = Debug|Win32 + {18430FEF-6B61-4C53-B396-718E02850F1B}.Debug|x86.Build.0 = Debug|Win32 + {18430FEF-6B61-4C53-B396-718E02850F1B}.Release|x64.ActiveCfg = Release|x64 + {18430FEF-6B61-4C53-B396-718E02850F1B}.Release|x64.Build.0 = Release|x64 + {18430FEF-6B61-4C53-B396-718E02850F1B}.Release|x86.ActiveCfg = Release|Win32 + {18430FEF-6B61-4C53-B396-718E02850F1B}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -190,3 +210,4 @@ Global SolutionGuid = {D0CAE2D0-8DB1-4A0B-80EE-800AA6C64323} SolutionGuid = {DA7D16A6-E5F0-45B3-B194-C3FE64F1BFCD} EndGlobalSection +EndGlobal diff --git a/build_msvc/bitcoind/bitcoind.vcxproj b/build_msvc/bitcoind/bitcoind.vcxproj index bb43d9821e..bb212af52e 100644 --- a/build_msvc/bitcoind/bitcoind.vcxproj +++ b/build_msvc/bitcoind/bitcoind.vcxproj @@ -79,7 +79,6 @@ <Optimization>Disabled</Optimization> <PreprocessorDefinitions>WIN32;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> </ClCompile> <Link> @@ -96,7 +95,6 @@ <Optimization>Disabled</Optimization> <PreprocessorDefinitions>WIN32;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> </ClCompile> <Link> @@ -113,9 +111,8 @@ <Optimization>MaxSpeed</Optimization> <FunctionLevelLinking>true</FunctionLevelLinking> <IntrinsicFunctions>true</IntrinsicFunctions> - <PreprocessorDefinitions>WIN32;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions>WIN32;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> </ClCompile> <Link> @@ -136,9 +133,8 @@ <Optimization>MaxSpeed</Optimization> <FunctionLevelLinking>true</FunctionLevelLinking> <IntrinsicFunctions>true</IntrinsicFunctions> - <PreprocessorDefinitions>WIN32;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions>WIN32;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> </ClCompile> <Link> @@ -180,6 +176,12 @@ <ProjectReference Include="..\libunivalue\libunivalue.vcxproj"> <Project>{5724ba7d-a09a-4ba8-800b-c4c1561b3d69}</Project> </ProjectReference> + <ProjectReference Include="..\libsecp256k1\libsecp256k1.vcxproj"> + <Project>{bb493552-3b8c-4a8c-bf69-a6e7a51d2ea6}</Project> + </ProjectReference> + <ProjectReference Include="..\libleveldb\libleveldb.vcxproj"> + <Project>{18430fef-6b61-4c53-b396-718e02850f1b}</Project> + </ProjectReference> </ItemGroup> <Import Label="configTarget" Project="..\common.vcxproj" /> </Project> diff --git a/build_msvc/common.vcxproj b/build_msvc/common.vcxproj index c7c20622e4..889dc6c2ad 100644 --- a/build_msvc/common.vcxproj +++ b/build_msvc/common.vcxproj @@ -3,20 +3,28 @@ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <PropertyGroup> <BuildDependsOn> - CopyConfig; + CopyBitcoinConfig; + CopySecp256k1Config; $(BuildDependsOn); </BuildDependsOn> </PropertyGroup> - <Target Name="CopyConfig" + <Target Name="CopyBitcoinConfig" Inputs="$(MSBuildThisFileDirectory)bitcoin_config.h" Outputs="$(MSBuildThisFileDirectory)..\src\config\bitcoin-config.h"> <Copy SourceFiles="$(MSBuildThisFileDirectory)bitcoin_config.h" DestinationFiles="$(MSBuildThisFileDirectory)..\src\config\bitcoin-config.h" /> </Target> + <Target Name="CopySecp256k1Config" + Inputs="$(MSBuildThisFileDirectory)libsecp256k1_config.h" + Outputs="$(MSBuildThisFileDirectory)..\src\secp256k1\src\libsecp256k1-config.h"> + <Copy SourceFiles="$(MSBuildThisFileDirectory)libsecp256k1_config.h" DestinationFiles="$(MSBuildThisFileDirectory)..\src\secp256k1\src\libsecp256k1-config.h" /> + </Target> <ItemDefinitionGroup> <ClCompile> <AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions> <DisableSpecificWarnings>4018;4244;4267;4715;4805;</DisableSpecificWarnings> <TreatWarningAsError>true</TreatWarningAsError> + <PreprocessorDefinitions>_WIN32_WINNT=0x0601;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;..\..\src\secp256k1\include;..\..\src\leveldb\include;..\..\src\leveldb\helpers\memenv;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> </ClCompile> </ItemDefinitionGroup> </Project> diff --git a/build_msvc/libbitcoin_cli/libbitcoin_cli.vcxproj.in b/build_msvc/libbitcoin_cli/libbitcoin_cli.vcxproj.in index b7265054fb..5849e463a6 100644 --- a/build_msvc/libbitcoin_cli/libbitcoin_cli.vcxproj.in +++ b/build_msvc/libbitcoin_cli/libbitcoin_cli.vcxproj.in @@ -97,9 +97,8 @@ <Optimization>MaxSpeed</Optimization> <FunctionLevelLinking>true</FunctionLevelLinking> <IntrinsicFunctions>true</IntrinsicFunctions> - <PreprocessorDefinitions>_SCL_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions>_SCL_SECURE_NO_WARNINGS;WIN32;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> </ClCompile> <Link> @@ -116,7 +115,6 @@ <Optimization>Disabled</Optimization> <PreprocessorDefinitions>_SCL_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> </ClCompile> <Link> @@ -131,7 +129,6 @@ <Optimization>Disabled</Optimization> <PreprocessorDefinitions>_SCL_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> </ClCompile> <Link> @@ -146,9 +143,8 @@ <Optimization>MaxSpeed</Optimization> <FunctionLevelLinking>true</FunctionLevelLinking> <IntrinsicFunctions>true</IntrinsicFunctions> - <PreprocessorDefinitions>_SCL_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions>_SCL_SECURE_NO_WARNINGS;WIN32;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> </ClCompile> <Link> diff --git a/build_msvc/libbitcoin_common/libbitcoin_common.vcxproj.in b/build_msvc/libbitcoin_common/libbitcoin_common.vcxproj.in index 42145c15ad..292e193f5d 100644 --- a/build_msvc/libbitcoin_common/libbitcoin_common.vcxproj.in +++ b/build_msvc/libbitcoin_common/libbitcoin_common.vcxproj.in @@ -91,7 +91,6 @@ <Optimization>Disabled</Optimization> <PreprocessorDefinitions>WIN32;HAVE_CONFIG_H;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;</AdditionalIncludeDirectories> <SuppressStartupBanner>false</SuppressStartupBanner> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> </ClCompile> @@ -109,7 +108,6 @@ <Optimization>Disabled</Optimization> <PreprocessorDefinitions>WIN32;HAVE_CONFIG_H;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;</AdditionalIncludeDirectories> <SuppressStartupBanner>false</SuppressStartupBanner> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> </ClCompile> @@ -127,9 +125,8 @@ <Optimization>MaxSpeed</Optimization> <FunctionLevelLinking>true</FunctionLevelLinking> <IntrinsicFunctions>true</IntrinsicFunctions> - <PreprocessorDefinitions>WIN32;HAVE_CONFIG_H;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions>WIN32;HAVE_CONFIG_H;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;WIN32;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;</AdditionalIncludeDirectories> <SuppressStartupBanner>false</SuppressStartupBanner> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> </ClCompile> @@ -149,9 +146,8 @@ <Optimization>MaxSpeed</Optimization> <FunctionLevelLinking>true</FunctionLevelLinking> <IntrinsicFunctions>true</IntrinsicFunctions> - <PreprocessorDefinitions>WIN32;HAVE_CONFIG_H;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions>WIN32;HAVE_CONFIG_H;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;</AdditionalIncludeDirectories> <SuppressStartupBanner>false</SuppressStartupBanner> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> </ClCompile> diff --git a/build_msvc/libbitcoin_crypto/libbitcoin_crypto.vcxproj.in b/build_msvc/libbitcoin_crypto/libbitcoin_crypto.vcxproj.in index a05125723a..e7002036ad 100644 --- a/build_msvc/libbitcoin_crypto/libbitcoin_crypto.vcxproj.in +++ b/build_msvc/libbitcoin_crypto/libbitcoin_crypto.vcxproj.in @@ -89,7 +89,6 @@ <Optimization>Disabled</Optimization> <PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\..\src</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> </ClCompile> <Link> @@ -104,7 +103,6 @@ <Optimization>Disabled</Optimization> <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\..\src</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> </ClCompile> <Link> @@ -119,9 +117,8 @@ <Optimization>MaxSpeed</Optimization> <FunctionLevelLinking>true</FunctionLevelLinking> <IntrinsicFunctions>true</IntrinsicFunctions> - <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions>WIN32;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\..\src</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> </ClCompile> <Link> @@ -138,9 +135,8 @@ <Optimization>MaxSpeed</Optimization> <FunctionLevelLinking>true</FunctionLevelLinking> <IntrinsicFunctions>true</IntrinsicFunctions> - <PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions>_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\..\src</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> </ClCompile> <Link> diff --git a/build_msvc/libbitcoin_qt/libbitcoin_qt.vcxproj b/build_msvc/libbitcoin_qt/libbitcoin_qt.vcxproj index 2e8ecb2d2c..73ba90aa88 100644 --- a/build_msvc/libbitcoin_qt/libbitcoin_qt.vcxproj +++ b/build_msvc/libbitcoin_qt/libbitcoin_qt.vcxproj @@ -61,6 +61,9 @@ <None Include="..\..\src\qt\locale\bitcoin_af_ZA.ts"> <DeploymentContent>true</DeploymentContent> </None> + <None Include="..\..\src\qt\locale\bitcoin_am.ts"> + <DeploymentContent>true</DeploymentContent> + </None> <None Include="..\..\src\qt\locale\bitcoin_ar.ts"> <DeploymentContent>true</DeploymentContent> </None> @@ -73,10 +76,10 @@ <None Include="..\..\src\qt\locale\bitcoin_bg_BG.ts"> <DeploymentContent>true</DeploymentContent> </None> - <None Include="..\..\src\qt\locale\bitcoin_ca%40valencia.ts"> + <None Include="..\..\src\qt\locale\bitcoin_ca.ts"> <DeploymentContent>true</DeploymentContent> </None> - <None Include="..\..\src\qt\locale\bitcoin_ca.ts"> + <None Include="..\..\src\qt\locale\bitcoin_ca%40valencia.ts"> <DeploymentContent>true</DeploymentContent> </None> <None Include="..\..\src\qt\locale\bitcoin_ca_ES.ts"> @@ -178,9 +181,15 @@ <None Include="..\..\src\qt\locale\bitcoin_hu.ts"> <DeploymentContent>true</DeploymentContent> </None> + <None Include="..\..\src\qt\locale\bitcoin_id.ts"> + <DeploymentContent>true</DeploymentContent> + </None> <None Include="..\..\src\qt\locale\bitcoin_id_ID.ts"> <DeploymentContent>true</DeploymentContent> </None> + <None Include="..\..\src\qt\locale\bitcoin_is.ts"> + <DeploymentContent>true</DeploymentContent> + </None> <None Include="..\..\src\qt\locale\bitcoin_it.ts"> <DeploymentContent>true</DeploymentContent> </None> @@ -196,6 +205,9 @@ <None Include="..\..\src\qt\locale\bitcoin_kk_KZ.ts"> <DeploymentContent>true</DeploymentContent> </None> + <None Include="..\..\src\qt\locale\bitcoin_ko.ts"> + <DeploymentContent>true</DeploymentContent> + </None> <None Include="..\..\src\qt\locale\bitcoin_ko_KR.ts"> <DeploymentContent>true</DeploymentContent> </None> @@ -217,6 +229,9 @@ <None Include="..\..\src\qt\locale\bitcoin_mk_MK.ts"> <DeploymentContent>true</DeploymentContent> </None> + <None Include="..\..\src\qt\locale\bitcoin_ml.ts"> + <DeploymentContent>true</DeploymentContent> + </None> <None Include="..\..\src\qt\locale\bitcoin_mn.ts"> <DeploymentContent>true</DeploymentContent> </None> @@ -262,18 +277,24 @@ <None Include="..\..\src\qt\locale\bitcoin_sl_SI.ts"> <DeploymentContent>true</DeploymentContent> </None> - <None Include="..\..\src\qt\locale\bitcoin_sq.ts"> + <None Include="..\..\src\qt\locale\bitcoin_sn.ts"> <DeploymentContent>true</DeploymentContent> </None> - <None Include="..\..\src\qt\locale\bitcoin_sr%40latin.ts"> + <None Include="..\..\src\qt\locale\bitcoin_sq.ts"> <DeploymentContent>true</DeploymentContent> </None> <None Include="..\..\src\qt\locale\bitcoin_sr.ts"> <DeploymentContent>true</DeploymentContent> </None> + <None Include="..\..\src\qt\locale\bitcoin_sr%40latin.ts"> + <DeploymentContent>true</DeploymentContent> + </None> <None Include="..\..\src\qt\locale\bitcoin_sv.ts"> <DeploymentContent>true</DeploymentContent> </None> + <None Include="..\..\src\qt\locale\bitcoin_szl.ts"> + <DeploymentContent>true</DeploymentContent> + </None> <None Include="..\..\src\qt\locale\bitcoin_ta.ts"> <DeploymentContent>true</DeploymentContent> </None> @@ -852,7 +873,7 @@ <Optimization>Disabled</Optimization> <FunctionLevelLinking>true</FunctionLevelLinking> <IntrinsicFunctions>false</IntrinsicFunctions> - <PreprocessorDefinitions>_X86_;WIN32;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions>_X86_;WIN32;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;WIN32;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> <AdditionalIncludeDirectories>.\GeneratedFiles;..\..\src;..\..\src\univalue\include;.\QtGenerated\mocheaders</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> @@ -901,7 +922,7 @@ <Optimization>MaxSpeed</Optimization> <FunctionLevelLinking>true</FunctionLevelLinking> <IntrinsicFunctions>true</IntrinsicFunctions> - <PreprocessorDefinitions>WIN32;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions>WIN32;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> <AdditionalIncludeDirectories>.\GeneratedFiles;..\..\src;..\..\src\univalue\include;.\QtGenerated\mocheaders</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> diff --git a/build_msvc/libbitcoin_server/libbitcoin_server.vcxproj.in b/build_msvc/libbitcoin_server/libbitcoin_server.vcxproj.in index e66277123a..48a117bcfe 100644 --- a/build_msvc/libbitcoin_server/libbitcoin_server.vcxproj.in +++ b/build_msvc/libbitcoin_server/libbitcoin_server.vcxproj.in @@ -89,9 +89,8 @@ <PrecompiledHeader>NotUsing</PrecompiledHeader> <WarningLevel>Level3</WarningLevel> <Optimization>Disabled</Optimization> - <PreprocessorDefinitions>WIN32;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions>WIN32;HAVE_CONFIG_H;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> </ClCompile> <Link> @@ -104,9 +103,8 @@ <PrecompiledHeader>NotUsing</PrecompiledHeader> <WarningLevel>Level3</WarningLevel> <Optimization>Disabled</Optimization> - <PreprocessorDefinitions>WIN32;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions>WIN32;HAVE_CONFIG_H;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> <SuppressStartupBanner>false</SuppressStartupBanner> </ClCompile> @@ -122,9 +120,8 @@ <Optimization>MaxSpeed</Optimization> <FunctionLevelLinking>true</FunctionLevelLinking> <IntrinsicFunctions>true</IntrinsicFunctions> - <PreprocessorDefinitions>WIN32;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions>WIN32;HAVE_CONFIG_H;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> </ClCompile> <Link> @@ -141,9 +138,8 @@ <Optimization>MaxSpeed</Optimization> <FunctionLevelLinking>true</FunctionLevelLinking> <IntrinsicFunctions>true</IntrinsicFunctions> - <PreprocessorDefinitions>WIN32;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions>WIN32;HAVE_CONFIG_H;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> </ClCompile> <Link> diff --git a/build_msvc/libbitcoin_util/libbitcoin_util.vcxproj.in b/build_msvc/libbitcoin_util/libbitcoin_util.vcxproj.in index dc17c98e98..dbd91cf4db 100644 --- a/build_msvc/libbitcoin_util/libbitcoin_util.vcxproj.in +++ b/build_msvc/libbitcoin_util/libbitcoin_util.vcxproj.in @@ -92,7 +92,6 @@ <Optimization>Disabled</Optimization> <PreprocessorDefinitions>HAVE_CONFIG_H;WIN32;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> </ClCompile> <Link> @@ -112,7 +111,6 @@ <Optimization>Disabled</Optimization> <PreprocessorDefinitions>HAVE_CONFIG_H;WIN32;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> </ClCompile> <Link> @@ -132,9 +130,8 @@ <Optimization>MaxSpeed</Optimization> <FunctionLevelLinking>true</FunctionLevelLinking> <IntrinsicFunctions>true</IntrinsicFunctions> - <PreprocessorDefinitions>HAVE_CONFIG_H;WIN32;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions>HAVE_CONFIG_H;WIN32;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;WIN32;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> </ClCompile> <Link> @@ -156,9 +153,8 @@ <Optimization>MaxSpeed</Optimization> <FunctionLevelLinking>true</FunctionLevelLinking> <IntrinsicFunctions>true</IntrinsicFunctions> - <PreprocessorDefinitions>HAVE_CONFIG_H;WIN32;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions>HAVE_CONFIG_H;WIN32;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> </ClCompile> <Link> diff --git a/build_msvc/libbitcoin_wallet/libbitcoin_wallet.vcxproj.in b/build_msvc/libbitcoin_wallet/libbitcoin_wallet.vcxproj.in index 1bb7be6f7f..33f4054546 100644 --- a/build_msvc/libbitcoin_wallet/libbitcoin_wallet.vcxproj.in +++ b/build_msvc/libbitcoin_wallet/libbitcoin_wallet.vcxproj.in @@ -97,7 +97,6 @@ <Optimization>Disabled</Optimization> <PreprocessorDefinitions>HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\..\src;..\..\src\wallet;..\..\src\univalue\include;</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions> </ClCompile> @@ -113,7 +112,6 @@ <Optimization>Disabled</Optimization> <PreprocessorDefinitions>HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\..\src;..\..\src\wallet;..\..\src\univalue\include;</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions> </ClCompile> @@ -129,9 +127,8 @@ <Optimization>MaxSpeed</Optimization> <FunctionLevelLinking>true</FunctionLevelLinking> <IntrinsicFunctions>true</IntrinsicFunctions> - <PreprocessorDefinitions>HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions>HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;WIN32;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\..\src;..\..\src\wallet;..\..\src\univalue\include;</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions> </ClCompile> @@ -149,9 +146,8 @@ <Optimization>MaxSpeed</Optimization> <FunctionLevelLinking>true</FunctionLevelLinking> <IntrinsicFunctions>true</IntrinsicFunctions> - <PreprocessorDefinitions>HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions>HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;WIN32;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\..\src;..\..\src\wallet;..\..\src\univalue\include;</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions> </ClCompile> diff --git a/build_msvc/libbitcoin_wallet_tool/libbitcoin_wallet_tool.vcxproj.in b/build_msvc/libbitcoin_wallet_tool/libbitcoin_wallet_tool.vcxproj.in index b9cf68aee0..187d955687 100644 --- a/build_msvc/libbitcoin_wallet_tool/libbitcoin_wallet_tool.vcxproj.in +++ b/build_msvc/libbitcoin_wallet_tool/libbitcoin_wallet_tool.vcxproj.in @@ -97,7 +97,6 @@ <Optimization>Disabled</Optimization> <PreprocessorDefinitions>NOMINMAX;ZMQ_STATIC;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> <SuppressStartupBanner>false</SuppressStartupBanner> </ClCompile> @@ -113,7 +112,6 @@ <Optimization>Disabled</Optimization> <PreprocessorDefinitions>NOMINMAX;ZMQ_STATIC;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> <SuppressStartupBanner>false</SuppressStartupBanner> </ClCompile> @@ -129,9 +127,8 @@ <Optimization>MaxSpeed</Optimization> <FunctionLevelLinking>true</FunctionLevelLinking> <IntrinsicFunctions>true</IntrinsicFunctions> - <PreprocessorDefinitions>NOMINMAX;ZMQ_STATIC;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions>NOMINMAX;ZMQ_STATIC;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;WIN32;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> <SuppressStartupBanner>false</SuppressStartupBanner> </ClCompile> @@ -149,9 +146,8 @@ <Optimization>MaxSpeed</Optimization> <FunctionLevelLinking>true</FunctionLevelLinking> <IntrinsicFunctions>true</IntrinsicFunctions> - <PreprocessorDefinitions>NOMINMAX;ZMQ_STATIC;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions>NOMINMAX;ZMQ_STATIC;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;WIN32;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> <SuppressStartupBanner>false</SuppressStartupBanner> </ClCompile> diff --git a/build_msvc/libbitcoin_zmq/libbitcoin_zmq.vcxproj.in b/build_msvc/libbitcoin_zmq/libbitcoin_zmq.vcxproj.in index e396c1ad0c..c877a280c0 100644 --- a/build_msvc/libbitcoin_zmq/libbitcoin_zmq.vcxproj.in +++ b/build_msvc/libbitcoin_zmq/libbitcoin_zmq.vcxproj.in @@ -97,7 +97,6 @@ <Optimization>Disabled</Optimization> <PreprocessorDefinitions>NOMINMAX;ZMQ_STATIC;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> <SuppressStartupBanner>false</SuppressStartupBanner> </ClCompile> @@ -113,7 +112,6 @@ <Optimization>Disabled</Optimization> <PreprocessorDefinitions>NOMINMAX;ZMQ_STATIC;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> <SuppressStartupBanner>false</SuppressStartupBanner> </ClCompile> @@ -129,9 +127,8 @@ <Optimization>MaxSpeed</Optimization> <FunctionLevelLinking>true</FunctionLevelLinking> <IntrinsicFunctions>true</IntrinsicFunctions> - <PreprocessorDefinitions>NOMINMAX;ZMQ_STATIC;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions>NOMINMAX;ZMQ_STATIC;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;WIN32;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> <SuppressStartupBanner>false</SuppressStartupBanner> </ClCompile> @@ -149,9 +146,8 @@ <Optimization>MaxSpeed</Optimization> <FunctionLevelLinking>true</FunctionLevelLinking> <IntrinsicFunctions>true</IntrinsicFunctions> - <PreprocessorDefinitions>NOMINMAX;ZMQ_STATIC;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions>NOMINMAX;ZMQ_STATIC;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;WIN32;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> <SuppressStartupBanner>false</SuppressStartupBanner> </ClCompile> diff --git a/build_msvc/libbitcoinconsensus/libbitcoinconsensus.vcxproj b/build_msvc/libbitcoinconsensus/libbitcoinconsensus.vcxproj index 2c6c0a8b7c..a32aafbd74 100644 --- a/build_msvc/libbitcoinconsensus/libbitcoinconsensus.vcxproj +++ b/build_msvc/libbitcoinconsensus/libbitcoinconsensus.vcxproj @@ -126,7 +126,6 @@ <Optimization>Disabled</Optimization> <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>false</SDLCheck> - <AdditionalIncludeDirectories>..\..\src;</AdditionalIncludeDirectories> <ExceptionHandling>Sync</ExceptionHandling> <SuppressStartupBanner>false</SuppressStartupBanner> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> @@ -143,7 +142,6 @@ <Optimization>Disabled</Optimization> <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>false</SDLCheck> - <AdditionalIncludeDirectories>..\..\src;</AdditionalIncludeDirectories> <ExceptionHandling>Sync</ExceptionHandling> <SuppressStartupBanner>false</SuppressStartupBanner> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> @@ -160,9 +158,8 @@ <Optimization>MaxSpeed</Optimization> <FunctionLevelLinking>true</FunctionLevelLinking> <IntrinsicFunctions>true</IntrinsicFunctions> - <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions>WIN32;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>false</SDLCheck> - <AdditionalIncludeDirectories>..\..\src;</AdditionalIncludeDirectories> <ExceptionHandling>Sync</ExceptionHandling> <SuppressStartupBanner>false</SuppressStartupBanner> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> @@ -181,9 +178,8 @@ <Optimization>MaxSpeed</Optimization> <FunctionLevelLinking>true</FunctionLevelLinking> <IntrinsicFunctions>true</IntrinsicFunctions> - <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions>WIN32;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>false</SDLCheck> - <AdditionalIncludeDirectories>..\..\src;</AdditionalIncludeDirectories> <ExceptionHandling>Sync</ExceptionHandling> <SuppressStartupBanner>false</SuppressStartupBanner> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> diff --git a/build_msvc/libleveldb/libleveldb.vcxproj b/build_msvc/libleveldb/libleveldb.vcxproj new file mode 100644 index 0000000000..545508001e --- /dev/null +++ b/build_msvc/libleveldb/libleveldb.vcxproj @@ -0,0 +1,202 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Label="configInitTarget" Project="..\common.init.vcxproj" /> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <ItemGroup> + <ClCompile Include="..\..\src\leveldb\db\builder.cc" /> + <ClCompile Include="..\..\src\leveldb\db\c.cc" /> + <ClCompile Include="..\..\src\leveldb\db\dbformat.cc" /> + <ClCompile Include="..\..\src\leveldb\db\db_impl.cc" /> + <ClCompile Include="..\..\src\leveldb\db\db_iter.cc" /> + <ClCompile Include="..\..\src\leveldb\db\dumpfile.cc" /> + <ClCompile Include="..\..\src\leveldb\db\filename.cc" /> + <ClCompile Include="..\..\src\leveldb\db\log_reader.cc" /> + <ClCompile Include="..\..\src\leveldb\db\log_writer.cc" /> + <ClCompile Include="..\..\src\leveldb\db\memtable.cc" /> + <ClCompile Include="..\..\src\leveldb\db\repair.cc" /> + <ClCompile Include="..\..\src\leveldb\db\table_cache.cc" /> + <ClCompile Include="..\..\src\leveldb\db\version_edit.cc" /> + <ClCompile Include="..\..\src\leveldb\db\version_set.cc" /> + <ClCompile Include="..\..\src\leveldb\db\write_batch.cc" /> + <ClCompile Include="..\..\src\leveldb\helpers\memenv\memenv.cc" /> + <ClCompile Include="..\..\src\leveldb\port\port_posix_sse.cc" /> + <ClCompile Include="..\..\src\leveldb\port\port_win.cc" /> + <ClCompile Include="..\..\src\leveldb\table\block.cc" /> + <ClCompile Include="..\..\src\leveldb\table\block_builder.cc" /> + <ClCompile Include="..\..\src\leveldb\table\filter_block.cc" /> + <ClCompile Include="..\..\src\leveldb\table\format.cc" /> + <ClCompile Include="..\..\src\leveldb\table\iterator.cc" /> + <ClCompile Include="..\..\src\leveldb\table\merger.cc" /> + <ClCompile Include="..\..\src\leveldb\table\table.cc" /> + <ClCompile Include="..\..\src\leveldb\table\table_builder.cc" /> + <ClCompile Include="..\..\src\leveldb\table\two_level_iterator.cc" /> + <ClCompile Include="..\..\src\leveldb\util\arena.cc" /> + <ClCompile Include="..\..\src\leveldb\util\bloom.cc" /> + <ClCompile Include="..\..\src\leveldb\util\cache.cc" /> + <ClCompile Include="..\..\src\leveldb\util\coding.cc" /> + <ClCompile Include="..\..\src\leveldb\util\comparator.cc" /> + <ClCompile Include="..\..\src\leveldb\util\crc32c.cc" /> + <ClCompile Include="..\..\src\leveldb\util\env.cc" /> + <ClCompile Include="..\..\src\leveldb\util\env_win.cc" /> + <ClCompile Include="..\..\src\leveldb\util\filter_policy.cc" /> + <ClCompile Include="..\..\src\leveldb\util\hash.cc" /> + <ClCompile Include="..\..\src\leveldb\util\histogram.cc" /> + <ClCompile Include="..\..\src\leveldb\util\logging.cc" /> + <ClCompile Include="..\..\src\leveldb\util\options.cc" /> + <ClCompile Include="..\..\src\leveldb\util\status.cc" /> + </ItemGroup> + <PropertyGroup Label="Globals"> + <VCProjectVersion>15.0</VCProjectVersion> + <ProjectGuid>{18430FEF-6B61-4C53-B396-718E02850F1B}</ProjectGuid> + <Keyword>Win32Proj</Keyword> + <RootNamespace>libunivalue</RootNamespace> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>v141</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <PlatformToolset>v141</PlatformToolset> + <WholeProgramOptimization>true</WholeProgramOptimization> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>v141</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <PlatformToolset>v141</PlatformToolset> + <WholeProgramOptimization>true</WholeProgramOptimization> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Label="Shared"> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <LinkIncremental>true</LinkIncremental> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <LinkIncremental>true</LinkIncremental> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <LinkIncremental>false</LinkIncremental> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <LinkIncremental>false</LinkIncremental> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <PrecompiledHeader>NotUsing</PrecompiledHeader> + <WarningLevel>Level3</WarningLevel> + <Optimization>Disabled</Optimization> + <PreprocessorDefinitions>_CRT_NONSTDC_NO_DEPRECATE;_SCL_SECURE_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;NOMINMAX;LEVELDB_PLATFORM_WINDOWS;LEVELDB_ATOMIC_PRESENT;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <SDLCheck>true</SDLCheck> + <AdditionalIncludeDirectories>..\..\src\leveldb;..\..\src\leveldb\include;</AdditionalIncludeDirectories> + <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <PrecompiledHeader>NotUsing</PrecompiledHeader> + <WarningLevel>Level3</WarningLevel> + <Optimization>Disabled</Optimization> + <PreprocessorDefinitions>_CRT_NONSTDC_NO_DEPRECATE;_SCL_SECURE_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;NOMINMAX;LEVELDB_PLATFORM_WINDOWS;LEVELDB_ATOMIC_PRESENT;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <SDLCheck>true</SDLCheck> + <AdditionalIncludeDirectories>..\..\src\leveldb;..\..\src\leveldb\include;</AdditionalIncludeDirectories> + <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <PrecompiledHeader>NotUsing</PrecompiledHeader> + <WarningLevel>Level3</WarningLevel> + <Optimization>MaxSpeed</Optimization> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <PreprocessorDefinitions>_CRT_NONSTDC_NO_DEPRECATE;_SCL_SECURE_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;NOMINMAX;LEVELDB_PLATFORM_WINDOWS;LEVELDB_ATOMIC_PRESENT;WIN32;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <SDLCheck>true</SDLCheck> + <AdditionalIncludeDirectories>..\..\src\leveldb;..\..\src\leveldb\include;</AdditionalIncludeDirectories> + <RuntimeLibrary>MultiThreaded</RuntimeLibrary> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + <GenerateDebugInformation>true</GenerateDebugInformation> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <PrecompiledHeader>NotUsing</PrecompiledHeader> + <WarningLevel>Level3</WarningLevel> + <Optimization>MaxSpeed</Optimization> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <PreprocessorDefinitions>_CRT_NONSTDC_NO_DEPRECATE;_SCL_SECURE_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;NOMINMAX;LEVELDB_PLATFORM_WINDOWS;LEVELDB_ATOMIC_PRESENT;WIN32;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <SDLCheck>true</SDLCheck> + <AdditionalIncludeDirectories>..\..\src\leveldb;..\..\src\leveldb\include;</AdditionalIncludeDirectories> + <RuntimeLibrary>MultiThreaded</RuntimeLibrary> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + <GenerateDebugInformation>true</GenerateDebugInformation> + </Link> + </ItemDefinitionGroup> + <Import Label="configTarget" Project="..\common.vcxproj" /> + <ItemDefinitionGroup> + <ClCompile> + <TreatWarningAsError>false</TreatWarningAsError> + </ClCompile> + </ItemDefinitionGroup> +</Project> diff --git a/build_msvc/libsecp256k1/libsecp256k1.vcxproj b/build_msvc/libsecp256k1/libsecp256k1.vcxproj new file mode 100644 index 0000000000..b4c9ec28ee --- /dev/null +++ b/build_msvc/libsecp256k1/libsecp256k1.vcxproj @@ -0,0 +1,157 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Label="configInitTarget" Project="..\common.init.vcxproj" /> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <ItemGroup> + <ClCompile Include="..\..\src\secp256k1\src\secp256k1.c" /> + </ItemGroup> + <PropertyGroup Label="Globals"> + <VCProjectVersion>15.0</VCProjectVersion> + <ProjectGuid>{BB493552-3B8C-4A8C-BF69-A6E7A51D2EA6}</ProjectGuid> + <Keyword>Win32Proj</Keyword> + <RootNamespace>libunivalue</RootNamespace> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>v141</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <PlatformToolset>v141</PlatformToolset> + <WholeProgramOptimization>true</WholeProgramOptimization> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>v141</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <PlatformToolset>v141</PlatformToolset> + <WholeProgramOptimization>true</WholeProgramOptimization> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Label="Shared"> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <LinkIncremental>true</LinkIncremental> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <LinkIncremental>true</LinkIncremental> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <LinkIncremental>false</LinkIncremental> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <LinkIncremental>false</LinkIncremental> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <PrecompiledHeader>NotUsing</PrecompiledHeader> + <WarningLevel>Level3</WarningLevel> + <Optimization>Disabled</Optimization> + <PreprocessorDefinitions>ENABLE_MODULE_ECDH;ENABLE_MODULE_RECOVERY;HAVE_CONFIG_H;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <SDLCheck>true</SDLCheck> + <AdditionalIncludeDirectories>..\..\src\secp256k1;</AdditionalIncludeDirectories> + <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <PrecompiledHeader>NotUsing</PrecompiledHeader> + <WarningLevel>Level3</WarningLevel> + <Optimization>Disabled</Optimization> + <PreprocessorDefinitions>ENABLE_MODULE_ECDH;ENABLE_MODULE_RECOVERY;HAVE_CONFIG_H;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <SDLCheck>true</SDLCheck> + <AdditionalIncludeDirectories>..\..\src\secp256k1;</AdditionalIncludeDirectories> + <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <PrecompiledHeader>NotUsing</PrecompiledHeader> + <WarningLevel>Level3</WarningLevel> + <Optimization>MaxSpeed</Optimization> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <PreprocessorDefinitions>ENABLE_MODULE_ECDH;ENABLE_MODULE_RECOVERY;HAVE_CONFIG_H;WIN32;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <SDLCheck>true</SDLCheck> + <AdditionalIncludeDirectories>..\..\src\secp256k1;</AdditionalIncludeDirectories> + <RuntimeLibrary>MultiThreaded</RuntimeLibrary> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + <GenerateDebugInformation>true</GenerateDebugInformation> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <PrecompiledHeader>NotUsing</PrecompiledHeader> + <WarningLevel>Level3</WarningLevel> + <Optimization>MaxSpeed</Optimization> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <PreprocessorDefinitions>ENABLE_MODULE_ECDH;ENABLE_MODULE_RECOVERY;HAVE_CONFIG_H;WIN32;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <SDLCheck>true</SDLCheck> + <AdditionalIncludeDirectories>..\..\src\secp256k1;</AdditionalIncludeDirectories> + <RuntimeLibrary>MultiThreaded</RuntimeLibrary> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + <GenerateDebugInformation>true</GenerateDebugInformation> + </Link> + </ItemDefinitionGroup> + <Import Label="configTarget" Project="..\common.vcxproj" /> +</Project> diff --git a/build_msvc/libsecp256k1_config.h b/build_msvc/libsecp256k1_config.h new file mode 100644 index 0000000000..5187c946a0 --- /dev/null +++ b/build_msvc/libsecp256k1_config.h @@ -0,0 +1,29 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef BITCOIN_LIBSECP256K1_CONFIG_H +#define BITCOIN_LIBSECP256K1_CONFIG_H + +#undef USE_ASM_X86_64 +#undef USE_ENDOMORPHISM +#undef USE_FIELD_10X26 +#undef USE_FIELD_5X52 +#undef USE_FIELD_INV_BUILTIN +#undef USE_FIELD_INV_NUM +#undef USE_NUM_GMP +#undef USE_NUM_NONE +#undef USE_SCALAR_4X64 +#undef USE_SCALAR_8X32 +#undef USE_SCALAR_INV_BUILTIN +#undef USE_SCALAR_INV_NUM + +#define USE_NUM_NONE 1 +#define USE_FIELD_INV_BUILTIN 1 +#define USE_SCALAR_INV_BUILTIN 1 +#define USE_FIELD_10X26 1 +#define USE_SCALAR_8X32 1 + +#endif /* BITCOIN_LIBSECP256K1_CONFIG_H */ diff --git a/build_msvc/libunivalue/libunivalue.vcxproj b/build_msvc/libunivalue/libunivalue.vcxproj index 57d469debf..c3799b6408 100644 --- a/build_msvc/libunivalue/libunivalue.vcxproj +++ b/build_msvc/libunivalue/libunivalue.vcxproj @@ -125,7 +125,7 @@ <Optimization>MaxSpeed</Optimization> <FunctionLevelLinking>true</FunctionLevelLinking> <IntrinsicFunctions>true</IntrinsicFunctions> - <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions>WIN32;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> <AdditionalIncludeDirectories>..\..\src\univalue\include;</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> @@ -144,7 +144,7 @@ <Optimization>MaxSpeed</Optimization> <FunctionLevelLinking>true</FunctionLevelLinking> <IntrinsicFunctions>true</IntrinsicFunctions> - <PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions>_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> <AdditionalIncludeDirectories>..\..\src\univalue\include;</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> diff --git a/build_msvc/test_bitcoin-qt/test_bitcoin-qt.vcxproj b/build_msvc/test_bitcoin-qt/test_bitcoin-qt.vcxproj index b2d4c118f3..a5d666c114 100644 --- a/build_msvc/test_bitcoin-qt/test_bitcoin-qt.vcxproj +++ b/build_msvc/test_bitcoin-qt/test_bitcoin-qt.vcxproj @@ -89,7 +89,7 @@ <Optimization>MaxSpeed</Optimization> <FunctionLevelLinking>true</FunctionLevelLinking> <IntrinsicFunctions>true</IntrinsicFunctions> - <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions>WIN32;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> </ClCompile> <Link> @@ -132,7 +132,7 @@ <Optimization>MaxSpeed</Optimization> <FunctionLevelLinking>true</FunctionLevelLinking> <IntrinsicFunctions>true</IntrinsicFunctions> - <PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions>_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> </ClCompile> <Link> diff --git a/build_msvc/test_bitcoin/test_bitcoin.vcxproj b/build_msvc/test_bitcoin/test_bitcoin.vcxproj index 2316e473aa..d05a03699f 100644 --- a/build_msvc/test_bitcoin/test_bitcoin.vcxproj +++ b/build_msvc/test_bitcoin/test_bitcoin.vcxproj @@ -21,6 +21,8 @@ </ItemGroup> <ItemGroup> <ClCompile Include="..\..\src\test\*_tests.cpp" /> + <ClCompile Include="..\..\src\test\*_properties.cpp" /> + <ClCompile Include="..\..\src\test\gen\*_gen.cpp" /> <ClCompile Include="..\..\src\wallet\test\*_tests.cpp" /> <ClCompile Include="..\..\src\test\test_bitcoin.cpp" /> <ClCompile Include="..\..\src\test\test_bitcoin_main.cpp" /> @@ -54,6 +56,12 @@ <ProjectReference Include="..\libunivalue\libunivalue.vcxproj"> <Project>{5724ba7d-a09a-4ba8-800b-c4c1561b3d69}</Project> </ProjectReference> + <ProjectReference Include="..\libsecp256k1\libsecp256k1.vcxproj"> + <Project>{bb493552-3b8c-4a8c-bf69-a6e7a51d2ea6}</Project> + </ProjectReference> + <ProjectReference Include="..\libleveldb\libleveldb.vcxproj"> + <Project>{18430fef-6b61-4c53-b396-718e02850f1b}</Project> + </ProjectReference> </ItemGroup> <PropertyGroup Label="Globals"> <VCProjectVersion>15.0</VCProjectVersion> @@ -127,7 +135,6 @@ <Optimization>Disabled</Optimization> <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;NOMINMAX;WIN32;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;..\..\src\test;</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> </ClCompile> <Link> @@ -144,7 +151,6 @@ <Optimization>Disabled</Optimization> <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;NOMINMAX;WIN32;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;..\..\src\test;</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> </ClCompile> <Link> @@ -162,7 +168,6 @@ <IntrinsicFunctions>true</IntrinsicFunctions> <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;NOMINMAX;WIN32;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;..\..\src\test;</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> </ClCompile> <Link> @@ -182,7 +187,6 @@ <IntrinsicFunctions>true</IntrinsicFunctions> <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;NOMINMAX;WIN32;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;..\..\src\test;</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> </ClCompile> <Link> diff --git a/build_msvc/testconsensus/testconsensus.vcxproj b/build_msvc/testconsensus/testconsensus.vcxproj index d73988df1c..a2f5659049 100644 --- a/build_msvc/testconsensus/testconsensus.vcxproj +++ b/build_msvc/testconsensus/testconsensus.vcxproj @@ -95,7 +95,6 @@ <Optimization>Disabled</Optimization> <PreprocessorDefinitions>HAVE_CONFIG_H;WIN32;_SCL_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\..\src\;</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> </ClCompile> <Link> @@ -110,7 +109,6 @@ <Optimization>Disabled</Optimization> <PreprocessorDefinitions>HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\..\src\;</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> </ClCompile> <Link> @@ -129,7 +127,6 @@ <IntrinsicFunctions>true</IntrinsicFunctions> <PreprocessorDefinitions>HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;WIN32;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\..\src\;</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> </ClCompile> <Link> @@ -148,7 +145,6 @@ <IntrinsicFunctions>true</IntrinsicFunctions> <PreprocessorDefinitions>HAVE_CONFIG_H;WIN32;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\..\src\;</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> </ClCompile> <Link> @@ -168,6 +164,9 @@ <ProjectReference Include="..\libbitcoin_util\libbitcoin_util.vcxproj"> <Project>{b53a5535-ee9d-4c6f-9a26-f79ee3bc3754}</Project> </ProjectReference> + <ProjectReference Include="..\libsecp256k1\libsecp256k1.vcxproj"> + <Project>{bb493552-3b8c-4a8c-bf69-a6e7a51d2ea6}</Project> + </ProjectReference> </ItemGroup> <Import Label="configTarget" Project="..\common.vcxproj" /> </Project> diff --git a/configure.ac b/configure.ac index 8ac5cb02d1..dec6d4fac3 100644 --- a/configure.ac +++ b/configure.ac @@ -85,8 +85,8 @@ AC_PATH_TOOL(RANLIB, ranlib) AC_PATH_TOOL(STRIP, strip) AC_PATH_TOOL(GCOV, gcov) AC_PATH_PROG(LCOV, lcov) -dnl Python 3.x is supported from 3.4 on (see https://github.com/bitcoin/bitcoin/issues/7893) -AC_PATH_PROGS([PYTHON], [python3.7 python3.6 python3.5 python3.4 python3 python]) +dnl Python 3.4 is specified in .python-version and should be used if available, see doc/dependencies.md +AC_PATH_PROGS([PYTHON], [python3.4 python3.5 python3.6 python3.7 python3 python]) AC_PATH_PROG(GENHTML, genhtml) AC_PATH_PROG([GIT], [git]) AC_PATH_PROG(CCACHE,ccache) @@ -496,7 +496,7 @@ case $host in AC_MSG_ERROR("windres not found") fi - CPPFLAGS="$CPPFLAGS -D_MT -DWIN32 -D_WINDOWS -DBOOST_THREAD_USE_LIB" + CPPFLAGS="$CPPFLAGS -D_MT -DWIN32 -D_WINDOWS -DBOOST_THREAD_USE_LIB -D_WIN32_WINNT=0x0601" LEVELDB_TARGET_FLAGS="-DOS_WINDOWS" if test "x$CXXFLAGS_overridden" = "xno"; then CXXFLAGS="$CXXFLAGS -w" diff --git a/contrib/bitcoin-cli.bash-completion b/contrib/bitcoin-cli.bash-completion index 732981fe7c..f4cac84182 100644 --- a/contrib/bitcoin-cli.bash-completion +++ b/contrib/bitcoin-cli.bash-completion @@ -50,7 +50,7 @@ _bitcoin_cli() { COMPREPLY=( $( compgen -W "true false" -- "$cur" ) ) return 0 ;; - signrawtransaction) + signrawtransactionwithkey|signrawtransactionwithwallet) COMPREPLY=( $( compgen -W "ALL NONE SINGLE ALL|ANYONECANPAY NONE|ANYONECANPAY SINGLE|ANYONECANPAY" -- "$cur" ) ) return 0 ;; diff --git a/contrib/devtools/gen-manpages.sh b/contrib/devtools/gen-manpages.sh index b5de5a395f..63b9847100 100755 --- a/contrib/devtools/gen-manpages.sh +++ b/contrib/devtools/gen-manpages.sh @@ -10,6 +10,7 @@ MANDIR=${MANDIR:-$TOPDIR/doc/man} BITCOIND=${BITCOIND:-$BINDIR/bitcoind} BITCOINCLI=${BITCOINCLI:-$BINDIR/bitcoin-cli} BITCOINTX=${BITCOINTX:-$BINDIR/bitcoin-tx} +WALLET_TOOL=${WALLET_TOOL:-$BINDIR/bitcoin-wallet} BITCOINQT=${BITCOINQT:-$BINDIR/qt/bitcoin-qt} [ ! -x $BITCOIND ] && echo "$BITCOIND not found or not executable." && exit 1 @@ -23,7 +24,7 @@ BTCVER=($($BITCOINCLI --version | head -n1 | awk -F'[ -]' '{ print $6, $7 }')) echo "[COPYRIGHT]" > footer.h2m $BITCOIND --version | sed -n '1!p' >> footer.h2m -for cmd in $BITCOIND $BITCOINCLI $BITCOINTX $BITCOINQT; do +for cmd in $BITCOIND $BITCOINCLI $BITCOINTX $WALLET_TOOL $BITCOINQT; do cmdname="${cmd##*/}" help2man -N --version-string=${BTCVER[0]} --include=footer.h2m -o ${MANDIR}/${cmdname}.1 ${cmd} sed -i "s/\\\-${BTCVER[1]}//g" ${MANDIR}/${cmdname}.1 diff --git a/contrib/init/bitcoind.service b/contrib/init/bitcoind.service index 877abafd19..cfc5f77580 100644 --- a/contrib/init/bitcoind.service +++ b/contrib/init/bitcoind.service @@ -5,21 +5,45 @@ # See "man systemd.service" for details. # Note that almost all daemon options could be specified in -# /etc/bitcoin/bitcoin.conf +# /etc/bitcoin/bitcoin.conf, except for those explicitly specified as arguments +# in ExecStart= [Unit] Description=Bitcoin daemon After=network.target [Service] -ExecStart=/usr/bin/bitcoind -daemon -conf=/etc/bitcoin/bitcoin.conf -pid=/run/bitcoind/bitcoind.pid -# Creates /run/bitcoind owned by bitcoin -RuntimeDirectory=bitcoind -User=bitcoin +ExecStart=/usr/bin/bitcoind -daemon \ + -pid=/run/bitcoind/bitcoind.pid \ + -conf=/etc/bitcoin/bitcoin.conf \ + -datadir=/var/lib/bitcoind + +# Process management +#################### + Type=forking PIDFile=/run/bitcoind/bitcoind.pid Restart=on-failure +# Directory creation and permissions +#################################### + +# Run as bitcoin:bitcoin +User=bitcoin +Group=bitcoin + +# /run/bitcoind +RuntimeDirectory=bitcoind +RuntimeDirectoryMode=0710 + +# /etc/bitcoin +ConfigurationDirectory=bitcoin +ConfigurationDirectoryMode=0710 + +# /var/lib/bitcoind +StateDirectory=bitcoind +StateDirectoryMode=0710 + # Hardening measures #################### diff --git a/contrib/install_db4.sh b/contrib/install_db4.sh index e90b8af7e1..088d1c9dce 100755 --- a/contrib/install_db4.sh +++ b/contrib/install_db4.sh @@ -6,7 +6,7 @@ export LC_ALL=C set -e if [ -z "${1}" ]; then - echo "Usage: ./install_db4.sh <base-dir> [<extra-bdb-configure-flag> ...]" + echo "Usage: $0 <base-dir> [<extra-bdb-configure-flag> ...]" echo echo "Must specify a single argument: the directory in which db4 will be built." echo "This is probably \`pwd\` if you're at the root of the bitcoin repository." diff --git a/contrib/linearize/linearize-hashes.py b/contrib/linearize/linearize-hashes.py index e10b46d831..8529470e09 100755 --- a/contrib/linearize/linearize-hashes.py +++ b/contrib/linearize/linearize-hashes.py @@ -7,7 +7,7 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. # -from http.client import HttpConnection +from http.client import HTTPConnection import json import re import base64 @@ -27,7 +27,7 @@ class BitcoinRPC: authpair = "%s:%s" % (username, password) authpair = authpair.encode('utf-8') self.authhdr = b"Basic " + base64.b64encode(authpair) - self.conn = HttpConnection(host, port=port, timeout=30) + self.conn = HTTPConnection(host, port=port, timeout=30) def execute(self, obj): try: diff --git a/contrib/verify-commits/README.md b/contrib/verify-commits/README.md index 27ca15acb4..1215962a16 100644 --- a/contrib/verify-commits/README.md +++ b/contrib/verify-commits/README.md @@ -37,7 +37,8 @@ Configuration files Import trusted keys ------------------- -In order to check the commit signatures you must add the trusted PGP keys to your machine. This can be done in Linux by running +In order to check the commit signatures, you must add the trusted PGP keys to your machine. [GnuPG](https://gnupg.org/) may be used to import the trusted keys by running the following command: + ```sh gpg --recv-keys $(<contrib/verify-commits/trusted-keys) ``` diff --git a/doc/README.md b/doc/README.md index 51950d4a13..8876ffdd72 100644 --- a/doc/README.md +++ b/doc/README.md @@ -51,6 +51,7 @@ Development The Bitcoin repo's [root README](/README.md) contains relevant information on the development process and automated testing. - [Developer Notes](developer-notes.md) +- [Productivity Notes](productivity.md) - [Release Notes](release-notes.md) - [Release Process](release-process.md) - [Source Code Documentation (External Link)](https://dev.visucore.com/bitcoin/doxygen/) diff --git a/doc/REST-interface.md b/doc/REST-interface.md index d21df36130..02a665008b 100644 --- a/doc/REST-interface.md +++ b/doc/REST-interface.md @@ -20,7 +20,8 @@ Supported API Given a transaction hash: returns a transaction in binary, hex-encoded binary, or JSON formats. -For full TX query capability, one must enable the transaction index via "txindex=1" command line / configuration option. +By default, this endpoint will only search the mempool. +To query for a confirmed transaction, enable the transaction index via "txindex=1" command line / configuration option. #### Blocks `GET /rest/block/<BLOCK-HASH>.<bin|hex|json>` diff --git a/doc/build-freebsd.md b/doc/build-freebsd.md index 70f5dfc882..d22b6e8383 100644 --- a/doc/build-freebsd.md +++ b/doc/build-freebsd.md @@ -1,6 +1,6 @@ FreeBSD build guide ====================== -(updated for FreeBSD 11.1) +(updated for FreeBSD 12.0) This guide describes how to build bitcoind and command-line utilities on FreeBSD. @@ -10,55 +10,51 @@ This guide does not contain instructions for building the GUI. You will need the following dependencies, which can be installed as root via pkg: -``` +```shell pkg install autoconf automake boost-libs git gmake libevent libtool openssl pkgconf + +git clone https://github.com/bitcoin/bitcoin.git ``` In order to run the test suite (recommended), you will need to have Python 3 installed: -``` +```shell pkg install python3 ``` -For the wallet (optional): -``` -./contrib/install_db4.sh `pwd` -export BDB_PREFIX="$PWD/db4" -``` - See [dependencies.md](dependencies.md) for a complete overview. -Download the source code: -``` -git clone https://github.com/bitcoin/bitcoin +### Building BerkeleyDB + +BerkeleyDB is only necessary for the wallet functionality. To skip this, pass +`--disable-wallet` to `./configure` and skip to the next section. + +```shell +./contrib/install_db4.sh `pwd` +export BDB_PREFIX="$PWD/db4" ``` ## Building Bitcoin Core **Important**: Use `gmake` (the non-GNU `make` will exit with an error): -``` +With wallet: +```shell ./autogen.sh - -./configure # to build with wallet OR -./configure --disable-wallet # to build without wallet +./configure --with-gui=no \ + BDB_LIBS="-L${BDB_PREFIX}/lib -ldb_cxx-4.8" \ + BDB_CFLAGS="-I${BDB_PREFIX}/include" ``` -followed by either: - -``` -gmake +Without wallet: +```shell +./autogen.sh +./configure --with-gui=no --disable-wallet ``` -to build without testing, or +followed by: +```shell +gmake # use -jX here for parallelism +gmake check # Run tests if Python 3 is available ``` -gmake check -``` - -to also run the test suite (recommended, if Python 3 is installed). - -*Note on debugging*: The version of `gdb` installed by default is [ancient and considered harmful](https://wiki.freebsd.org/GdbRetirement). -It is not suitable for debugging a multi-threaded C++ program, not even for getting backtraces. Please install the package `gdb` and -use the versioned gdb command (e.g. `gdb7111`). - diff --git a/doc/dependencies.md b/doc/dependencies.md index b833e9151f..e4be63772c 100644 --- a/doc/dependencies.md +++ b/doc/dependencies.md @@ -17,14 +17,30 @@ These are the dependencies currently used by Bitcoin Core. You can find instruct | libevent | [2.1.8-stable](https://github.com/libevent/libevent/releases) | 2.0.22 | No | | | | libjpeg | | | | | [Yes](https://github.com/bitcoin/bitcoin/blob/master/depends/packages/qt.mk#L65) | | libpng | | | | | [Yes](https://github.com/bitcoin/bitcoin/blob/master/depends/packages/qt.mk#L64) | +| libsrvg | | | | | | | MiniUPnPc | [2.0.20180203](http://miniupnp.free.fr/files) | | No | | | | OpenSSL | [1.0.1k](https://www.openssl.org/source) | | Yes | | | | PCRE | | | | | [Yes](https://github.com/bitcoin/bitcoin/blob/master/depends/packages/qt.mk#L66) | | protobuf | [2.6.1](https://github.com/google/protobuf/releases) | | No | | | | Python (tests) | | [3.4](https://www.python.org/downloads) | | | | | qrencode | [3.4.4](https://fukuchi.org/works/qrencode) | | No | | | -| Qt | [5.9.7](https://download.qt.io/official_releases/qt/) | [5.2](https://github.com/bitcoin/bitcoin/pull/14725) | No | | | +| Qt | [5.9.7](https://download.qt.io/official_releases/qt/) | [5.5.1](https://github.com/bitcoin/bitcoin/issues/13478) | No | | | | XCB | | | | | [Yes](https://github.com/bitcoin/bitcoin/blob/master/depends/packages/qt.mk#L87) (Linux only) | | xkbcommon | | | | | [Yes](https://github.com/bitcoin/bitcoin/blob/master/depends/packages/qt.mk#L86) (Linux only) | | ZeroMQ | [4.3.1](https://github.com/zeromq/libzmq/releases) | 4.0.0 | No | | | | zlib | [1.2.11](https://zlib.net/) | | | | No | + +Controlling dependencies +------------------------ +Some dependencies are not needed in all configurations. The following are some factors that affect the dependency list. + +#### Options passed to `./configure` +* MiniUPnPc is not needed with `--with-miniupnpc=no`. +* Berkeley DB is not needed with `--disable-wallet`. +* protobuf is not needed with `--disable-bip70`. +* Qt is not needed with `--without-gui`. +* If the qrencode dependency is absent, QR support won't be added. To force an error when that happens, pass `--with-qrencode`. +* ZeroMQ is needed only with the `--with-zmq` option. + +#### Other +* librsvg is only needed if you need to run `make deploy` on (cross-compliation to) macOS.
\ No newline at end of file diff --git a/doc/descriptors.md b/doc/descriptors.md index de4d4e574f..5dbcd95e1d 100644 --- a/doc/descriptors.md +++ b/doc/descriptors.md @@ -39,7 +39,7 @@ Output descriptors currently support: ## Reference -Descriptors consist of several types of expressions. The top level expression is always a `SCRIPT`. +Descriptors consist of several types of expressions. The top level expression is either a `SCRIPT`, or `SCRIPT#CHECKSUM` where `CHECKSUM` is an 8-character alphanumeric descriptor checksum. `SCRIPT` expressions: - `sh(SCRIPT)` (top level only): P2SH embed the argument. @@ -169,3 +169,20 @@ existing Bitcoin Core wallets, a convenience function `combo` is provided, which takes as input a public key, and describes a set of P2PK, P2PKH, P2WPKH, and P2SH-P2WPH scripts for that key. In case the key is uncompressed, the set only includes P2PK and P2PKH scripts. + +### Checksums + +Descriptors can optionally be suffixed with a checksum to protect against +typos or copy-paste errors. + +These checksums consist of 8 alphanumeric characters. As long as errors are +restricted to substituting characters in `0123456789()[],'/*abcdefgh@:$%{}` +for others in that set and changes in letter case, up to 4 errors will always +be detected in descriptors up to 501 characters, and up to 3 errors in longer +ones. For larger numbers of errors, or other types of errors, there is a +roughly 1 in a trillion chance of not detecting the errors. + +All RPCs in Bitcoin Core will include the checksum in their output. Only +certain RPCs require checksums on input, including `deriveaddress` and +`importmulti`. The checksum for a descriptor without one can be computed +using the `getdescriptorinfo` RPC. diff --git a/doc/developer-notes.md b/doc/developer-notes.md index ec29310ffe..f765346cd8 100644 --- a/doc/developer-notes.md +++ b/doc/developer-notes.md @@ -17,6 +17,7 @@ Developer Notes - [DEBUG_LOCKORDER](#debug_lockorder) - [Valgrind suppressions file](#valgrind-suppressions-file) - [Compiling for test coverage](#compiling-for-test-coverage) + - [Performance profiling with perf](#performance-profiling-with-perf) - [Locking/mutex usage notes](#lockingmutex-usage-notes) - [Threads](#threads) - [Ignoring IDE/editor files](#ignoring-ideeditor-files) @@ -265,6 +266,51 @@ make cov # A coverage report will now be accessible at `./test_bitcoin.coverage/index.html`. ``` +### Performance profiling with perf + +Profiling is a good way to get a precise idea of where time is being spent in +code. One tool for doing profiling on Linux platforms is called +[`perf`](http://www.brendangregg.com/perf.html), and has been integrated into +the functional test framework. Perf can observe a running process and sample +(at some frequency) where its execution is. + +Perf installation is contingent on which kernel version you're running; see +[this StackExchange +thread](https://askubuntu.com/questions/50145/how-to-install-perf-monitoring-tool) +for specific instructions. + +Certain kernel parameters may need to be set for perf to be able to inspect the +running process' stack. + +```sh +$ sudo sysctl -w kernel.perf_event_paranoid=-1 +$ sudo sysctl -w kernel.kptr_restrict=0 +``` + +Make sure you [understand the security +trade-offs](https://lwn.net/Articles/420403/) of setting these kernel +parameters. + +To profile a running bitcoind process for 60 seconds, you could use an +invocation of `perf record` like this: + +```sh +$ perf record \ + -g --call-graph dwarf --per-thread -F 140 \ + -p `pgrep bitcoind` -- sleep 60 +``` + +You could then analyze the results by running + +```sh +perf report --stdio | c++filt | less +``` + +or using a graphical tool like [Hotspot](https://github.com/KDAB/hotspot). + +See the functional test documentation for how to invoke perf within tests. + + **Sanitizers** Bitcoin Core can be compiled with various "sanitizers" enabled, which add @@ -798,54 +844,6 @@ would be to revert the upstream fix before applying the updates to Bitcoin's copy of LevelDB. In general you should be wary of any upstream changes affecting what data is returned from LevelDB queries. -Git and GitHub tips ---------------------- - -- For resolving merge/rebase conflicts, it can be useful to enable diff3 style using - `git config merge.conflictstyle diff3`. Instead of - - <<< - yours - === - theirs - >>> - - you will see - - <<< - yours - ||| - original - === - theirs - >>> - - This may make it much clearer what caused the conflict. In this style, you can often just look - at what changed between *original* and *theirs*, and mechanically apply that to *yours* (or the other way around). - -- When reviewing patches which change indentation in C++ files, use `git diff -w` and `git show -w`. This makes - the diff algorithm ignore whitespace changes. This feature is also available on github.com, by adding `?w=1` - at the end of any URL which shows a diff. - -- When reviewing patches that change symbol names in many places, use `git diff --word-diff`. This will instead - of showing the patch as deleted/added *lines*, show deleted/added *words*. - -- When reviewing patches that move code around, try using - `git diff --patience commit~:old/file.cpp commit:new/file/name.cpp`, and ignoring everything except the - moved body of code which should show up as neither `+` or `-` lines. In case it was not a pure move, this may - even work when combined with the `-w` or `--word-diff` options described above. - -- When looking at other's pull requests, it may make sense to add the following section to your `.git/config` - file: - - [remote "upstream-pull"] - fetch = +refs/pull/*:refs/remotes/upstream-pull/* - url = git@github.com:bitcoin/bitcoin.git - - This will add an `upstream-pull` remote to your git repository, which can be fetched using `git fetch --all` - or `git fetch upstream-pull`. Afterwards, you can use `upstream-pull/NUMBER/head` in arguments to `git show`, - `git checkout` and anywhere a commit id would be acceptable to see the changes from pull request NUMBER. - Scripted diffs -------------- diff --git a/doc/fuzzing.md b/doc/fuzzing.md index 08b73d3b3c..f9221dde5b 100644 --- a/doc/fuzzing.md +++ b/doc/fuzzing.md @@ -5,6 +5,29 @@ A special test harness in `src/test/fuzz/` is provided for each fuzz target to provide an easy entry point for fuzzers and the like. In this document we'll describe how to use it with AFL and libFuzzer. +## Preparing fuzzing + +AFL needs an input directory with examples, and an output directory where it +will place examples that it found. These can be anywhere in the file system, +we'll define environment variables to make it easy to reference them. + +libFuzzer will use the input directory as output directory. + +Extract the example seeds (or other starting inputs) into the inputs +directory before starting fuzzing. + +``` +git clone https://github.com/bitcoin-core/qa-assets +export DIR_FUZZ_IN=$PWD/qa-assets/fuzz_seed_corpus +``` + +Only for AFL: + +``` +mkdir outputs +export AFLOUT=$PWD/outputs +``` + ## AFL ### Building AFL @@ -23,7 +46,7 @@ export AFLPATH=$PWD To build Bitcoin Core using AFL instrumentation (this assumes that the `AFLPATH` was set as above): ``` -./configure --disable-ccache --disable-shared --enable-tests --enable-fuzz CC=${AFLPATH}/afl-gcc CXX=${AFLPATH}/afl-g++ +./configure --disable-ccache --disable-shared --enable-tests --enable-fuzz --disable-wallet --disable-bench --with-utils=no --with-daemon=no --with-libs=no --with-gui=no CC=${AFLPATH}/afl-gcc CXX=${AFLPATH}/afl-g++ export AFL_HARDEN=1 cd src/ make @@ -39,31 +62,14 @@ binary will be instrumented in such a way that the AFL features "persistent mode" and "deferred forkserver" can be used. See https://github.com/mcarpenter/afl/tree/master/llvm_mode for details. -### Preparing fuzzing - -AFL needs an input directory with examples, and an output directory where it -will place examples that it found. These can be anywhere in the file system, -we'll define environment variables to make it easy to reference them. - -``` -mkdir inputs -AFLIN=$PWD/inputs -mkdir outputs -AFLOUT=$PWD/outputs -``` - -Example inputs are available from: - -- https://download.visucore.com/bitcoin/bitcoin_fuzzy_in.tar.xz -- http://strateman.ninja/fuzzing.tar.xz - -Extract these (or other starting inputs) into the `inputs` directory before starting fuzzing. - ### Fuzzing To start the actual fuzzing use: + ``` -$AFLPATH/afl-fuzz -i ${AFLIN} -o ${AFLOUT} -m52 -- test/fuzz/fuzz_target_foo +export FUZZ_TARGET=fuzz_target_foo # Pick a fuzz_target +mkdir ${AFLOUT}/${FUZZ_TARGET} +$AFLPATH/afl-fuzz -i ${DIR_FUZZ_IN}/${FUZZ_TARGET} -o ${AFLOUT}/${FUZZ_TARGET} -m52 -- test/fuzz/${FUZZ_TARGET} ``` You may have to change a few kernel parameters to test optimally - `afl-fuzz` @@ -74,10 +80,10 @@ will print an error and suggestion if so. A recent version of `clang`, the address sanitizer and libFuzzer is needed (all found in the `compiler-rt` runtime libraries package). -To build the `test/test_bitcoin_fuzzy` executable run +To build all fuzz targets with libFuzzer, run ``` -./configure --disable-ccache --enable-fuzz --with-sanitizers=fuzzer,address CC=clang CXX=clang++ +./configure --disable-ccache --disable-wallet --disable-bench --with-utils=no --with-daemon=no --with-libs=no --with-gui=no --enable-fuzz --with-sanitizers=fuzzer,address CC=clang CXX=clang++ make ``` @@ -86,3 +92,6 @@ interchangeably between libFuzzer and AFL. See https://llvm.org/docs/LibFuzzer.html#running on how to run the libFuzzer instrumented executable. + +Alternatively run the script in `./test/fuzz/test_runner.py` and provide it +with the `${DIR_FUZZ_IN}` created earlier. diff --git a/doc/init.md b/doc/init.md index 5778b09d05..a6c9bb94d8 100644 --- a/doc/init.md +++ b/doc/init.md @@ -56,7 +56,7 @@ All three configurations assume several paths that might need to be adjusted. Binary: `/usr/bin/bitcoind` Configuration file: `/etc/bitcoin/bitcoin.conf` Data directory: `/var/lib/bitcoind` -PID file: `/var/run/bitcoind/bitcoind.pid` (OpenRC and Upstart) or `/var/lib/bitcoind/bitcoind.pid` (systemd) +PID file: `/var/run/bitcoind/bitcoind.pid` (OpenRC and Upstart) or `/run/bitcoind/bitcoind.pid` (systemd) Lock file: `/var/lock/subsys/bitcoind` (CentOS) The configuration file, PID directory (if applicable) and data directory @@ -65,6 +65,22 @@ reasons to make the configuration file and data directory only readable by the bitcoin user and group. Access to bitcoin-cli and other bitcoind rpc clients can then be controlled by group membership. +NOTE: When using the systemd .service file, the creation of the aforementioned +directories and the setting of their permissions is automatically handled by +systemd. Directories are given a permission of 710, giving the bitcoin group +access to files under it _if_ the files themselves give permission to the +bitcoin group to do so (e.g. when `-sysperms` is specified). This does not allow +for the listing of files under the directory. + +NOTE: It is not currently possible to override `datadir` in +`/etc/bitcoin/bitcoin.conf` with the current systemd, OpenRC, and Upstart init +files out-of-the-box. This is because the command line options specified in the +init files take precedence over the configurations in +`/etc/bitcoin/bitcoin.conf`. However, some init systems have their own +configuration mechanisms that would allow for overriding the command line +options specified in the init files (e.g. setting `BITCOIND_DATADIR` for +OpenRC). + ### macOS Binary: `/usr/local/bin/bitcoind` diff --git a/doc/man/bitcoin-cli.1 b/doc/man/bitcoin-cli.1 index 553addfa84..95c1d24dff 100644 --- a/doc/man/bitcoin-cli.1 +++ b/doc/man/bitcoin-cli.1 @@ -1,5 +1,5 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.6. -.TH BITCOIN-CLI "1" "December 2018" "bitcoin-cli v0.17.99.0" "User Commands" +.TH BITCOIN-CLI "1" "February 2019" "bitcoin-cli v0.17.99.0" "User Commands" .SH NAME bitcoin-cli \- manual page for bitcoin-cli v0.17.99.0 .SH SYNOPSIS @@ -20,7 +20,7 @@ Bitcoin Core RPC client version v0.17.99.0 .HP \-? .IP -This help message +Print this help message and exit .HP \fB\-conf=\fR<file> .IP @@ -104,7 +104,7 @@ Chain selection options: .IP Use the test chain .SH COPYRIGHT -Copyright (C) 2009-2018 The Bitcoin Core developers +Copyright (C) 2009-2019 The Bitcoin Core developers Please contribute if you find Bitcoin Core useful. Visit <https://bitcoincore.org> for further information about the software. diff --git a/doc/man/bitcoin-qt.1 b/doc/man/bitcoin-qt.1 index 1d87acd3de..052d420608 100644 --- a/doc/man/bitcoin-qt.1 +++ b/doc/man/bitcoin-qt.1 @@ -1,5 +1,5 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.6. -.TH BITCOIN-QT "1" "December 2018" "bitcoin-qt v0.17.99.0" "User Commands" +.TH BITCOIN-QT "1" "February 2019" "bitcoin-qt v0.17.99.0" "User Commands" .SH NAME bitcoin-qt \- manual page for bitcoin-qt v0.17.99.0 .SH SYNOPSIS @@ -56,7 +56,7 @@ Specify data directory .HP \fB\-dbcache=\fR<n> .IP -Set database cache size in megabytes (4 to 16384, default: 450) +Set database cache size in MiB (4 to 16384, default: 450) .HP \fB\-debuglogfile=\fR<file> .IP @@ -500,7 +500,7 @@ mining and transaction creation (default: 0.00001) \fB\-whitelistforcerelay\fR .IP Force relay of transactions from whitelisted peers even if they violate -local relay policy (default: 1) +local relay policy (default: 0) .HP \fB\-whitelistrelay\fR .IP @@ -606,7 +606,7 @@ Set SSL root certificates for payment request (default: \fB\-system\-\fR) .IP Show splash screen on startup (default: 1) .SH COPYRIGHT -Copyright (C) 2009-2018 The Bitcoin Core developers +Copyright (C) 2009-2019 The Bitcoin Core developers Please contribute if you find Bitcoin Core useful. Visit <https://bitcoincore.org> for further information about the software. diff --git a/doc/man/bitcoin-tx.1 b/doc/man/bitcoin-tx.1 index f16c68ca14..6b6071d9b7 100644 --- a/doc/man/bitcoin-tx.1 +++ b/doc/man/bitcoin-tx.1 @@ -1,5 +1,5 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.6. -.TH BITCOIN-TX "1" "December 2018" "bitcoin-tx v0.17.99.0" "User Commands" +.TH BITCOIN-TX "1" "February 2019" "bitcoin-tx v0.17.99.0" "User Commands" .SH NAME bitcoin-tx \- manual page for bitcoin-tx v0.17.99.0 .SH SYNOPSIS @@ -14,7 +14,7 @@ Bitcoin Core bitcoin\-tx utility version v0.17.99.0 .HP \-? .IP -This help message +Print this help message and exit .HP \fB\-create\fR .IP @@ -92,7 +92,7 @@ sign=SIGHASH\-FLAGS .IP Add zero or more signatures to transaction. This command requires JSON registers:prevtxs=JSON object, privatekeys=JSON object. See -signrawtransaction docs for format of sighash flags, JSON +signrawtransactionwithkey docs for format of sighash flags, JSON objects. .PP Register Commands: @@ -105,7 +105,7 @@ set=NAME:JSON\-STRING .IP Set register NAME to given JSON\-STRING .SH COPYRIGHT -Copyright (C) 2009-2018 The Bitcoin Core developers +Copyright (C) 2009-2019 The Bitcoin Core developers Please contribute if you find Bitcoin Core useful. Visit <https://bitcoincore.org> for further information about the software. diff --git a/doc/man/bitcoin-wallet.1 b/doc/man/bitcoin-wallet.1 new file mode 100644 index 0000000000..1cb8cdebcd --- /dev/null +++ b/doc/man/bitcoin-wallet.1 @@ -0,0 +1,67 @@ +.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.6. +.TH BITCOIN-WALLET "1" "February 2019" "bitcoin-wallet v0.17.99.0" "User Commands" +.SH NAME +bitcoin-wallet \- manual page for bitcoin-wallet v0.17.99.0 +.SH DESCRIPTION +Bitcoin Core bitcoin\-wallet version v0.17.99.0 +.PP +wallet\-tool is an offline tool for creating and interacting with Bitcoin Core wallet files. +By default wallet\-tool will act on wallets in the default mainnet wallet directory in the datadir. +To change the target wallet, use the \fB\-datadir\fR, \fB\-wallet\fR and \fB\-testnet\fR/\-regtest arguments. +.SS "Usage:" +.IP +bitcoin\-wallet [options] <command> +.SH OPTIONS +.HP +\-? +.IP +Print this help message and exit +.HP +\fB\-datadir=\fR<dir> +.IP +Specify data directory +.HP +\fB\-wallet=\fR<wallet\-name> +.IP +Specify wallet name +.PP +Debugging/Testing options: +.HP +\fB\-debug=\fR<category> +.IP +Output debugging information (default: 0). +.HP +\fB\-printtoconsole\fR +.IP +Send trace/debug info to console (default: 1 when no \fB\-debug\fR is true, 0 +otherwise. +.PP +Chain selection options: +.HP +\fB\-testnet\fR +.IP +Use the test chain +.PP +Commands: +.IP +create +.IP +Create new wallet file +.IP +info +.IP +Get wallet info +.SH COPYRIGHT +Copyright (C) 2009-2019 The Bitcoin Core developers + +Please contribute if you find Bitcoin Core useful. Visit +<https://bitcoincore.org> for further information about the software. +The source code is available from <https://github.com/bitcoin/bitcoin>. + +This is experimental software. +Distributed under the MIT software license, see the accompanying file COPYING +or <https://opensource.org/licenses/MIT> + +This product includes software developed by the OpenSSL Project for use in the +OpenSSL Toolkit <https://www.openssl.org> and cryptographic software written by +Eric Young and UPnP software written by Thomas Bernard. diff --git a/doc/man/bitcoind.1 b/doc/man/bitcoind.1 index 5c4b1cd03b..5e057d923f 100644 --- a/doc/man/bitcoind.1 +++ b/doc/man/bitcoind.1 @@ -1,5 +1,5 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.6. -.TH BITCOIND "1" "December 2018" "bitcoind v0.17.99.0" "User Commands" +.TH BITCOIND "1" "February 2019" "bitcoind v0.17.99.0" "User Commands" .SH NAME bitcoind \- manual page for bitcoind v0.17.99.0 .SH SYNOPSIS @@ -56,7 +56,7 @@ Specify data directory .HP \fB\-dbcache=\fR<n> .IP -Set database cache size in megabytes (4 to 16384, default: 450) +Set database cache size in MiB (4 to 16384, default: 450) .HP \fB\-debuglogfile=\fR<file> .IP @@ -500,7 +500,7 @@ mining and transaction creation (default: 0.00001) \fB\-whitelistforcerelay\fR .IP Force relay of transactions from whitelisted peers even if they violate -local relay policy (default: 1) +local relay policy (default: 0) .HP \fB\-whitelistrelay\fR .IP @@ -580,7 +580,7 @@ Username for JSON\-RPC connections .IP Accept command line and JSON\-RPC commands .SH COPYRIGHT -Copyright (C) 2009-2018 The Bitcoin Core developers +Copyright (C) 2009-2019 The Bitcoin Core developers Please contribute if you find Bitcoin Core useful. Visit <https://bitcoincore.org> for further information about the software. diff --git a/doc/productivity.md b/doc/productivity.md new file mode 100644 index 0000000000..862017290d --- /dev/null +++ b/doc/productivity.md @@ -0,0 +1,161 @@ +Productivity Notes +================== + +Table of Contents +----------------- + +* [General](#general) + * [Cache compilations with `ccache`](#cache-compilations-with-ccache) + * [Disable features with `./configure`](#disable-features-with-configure) + * [Make use of your threads with `make -j`](#make-use-of-your-threads-with-make--j) + * [Multiple working directories with `git worktrees`](#multiple-working-directories-with-git-worktrees) +* [Writing code](#writing-code) + * [Format C/C++/Protobuf diffs with `clang-format-diff.py`](#format-ccprotobuf-diffs-with-clang-format-diffpy) + * [Format Python diffs with `yapf-diff.py`](#format-python-diffs-with-yapf-diffpy) +* [Rebasing/Merging code](#rebasingmerging-code) + * [More conflict context with `merge.conflictstyle diff3`](#more-conflict-context-with-mergeconflictstyle-diff3) +* [Reviewing code](#reviewing-code) + * [Reduce mental load with `git diff` options](#reduce-mental-load-with-git-diff-options) + * [Reference PRs easily with `refspec`s](#reference-prs-easily-with-refspecs) + * [Diff the diffs with `git range-diff`](#diff-the-diffs-with-git-range-diff) + +General +------ + +### Cache compilations with `ccache` + +The easiest way to faster compile times is to cache compiles. `ccache` is a way to do so, from its description at the time of writing: + +> ccache is a compiler cache. It speeds up recompilation by caching the result of previous compilations and detecting when the same compilation is being done again. Supported languages are C, C++, Objective-C and Objective-C++. + +Install `ccache` through your distribution's package manager, and run `./configure` with your normal flags to pick it up. + +To use ccache for all your C/C++ projects, follow the symlinks method [here](https://ccache.samba.org/manual/latest.html#_run_modes) to set it up. + +### Disable features with `./configure` + +After running `./autogen.sh`, which generates the `./configure` file, use `./configure --help` to identify features that you can disable to save on compilation time. A few common flags: + +```sh +--without-miniupnpc +--disable-bench +--disable-wallet +--without-gui +``` + +### Make use of your threads with `make -j` + +If you have multiple threads on your machine, you can tell `make` to utilize all of them with: + +```sh +make -j"$(($(nproc)+1))" +``` + +### Multiple working directories with `git worktrees` + +If you work with multiple branches or multiple copies of the repository, you should try `git worktrees`. + +To create a new branch that lives under a new working directory without disrupting your current working directory (useful for creating pull requests): +```sh +git worktree add -b my-shiny-new-branch ../living-at-my-new-working-directory based-on-my-crufty-old-commit-ish +``` + +To simply check out a commit-ish under a new working directory without disrupting your current working directory (useful for reviewing pull requests): +```sh +git worktree add --checkout ../where-my-checkout-commit-ish-will-live my-checkout-commit-ish +``` + +----- + +This synergizes well with [`ccache`](#cache-compilations-with-ccache) as objects resulting from unchanged code will most likely hit the cache and won't need to be recompiled. + +You can also set up [upstream refspecs](#reference-prs-easily-with-refspecs) to refer to pull requests easier in the above `git worktree` commands. + +Writing code +------------ + +### Format C/C++/Protobuf diffs with `clang-format-diff.py` + +See [contrib/devtools/README.md](contrib/devtools/README.md#clang-format-diff.py). + +### Format Python diffs with `yapf-diff.py` + +Usage is exactly the same as [`clang-format-diff.py`](#format-ccprotobuf-diffs-with-clang-format-diffpy). You can get it [here](https://github.com/MarcoFalke/yapf-diff). + +Rebasing/Merging code +------------- + +### More conflict context with `merge.conflictstyle diff3` + +For resolving merge/rebase conflicts, it can be useful to enable diff3 style using `git config merge.conflictstyle diff3`. Instead of + +```diff +<<< +yours +=== +theirs +>>> +``` + + you will see + +```diff +<<< +yours +||| +original +=== +theirs +>>> +``` + +This may make it much clearer what caused the conflict. In this style, you can often just look at what changed between *original* and *theirs*, and mechanically apply that to *yours* (or the other way around). + +Reviewing code +-------------- + +### Reduce mental load with `git diff` options + +When reviewing patches which change indentation in C++ files, use `git diff -w` and `git show -w`. This makes the diff algorithm ignore whitespace changes. This feature is also available on github.com, by adding `?w=1` at the end of any URL which shows a diff. + +When reviewing patches that change symbol names in many places, use `git diff --word-diff`. This will instead of showing the patch as deleted/added *lines*, show deleted/added *words*. + +When reviewing patches that move code around, try using `git diff --patience commit~:old/file.cpp commit:new/file/name.cpp`, and ignoring everything except the moved body of code which should show up as neither `+` or `-` lines. In case it was not a pure move, this may even work when combined with the `-w` or `--word-diff` options described above. `--color-moved=dimmed-zebra` will also dim the coloring of moved hunks in the diff on compatible terminals. + +### Reference PRs easily with `refspec`s + +When looking at other's pull requests, it may make sense to add the following section to your `.git/config` file: + +``` +[remote "upstream-pull"] + fetch = +refs/pull/*:refs/remotes/upstream-pull/* + url = git@github.com:bitcoin/bitcoin.git +``` + +This will add an `upstream-pull` remote to your git repository, which can be fetched using `git fetch --all` or `git fetch upstream-pull`. Afterwards, you can use `upstream-pull/NUMBER/head` in arguments to `git show`, `git checkout` and anywhere a commit id would be acceptable to see the changes from pull request NUMBER. + +### Diff the diffs with `git range-diff` + +It is very common for contributors to rebase their pull requests, or make changes to commits (perhaps in response to review) that are not at the head of their branch. This poses a problem for reviewers as when the contributor force pushes, the reviewer is no longer sure that his previous reviews of commits are still valid (as the commit hashes can now be different even though the diff is semantically the same). `git range-diff` can help solve this problem by diffing the diffs. + +For example, to identify the differences between your previously reviewed diffs P1-5, and the new diffs P1-2,N3-4 as illustrated below: +``` + P1--P2--P3--P4--P5 <-- previously-reviewed-head + / +...--m <-- master + \ + P1--P2--N3--N4--N5 <-- new-head (with P3 slightly modified) +``` + +You can do: +```sh +git range-diff master previously-reviewed-head new-head +``` + +Note that `git range-diff` also work for rebases. + +----- + +`git range-diff` also accepts normal `git diff` options, see [Reduce mental load with `git diff` options](#reduce-mental-load-with-git-diff-options) for useful `git diff` options. + +You can also set up [upstream refspecs](#reference-prs-easily-with-refspecs) to refer to pull requests easier in the above `git range-diff` commands. diff --git a/doc/release-notes-14021.md b/doc/release-notes-14021.md new file mode 100644 index 0000000000..4797a95bdb --- /dev/null +++ b/doc/release-notes-14021.md @@ -0,0 +1,11 @@ +Miscellaneous RPC Changes +------------------------- +- Descriptors with key origin information imported through `importmulti` will have their key origin information stored in the wallet for use with creating PSBTs. +- If `bip32derivs` of both `walletprocesspsbt` and `walletcreatefundedpsbt` is set to true but the key metadata for a public key has not been updated yet, then that key will have a derivation path as if it were just an independent key (i.e. no derivation path and its master fingerprint is itself) + +Miscellaneous Wallet changes +---------------------------- + +- The key metadata will need to be upgraded the first time that the HD seed is available. +For unencrypted wallets this will occur on wallet loading. +For encrypted wallets this will occur the first time the wallet is unlocked. diff --git a/doc/release-notes-14481.md b/doc/release-notes-14481.md new file mode 100644 index 0000000000..ea8fc3c34e --- /dev/null +++ b/doc/release-notes-14481.md @@ -0,0 +1,9 @@ +Low-level RPC changes +---------------------- + +The `listunspent` RPC has been modified so that it also returns `witnessScript`, +the witness script in the case of a P2WSH or P2SH-P2WSH output. + +The `signrawtransactionwithkey` and `signrawtransactionwithwallet` RPCs have been +modified so that they also optionally accept a `witnessScript`, the witness script in the +case of a P2WSH or P2SH-P2WSH output. This is compatible with the change to `listunspent`. diff --git a/doc/release-notes-14491.md b/doc/release-notes-14491.md new file mode 100644 index 0000000000..1cf36e85cf --- /dev/null +++ b/doc/release-notes-14491.md @@ -0,0 +1,5 @@ +Descriptor import support +--------------------- + +The `importmulti` RPC now supports importing of addresses from descriptors. A "desc" parameter can be provided instead of the "scriptPubKey" in a request, as well as an optional range for ranged descriptors to specify the start and end of the range to import. More information about +descriptors can be found [here](https://github.com/bitcoin/bitcoin/blob/master/doc/descriptors.md). diff --git a/doc/release-notes-14667.md b/doc/release-notes-14667.md new file mode 100644 index 0000000000..5cb1d0aee7 --- /dev/null +++ b/doc/release-notes-14667.md @@ -0,0 +1,4 @@ +New RPC methods +------------ + +- `deriveaddresses` returns one or more addresses corresponding to an [output descriptor](/doc/descriptors.md). diff --git a/doc/release-notes-14941.md b/doc/release-notes-14941.md deleted file mode 100644 index c3820d0368..0000000000 --- a/doc/release-notes-14941.md +++ /dev/null @@ -1,5 +0,0 @@ -Miscellaneous RPC changes ------------- - -- The `unloadwallet` RPC is now synchronous, meaning that it blocks until the - wallet is fully unloaded. diff --git a/doc/release-notes-14982.md b/doc/release-notes-14982.md deleted file mode 100644 index 3f0bf8aacd..0000000000 --- a/doc/release-notes-14982.md +++ /dev/null @@ -1,5 +0,0 @@ -New RPCs --------- - -- The RPC `getrpcinfo` returns runtime details of the RPC server. At the moment - it returns the active commands and the corresponding execution time. diff --git a/doc/release-notes-15226.md b/doc/release-notes-15226.md new file mode 100644 index 0000000000..3be84db3e9 --- /dev/null +++ b/doc/release-notes-15226.md @@ -0,0 +1,8 @@ +Miscellaneous RPC changes +------------ + +- The RPC `createwallet` now has an optional `blank` argument that can be used to create a blank wallet. +Blank wallets do not have any keys or HD seed. +They cannot be opened in software older than 0.18. +Once a blank wallet has a HD seed set (by using `sethdseed`) or private keys, scripts, addresses, and other watch only things have been imported, the wallet is no longer blank and can be opened in 0.17.x. +Encrypting a blank wallet will also set a HD seed for it. diff --git a/doc/release-notes-15393.md b/doc/release-notes-15393.md new file mode 100644 index 0000000000..f478dc798d --- /dev/null +++ b/doc/release-notes-15393.md @@ -0,0 +1,4 @@ +Dependencies +------------ + +- The minimum required version of QT has been increased from 5.2 to 5.5.1 (the [depends system](https://github.com/bitcoin/bitcoin/blob/master/depends/README.md) provides 5.9.7) diff --git a/doc/release-notes.md b/doc/release-notes.md index a54b08848f..a6408cf1e6 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -116,7 +116,8 @@ Configuration option changes defaults to being off, so that changes in policy and disconnect/ban behavior will not cause a node that is whitelisting another to be dropped by peers. Users can still explicitly enable this behavior with the command line option - (and may want to consider letting the Bitcoin Core project know about their + (and may want to consider [contacting](https://bitcoincore.org/en/contact/) + the Bitcoin Core project to let us know about their use-case, as this feature could be deprecated in the future). Documentation @@ -130,6 +131,10 @@ Documentation to the [REST interface documentation](https://github.com/bitcoin/bitcoin/blob/master/doc/REST-interface.md) indicating that the same rules apply. +- Further information is added to the [JSON-RPC + documentation](https://github.com/bitcoin/bitcoin/blob/master/doc/JSON-RPC-interface.md) + about how to secure this interface. + - A new [document](https://github.com/bitcoin/bitcoin/blob/master/doc/bitcoin-conf.md) about the `bitcoin.conf` file describes how to use it to configure Bitcoin Core. @@ -190,14 +195,18 @@ Deprecated or removed RPCs New RPCs -------- -- A new `getnodeaddresses` RPC returns peer addresses known to this +- The `getnodeaddresses` RPC returns peer addresses known to this node. It may be used to find nodes to connect to without using a DNS seeder. -- A new `listwalletdir` RPC returns a list of wallets in the wallet +- The `listwalletdir` RPC returns a list of wallets in the wallet directory (either the default wallet directory or the directory configured by the `-walletdir` parameter). +- The `getrpcinfo` returns runtime details of the RPC server. At the + moment, it returns an array of the currently active commands and how + long they've been running. + Updated RPCs ------------ @@ -254,11 +263,24 @@ in the Low-level Changes section below. - See the [Mining](#mining) section for changes to `getblocktemplate`. -- The `getrawtransaction` RPC no longer checks the unspent UTXO set for - a transaction. The remaining behaviors are as follows: 1. If a - blockhash is provided, check the corresponding block. 2. If no - blockhash is provided, check the mempool. 3. If no blockhash is - provided but txindex is enabled, also check txindex. +- The `getmininginfo` RPC now omits `currentblockweight` and `currentblocktx` + when a block was never assembled via RPC on this node. + +- The `getrawtransaction` RPC & REST endpoints no longer check the + unspent UTXO set for a transaction. The remaining behaviors are as + follows: 1. If a blockhash is provided, check the corresponding block. + 2. If no blockhash is provided, check the mempool. 3. If no blockhash + is provided but txindex is enabled, also check txindex. + +- The `unloadwallet` RPC is now synchronous, meaning it will not return + until the wallet is fully unloaded. + +REST changes +------------ + +- A new `/rest/blockhashbyheight/` endpoint is added for fetching the + hash of the block in the current best blockchain based on its height + (how many blocks it is after the Genesis Block). Graphical User Interface (GUI) ------------------------------ @@ -282,6 +304,16 @@ Graphical User Interface (GUI) CFLAGS="-mmacosx-version-min=10.11" for setting the deployment sdk version) +Tools +---- + +- A new `bitcoin-wallet` tool is now distributed alongside Bitcoin + Core's other executables. Without needing to use any RPCs, this tool + can currently create a new wallet file or display some basic + information about an existing wallet, such as whether the wallet is + encrypted, whether it uses an HD seed, how many transactions it + contains, and how many address book entries it has. + Low-level changes ================= @@ -306,6 +338,32 @@ Configuration deterministic wallets. This release makes specifying `-usehd` an invalid configuration option. +Network +------- + +- This release allows peers that your node automatically disconnected + for misbehavior (e.g. sending invalid data) to reconnect to your node + if you have unused incoming connection slots. If your slots fill up, + a misbehaving node will be disconnected to make room for nodes without + a history of problems (unless the misbehaving node helps your node in + some other way, such as by connecting to a part of the Internet from + which you don't have many other peers). Previously, Bitcoin Core + banned the IP addresses of misbehaving peers for a period of time + (default of 1 day); this was easily circumvented by attackers with + multiple IP addresses. If you manually ban a peer, such as by using + the `setban` RPC, all connections from that peer will still be + rejected. + +Security +-------- + +- This release changes the Random Number Generator (RNG) used from + OpenSSL to Bitcoin Core's own implementation, although entropy + gathered by Bitcoin Core is fed out to OpenSSL and then read back in + when the program needs strong randomness. This moves Bitcoin Core a + little closer to no longer needing to depend on OpenSSL, a dependency + that has caused security issues in the past. + Changes for particular platforms -------------------------------- diff --git a/doc/release-notes/release-notes-pr12255.md b/doc/release-notes/release-notes-pr12255.md new file mode 100644 index 0000000000..5ac8b44283 --- /dev/null +++ b/doc/release-notes/release-notes-pr12255.md @@ -0,0 +1,17 @@ +systemd init file +========= + +The systemd init file (`contrib/init/bitcoind.service`) has been changed to use +`/var/lib/bitcoind` as the data directory instead of `~bitcoin/.bitcoin`. This +change makes Bitcoin Core more consistent with other services, and makes the +systemd init config more consistent with existing Upstart and OpenRC configs. + +The configuration, PID, and data directories are now completely managed by +systemd, which will take care of their creation, permissions, etc. See +[`systemd.exec (5)`](https://www.freedesktop.org/software/systemd/man/systemd.exec.html#RuntimeDirectory=) +for more details. + +When using the provided init files under `contrib/init`, overriding the +`datadir` option in `/etc/bitcoin/bitcoin.conf` will have no effect. This is +because the command line arguments specified in the init files take precedence +over the options specified in `/etc/bitcoin/bitcoin.conf`. diff --git a/doc/release-process.md b/doc/release-process.md index d20a3dc6b3..eb1f5ad222 100644 --- a/doc/release-process.md +++ b/doc/release-process.md @@ -291,24 +291,48 @@ bitcoin.org (see below for bitcoin.org update instructions). - After the pull request is merged, the website will automatically show the newest version within 15 minutes, as well as update the OS download links. Ping @saivann/@harding (saivann/harding on Freenode) in case anything goes wrong -- Announce the release: - - - bitcoin-dev and bitcoin-core-dev mailing list - - - Bitcoin Core announcements list https://bitcoincore.org/en/list/announcements/join/ +- Update other repositories and websites for new version - bitcoincore.org blog post - bitcoincore.org RPC documentation update - - Update title of #bitcoin on Freenode IRC + - Update packaging repo - - Optionally twitter, reddit /r/Bitcoin, ... but this will usually sort out itself + - Notify BlueMatt so that he can start building [the PPAs](https://launchpad.net/~bitcoin/+archive/ubuntu/bitcoin) + + - Create a new branch for the major release "0.xx" (used to build the snap package) + + - Notify MarcoFalke so that he can start building the snap package + + - https://code.launchpad.net/~bitcoin-core/bitcoin-core-snap/+git/packaging (Click "Import Now" to fetch the branch) + - https://code.launchpad.net/~bitcoin-core/bitcoin-core-snap/+git/packaging/+ref/0.xx (Click "Create snap package") + - Name it "bitcoin-core-snap-0.xx" + - Leave owner and series as-is + - Select architectures that are compiled via gitian + - Leave "automatically build when branch changes" unticked + - Tick "automatically upload to store" + - Put "bitcoin-core" in the registered store package name field + - Tick the "edge" box + - Put "0.xx" in the track field + - Click "create snap package" + - Click "Request builds" for every new release on this branch (after updating the snapcraft.yml in the branch to reflect the latest gitian results) + - Promote release on https://snapcraft.io/bitcoin-core/releases if it passes sanity checks - - Notify BlueMatt so that he can start building [the PPAs](https://launchpad.net/~bitcoin/+archive/ubuntu/bitcoin) + - This repo - - Archive release notes for the new version to `doc/release-notes/` (branch `master` and branch of the release) + - Archive release notes for the new version to `doc/release-notes/` (branch `master` and branch of the release) - - Create a [new GitHub release](https://github.com/bitcoin/bitcoin/releases/new) with a link to the archived release notes. + - Create a [new GitHub release](https://github.com/bitcoin/bitcoin/releases/new) with a link to the archived release notes. + +- Announce the release: + + - bitcoin-dev and bitcoin-core-dev mailing list + + - Bitcoin Core announcements list https://bitcoincore.org/en/list/announcements/join/ + + - Update title of #bitcoin on Freenode IRC + + - Optionally twitter, reddit /r/Bitcoin, ... but this will usually sort out itself - Celebrate diff --git a/doc/translation_process.md b/doc/translation_process.md index 19f145e9bf..9692832842 100644 --- a/doc/translation_process.md +++ b/doc/translation_process.md @@ -68,11 +68,21 @@ The Transifex Bitcoin project config file is included as part of the repo. It ca To assist in updating translations, we have created a script to help. 1. `python contrib/devtools/update-translations.py` -2. Update `src/qt/bitcoin_locale.qrc` manually or via - `ls src/qt/locale/*ts|xargs -n1 basename|sed 's/\(bitcoin_\(.*\)\).ts/<file alias="\2">locale\/\1.qm<\/file>/'` -3. Update `src/Makefile.qt.include` manually or via - `ls src/qt/locale/*ts|xargs -n1 basename|sed 's/\(bitcoin_\(.*\)\).ts/ qt\/locale\/\1.ts \\/'` -4. `git add` new translations from `src/qt/locale/` +2. `git add` new translations from `src/qt/locale/` +3. Update `src/qt/bitcoin_locale.qrc` manually or via +```bash +git ls-files src/qt/locale/*ts|xargs -n1 basename|sed 's/\(bitcoin_\(.*\)\).ts/<file alias="\2">locale\/\1.qm<\/file>/' +``` +4. Update `src/Makefile.qt.include` manually or via +```bash +git ls-files src/qt/locale/*ts|xargs -n1 basename|sed 's/\(bitcoin_\(.*\)\).ts/ qt\/locale\/\1.ts \\/' +``` +5. Update `build_msvc/libbitcoin_qt/libbitcoin_qt.vcxproj` or via +```bash +git ls-files src/qt/locale/*ts|xargs -n1 basename | + sed 's/@/%40/' | + sed 's/\(bitcoin_\(.*\)\).ts/ <None Include="..\\..\\src\\qt\\locale\\\1.ts">\n <DeploymentContent>true<\/DeploymentContent>\n <\/None>/' +``` **Do not directly download translations** one by one from the Transifex website, as we do a few post-processing steps before committing the translations. diff --git a/doc/translation_strings_policy.md b/doc/translation_strings_policy.md index 737d11f045..634aca3559 100644 --- a/doc/translation_strings_policy.md +++ b/doc/translation_strings_policy.md @@ -33,25 +33,25 @@ General recommendations Try not to burden translators with translating messages that are e.g. slight variations of other messages. In the GUI, avoid the use of text where an icon or symbol will do. -Make sure that placeholder texts in forms don't end up in the list of strings to be translated (use `<string notr="true">`). +Make sure that placeholder texts in forms do not end up in the list of strings to be translated (use `<string notr="true">`). ### Make translated strings understandable -Try to write translation strings in an understandable way, for both the user and the translator. Avoid overly technical or detailed messages +Try to write translation strings in an understandable way, for both the user and the translator. Avoid overly technical or detailed messages. ### Do not translate internal errors -Do not translate internal errors, or log messages, or messages that appear on the RPC interface. If an error is to be shown to the user, -use a translatable generic message, then log the detailed message to the log. E.g. "A fatal internal error occurred, see debug.log for details". +Do not translate internal errors, log messages, or messages that appear on the RPC interface. If an error is to be shown to the user, +use a translatable generic message, then log the detailed message to the log. E.g., "A fatal internal error occurred, see debug.log for details". This helps troubleshooting; if the error is the same for everyone, the likelihood is increased that it can be found using a search engine. ### Avoid fragments -Avoid dividing up a message into fragments. Translators see every string separately, so may misunderstand the context if the messages are not self-contained. +Avoid dividing up a message into fragments. Translators see every string separately, so they may misunderstand the context if the messages are not self-contained. ### Avoid HTML in translation strings -There have been difficulties with use of HTML in translation strings; translators should not be able to accidentally affect the formatting of messages. +There have been difficulties with the use of HTML in translation strings; translators should not be able to accidentally affect the formatting of messages. This may sometimes be at conflict with the recommendation in the previous section. ### Plurals @@ -66,7 +66,7 @@ Plurals can be complex in some languages. A quote from the gettext documentation 25-31 pliko'w and so on -In Qt code use tr's third argument for optional plurality. For example: +In Qt code, use tr's third argument for optional plurality. For example: tr("%n hour(s)","",secs/HOUR_IN_SECONDS); tr("%n day(s)","",secs/DAY_IN_SECONDS); @@ -82,7 +82,7 @@ This adds `<numerusform>`s to the respective `.ts` file, which can be translated </translation> </message> -Where it is possible try to avoid embedding numbers into the flow of the string at all. e.g. +Where possible, try to avoid embedding numbers into the flow of the string at all. E.g., WARNING: check your network connection, %d blocks received in the last %d hours (%d expected) diff --git a/share/setup.nsi.in b/share/setup.nsi.in index 6542370f97..046deed9ea 100644 --- a/share/setup.nsi.in +++ b/share/setup.nsi.in @@ -81,6 +81,7 @@ Section -Main SEC0000 File @abs_top_srcdir@/release/@BITCOIN_DAEMON_NAME@@EXEEXT@ File @abs_top_srcdir@/release/@BITCOIN_CLI_NAME@@EXEEXT@ File @abs_top_srcdir@/release/@BITCOIN_TX_NAME@@EXEEXT@ + File @abs_top_srcdir@/release/@BITCOIN_WALLET_TOOL_NAME@@EXEEXT@ SetOutPath $INSTDIR\doc File /r /x Makefile* @abs_top_srcdir@/doc\*.* SetOutPath $INSTDIR diff --git a/src/Makefile.am b/src/Makefile.am index a57fcb0711..d491530ca1 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -118,6 +118,7 @@ BITCOIN_CORE_H = \ clientversion.h \ coins.h \ compat.h \ + compat/assumptions.h \ compat/byteswap.h \ compat/endian.h \ compat/sanity.h \ @@ -152,6 +153,7 @@ BITCOIN_CORE_H = \ netaddress.h \ netbase.h \ netmessagemaker.h \ + node/transaction.h \ noui.h \ optional.h \ outputtype.h \ @@ -161,6 +163,7 @@ BITCOIN_CORE_H = \ policy/rbf.h \ pow.h \ protocol.h \ + psbt.h \ random.h \ reverse_iterator.h \ reverselock.h \ @@ -194,6 +197,7 @@ BITCOIN_CORE_H = \ txmempool.h \ ui_interface.h \ undo.h \ + util/bip32.h \ util/bytevectorhash.h \ util/system.h \ util/memory.h \ @@ -209,6 +213,7 @@ BITCOIN_CORE_H = \ wallet/db.h \ wallet/feebumper.h \ wallet/fees.h \ + wallet/psbtwallet.h \ wallet/rpcwallet.h \ wallet/wallet.h \ wallet/walletdb.h \ @@ -255,6 +260,7 @@ libbitcoin_server_a_SOURCES = \ miner.cpp \ net.cpp \ net_processing.cpp \ + node/transaction.cpp \ noui.cpp \ outputtype.cpp \ policy/fees.cpp \ @@ -308,6 +314,7 @@ libbitcoin_wallet_a_SOURCES = \ wallet/feebumper.cpp \ wallet/fees.cpp \ wallet/init.cpp \ + wallet/psbtwallet.cpp \ wallet/rpcdump.cpp \ wallet/rpcwallet.cpp \ wallet/wallet.cpp \ @@ -421,6 +428,7 @@ libbitcoin_common_a_SOURCES = \ netaddress.cpp \ netbase.cpp \ policy/feerate.cpp \ + psbt.cpp \ protocol.cpp \ scheduler.cpp \ script/descriptor.cpp \ @@ -450,6 +458,7 @@ libbitcoin_util_a_SOURCES = \ support/cleanse.cpp \ sync.cpp \ threadinterrupt.cpp \ + util/bip32.cpp \ util/bytevectorhash.cpp \ util/system.cpp \ util/moneystr.cpp \ diff --git a/src/Makefile.leveldb.include b/src/Makefile.leveldb.include index 833f3d2a10..bd08bcb4ed 100644 --- a/src/Makefile.leveldb.include +++ b/src/Makefile.leveldb.include @@ -24,7 +24,7 @@ LEVELDB_CPPFLAGS_INT += -DLEVELDB_ATOMIC_PRESENT LEVELDB_CPPFLAGS_INT += -D__STDC_LIMIT_MACROS if TARGET_WINDOWS -LEVELDB_CPPFLAGS_INT += -DLEVELDB_PLATFORM_WINDOWS -DWINVER=0x0500 -D__USE_MINGW_ANSI_STDIO=1 +LEVELDB_CPPFLAGS_INT += -DLEVELDB_PLATFORM_WINDOWS -D__USE_MINGW_ANSI_STDIO=1 else LEVELDB_CPPFLAGS_INT += -DLEVELDB_PLATFORM_POSIX endif diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 12112375ea..84bc326cfe 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -2,7 +2,6 @@ # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. -bin_PROGRAMS += test/test_bitcoin FUZZ_TARGETS = \ test/fuzz/address_deserialize \ @@ -21,6 +20,7 @@ FUZZ_TARGETS = \ test/fuzz/inv_deserialize \ test/fuzz/messageheader_deserialize \ test/fuzz/netaddr_deserialize \ + test/fuzz/script_flags \ test/fuzz/service_deserialize \ test/fuzz/transaction_deserialize \ test/fuzz/txoutcompressor_deserialize \ @@ -28,6 +28,8 @@ FUZZ_TARGETS = \ if ENABLE_FUZZ noinst_PROGRAMS += $(FUZZ_TARGETS:=) +else +bin_PROGRAMS += test/test_bitcoin endif TEST_SRCDIR = test @@ -171,7 +173,7 @@ test_test_bitcoin_LDADD += $(ZMQ_LIBS) endif if ENABLE_FUZZ -test_fuzz_block_deserialize_SOURCES = $(FUZZ_SUITE) test/test_bitcoin_fuzzy.cpp +test_fuzz_block_deserialize_SOURCES = $(FUZZ_SUITE) test/fuzz/deserialize.cpp test_fuzz_block_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DBLOCK_DESERIALIZE=1 test_fuzz_block_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) test_fuzz_block_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) @@ -188,7 +190,7 @@ test_fuzz_block_deserialize_LDADD = \ $(LIBSECP256K1) test_fuzz_block_deserialize_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS) -test_fuzz_transaction_deserialize_SOURCES = $(FUZZ_SUITE) test/test_bitcoin_fuzzy.cpp +test_fuzz_transaction_deserialize_SOURCES = $(FUZZ_SUITE) test/fuzz/deserialize.cpp test_fuzz_transaction_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DTRANSACTION_DESERIALIZE=1 test_fuzz_transaction_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) test_fuzz_transaction_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) @@ -205,7 +207,7 @@ test_fuzz_transaction_deserialize_LDADD = \ $(LIBSECP256K1) test_fuzz_transaction_deserialize_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS) -test_fuzz_blocklocator_deserialize_SOURCES = $(FUZZ_SUITE) test/test_bitcoin_fuzzy.cpp +test_fuzz_blocklocator_deserialize_SOURCES = $(FUZZ_SUITE) test/fuzz/deserialize.cpp test_fuzz_blocklocator_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DBLOCKLOCATOR_DESERIALIZE=1 test_fuzz_blocklocator_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) test_fuzz_blocklocator_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) @@ -222,7 +224,7 @@ test_fuzz_blocklocator_deserialize_LDADD = \ $(LIBSECP256K1) test_fuzz_blocklocator_deserialize_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS) -test_fuzz_blockmerkleroot_SOURCES = $(FUZZ_SUITE) test/test_bitcoin_fuzzy.cpp +test_fuzz_blockmerkleroot_SOURCES = $(FUZZ_SUITE) test/fuzz/deserialize.cpp test_fuzz_blockmerkleroot_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DBLOCKMERKLEROOT=1 test_fuzz_blockmerkleroot_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) test_fuzz_blockmerkleroot_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) @@ -239,7 +241,7 @@ test_fuzz_blockmerkleroot_LDADD = \ $(LIBSECP256K1) test_fuzz_blockmerkleroot_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS) -test_fuzz_addrman_deserialize_SOURCES = $(FUZZ_SUITE) test/test_bitcoin_fuzzy.cpp +test_fuzz_addrman_deserialize_SOURCES = $(FUZZ_SUITE) test/fuzz/deserialize.cpp test_fuzz_addrman_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DADDRMAN_DESERIALIZE=1 test_fuzz_addrman_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) test_fuzz_addrman_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) @@ -256,7 +258,7 @@ test_fuzz_addrman_deserialize_LDADD = \ $(LIBSECP256K1) test_fuzz_addrman_deserialize_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS) -test_fuzz_blockheader_deserialize_SOURCES = $(FUZZ_SUITE) test/test_bitcoin_fuzzy.cpp +test_fuzz_blockheader_deserialize_SOURCES = $(FUZZ_SUITE) test/fuzz/deserialize.cpp test_fuzz_blockheader_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DBLOCKHEADER_DESERIALIZE=1 test_fuzz_blockheader_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) test_fuzz_blockheader_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) @@ -273,7 +275,7 @@ test_fuzz_blockheader_deserialize_LDADD = \ $(LIBSECP256K1) test_fuzz_blockheader_deserialize_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS) -test_fuzz_banentry_deserialize_SOURCES = $(FUZZ_SUITE) test/test_bitcoin_fuzzy.cpp +test_fuzz_banentry_deserialize_SOURCES = $(FUZZ_SUITE) test/fuzz/deserialize.cpp test_fuzz_banentry_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DBANENTRY_DESERIALIZE=1 test_fuzz_banentry_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) test_fuzz_banentry_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) @@ -290,7 +292,7 @@ test_fuzz_banentry_deserialize_LDADD = \ $(LIBSECP256K1) test_fuzz_banentry_deserialize_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS) -test_fuzz_txundo_deserialize_SOURCES = $(FUZZ_SUITE) test/test_bitcoin_fuzzy.cpp +test_fuzz_txundo_deserialize_SOURCES = $(FUZZ_SUITE) test/fuzz/deserialize.cpp test_fuzz_txundo_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DTXUNDO_DESERIALIZE=1 test_fuzz_txundo_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) test_fuzz_txundo_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) @@ -307,7 +309,7 @@ test_fuzz_txundo_deserialize_LDADD = \ $(LIBSECP256K1) test_fuzz_txundo_deserialize_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS) -test_fuzz_blockundo_deserialize_SOURCES = $(FUZZ_SUITE) test/test_bitcoin_fuzzy.cpp +test_fuzz_blockundo_deserialize_SOURCES = $(FUZZ_SUITE) test/fuzz/deserialize.cpp test_fuzz_blockundo_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DBLOCKUNDO_DESERIALIZE=1 test_fuzz_blockundo_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) test_fuzz_blockundo_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) @@ -324,7 +326,7 @@ test_fuzz_blockundo_deserialize_LDADD = \ $(LIBSECP256K1) test_fuzz_blockundo_deserialize_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS) -test_fuzz_coins_deserialize_SOURCES = $(FUZZ_SUITE) test/test_bitcoin_fuzzy.cpp +test_fuzz_coins_deserialize_SOURCES = $(FUZZ_SUITE) test/fuzz/deserialize.cpp test_fuzz_coins_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DCOINS_DESERIALIZE=1 test_fuzz_coins_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) test_fuzz_coins_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) @@ -341,7 +343,7 @@ test_fuzz_coins_deserialize_LDADD = \ $(LIBSECP256K1) test_fuzz_coins_deserialize_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS) -test_fuzz_netaddr_deserialize_SOURCES = $(FUZZ_SUITE) test/test_bitcoin_fuzzy.cpp +test_fuzz_netaddr_deserialize_SOURCES = $(FUZZ_SUITE) test/fuzz/deserialize.cpp test_fuzz_netaddr_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DNETADDR_DESERIALIZE=1 test_fuzz_netaddr_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) test_fuzz_netaddr_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) @@ -358,7 +360,24 @@ test_fuzz_netaddr_deserialize_LDADD = \ $(LIBSECP256K1) test_fuzz_netaddr_deserialize_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS) -test_fuzz_service_deserialize_SOURCES = $(FUZZ_SUITE) test/test_bitcoin_fuzzy.cpp +test_fuzz_script_flags_SOURCES = $(FUZZ_SUITE) test/fuzz/script_flags.cpp +test_fuzz_script_flags_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) +test_fuzz_script_flags_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) +test_fuzz_script_flags_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) +test_fuzz_script_flags_LDADD = \ + $(LIBUNIVALUE) \ + $(LIBBITCOIN_SERVER) \ + $(LIBBITCOIN_COMMON) \ + $(LIBBITCOIN_UTIL) \ + $(LIBBITCOIN_CONSENSUS) \ + $(LIBBITCOIN_CRYPTO) \ + $(LIBBITCOIN_CRYPTO_SSE41) \ + $(LIBBITCOIN_CRYPTO_AVX2) \ + $(LIBBITCOIN_CRYPTO_SHANI) \ + $(LIBSECP256K1) +test_fuzz_script_flags_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS) + +test_fuzz_service_deserialize_SOURCES = $(FUZZ_SUITE) test/fuzz/deserialize.cpp test_fuzz_service_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DSERVICE_DESERIALIZE=1 test_fuzz_service_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) test_fuzz_service_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) @@ -375,7 +394,7 @@ test_fuzz_service_deserialize_LDADD = \ $(LIBSECP256K1) test_fuzz_service_deserialize_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS) -test_fuzz_messageheader_deserialize_SOURCES = $(FUZZ_SUITE) test/test_bitcoin_fuzzy.cpp +test_fuzz_messageheader_deserialize_SOURCES = $(FUZZ_SUITE) test/fuzz/deserialize.cpp test_fuzz_messageheader_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DMESSAGEHEADER_DESERIALIZE=1 test_fuzz_messageheader_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) test_fuzz_messageheader_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) @@ -392,7 +411,7 @@ test_fuzz_messageheader_deserialize_LDADD = \ $(LIBSECP256K1) test_fuzz_messageheader_deserialize_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS) -test_fuzz_address_deserialize_SOURCES = $(FUZZ_SUITE) test/test_bitcoin_fuzzy.cpp +test_fuzz_address_deserialize_SOURCES = $(FUZZ_SUITE) test/fuzz/deserialize.cpp test_fuzz_address_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DADDRESS_DESERIALIZE=1 test_fuzz_address_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) test_fuzz_address_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) @@ -409,7 +428,7 @@ test_fuzz_address_deserialize_LDADD = \ $(LIBSECP256K1) test_fuzz_address_deserialize_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS) -test_fuzz_inv_deserialize_SOURCES = $(FUZZ_SUITE) test/test_bitcoin_fuzzy.cpp +test_fuzz_inv_deserialize_SOURCES = $(FUZZ_SUITE) test/fuzz/deserialize.cpp test_fuzz_inv_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DINV_DESERIALIZE=1 test_fuzz_inv_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) test_fuzz_inv_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) @@ -426,7 +445,7 @@ test_fuzz_inv_deserialize_LDADD = \ $(LIBSECP256K1) test_fuzz_inv_deserialize_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS) -test_fuzz_bloomfilter_deserialize_SOURCES = $(FUZZ_SUITE) test/test_bitcoin_fuzzy.cpp +test_fuzz_bloomfilter_deserialize_SOURCES = $(FUZZ_SUITE) test/fuzz/deserialize.cpp test_fuzz_bloomfilter_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DBLOOMFILTER_DESERIALIZE=1 test_fuzz_bloomfilter_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) test_fuzz_bloomfilter_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) @@ -443,7 +462,7 @@ test_fuzz_bloomfilter_deserialize_LDADD = \ $(LIBSECP256K1) test_fuzz_bloomfilter_deserialize_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS) -test_fuzz_diskblockindex_deserialize_SOURCES = $(FUZZ_SUITE) test/test_bitcoin_fuzzy.cpp +test_fuzz_diskblockindex_deserialize_SOURCES = $(FUZZ_SUITE) test/fuzz/deserialize.cpp test_fuzz_diskblockindex_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DDISKBLOCKINDEX_DESERIALIZE=1 test_fuzz_diskblockindex_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) test_fuzz_diskblockindex_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) @@ -460,7 +479,7 @@ test_fuzz_diskblockindex_deserialize_LDADD = \ $(LIBSECP256K1) test_fuzz_diskblockindex_deserialize_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS) -test_fuzz_txoutcompressor_deserialize_SOURCES = $(FUZZ_SUITE) test/test_bitcoin_fuzzy.cpp +test_fuzz_txoutcompressor_deserialize_SOURCES = $(FUZZ_SUITE) test/fuzz/deserialize.cpp test_fuzz_txoutcompressor_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DTXOUTCOMPRESSOR_DESERIALIZE=1 test_fuzz_txoutcompressor_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) test_fuzz_txoutcompressor_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) @@ -477,7 +496,7 @@ test_fuzz_txoutcompressor_deserialize_LDADD = \ $(LIBSECP256K1) test_fuzz_txoutcompressor_deserialize_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS) -test_fuzz_blocktransactions_deserialize_SOURCES = $(FUZZ_SUITE) test/test_bitcoin_fuzzy.cpp +test_fuzz_blocktransactions_deserialize_SOURCES = $(FUZZ_SUITE) test/fuzz/deserialize.cpp test_fuzz_blocktransactions_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DBLOCKTRANSACTIONS_DESERIALIZE=1 test_fuzz_blocktransactions_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) test_fuzz_blocktransactions_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) @@ -494,7 +513,7 @@ test_fuzz_blocktransactions_deserialize_LDADD = \ $(LIBSECP256K1) test_fuzz_blocktransactions_deserialize_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS) -test_fuzz_blocktransactionsrequest_deserialize_SOURCES = $(FUZZ_SUITE) test/test_bitcoin_fuzzy.cpp +test_fuzz_blocktransactionsrequest_deserialize_SOURCES = $(FUZZ_SUITE) test/fuzz/deserialize.cpp test_fuzz_blocktransactionsrequest_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DBLOCKTRANSACTIONSREQUEST_DESERIALIZE=1 test_fuzz_blocktransactionsrequest_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) test_fuzz_blocktransactionsrequest_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) diff --git a/src/bench/bench_bitcoin.cpp b/src/bench/bench_bitcoin.cpp index b804a84478..d67b2c5bc7 100644 --- a/src/bench/bench_bitcoin.cpp +++ b/src/bench/bench_bitcoin.cpp @@ -24,7 +24,8 @@ static const int64_t DEFAULT_PLOT_HEIGHT = 768; static void SetupBenchArgs() { - gArgs.AddArg("-?", "Print this help message and exit", false, OptionsCategory::OPTIONS); + SetupHelpOptions(gArgs); + gArgs.AddArg("-list", "List benchmarks without executing them. Can be combined with -scaling and -filter", false, OptionsCategory::OPTIONS); gArgs.AddArg("-evals=<n>", strprintf("Number of measurement evaluations to perform. (default: %u)", DEFAULT_BENCH_EVALUATIONS), false, OptionsCategory::OPTIONS); gArgs.AddArg("-filter=<regex>", strprintf("Regular expression filter to select benchmark by name (default: %s)", DEFAULT_BENCH_FILTER), false, OptionsCategory::OPTIONS); @@ -33,10 +34,6 @@ static void SetupBenchArgs() gArgs.AddArg("-plot-plotlyurl=<uri>", strprintf("URL to use for plotly.js (default: %s)", DEFAULT_PLOT_PLOTLYURL), false, OptionsCategory::OPTIONS); gArgs.AddArg("-plot-width=<x>", strprintf("Plot width in pixel (default: %u)", DEFAULT_PLOT_WIDTH), false, OptionsCategory::OPTIONS); gArgs.AddArg("-plot-height=<x>", strprintf("Plot height in pixel (default: %u)", DEFAULT_PLOT_HEIGHT), false, OptionsCategory::OPTIONS); - - // Hidden - gArgs.AddArg("-h", "", false, OptionsCategory::HIDDEN); - gArgs.AddArg("-help", "", false, OptionsCategory::HIDDEN); } static fs::path SetDataDir() diff --git a/src/bench/block_assemble.cpp b/src/bench/block_assemble.cpp index 8133fd9d65..cd4543c012 100644 --- a/src/bench/block_assemble.cpp +++ b/src/bench/block_assemble.cpp @@ -73,10 +73,12 @@ static void AssembleBlock(benchmark::State& state) boost::thread_group thread_group; CScheduler scheduler; { + LOCK(cs_main); ::pblocktree.reset(new CBlockTreeDB(1 << 20, true)); ::pcoinsdbview.reset(new CCoinsViewDB(1 << 23, true)); ::pcoinsTip.reset(new CCoinsViewCache(pcoinsdbview.get())); - + } + { const CChainParams& chainparams = Params(); thread_group.create_thread(std::bind(&CScheduler::serviceQueue, &scheduler)); GetMainSignals().RegisterBackgroundSignalScheduler(scheduler); diff --git a/src/bench/duplicate_inputs.cpp b/src/bench/duplicate_inputs.cpp index e0854e2c62..1f6840d813 100644 --- a/src/bench/duplicate_inputs.cpp +++ b/src/bench/duplicate_inputs.cpp @@ -37,10 +37,12 @@ static void DuplicateInputs(benchmark::State& state) CScheduler scheduler; const CChainParams& chainparams = Params(); { + LOCK(cs_main); ::pblocktree.reset(new CBlockTreeDB(1 << 20, true)); ::pcoinsdbview.reset(new CCoinsViewDB(1 << 23, true)); ::pcoinsTip.reset(new CCoinsViewCache(pcoinsdbview.get())); - + } + { thread_group.create_thread(std::bind(&CScheduler::serviceQueue, &scheduler)); GetMainSignals().RegisterBackgroundSignalScheduler(scheduler); LoadGenesisBlock(chainparams); diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp index 7cdf61ad35..b0e1f67d93 100644 --- a/src/bitcoin-cli.cpp +++ b/src/bitcoin-cli.cpp @@ -34,11 +34,12 @@ static const int CONTINUE_EXECUTION=-1; static void SetupCliArgs() { + SetupHelpOptions(gArgs); + const auto defaultBaseParams = CreateBaseChainParams(CBaseChainParams::MAIN); const auto testnetBaseParams = CreateBaseChainParams(CBaseChainParams::TESTNET); const auto regtestBaseParams = CreateBaseChainParams(CBaseChainParams::REGTEST); - gArgs.AddArg("-?", "This help message", false, OptionsCategory::OPTIONS); gArgs.AddArg("-version", "Print version and exit", false, OptionsCategory::OPTIONS); gArgs.AddArg("-conf=<file>", strprintf("Specify configuration file. Relative paths will be prefixed by datadir location. (default: %s)", BITCOIN_CONF_FILENAME), false, OptionsCategory::OPTIONS); gArgs.AddArg("-datadir=<dir>", "Specify data directory", false, OptionsCategory::OPTIONS); @@ -55,10 +56,6 @@ static void SetupCliArgs() gArgs.AddArg("-rpcwallet=<walletname>", "Send RPC for non-default wallet on RPC server (needs to exactly match corresponding -wallet option passed to bitcoind). This changes the RPC endpoint used, e.g. http://127.0.0.1:8332/wallet/<walletname>", false, OptionsCategory::OPTIONS); gArgs.AddArg("-stdin", "Read extra arguments from standard input, one per line until EOF/Ctrl-D (recommended for sensitive information such as passphrases). When combined with -stdinrpcpass, the first line from standard input is used for the RPC password.", false, OptionsCategory::OPTIONS); gArgs.AddArg("-stdinrpcpass", "Read RPC password from standard input as a single line. When combined with -stdin, the first line from standard input is used for the RPC password.", false, OptionsCategory::OPTIONS); - - // Hidden - gArgs.AddArg("-h", "", false, OptionsCategory::HIDDEN); - gArgs.AddArg("-help", "", false, OptionsCategory::HIDDEN); } /** libevent event log callback */ diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp index 7c0c674a00..4be89aab6c 100644 --- a/src/bitcoin-tx.cpp +++ b/src/bitcoin-tx.cpp @@ -35,7 +35,8 @@ const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr; static void SetupBitcoinTxArgs() { - gArgs.AddArg("-?", "This help message", false, OptionsCategory::OPTIONS); + SetupHelpOptions(gArgs); + gArgs.AddArg("-create", "Create new, empty TX.", false, OptionsCategory::OPTIONS); gArgs.AddArg("-json", "Select JSON output", false, OptionsCategory::OPTIONS); gArgs.AddArg("-txid", "Output only the hex-encoded transaction id of the resultant transaction.", false, OptionsCategory::OPTIONS); @@ -62,14 +63,10 @@ static void SetupBitcoinTxArgs() "This command requires JSON registers:" "prevtxs=JSON object, " "privatekeys=JSON object. " - "See signrawtransaction docs for format of sighash flags, JSON objects.", false, OptionsCategory::COMMANDS); + "See signrawtransactionwithkey docs for format of sighash flags, JSON objects.", false, OptionsCategory::COMMANDS); gArgs.AddArg("load=NAME:FILENAME", "Load JSON file FILENAME into register NAME", false, OptionsCategory::REGISTER_COMMANDS); gArgs.AddArg("set=NAME:JSON-STRING", "Set register NAME to given JSON-STRING", false, OptionsCategory::REGISTER_COMMANDS); - - // Hidden - gArgs.AddArg("-h", "", false, OptionsCategory::HIDDEN); - gArgs.AddArg("-help", "", false, OptionsCategory::HIDDEN); } // diff --git a/src/bitcoin-wallet.cpp b/src/bitcoin-wallet.cpp index 293e3efa5c..32a539aac6 100644 --- a/src/bitcoin-wallet.cpp +++ b/src/bitcoin-wallet.cpp @@ -20,9 +20,9 @@ const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr; static void SetupWalletToolArgs() { + SetupHelpOptions(gArgs); SetupChainParamsBaseOptions(); - gArgs.AddArg("-?", "This help message", false, OptionsCategory::OPTIONS); gArgs.AddArg("-datadir=<dir>", "Specify data directory", false, OptionsCategory::OPTIONS); gArgs.AddArg("-wallet=<wallet-name>", "Specify wallet name", false, OptionsCategory::OPTIONS); gArgs.AddArg("-debug=<category>", "Output debugging information (default: 0).", false, OptionsCategory::DEBUG_TEST); @@ -30,10 +30,6 @@ static void SetupWalletToolArgs() gArgs.AddArg("info", "Get wallet info", false, OptionsCategory::COMMANDS); gArgs.AddArg("create", "Create new wallet file", false, OptionsCategory::COMMANDS); - - // Hidden - gArgs.AddArg("-h", "", false, OptionsCategory::HIDDEN); - gArgs.AddArg("-help", "", false, OptionsCategory::HIDDEN); } static bool WalletAppInit(int argc, char* argv[]) @@ -58,7 +54,7 @@ static bool WalletAppInit(int argc, char* argv[]) } // check for printtoconsole, allow -debug - g_logger->m_print_to_console = gArgs.GetBoolArg("-printtoconsole", gArgs.GetBoolArg("-debug", false)); + LogInstance().m_print_to_console = gArgs.GetBoolArg("-printtoconsole", gArgs.GetBoolArg("-debug", false)); if (!fs::is_directory(GetDataDir(false))) { fprintf(stderr, "Error: Specified data directory \"%s\" does not exist.\n", gArgs.GetArg("-datadir", "").c_str()); diff --git a/src/chainparams.cpp b/src/chainparams.cpp index d3972fdb89..b8e0ea23dd 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -91,10 +91,10 @@ public: consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout = 1510704000; // November 15th, 2017. // The best chain should have at least this much work. - consensus.nMinimumChainWork = uint256S("0x0000000000000000000000000000000000000000028822fef1c230963535a90d"); + consensus.nMinimumChainWork = uint256S("0x0000000000000000000000000000000000000000051dc8b82f450202ecb3d471"); // By default assume that the signatures in ancestors of this block are valid. - consensus.defaultAssumeValid = uint256S("0x0000000000000000002e63058c023a9a1de233554f28c7b21380b6c9003f36a8"); //534292 + consensus.defaultAssumeValid = uint256S("0x0000000000000000000f1c54590ee18d15ec70e68c8cd4cfbadb1b4f11697eee"); //563378 /** * The message start string is designed to be unlikely to occur in normal data. @@ -107,7 +107,7 @@ public: pchMessageStart[3] = 0xd9; nDefaultPort = 8333; nPruneAfterHeight = 100000; - m_assumed_blockchain_size = 200; + m_assumed_blockchain_size = 240; m_assumed_chain_state_size = 3; genesis = CreateGenesisBlock(1231006505, 2083236893, 0x1d00ffff, 1, 50 * COIN); @@ -162,10 +162,10 @@ public: }; chainTxData = ChainTxData{ - // Data from rpc: getchaintxstats 4096 0000000000000000002e63058c023a9a1de233554f28c7b21380b6c9003f36a8 - /* nTime */ 1532884444, - /* nTxCount */ 331282217, - /* dTxRate */ 2.4 + // Data from rpc: getchaintxstats 4096 0000000000000000000f1c54590ee18d15ec70e68c8cd4cfbadb1b4f11697eee + /* nTime */ 1550374134, + /* nTxCount */ 383732546, + /* dTxRate */ 3.685496590998308 }; /* disable fallback fee on mainnet */ @@ -219,7 +219,7 @@ public: pchMessageStart[3] = 0x07; nDefaultPort = 18333; nPruneAfterHeight = 1000; - m_assumed_blockchain_size = 20; + m_assumed_blockchain_size = 30; m_assumed_chain_state_size = 2; genesis = CreateGenesisBlock(1296688602, 414098458, 0x1d00ffff, 1, 50 * COIN); diff --git a/src/compat.h b/src/compat.h index 7b164d5630..68f6eb692c 100644 --- a/src/compat.h +++ b/src/compat.h @@ -11,10 +11,6 @@ #endif #ifdef WIN32 -#ifdef _WIN32_WINNT -#undef _WIN32_WINNT -#endif -#define _WIN32_WINNT 0x0501 #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN 1 #endif diff --git a/src/compat/assumptions.h b/src/compat/assumptions.h new file mode 100644 index 0000000000..820c9b93d9 --- /dev/null +++ b/src/compat/assumptions.h @@ -0,0 +1,49 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2019 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +// Compile-time verification of assumptions we make. + +#ifndef BITCOIN_COMPAT_ASSUMPTIONS_H +#define BITCOIN_COMPAT_ASSUMPTIONS_H + +#include <limits> + +// Assumption: We assume that the macro NDEBUG is not defined. +// Example(s): We use assert(...) extensively with the assumption of it never +// being a noop at runtime. +#if defined(NDEBUG) +# error "Bitcoin cannot be compiled without assertions." +#endif + +// Assumption: We assume the floating-point types to fulfill the requirements of +// IEC 559 (IEEE 754) standard. +// Example(s): Floating-point division by zero in ConnectBlock, CreateTransaction +// and EstimateMedianVal. +static_assert(std::numeric_limits<float>::is_iec559, "IEEE 754 float assumed"); +static_assert(std::numeric_limits<double>::is_iec559, "IEEE 754 double assumed"); + +// Assumption: We assume eight bits per byte (obviously, but remember: don't +// trust -- verify!). +// Example(s): Everywhere :-) +static_assert(std::numeric_limits<unsigned char>::digits == 8, "8-bit byte assumed"); + +// Assumption: We assume floating-point widths. +// Example(s): Type punning in serialization code (ser_{float,double}_to_uint{32,64}). +static_assert(sizeof(float) == 4, "32-bit float assumed"); +static_assert(sizeof(double) == 8, "64-bit double assumed"); + +// Assumption: We assume integer widths. +// Example(s): GetSizeOfCompactSize and WriteCompactSize in the serialization +// code. +static_assert(sizeof(short) == 2, "16-bit short assumed"); +static_assert(sizeof(int) == 4, "32-bit int assumed"); + +// Some important things we are NOT assuming (non-exhaustive list): +// * We are NOT assuming a specific value for sizeof(std::size_t). +// * We are NOT assuming a specific value for std::endian::native. +// * We are NOT assuming a specific value for std::locale("").name(). +// * We are NOT assuming a specific value for std::numeric_limits<char>::is_signed. + +#endif // BITCOIN_COMPAT_ASSUMPTIONS_H diff --git a/src/core_io.h b/src/core_io.h index 6f87161f46..ae377eb6e8 100644 --- a/src/core_io.h +++ b/src/core_io.h @@ -37,7 +37,11 @@ bool DecodeHexBlockHeader(CBlockHeader&, const std::string& hex_header); */ bool ParseHashStr(const std::string& strHex, uint256& result); std::vector<unsigned char> ParseHexUV(const UniValue& v, const std::string& strName); -NODISCARD bool DecodePSBT(PartiallySignedTransaction& psbt, const std::string& base64_tx, std::string& error); + +//! Decode a base64ed PSBT into a PartiallySignedTransaction +NODISCARD bool DecodeBase64PSBT(PartiallySignedTransaction& decoded_psbt, const std::string& base64_psbt, std::string& error); +//! Decode a raw (binary blob) PSBT into a PartiallySignedTransaction +NODISCARD bool DecodeRawPSBT(PartiallySignedTransaction& decoded_psbt, const std::string& raw_psbt, std::string& error); int ParseSighashString(const UniValue& sighash); // core_write.cpp diff --git a/src/core_read.cpp b/src/core_read.cpp index 3b82b2853c..536a7f4f17 100644 --- a/src/core_read.cpp +++ b/src/core_read.cpp @@ -4,6 +4,7 @@ #include <core_io.h> +#include <psbt.h> #include <primitives/block.h> #include <primitives/transaction.h> #include <script/script.h> @@ -176,10 +177,20 @@ bool DecodeHexBlk(CBlock& block, const std::string& strHexBlk) return true; } -bool DecodePSBT(PartiallySignedTransaction& psbt, const std::string& base64_tx, std::string& error) +bool DecodeBase64PSBT(PartiallySignedTransaction& psbt, const std::string& base64_tx, std::string& error) { - std::vector<unsigned char> tx_data = DecodeBase64(base64_tx.c_str()); - CDataStream ss_data(tx_data, SER_NETWORK, PROTOCOL_VERSION); + bool invalid; + std::string tx_data = DecodeBase64(base64_tx, &invalid); + if (invalid) { + error = "invalid base64"; + return false; + } + return DecodeRawPSBT(psbt, tx_data, error); +} + +bool DecodeRawPSBT(PartiallySignedTransaction& psbt, const std::string& tx_data, std::string& error) +{ + CDataStream ss_data(tx_data.data(), tx_data.data() + tx_data.size(), SER_NETWORK, PROTOCOL_VERSION); try { ss_data >> psbt; if (!ss_data.empty()) { diff --git a/src/dummywallet.cpp b/src/dummywallet.cpp index 9211a7596b..8a76021a5b 100644 --- a/src/dummywallet.cpp +++ b/src/dummywallet.cpp @@ -8,6 +8,10 @@ class CWallet; +namespace interfaces { +class Chain; +} + class DummyWalletInit : public WalletInitInterface { public: @@ -43,6 +47,11 @@ std::vector<std::shared_ptr<CWallet>> GetWallets() throw std::logic_error("Wallet function called in non-wallet build."); } +std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const std::string& name, std::string& error, std::string& warning) +{ + throw std::logic_error("Wallet function called in non-wallet build."); +} + namespace interfaces { class Wallet; diff --git a/src/fs.cpp b/src/fs.cpp index 3c8f4c0247..f937f64e04 100644 --- a/src/fs.cpp +++ b/src/fs.cpp @@ -160,6 +160,7 @@ static std::string openmodeToStr(std::ios_base::openmode mode) void ifstream::open(const fs::path& p, std::ios_base::openmode mode) { close(); + mode |= std::ios_base::in; m_file = fsbridge::fopen(p, openmodeToStr(mode).c_str()); if (m_file == nullptr) { return; @@ -183,6 +184,7 @@ void ifstream::close() void ofstream::open(const fs::path& p, std::ios_base::openmode mode) { close(); + mode |= std::ios_base::out; m_file = fsbridge::fopen(p, openmodeToStr(mode).c_str()); if (m_file == nullptr) { return; diff --git a/src/httpserver.cpp b/src/httpserver.cpp index ca60ea43a7..b9ca037c9d 100644 --- a/src/httpserver.cpp +++ b/src/httpserver.cpp @@ -364,8 +364,8 @@ bool InitHTTPServer() // Update libevent's log handling. Returns false if our version of // libevent doesn't support debug logging, in which case we should // clear the BCLog::LIBEVENT flag. - if (!UpdateHTTPServerLogging(g_logger->WillLogCategory(BCLog::LIBEVENT))) { - g_logger->DisableCategory(BCLog::LIBEVENT); + if (!UpdateHTTPServerLogging(LogInstance().WillLogCategory(BCLog::LIBEVENT))) { + LogInstance().DisableCategory(BCLog::LIBEVENT); } #ifdef WIN32 diff --git a/src/init.cpp b/src/init.cpp index 019b2e469e..8876b54fde 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -53,6 +53,8 @@ #include <stdio.h> #ifndef WIN32 +#include <attributes.h> +#include <cerrno> #include <signal.h> #include <sys/stat.h> #endif @@ -92,6 +94,32 @@ std::unique_ptr<BanMan> g_banman; static const char* FEE_ESTIMATES_FILENAME="fee_estimates.dat"; +/** + * The PID file facilities. + */ +static const char* BITCOIN_PID_FILENAME = "bitcoind.pid"; + +static fs::path GetPidFile() +{ + return AbsPathForConfigVal(fs::path(gArgs.GetArg("-pid", BITCOIN_PID_FILENAME))); +} + +NODISCARD static bool CreatePidFile() +{ + FILE* file = fsbridge::fopen(GetPidFile(), "w"); + if (file) { +#ifdef WIN32 + fprintf(file, "%d\n", GetCurrentProcessId()); +#else + fprintf(file, "%d\n", getpid()); +#endif + fclose(file); + return true; + } else { + return InitError(strprintf(_("Unable to create the PID file '%s': %s"), GetPidFile().string(), std::strerror(errno))); + } +} + ////////////////////////////////////////////////////////////////////////////// // // Shutdown @@ -260,13 +288,13 @@ void Shutdown(InitInterfaces& interfaces) } #endif -#ifndef WIN32 try { - fs::remove(GetPidFile()); + if (!fs::remove(GetPidFile())) { + LogPrintf("%s: Unable to remove PID file: File does not exist\n", __func__); + } } catch (const fs::filesystem_error& e) { - LogPrintf("%s: Unable to remove pidfile: %s\n", __func__, e.what()); + LogPrintf("%s: Unable to remove PID file: %s\n", __func__, fsbridge::get_filesystem_error_message(e)); } -#endif interfaces.chain_clients.clear(); UnregisterAllValidationInterfaces(); GetMainSignals().UnregisterBackgroundSignalScheduler(); @@ -289,7 +317,7 @@ static void HandleSIGTERM(int) static void HandleSIGHUP(int) { - g_logger->m_reopen_file = true; + LogInstance().m_reopen_file = true; } #else static BOOL WINAPI consoleCtrlHandler(DWORD dwCtrlType) @@ -326,6 +354,9 @@ static void OnRPCStopped() void SetupServerArgs() { + SetupHelpOptions(gArgs); + gArgs.AddArg("-help-debug", "Print help message with debugging options and exit", false, OptionsCategory::DEBUG_TEST); // server-only for now + const auto defaultBaseParams = CreateBaseChainParams(CBaseChainParams::MAIN); const auto testnetBaseParams = CreateBaseChainParams(CBaseChainParams::TESTNET); const auto regtestBaseParams = CreateBaseChainParams(CBaseChainParams::REGTEST); @@ -334,14 +365,11 @@ void SetupServerArgs() const auto regtestChainParams = CreateChainParams(CBaseChainParams::REGTEST); // Hidden Options - std::vector<std::string> hidden_args = {"-h", "-help", + std::vector<std::string> hidden_args = { "-dbcrashratio", "-forcecompactdb", // GUI args. These will be overwritten by SetupUIArgs for the GUI "-allowselfsignedrootcertificates", "-choosedatadir", "-lang=<lang>", "-min", "-resetguisettings", "-rootcertificates=<file>", "-splash", "-uiplatform"}; - // Set all of the args and their help - // When adding new options to the categories, please keep and ensure alphabetical ordering. - gArgs.AddArg("-?", "Print this help message and exit", false, OptionsCategory::OPTIONS); gArgs.AddArg("-version", "Print version and exit", false, OptionsCategory::OPTIONS); gArgs.AddArg("-alertnotify=<cmd>", "Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message)", false, OptionsCategory::OPTIONS); gArgs.AddArg("-assumevalid=<hex>", strprintf("If this block is in the chain assume that it and its ancestors are valid and potentially skip their script verification (0 to verify all, default: %s, testnet: %s)", defaultChainParams->GetConsensus().defaultAssumeValid.GetHex(), testnetChainParams->GetConsensus().defaultAssumeValid.GetHex()), false, OptionsCategory::OPTIONS); @@ -352,7 +380,7 @@ void SetupServerArgs() gArgs.AddArg("-conf=<file>", strprintf("Specify configuration file. Relative paths will be prefixed by datadir location. (default: %s)", BITCOIN_CONF_FILENAME), false, OptionsCategory::OPTIONS); gArgs.AddArg("-datadir=<dir>", "Specify data directory", false, OptionsCategory::OPTIONS); gArgs.AddArg("-dbbatchsize", strprintf("Maximum database write batch size in bytes (default: %u)", nDefaultDbBatchSize), true, OptionsCategory::OPTIONS); - gArgs.AddArg("-dbcache=<n>", strprintf("Set database cache size in MiB (%d to %d, default: %d)", nMinDbCache, nMaxDbCache, nDefaultDbCache), false, OptionsCategory::OPTIONS); + gArgs.AddArg("-dbcache=<n>", strprintf("Maximum database cache size <n> MiB (%d to %d, default: %d). In addition, unused mempool memory is shared for this cache (see -maxmempool).", nMinDbCache, nMaxDbCache, nDefaultDbCache), false, OptionsCategory::OPTIONS); gArgs.AddArg("-debuglogfile=<file>", strprintf("Specify location of debug log file. Relative paths will be prefixed by a net-specific datadir location. (-nodebuglogfile to disable; default: %s)", DEFAULT_DEBUGLOGFILE), false, OptionsCategory::OPTIONS); gArgs.AddArg("-feefilter", strprintf("Tell other nodes to filter invs to us by our mempool min fee (default: %u)", DEFAULT_FEEFILTER), true, OptionsCategory::OPTIONS); gArgs.AddArg("-includeconf=<file>", "Specify additional configuration file, relative to the -datadir path (only useable from configuration file, not command line)", false, OptionsCategory::OPTIONS); @@ -364,11 +392,7 @@ void SetupServerArgs() gArgs.AddArg("-par=<n>", strprintf("Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d)", -GetNumCores(), MAX_SCRIPTCHECK_THREADS, DEFAULT_SCRIPTCHECK_THREADS), false, OptionsCategory::OPTIONS); gArgs.AddArg("-persistmempool", strprintf("Whether to save the mempool on shutdown and load on restart (default: %u)", DEFAULT_PERSIST_MEMPOOL), false, OptionsCategory::OPTIONS); -#ifndef WIN32 gArgs.AddArg("-pid=<file>", strprintf("Specify pid file. Relative paths will be prefixed by a net-specific datadir location. (default: %s)", BITCOIN_PID_FILENAME), false, OptionsCategory::OPTIONS); -#else - hidden_args.emplace_back("-pid"); -#endif gArgs.AddArg("-prune=<n>", strprintf("Reduce storage requirements by enabling pruning (deleting) of old blocks. This allows the pruneblockchain RPC to be called to delete specific blocks, and enables automatic pruning of old blocks if a target size in MiB is provided. This mode is incompatible with -txindex and -rescan. " "Warning: Reverting this setting requires re-downloading the entire blockchain. " "(default: 0 = disable pruning blocks, 1 = allow manual pruning via RPC, >=%u = automatically prune block files to stay under the specified target size in MiB)", MIN_DISK_SPACE_FOR_BLOCK_FILES / 1024 / 1024), false, OptionsCategory::OPTIONS); @@ -470,7 +494,6 @@ void SetupServerArgs() gArgs.AddArg("-debug=<category>", "Output debugging information (default: -nodebug, supplying <category> is optional). " "If <category> is not supplied or if <category> = 1, output all debugging information. <category> can be: " + ListLogCategories() + ".", false, OptionsCategory::DEBUG_TEST); gArgs.AddArg("-debugexclude=<category>", strprintf("Exclude debugging information for a category. Can be used in conjunction with -debug=1 to output debug logs for all categories except one or more specified categories."), false, OptionsCategory::DEBUG_TEST); - gArgs.AddArg("-help-debug", "Print help message with debugging options and exit", false, OptionsCategory::DEBUG_TEST); gArgs.AddArg("-logips", strprintf("Include IP addresses in debug output (default: %u)", DEFAULT_LOGIPS), false, OptionsCategory::DEBUG_TEST); gArgs.AddArg("-logtimestamps", strprintf("Prepend debug output with timestamp (default: %u)", DEFAULT_LOGTIMESTAMPS), false, OptionsCategory::DEBUG_TEST); gArgs.AddArg("-logtimemicros", strprintf("Add microsecond precision to debug timestamps (default: %u)", DEFAULT_LOGTIMEMICROS), true, OptionsCategory::DEBUG_TEST); @@ -833,17 +856,17 @@ static std::string ResolveErrMsg(const char * const optname, const std::string& */ void InitLogging() { - g_logger->m_print_to_file = !gArgs.IsArgNegated("-debuglogfile"); - g_logger->m_file_path = AbsPathForConfigVal(gArgs.GetArg("-debuglogfile", DEFAULT_DEBUGLOGFILE)); + LogInstance().m_print_to_file = !gArgs.IsArgNegated("-debuglogfile"); + LogInstance().m_file_path = AbsPathForConfigVal(gArgs.GetArg("-debuglogfile", DEFAULT_DEBUGLOGFILE)); // Add newlines to the logfile to distinguish this execution from the last // one; called before console logging is set up, so this is only sent to // debug.log. LogPrintf("\n\n\n\n\n"); - g_logger->m_print_to_console = gArgs.GetBoolArg("-printtoconsole", !gArgs.GetBoolArg("-daemon", false)); - g_logger->m_log_timestamps = gArgs.GetBoolArg("-logtimestamps", DEFAULT_LOGTIMESTAMPS); - g_logger->m_log_time_micros = gArgs.GetBoolArg("-logtimemicros", DEFAULT_LOGTIMEMICROS); + LogInstance().m_print_to_console = gArgs.GetBoolArg("-printtoconsole", !gArgs.GetBoolArg("-daemon", false)); + LogInstance().m_log_timestamps = gArgs.GetBoolArg("-logtimestamps", DEFAULT_LOGTIMESTAMPS); + LogInstance().m_log_time_micros = gArgs.GetBoolArg("-logtimemicros", DEFAULT_LOGTIMEMICROS); fLogIPs = gArgs.GetBoolArg("-logips", DEFAULT_LOGIPS); @@ -891,16 +914,7 @@ bool AppInitBasicSetup() #endif #ifdef WIN32 // Enable Data Execution Prevention (DEP) - // Minimum supported OS versions: WinXP SP3, WinVista >= SP1, Win Server 2008 - // A failure is non-critical and needs no further attention! -#ifndef PROCESS_DEP_ENABLE - // We define this here, because GCCs winbase.h limits this to _WIN32_WINNT >= 0x0601 (Windows 7), - // which is not correct. Can be removed, when GCCs winbase.h is fixed! -#define PROCESS_DEP_ENABLE 0x00000001 -#endif - typedef BOOL (WINAPI *PSETPROCDEPPOL)(DWORD); - PSETPROCDEPPOL setProcDEPPol = (PSETPROCDEPPOL)GetProcAddress(GetModuleHandleA("Kernel32.dll"), "SetProcessDEPPolicy"); - if (setProcDEPPol != nullptr) setProcDEPPol(PROCESS_DEP_ENABLE); + SetProcessDEPPolicy(PROCESS_DEP_ENABLE); #endif if (!SetupNetworking()) @@ -981,7 +995,7 @@ bool AppInitParameterInteraction() if (std::none_of(categories.begin(), categories.end(), [](std::string cat){return cat == "0" || cat == "none";})) { for (const auto& cat : categories) { - if (!g_logger->EnableCategory(cat)) { + if (!LogInstance().EnableCategory(cat)) { InitWarning(strprintf(_("Unsupported logging category %s=%s."), "-debug", cat)); } } @@ -990,7 +1004,7 @@ bool AppInitParameterInteraction() // Now remove the logging categories which were explicitly excluded for (const std::string& cat : gArgs.GetArgs("-debugexclude")) { - if (!g_logger->DisableCategory(cat)) { + if (!LogInstance().DisableCategory(cat)) { InitWarning(strprintf(_("Unsupported logging category %s=%s."), "-debugexclude", cat)); } } @@ -1107,6 +1121,22 @@ bool AppInitParameterInteraction() dustRelayFee = CFeeRate(n); } + // This is required by both the wallet and node + if (gArgs.IsArgSet("-maxtxfee")) + { + CAmount nMaxFee = 0; + if (!ParseMoney(gArgs.GetArg("-maxtxfee", ""), nMaxFee)) + return InitError(AmountErrMsg("maxtxfee", gArgs.GetArg("-maxtxfee", ""))); + if (nMaxFee > HIGH_MAX_TX_FEE) + InitWarning(_("-maxtxfee is set very high! Fees this large could be paid on a single transaction.")); + maxTxFee = nMaxFee; + if (CFeeRate(maxTxFee, 1000) < ::minRelayTxFee) + { + return InitError(strprintf(_("Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)"), + gArgs.GetArg("-maxtxfee", ""), ::minRelayTxFee.ToString())); + } + } + fRequireStandard = !gArgs.GetBoolArg("-acceptnonstdtxn", !chainparams.RequireStandard()); if (chainparams.RequireStandard() && !fRequireStandard) return InitError(strprintf("acceptnonstdtxn is not currently supported for %s chain", chainparams.NetworkIDString())); @@ -1194,22 +1224,23 @@ bool AppInitMain(InitInterfaces& interfaces) { const CChainParams& chainparams = Params(); // ********************************************************* Step 4a: application initialization -#ifndef WIN32 - CreatePidFile(GetPidFile(), getpid()); -#endif - if (g_logger->m_print_to_file) { - if (gArgs.GetBoolArg("-shrinkdebugfile", g_logger->DefaultShrinkDebugFile())) { + if (!CreatePidFile()) { + // Detailed error printed inside CreatePidFile(). + return false; + } + if (LogInstance().m_print_to_file) { + if (gArgs.GetBoolArg("-shrinkdebugfile", LogInstance().DefaultShrinkDebugFile())) { // Do this first since it both loads a bunch of debug.log into memory, // and because this needs to happen before any other debug.log printing - g_logger->ShrinkDebugFile(); + LogInstance().ShrinkDebugFile(); } - if (!g_logger->OpenDebugLog()) { + if (!LogInstance().OpenDebugLog()) { return InitError(strprintf("Could not open debug log file %s", - g_logger->m_file_path.string())); + LogInstance().m_file_path.string())); } } - if (!g_logger->m_log_timestamps) + if (!LogInstance().m_log_timestamps) LogPrintf("Startup time: %s\n", FormatISO8601DateTime(GetTime())); LogPrintf("Default data directory %s\n", GetDefaultDataDir().string()); LogPrintf("Using data directory %s\n", GetDataDir().string()); diff --git a/src/interfaces/chain.cpp b/src/interfaces/chain.cpp index 38888be8a3..da810bc5e6 100644 --- a/src/interfaces/chain.cpp +++ b/src/interfaces/chain.cpp @@ -123,7 +123,7 @@ class LockImpl : public Chain::Lock CBlockIndex* block = LookupBlockIndex(hash); return block && block->GetAncestor(::chainActive.Height()) == ::chainActive.Tip(); } - CBlockLocator getLocator() override { return ::chainActive.GetLocator(); } + CBlockLocator getTipLocator() override { return ::chainActive.GetLocator(); } Optional<int> findLocatorFork(const CBlockLocator& locator) override { LockAnnotation lock(::cs_main); diff --git a/src/interfaces/chain.h b/src/interfaces/chain.h index 735d5b60df..3a54b9164e 100644 --- a/src/interfaces/chain.h +++ b/src/interfaces/chain.h @@ -96,7 +96,7 @@ public: virtual bool isPotentialTip(const uint256& hash) = 0; //! Get locator for the current chain tip. - virtual CBlockLocator getLocator() = 0; + virtual CBlockLocator getTipLocator() = 0; //! Return height of the latest block common to locator and chain, which //! is guaranteed to be an ancestor of the block used to create the diff --git a/src/interfaces/node.cpp b/src/interfaces/node.cpp index c574f960e6..96bde7e9f2 100644 --- a/src/interfaces/node.cpp +++ b/src/interfaces/node.cpp @@ -42,6 +42,7 @@ class CWallet; fs::path GetWalletDir(); std::vector<fs::path> ListWalletDir(); std::vector<std::shared_ptr<CWallet>> GetWallets(); +std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const std::string& name, std::string& error, std::string& warning); namespace interfaces { @@ -67,7 +68,7 @@ public: void initLogging() override { InitLogging(); } void initParameterInteraction() override { InitParameterInteraction(); } std::string getWarnings(const std::string& type) override { return GetWarnings(type); } - uint32_t getLogCategories() override { return g_logger->GetCategoryMask(); } + uint32_t getLogCategories() override { return LogInstance().GetCategoryMask(); } bool baseInitialize() override { return AppInitBasicSetup() && AppInitParameterInteraction() && AppInitSanityChecks() && @@ -252,6 +253,10 @@ public: } return wallets; } + std::unique_ptr<Wallet> loadWallet(const std::string& name, std::string& error, std::string& warning) override + { + return MakeWallet(LoadWallet(*m_interfaces.chain, name, error, warning)); + } std::unique_ptr<Handler> handleInitMessage(InitMessageFn fn) override { return MakeHandler(::uiInterface.InitMessage_connect(fn)); diff --git a/src/interfaces/node.h b/src/interfaces/node.h index 54c2d78338..76b93af234 100644 --- a/src/interfaces/node.h +++ b/src/interfaces/node.h @@ -192,6 +192,11 @@ public: //! Return interfaces for accessing wallets (if any). virtual std::vector<std::unique_ptr<Wallet>> getWallets() = 0; + //! Attempts to load a wallet from file or directory. + //! The loaded wallet is also notified to handlers previously registered + //! with handleLoadWallet. + virtual std::unique_ptr<Wallet> loadWallet(const std::string& name, std::string& error, std::string& warning) = 0; + //! Register handler for init messages. using InitMessageFn = std::function<void(const std::string& message)>; virtual std::unique_ptr<Handler> handleInitMessage(InitMessageFn fn) = 0; diff --git a/src/interfaces/wallet.cpp b/src/interfaces/wallet.cpp index 62ede0a95a..0dac75834e 100644 --- a/src/interfaces/wallet.cpp +++ b/src/interfaces/wallet.cpp @@ -135,55 +135,55 @@ WalletTxOut MakeWalletTxOut(interfaces::Chain::Lock& locked_chain, class WalletImpl : public Wallet { public: - explicit WalletImpl(const std::shared_ptr<CWallet>& wallet) : m_shared_wallet(wallet), m_wallet(*wallet.get()) {} + explicit WalletImpl(const std::shared_ptr<CWallet>& wallet) : m_wallet(wallet) {} bool encryptWallet(const SecureString& wallet_passphrase) override { - return m_wallet.EncryptWallet(wallet_passphrase); + return m_wallet->EncryptWallet(wallet_passphrase); } - bool isCrypted() override { return m_wallet.IsCrypted(); } - bool lock() override { return m_wallet.Lock(); } - bool unlock(const SecureString& wallet_passphrase) override { return m_wallet.Unlock(wallet_passphrase); } - bool isLocked() override { return m_wallet.IsLocked(); } + bool isCrypted() override { return m_wallet->IsCrypted(); } + bool lock() override { return m_wallet->Lock(); } + bool unlock(const SecureString& wallet_passphrase) override { return m_wallet->Unlock(wallet_passphrase); } + bool isLocked() override { return m_wallet->IsLocked(); } bool changeWalletPassphrase(const SecureString& old_wallet_passphrase, const SecureString& new_wallet_passphrase) override { - return m_wallet.ChangeWalletPassphrase(old_wallet_passphrase, new_wallet_passphrase); + return m_wallet->ChangeWalletPassphrase(old_wallet_passphrase, new_wallet_passphrase); } - void abortRescan() override { m_wallet.AbortRescan(); } - bool backupWallet(const std::string& filename) override { return m_wallet.BackupWallet(filename); } - std::string getWalletName() override { return m_wallet.GetName(); } + void abortRescan() override { m_wallet->AbortRescan(); } + bool backupWallet(const std::string& filename) override { return m_wallet->BackupWallet(filename); } + std::string getWalletName() override { return m_wallet->GetName(); } bool getKeyFromPool(bool internal, CPubKey& pub_key) override { - return m_wallet.GetKeyFromPool(pub_key, internal); + return m_wallet->GetKeyFromPool(pub_key, internal); } - bool getPubKey(const CKeyID& address, CPubKey& pub_key) override { return m_wallet.GetPubKey(address, pub_key); } - bool getPrivKey(const CKeyID& address, CKey& key) override { return m_wallet.GetKey(address, key); } - bool isSpendable(const CTxDestination& dest) override { return IsMine(m_wallet, dest) & ISMINE_SPENDABLE; } - bool haveWatchOnly() override { return m_wallet.HaveWatchOnly(); }; + bool getPubKey(const CKeyID& address, CPubKey& pub_key) override { return m_wallet->GetPubKey(address, pub_key); } + bool getPrivKey(const CKeyID& address, CKey& key) override { return m_wallet->GetKey(address, key); } + bool isSpendable(const CTxDestination& dest) override { return IsMine(*m_wallet, dest) & ISMINE_SPENDABLE; } + bool haveWatchOnly() override { return m_wallet->HaveWatchOnly(); }; bool setAddressBook(const CTxDestination& dest, const std::string& name, const std::string& purpose) override { - return m_wallet.SetAddressBook(dest, name, purpose); + return m_wallet->SetAddressBook(dest, name, purpose); } bool delAddressBook(const CTxDestination& dest) override { - return m_wallet.DelAddressBook(dest); + return m_wallet->DelAddressBook(dest); } bool getAddress(const CTxDestination& dest, std::string* name, isminetype* is_mine, std::string* purpose) override { - LOCK(m_wallet.cs_wallet); - auto it = m_wallet.mapAddressBook.find(dest); - if (it == m_wallet.mapAddressBook.end()) { + LOCK(m_wallet->cs_wallet); + auto it = m_wallet->mapAddressBook.find(dest); + if (it == m_wallet->mapAddressBook.end()) { return false; } if (name) { *name = it->second.name; } if (is_mine) { - *is_mine = IsMine(m_wallet, dest); + *is_mine = IsMine(*m_wallet, dest); } if (purpose) { *purpose = it->second.purpose; @@ -192,51 +192,52 @@ public: } std::vector<WalletAddress> getAddresses() override { - LOCK(m_wallet.cs_wallet); + LOCK(m_wallet->cs_wallet); std::vector<WalletAddress> result; - for (const auto& item : m_wallet.mapAddressBook) { - result.emplace_back(item.first, IsMine(m_wallet, item.first), item.second.name, item.second.purpose); + for (const auto& item : m_wallet->mapAddressBook) { + result.emplace_back(item.first, IsMine(*m_wallet, item.first), item.second.name, item.second.purpose); } return result; } - void learnRelatedScripts(const CPubKey& key, OutputType type) override { m_wallet.LearnRelatedScripts(key, type); } + void learnRelatedScripts(const CPubKey& key, OutputType type) override { m_wallet->LearnRelatedScripts(key, type); } bool addDestData(const CTxDestination& dest, const std::string& key, const std::string& value) override { - LOCK(m_wallet.cs_wallet); - return m_wallet.AddDestData(dest, key, value); + LOCK(m_wallet->cs_wallet); + return m_wallet->AddDestData(dest, key, value); } bool eraseDestData(const CTxDestination& dest, const std::string& key) override { - LOCK(m_wallet.cs_wallet); - return m_wallet.EraseDestData(dest, key); + LOCK(m_wallet->cs_wallet); + return m_wallet->EraseDestData(dest, key); } std::vector<std::string> getDestValues(const std::string& prefix) override { - return m_wallet.GetDestValues(prefix); + LOCK(m_wallet->cs_wallet); + return m_wallet->GetDestValues(prefix); } void lockCoin(const COutPoint& output) override { - auto locked_chain = m_wallet.chain().lock(); - LOCK(m_wallet.cs_wallet); - return m_wallet.LockCoin(output); + auto locked_chain = m_wallet->chain().lock(); + LOCK(m_wallet->cs_wallet); + return m_wallet->LockCoin(output); } void unlockCoin(const COutPoint& output) override { - auto locked_chain = m_wallet.chain().lock(); - LOCK(m_wallet.cs_wallet); - return m_wallet.UnlockCoin(output); + auto locked_chain = m_wallet->chain().lock(); + LOCK(m_wallet->cs_wallet); + return m_wallet->UnlockCoin(output); } bool isLockedCoin(const COutPoint& output) override { - auto locked_chain = m_wallet.chain().lock(); - LOCK(m_wallet.cs_wallet); - return m_wallet.IsLockedCoin(output.hash, output.n); + auto locked_chain = m_wallet->chain().lock(); + LOCK(m_wallet->cs_wallet); + return m_wallet->IsLockedCoin(output.hash, output.n); } void listLockedCoins(std::vector<COutPoint>& outputs) override { - auto locked_chain = m_wallet.chain().lock(); - LOCK(m_wallet.cs_wallet); - return m_wallet.ListLockedCoins(outputs); + auto locked_chain = m_wallet->chain().lock(); + LOCK(m_wallet->cs_wallet); + return m_wallet->ListLockedCoins(outputs); } std::unique_ptr<PendingWalletTx> createTransaction(const std::vector<CRecipient>& recipients, const CCoinControl& coin_control, @@ -245,25 +246,25 @@ public: CAmount& fee, std::string& fail_reason) override { - auto locked_chain = m_wallet.chain().lock(); - LOCK(m_wallet.cs_wallet); - auto pending = MakeUnique<PendingWalletTxImpl>(m_wallet); - if (!m_wallet.CreateTransaction(*locked_chain, recipients, pending->m_tx, pending->m_key, fee, change_pos, + auto locked_chain = m_wallet->chain().lock(); + LOCK(m_wallet->cs_wallet); + auto pending = MakeUnique<PendingWalletTxImpl>(*m_wallet); + if (!m_wallet->CreateTransaction(*locked_chain, recipients, pending->m_tx, pending->m_key, fee, change_pos, fail_reason, coin_control, sign)) { return {}; } return std::move(pending); } - bool transactionCanBeAbandoned(const uint256& txid) override { return m_wallet.TransactionCanBeAbandoned(txid); } + bool transactionCanBeAbandoned(const uint256& txid) override { return m_wallet->TransactionCanBeAbandoned(txid); } bool abandonTransaction(const uint256& txid) override { - auto locked_chain = m_wallet.chain().lock(); - LOCK(m_wallet.cs_wallet); - return m_wallet.AbandonTransaction(*locked_chain, txid); + auto locked_chain = m_wallet->chain().lock(); + LOCK(m_wallet->cs_wallet); + return m_wallet->AbandonTransaction(*locked_chain, txid); } bool transactionCanBeBumped(const uint256& txid) override { - return feebumper::TransactionCanBeBumped(&m_wallet, txid); + return feebumper::TransactionCanBeBumped(m_wallet.get(), txid); } bool createBumpTransaction(const uint256& txid, const CCoinControl& coin_control, @@ -273,46 +274,46 @@ public: CAmount& new_fee, CMutableTransaction& mtx) override { - return feebumper::CreateTransaction(&m_wallet, txid, coin_control, total_fee, errors, old_fee, new_fee, mtx) == + return feebumper::CreateTransaction(m_wallet.get(), txid, coin_control, total_fee, errors, old_fee, new_fee, mtx) == feebumper::Result::OK; } - bool signBumpTransaction(CMutableTransaction& mtx) override { return feebumper::SignTransaction(&m_wallet, mtx); } + bool signBumpTransaction(CMutableTransaction& mtx) override { return feebumper::SignTransaction(m_wallet.get(), mtx); } bool commitBumpTransaction(const uint256& txid, CMutableTransaction&& mtx, std::vector<std::string>& errors, uint256& bumped_txid) override { - return feebumper::CommitTransaction(&m_wallet, txid, std::move(mtx), errors, bumped_txid) == + return feebumper::CommitTransaction(m_wallet.get(), txid, std::move(mtx), errors, bumped_txid) == feebumper::Result::OK; } CTransactionRef getTx(const uint256& txid) override { - auto locked_chain = m_wallet.chain().lock(); - LOCK(m_wallet.cs_wallet); - auto mi = m_wallet.mapWallet.find(txid); - if (mi != m_wallet.mapWallet.end()) { + auto locked_chain = m_wallet->chain().lock(); + LOCK(m_wallet->cs_wallet); + auto mi = m_wallet->mapWallet.find(txid); + if (mi != m_wallet->mapWallet.end()) { return mi->second.tx; } return {}; } WalletTx getWalletTx(const uint256& txid) override { - auto locked_chain = m_wallet.chain().lock(); - LOCK(m_wallet.cs_wallet); - auto mi = m_wallet.mapWallet.find(txid); - if (mi != m_wallet.mapWallet.end()) { - return MakeWalletTx(*locked_chain, m_wallet, mi->second); + auto locked_chain = m_wallet->chain().lock(); + LOCK(m_wallet->cs_wallet); + auto mi = m_wallet->mapWallet.find(txid); + if (mi != m_wallet->mapWallet.end()) { + return MakeWalletTx(*locked_chain, *m_wallet, mi->second); } return {}; } std::vector<WalletTx> getWalletTxs() override { - auto locked_chain = m_wallet.chain().lock(); - LOCK(m_wallet.cs_wallet); + auto locked_chain = m_wallet->chain().lock(); + LOCK(m_wallet->cs_wallet); std::vector<WalletTx> result; - result.reserve(m_wallet.mapWallet.size()); - for (const auto& entry : m_wallet.mapWallet) { - result.emplace_back(MakeWalletTx(*locked_chain, m_wallet, entry.second)); + result.reserve(m_wallet->mapWallet.size()); + for (const auto& entry : m_wallet->mapWallet) { + result.emplace_back(MakeWalletTx(*locked_chain, *m_wallet, entry.second)); } return result; } @@ -321,16 +322,16 @@ public: int& num_blocks, int64_t& block_time) override { - auto locked_chain = m_wallet.chain().lock(true /* try_lock */); + auto locked_chain = m_wallet->chain().lock(true /* try_lock */); if (!locked_chain) { return false; } - TRY_LOCK(m_wallet.cs_wallet, locked_wallet); + TRY_LOCK(m_wallet->cs_wallet, locked_wallet); if (!locked_wallet) { return false; } - auto mi = m_wallet.mapWallet.find(txid); - if (mi == m_wallet.mapWallet.end()) { + auto mi = m_wallet->mapWallet.find(txid); + if (mi == m_wallet->mapWallet.end()) { return false; } if (Optional<int> height = locked_chain->getHeight()) { @@ -349,106 +350,106 @@ public: bool& in_mempool, int& num_blocks) override { - auto locked_chain = m_wallet.chain().lock(); - LOCK(m_wallet.cs_wallet); - auto mi = m_wallet.mapWallet.find(txid); - if (mi != m_wallet.mapWallet.end()) { - num_blocks = locked_chain->getHeight().value_or(-1); + auto locked_chain = m_wallet->chain().lock(); + LOCK(m_wallet->cs_wallet); + auto mi = m_wallet->mapWallet.find(txid); + if (mi != m_wallet->mapWallet.end()) { + num_blocks = locked_chain->getHeight().get_value_or(-1); in_mempool = mi->second.InMempool(); order_form = mi->second.vOrderForm; tx_status = MakeWalletTxStatus(*locked_chain, mi->second); - return MakeWalletTx(*locked_chain, m_wallet, mi->second); + return MakeWalletTx(*locked_chain, *m_wallet, mi->second); } return {}; } WalletBalances getBalances() override { WalletBalances result; - result.balance = m_wallet.GetBalance(); - result.unconfirmed_balance = m_wallet.GetUnconfirmedBalance(); - result.immature_balance = m_wallet.GetImmatureBalance(); - result.have_watch_only = m_wallet.HaveWatchOnly(); + result.balance = m_wallet->GetBalance(); + result.unconfirmed_balance = m_wallet->GetUnconfirmedBalance(); + result.immature_balance = m_wallet->GetImmatureBalance(); + result.have_watch_only = m_wallet->HaveWatchOnly(); if (result.have_watch_only) { - result.watch_only_balance = m_wallet.GetBalance(ISMINE_WATCH_ONLY); - result.unconfirmed_watch_only_balance = m_wallet.GetUnconfirmedWatchOnlyBalance(); - result.immature_watch_only_balance = m_wallet.GetImmatureWatchOnlyBalance(); + result.watch_only_balance = m_wallet->GetBalance(ISMINE_WATCH_ONLY); + result.unconfirmed_watch_only_balance = m_wallet->GetUnconfirmedWatchOnlyBalance(); + result.immature_watch_only_balance = m_wallet->GetImmatureWatchOnlyBalance(); } return result; } bool tryGetBalances(WalletBalances& balances, int& num_blocks) override { - auto locked_chain = m_wallet.chain().lock(true /* try_lock */); + auto locked_chain = m_wallet->chain().lock(true /* try_lock */); if (!locked_chain) return false; - TRY_LOCK(m_wallet.cs_wallet, locked_wallet); + TRY_LOCK(m_wallet->cs_wallet, locked_wallet); if (!locked_wallet) { return false; } balances = getBalances(); - num_blocks = locked_chain->getHeight().value_or(-1); + num_blocks = locked_chain->getHeight().get_value_or(-1); return true; } - CAmount getBalance() override { return m_wallet.GetBalance(); } + CAmount getBalance() override { return m_wallet->GetBalance(); } CAmount getAvailableBalance(const CCoinControl& coin_control) override { - return m_wallet.GetAvailableBalance(&coin_control); + return m_wallet->GetAvailableBalance(&coin_control); } isminetype txinIsMine(const CTxIn& txin) override { - auto locked_chain = m_wallet.chain().lock(); - LOCK(m_wallet.cs_wallet); - return m_wallet.IsMine(txin); + auto locked_chain = m_wallet->chain().lock(); + LOCK(m_wallet->cs_wallet); + return m_wallet->IsMine(txin); } isminetype txoutIsMine(const CTxOut& txout) override { - auto locked_chain = m_wallet.chain().lock(); - LOCK(m_wallet.cs_wallet); - return m_wallet.IsMine(txout); + auto locked_chain = m_wallet->chain().lock(); + LOCK(m_wallet->cs_wallet); + return m_wallet->IsMine(txout); } CAmount getDebit(const CTxIn& txin, isminefilter filter) override { - auto locked_chain = m_wallet.chain().lock(); - LOCK(m_wallet.cs_wallet); - return m_wallet.GetDebit(txin, filter); + auto locked_chain = m_wallet->chain().lock(); + LOCK(m_wallet->cs_wallet); + return m_wallet->GetDebit(txin, filter); } CAmount getCredit(const CTxOut& txout, isminefilter filter) override { - auto locked_chain = m_wallet.chain().lock(); - LOCK(m_wallet.cs_wallet); - return m_wallet.GetCredit(txout, filter); + auto locked_chain = m_wallet->chain().lock(); + LOCK(m_wallet->cs_wallet); + return m_wallet->GetCredit(txout, filter); } CoinsList listCoins() override { - auto locked_chain = m_wallet.chain().lock(); - LOCK(m_wallet.cs_wallet); + auto locked_chain = m_wallet->chain().lock(); + LOCK(m_wallet->cs_wallet); CoinsList result; - for (const auto& entry : m_wallet.ListCoins(*locked_chain)) { + for (const auto& entry : m_wallet->ListCoins(*locked_chain)) { auto& group = result[entry.first]; for (const auto& coin : entry.second) { group.emplace_back(COutPoint(coin.tx->GetHash(), coin.i), - MakeWalletTxOut(*locked_chain, m_wallet, *coin.tx, coin.i, coin.nDepth)); + MakeWalletTxOut(*locked_chain, *m_wallet, *coin.tx, coin.i, coin.nDepth)); } } return result; } std::vector<WalletTxOut> getCoins(const std::vector<COutPoint>& outputs) override { - auto locked_chain = m_wallet.chain().lock(); - LOCK(m_wallet.cs_wallet); + auto locked_chain = m_wallet->chain().lock(); + LOCK(m_wallet->cs_wallet); std::vector<WalletTxOut> result; result.reserve(outputs.size()); for (const auto& output : outputs) { result.emplace_back(); - auto it = m_wallet.mapWallet.find(output.hash); - if (it != m_wallet.mapWallet.end()) { + auto it = m_wallet->mapWallet.find(output.hash); + if (it != m_wallet->mapWallet.end()) { int depth = it->second.GetDepthInMainChain(*locked_chain); if (depth >= 0) { - result.back() = MakeWalletTxOut(*locked_chain, m_wallet, it->second, output.n, depth); + result.back() = MakeWalletTxOut(*locked_chain, *m_wallet, it->second, output.n, depth); } } } return result; } - CAmount getRequiredFee(unsigned int tx_bytes) override { return GetRequiredFee(m_wallet, tx_bytes); } + CAmount getRequiredFee(unsigned int tx_bytes) override { return GetRequiredFee(*m_wallet, tx_bytes); } CAmount getMinimumFee(unsigned int tx_bytes, const CCoinControl& coin_control, int* returned_target, @@ -456,50 +457,54 @@ public: { FeeCalculation fee_calc; CAmount result; - result = GetMinimumFee(m_wallet, tx_bytes, coin_control, ::mempool, ::feeEstimator, &fee_calc); + result = GetMinimumFee(*m_wallet, tx_bytes, coin_control, ::mempool, ::feeEstimator, &fee_calc); if (returned_target) *returned_target = fee_calc.returnedTarget; if (reason) *reason = fee_calc.reason; return result; } - unsigned int getConfirmTarget() override { return m_wallet.m_confirm_target; } - bool hdEnabled() override { return m_wallet.IsHDEnabled(); } - bool IsWalletFlagSet(uint64_t flag) override { return m_wallet.IsWalletFlagSet(flag); } - OutputType getDefaultAddressType() override { return m_wallet.m_default_address_type; } - OutputType getDefaultChangeType() override { return m_wallet.m_default_change_type; } + unsigned int getConfirmTarget() override { return m_wallet->m_confirm_target; } + bool hdEnabled() override { return m_wallet->IsHDEnabled(); } + bool canGetAddresses() override { return m_wallet->CanGetAddresses(); } + bool IsWalletFlagSet(uint64_t flag) override { return m_wallet->IsWalletFlagSet(flag); } + OutputType getDefaultAddressType() override { return m_wallet->m_default_address_type; } + OutputType getDefaultChangeType() override { return m_wallet->m_default_change_type; } + void remove() override + { + RemoveWallet(m_wallet); + } std::unique_ptr<Handler> handleUnload(UnloadFn fn) override { - return MakeHandler(m_wallet.NotifyUnload.connect(fn)); + return MakeHandler(m_wallet->NotifyUnload.connect(fn)); } std::unique_ptr<Handler> handleShowProgress(ShowProgressFn fn) override { - return MakeHandler(m_wallet.ShowProgress.connect(fn)); + return MakeHandler(m_wallet->ShowProgress.connect(fn)); } std::unique_ptr<Handler> handleStatusChanged(StatusChangedFn fn) override { - return MakeHandler(m_wallet.NotifyStatusChanged.connect([fn](CCryptoKeyStore*) { fn(); })); + return MakeHandler(m_wallet->NotifyStatusChanged.connect([fn](CCryptoKeyStore*) { fn(); })); } std::unique_ptr<Handler> handleAddressBookChanged(AddressBookChangedFn fn) override { - return MakeHandler(m_wallet.NotifyAddressBookChanged.connect( + return MakeHandler(m_wallet->NotifyAddressBookChanged.connect( [fn](CWallet*, const CTxDestination& address, const std::string& label, bool is_mine, const std::string& purpose, ChangeType status) { fn(address, label, is_mine, purpose, status); })); } std::unique_ptr<Handler> handleTransactionChanged(TransactionChangedFn fn) override { - return MakeHandler(m_wallet.NotifyTransactionChanged.connect( + return MakeHandler(m_wallet->NotifyTransactionChanged.connect( [fn](CWallet*, const uint256& txid, ChangeType status) { fn(txid, status); })); } std::unique_ptr<Handler> handleWatchOnlyChanged(WatchOnlyChangedFn fn) override { - return MakeHandler(m_wallet.NotifyWatchonlyChanged.connect(fn)); + return MakeHandler(m_wallet->NotifyWatchonlyChanged.connect(fn)); } std::unique_ptr<Handler> handleCanGetAddressesChanged(CanGetAddressesChangedFn fn) override { - return MakeHandler(m_wallet.NotifyCanGetAddressesChanged.connect(fn)); + return MakeHandler(m_wallet->NotifyCanGetAddressesChanged.connect(fn)); } - std::shared_ptr<CWallet> m_shared_wallet; - CWallet& m_wallet; + std::shared_ptr<CWallet> m_wallet; }; class WalletClientImpl : public ChainClient @@ -523,7 +528,7 @@ public: } // namespace -std::unique_ptr<Wallet> MakeWallet(const std::shared_ptr<CWallet>& wallet) { return MakeUnique<WalletImpl>(wallet); } +std::unique_ptr<Wallet> MakeWallet(const std::shared_ptr<CWallet>& wallet) { return wallet ? MakeUnique<WalletImpl>(wallet) : nullptr; } std::unique_ptr<ChainClient> MakeWalletClient(Chain& chain, std::vector<std::string> wallet_filenames) { diff --git a/src/interfaces/wallet.h b/src/interfaces/wallet.h index 72c64ded01..a931e5fafb 100644 --- a/src/interfaces/wallet.h +++ b/src/interfaces/wallet.h @@ -235,6 +235,9 @@ public: // Return whether HD enabled. virtual bool hdEnabled() = 0; + // Return whether the wallet is blank. + virtual bool canGetAddresses() = 0; + // check if a certain wallet flag is set. virtual bool IsWalletFlagSet(uint64_t flag) = 0; @@ -244,6 +247,9 @@ public: // Get default change type. virtual OutputType getDefaultChangeType() = 0; + // Remove wallet. + virtual void remove() = 0; + //! Register handler for unload message. using UnloadFn = std::function<void()>; virtual std::unique_ptr<Handler> handleUnload(UnloadFn fn) = 0; diff --git a/src/key_io.cpp b/src/key_io.cpp index d998089535..1d53a5e074 100644 --- a/src/key_io.cpp +++ b/src/key_io.cpp @@ -142,7 +142,9 @@ CKey DecodeSecret(const std::string& str) key.Set(data.begin() + privkey_prefix.size(), data.begin() + privkey_prefix.size() + 32, compressed); } } - memory_cleanse(data.data(), data.size()); + if (!data.empty()) { + memory_cleanse(data.data(), data.size()); + } return key; } diff --git a/src/logging.cpp b/src/logging.cpp index 77dc2d0939..36cad6573a 100644 --- a/src/logging.cpp +++ b/src/logging.cpp @@ -8,6 +8,8 @@ const char * const DEFAULT_DEBUGLOGFILE = "debug.log"; +BCLog::Logger& LogInstance() +{ /** * NOTE: the logger instances is leaked on exit. This is ugly, but will be * cleaned up by the OS/libc. Defining a logger as a global object doesn't work @@ -17,11 +19,15 @@ const char * const DEFAULT_DEBUGLOGFILE = "debug.log"; * access the logger. When the shutdown sequence is fully audited and tested, * explicit destruction of these objects can be implemented by changing this * from a raw pointer to a std::unique_ptr. + * Since the destructor is never called, the logger and all its members must + * have a trivial destructor. * * This method of initialization was originally introduced in * ee3374234c60aba2cc4c5cd5cac1c0aefc2d817c. */ -BCLog::Logger* const g_logger = new BCLog::Logger(); + static BCLog::Logger* g_logger{new BCLog::Logger()}; + return *g_logger; +} bool fLogIPs = DEFAULT_LOGIPS; diff --git a/src/logging.h b/src/logging.h index 0c8e7f5291..ac9d0dc0c7 100644 --- a/src/logging.h +++ b/src/logging.h @@ -108,12 +108,12 @@ namespace BCLog { } // namespace BCLog -extern BCLog::Logger* const g_logger; +BCLog::Logger& LogInstance(); /** Return true if log accepts specified category */ static inline bool LogAcceptCategory(BCLog::LogFlags category) { - return g_logger->WillLogCategory(category); + return LogInstance().WillLogCategory(category); } /** Returns a string with the log categories. */ @@ -132,7 +132,7 @@ bool GetLogCategory(BCLog::LogFlags& flag, const std::string& str); template <typename... Args> static inline void LogPrintf(const char* fmt, const Args&... args) { - if (g_logger->Enabled()) { + if (LogInstance().Enabled()) { std::string log_msg; try { log_msg = tfm::format(fmt, args...); @@ -140,7 +140,7 @@ static inline void LogPrintf(const char* fmt, const Args&... args) /* Original format string will have newline so don't add one here */ log_msg = "Error \"" + std::string(fmterr.what()) + "\" while formatting log message: " + fmt; } - g_logger->LogPrintStr(log_msg); + LogInstance().LogPrintStr(log_msg); } } diff --git a/src/miner.cpp b/src/miner.cpp index ef48a86e32..80a2f8f018 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2018 The Bitcoin Core developers +// Copyright (c) 2009-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -10,8 +10,8 @@ #include <chainparams.h> #include <coins.h> #include <consensus/consensus.h> -#include <consensus/tx_verify.h> #include <consensus/merkle.h> +#include <consensus/tx_verify.h> #include <consensus/validation.h> #include <hash.h> #include <net.h> @@ -21,22 +21,14 @@ #include <primitives/transaction.h> #include <script/standard.h> #include <timedata.h> -#include <util/system.h> #include <util/moneystr.h> +#include <util/system.h> #include <validationinterface.h> #include <algorithm> #include <queue> #include <utility> -// Unconfirmed transactions in the memory pool often depend on other -// transactions in the memory pool. When we select transactions from the -// pool, we select by highest fee rate of a transaction combined with all -// its ancestors. - -uint64_t nLastBlockTx = 0; -uint64_t nLastBlockWeight = 0; - int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev) { int64_t nOldTime = pblock->nTime; @@ -95,6 +87,9 @@ void BlockAssembler::resetBlock() nFees = 0; } +Optional<int64_t> BlockAssembler::m_last_block_num_txs{nullopt}; +Optional<int64_t> BlockAssembler::m_last_block_weight{nullopt}; + std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn) { int64_t nTimeStart = GetTimeMicros(); @@ -147,8 +142,8 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc int64_t nTime1 = GetTimeMicros(); - nLastBlockTx = nBlockTx; - nLastBlockWeight = nBlockWeight; + m_last_block_num_txs = nBlockTx; + m_last_block_weight = nBlockWeight; // Create coinbase transaction. CMutableTransaction coinbaseTx; diff --git a/src/miner.h b/src/miner.h index 44c50b01ad..7c4c455072 100644 --- a/src/miner.h +++ b/src/miner.h @@ -1,17 +1,19 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2018 The Bitcoin Core developers +// Copyright (c) 2009-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_MINER_H #define BITCOIN_MINER_H +#include <optional.h> #include <primitives/block.h> #include <txmempool.h> #include <validation.h> -#include <stdint.h> #include <memory> +#include <stdint.h> + #include <boost/multi_index_container.hpp> #include <boost/multi_index/ordered_index.hpp> @@ -159,6 +161,9 @@ public: /** Construct a new block template with coinbase to scriptPubKeyIn */ std::unique_ptr<CBlockTemplate> CreateNewBlock(const CScript& scriptPubKeyIn); + static Optional<int64_t> m_last_block_num_txs; + static Optional<int64_t> m_last_block_weight; + private: // utility functions /** Clear the block's state and prepare for assembling a new block */ diff --git a/src/net.cpp b/src/net.cpp index be249b4466..87f1ef0577 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -58,17 +58,6 @@ static constexpr int DUMP_PEERS_INTERVAL = 15 * 60; #define MSG_DONTWAIT 0 #endif -// Fix for ancient MinGW versions, that don't have defined these in ws2tcpip.h. -// Todo: Can be removed when our pull-tester is upgraded to a modern MinGW version. -#ifdef WIN32 -#ifndef PROTECTION_LEVEL_UNRESTRICTED -#define PROTECTION_LEVEL_UNRESTRICTED 10 -#endif -#ifndef IPV6_PROTECTION_LEVEL -#define IPV6_PROTECTION_LEVEL 23 -#endif -#endif - /** Used to pass flags to the Bind() function */ enum BindFlags { BF_NONE = 0, @@ -96,8 +85,6 @@ std::map<CNetAddr, LocalServiceInfo> mapLocalHost GUARDED_BY(cs_mapLocalHost); static bool vfLimited[NET_MAX] GUARDED_BY(cs_mapLocalHost) = {}; std::string strSubVersion; -limitedmap<uint256, int64_t> mapAlreadyAskedFor(MAX_INV_SZ); - void CConnman::AddOneShot(const std::string& strDest) { LOCK(cs_vOneShots); @@ -174,8 +161,7 @@ CAddress GetLocalAddress(const CNetAddr *paddrPeer, ServiceFlags nLocalServices) static int GetnScore(const CService& addr) { LOCK(cs_mapLocalHost); - if (mapLocalHost.count(addr) == LOCAL_NONE) - return 0; + if (mapLocalHost.count(addr) == 0) return 0; return mapLocalHost[addr].nScore; } @@ -2656,40 +2642,6 @@ CNode::~CNode() CloseSocket(hSocket); } -void CNode::AskFor(const CInv& inv) -{ - if (mapAskFor.size() > MAPASKFOR_MAX_SZ || setAskFor.size() > SETASKFOR_MAX_SZ) - return; - // a peer may not have multiple non-responded queue positions for a single inv item - if (!setAskFor.insert(inv.hash).second) - return; - - // We're using mapAskFor as a priority queue, - // the key is the earliest time the request can be sent - int64_t nRequestTime; - limitedmap<uint256, int64_t>::const_iterator it = mapAlreadyAskedFor.find(inv.hash); - if (it != mapAlreadyAskedFor.end()) - nRequestTime = it->second; - else - nRequestTime = 0; - LogPrint(BCLog::NET, "askfor %s %d (%s) peer=%d\n", inv.ToString(), nRequestTime, FormatISO8601Time(nRequestTime/1000000), id); - - // Make sure not to reuse time indexes to keep things in the same order - int64_t nNow = GetTimeMicros() - 1000000; - static int64_t nLastTime; - ++nLastTime; - nNow = std::max(nNow, nLastTime); - nLastTime = nNow; - - // Each retry is 2 minutes after the last - nRequestTime = std::max(nRequestTime + 2 * 60 * 1000000, nNow); - if (it != mapAlreadyAskedFor.end()) - mapAlreadyAskedFor.update(it, nRequestTime); - else - mapAlreadyAskedFor.insert(std::make_pair(inv.hash, nRequestTime)); - mapAskFor.insert(std::make_pair(nRequestTime, inv)); -} - bool CConnman::NodeFullyConnected(const CNode* pnode) { return pnode && pnode->fSuccessfullyConnected && !pnode->fDisconnect; @@ -67,10 +67,6 @@ static const bool DEFAULT_UPNP = USE_UPNP; #else static const bool DEFAULT_UPNP = false; #endif -/** The maximum number of entries in mapAskFor */ -static const size_t MAPASKFOR_MAX_SZ = MAX_INV_SZ; -/** The maximum number of entries in setAskFor (larger due to getdata latency)*/ -static const size_t SETASKFOR_MAX_SZ = 2 * MAX_INV_SZ; /** The maximum number of peer connections to maintain. */ static const unsigned int DEFAULT_MAX_PEER_CONNECTIONS = 125; /** The default for -maxuploadtarget. 0 = Unlimited */ @@ -178,7 +174,18 @@ public: CConnman(uint64_t seed0, uint64_t seed1); ~CConnman(); bool Start(CScheduler& scheduler, const Options& options); - void Stop(); + + // TODO: Remove NO_THREAD_SAFETY_ANALYSIS. Lock cs_vNodes before reading the variable vNodes. + // + // When removing NO_THREAD_SAFETY_ANALYSIS be aware of the following lock order requirements: + // * CheckForStaleTipAndEvictPeers locks cs_main before indirectly calling GetExtraOutboundCount + // which locks cs_vNodes. + // * ProcessMessage locks cs_main and g_cs_orphans before indirectly calling ForEachNode which + // locks cs_vNodes. + // + // Thus the implicit locking order requirement is: (1) cs_main, (2) g_cs_orphans, (3) cs_vNodes. + void Stop() NO_THREAD_SAFETY_ANALYSIS; + void Interrupt(); bool GetNetworkActive() const { return fNetworkActive; }; bool GetUseAddrmanOutgoing() const { return m_use_addrman_outgoing; }; @@ -386,7 +393,7 @@ private: CCriticalSection cs_vOneShots; std::vector<std::string> vAddedNodes GUARDED_BY(cs_vAddedNodes); CCriticalSection cs_vAddedNodes; - std::vector<CNode*> vNodes; + std::vector<CNode*> vNodes GUARDED_BY(cs_vNodes); std::list<CNode*> vNodesDisconnected; mutable CCriticalSection cs_vNodes; std::atomic<NodeId> nLastNodeId{0}; @@ -514,8 +521,6 @@ extern bool fDiscover; extern bool fListen; extern bool fRelayTxes; -extern limitedmap<uint256, int64_t> mapAlreadyAskedFor; - /** Subversion as sent to the P2P network in `version` messages */ extern std::string strSubVersion; @@ -704,8 +709,6 @@ public: // and in the order requested. std::vector<uint256> vInventoryBlockToSend GUARDED_BY(cs_inventory); CCriticalSection cs_inventory; - std::set<uint256> setAskFor; - std::multimap<int64_t, CInv> mapAskFor; int64_t nNextInvSend{0}; // Used for headers announcements - unfiltered blocks to relay std::vector<uint256> vBlockHashesToAnnounce GUARDED_BY(cs_inventory); @@ -852,8 +855,6 @@ public: vBlockHashesToAnnounce.push_back(hash); } - void AskFor(const CInv& inv); - void CloseSocketDisconnect(); void copyStats(CNodeStats &stats); diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 62b7d4e966..18dd2f010c 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -64,12 +64,28 @@ static constexpr int STALE_RELAY_AGE_LIMIT = 30 * 24 * 60 * 60; /// Age after which a block is considered historical for purposes of rate /// limiting block relay. Set to one week, denominated in seconds. static constexpr int HISTORICAL_BLOCK_AGE = 7 * 24 * 60 * 60; +/** Maximum number of in-flight transactions from a peer */ +static constexpr int32_t MAX_PEER_TX_IN_FLIGHT = 100; +/** Maximum number of announced transactions from a peer */ +static constexpr int32_t MAX_PEER_TX_ANNOUNCEMENTS = 2 * MAX_INV_SZ; +/** How many microseconds to delay requesting transactions from inbound peers */ +static constexpr int64_t INBOUND_PEER_TX_DELAY = 2 * 1000000; +/** How long to wait (in microseconds) before downloading a transaction from an additional peer */ +static constexpr int64_t GETDATA_TX_INTERVAL = 60 * 1000000; +/** Maximum delay (in microseconds) for transaction requests to avoid biasing some peers over others. */ +static constexpr int64_t MAX_GETDATA_RANDOM_DELAY = 2 * 1000000; +static_assert(INBOUND_PEER_TX_DELAY >= MAX_GETDATA_RANDOM_DELAY, +"To preserve security, MAX_GETDATA_RANDOM_DELAY should not exceed INBOUND_PEER_DELAY"); +/** Limit to avoid sending big packets. Not used in processing incoming GETDATA for compatibility */ +static const unsigned int MAX_GETDATA_SZ = 1000; + struct COrphanTx { // When modifying, adapt the copy of this definition in tests/DoS_tests. CTransactionRef tx; NodeId fromPeer; int64_t nTimeExpire; + size_t list_pos; }; CCriticalSection g_cs_orphans; std::map<uint256, COrphanTx> mapOrphanTransactions GUARDED_BY(g_cs_orphans); @@ -171,6 +187,8 @@ namespace { }; std::map<COutPoint, std::set<std::map<uint256, COrphanTx>::iterator, IteratorComparator>> mapOrphanTransactionsByPrev GUARDED_BY(g_cs_orphans); + std::vector<std::map<uint256, COrphanTx>::iterator> g_orphan_list GUARDED_BY(g_cs_orphans); //! For random eviction + static size_t vExtraTxnForCompactIt GUARDED_BY(g_cs_orphans) = 0; static std::vector<std::pair<uint256, CTransactionRef>> vExtraTxnForCompact GUARDED_BY(g_cs_orphans); } // namespace @@ -274,6 +292,66 @@ struct CNodeState { //! Time of last new block announcement int64_t m_last_block_announcement; + /* + * State associated with transaction download. + * + * Tx download algorithm: + * + * When inv comes in, queue up (process_time, txid) inside the peer's + * CNodeState (m_tx_process_time) as long as m_tx_announced for the peer + * isn't too big (MAX_PEER_TX_ANNOUNCEMENTS). + * + * The process_time for a transaction is set to nNow for outbound peers, + * nNow + 2 seconds for inbound peers. This is the time at which we'll + * consider trying to request the transaction from the peer in + * SendMessages(). The delay for inbound peers is to allow outbound peers + * a chance to announce before we request from inbound peers, to prevent + * an adversary from using inbound connections to blind us to a + * transaction (InvBlock). + * + * When we call SendMessages() for a given peer, + * we will loop over the transactions in m_tx_process_time, looking + * at the transactions whose process_time <= nNow. We'll request each + * such transaction that we don't have already and that hasn't been + * requested from another peer recently, up until we hit the + * MAX_PEER_TX_IN_FLIGHT limit for the peer. Then we'll update + * g_already_asked_for for each requested txid, storing the time of the + * GETDATA request. We use g_already_asked_for to coordinate transaction + * requests amongst our peers. + * + * For transactions that we still need but we have already recently + * requested from some other peer, we'll reinsert (process_time, txid) + * back into the peer's m_tx_process_time at the point in the future at + * which the most recent GETDATA request would time out (ie + * GETDATA_TX_INTERVAL + the request time stored in g_already_asked_for). + * We add an additional delay for inbound peers, again to prefer + * attempting download from outbound peers first. + * We also add an extra small random delay up to 2 seconds + * to avoid biasing some peers over others. (e.g., due to fixed ordering + * of peer processing in ThreadMessageHandler). + * + * When we receive a transaction from a peer, we remove the txid from the + * peer's m_tx_in_flight set and from their recently announced set + * (m_tx_announced). We also clear g_already_asked_for for that entry, so + * that if somehow the transaction is not accepted but also not added to + * the reject filter, then we will eventually redownload from other + * peers. + */ + struct TxDownloadState { + /* Track when to attempt download of announced transactions (process + * time in micros -> txid) + */ + std::multimap<int64_t, uint256> m_tx_process_time; + + //! Store all the transactions a peer has recently announced + std::set<uint256> m_tx_announced; + + //! Store transactions which were requested by us + std::set<uint256> m_tx_in_flight; + }; + + TxDownloadState m_tx_download; + CNodeState(CAddress addrIn, std::string addrNameIn) : address(addrIn), name(addrNameIn) { fCurrentlyConnected = false; nMisbehavior = 0; @@ -301,6 +379,9 @@ struct CNodeState { } }; +// Keeps track of the time (in microseconds) when transactions were requested last time +limitedmap<uint256, int64_t> g_already_asked_for GUARDED_BY(cs_main)(MAX_INV_SZ); + /** Map maintaining per-node state. */ static std::map<NodeId, CNodeState> mapNodeState GUARDED_BY(cs_main); @@ -591,6 +672,58 @@ static void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vec } } +void EraseTxRequest(const uint256& txid) EXCLUSIVE_LOCKS_REQUIRED(cs_main) +{ + g_already_asked_for.erase(txid); +} + +int64_t GetTxRequestTime(const uint256& txid) EXCLUSIVE_LOCKS_REQUIRED(cs_main) +{ + auto it = g_already_asked_for.find(txid); + if (it != g_already_asked_for.end()) { + return it->second; + } + return 0; +} + +void UpdateTxRequestTime(const uint256& txid, int64_t request_time) EXCLUSIVE_LOCKS_REQUIRED(cs_main) +{ + auto it = g_already_asked_for.find(txid); + if (it == g_already_asked_for.end()) { + g_already_asked_for.insert(std::make_pair(txid, request_time)); + } else { + g_already_asked_for.update(it, request_time); + } +} + + +void RequestTx(CNodeState* state, const uint256& txid, int64_t nNow) EXCLUSIVE_LOCKS_REQUIRED(cs_main) +{ + CNodeState::TxDownloadState& peer_download_state = state->m_tx_download; + if (peer_download_state.m_tx_announced.size() >= MAX_PEER_TX_ANNOUNCEMENTS || peer_download_state.m_tx_announced.count(txid)) { + // Too many queued announcements from this peer, or we already have + // this announcement + return; + } + peer_download_state.m_tx_announced.insert(txid); + + int64_t process_time; + int64_t last_request_time = GetTxRequestTime(txid); + // First time requesting this tx + if (last_request_time == 0) { + process_time = nNow; + } else { + // Randomize the delay to avoid biasing some peers over others (such as due to + // fixed ordering of peer processing in ThreadMessageHandler) + process_time = last_request_time + GETDATA_TX_INTERVAL + GetRand(MAX_GETDATA_RANDOM_DELAY); + } + + // We delay processing announcements from non-preferred (eg inbound) peers + if (!state->fPreferredDownload) process_time += INBOUND_PEER_TX_DELAY; + + peer_download_state.m_tx_process_time.emplace(process_time, txid); +} + } // namespace // This function is used for testing the stale tip eviction logic, see @@ -707,8 +840,9 @@ bool AddOrphanTx(const CTransactionRef& tx, NodeId peer) EXCLUSIVE_LOCKS_REQUIRE return false; } - auto ret = mapOrphanTransactions.emplace(hash, COrphanTx{tx, peer, GetTime() + ORPHAN_TX_EXPIRE_TIME}); + auto ret = mapOrphanTransactions.emplace(hash, COrphanTx{tx, peer, GetTime() + ORPHAN_TX_EXPIRE_TIME, g_orphan_list.size()}); assert(ret.second); + g_orphan_list.push_back(ret.first); for (const CTxIn& txin : tx->vin) { mapOrphanTransactionsByPrev[txin.prevout].insert(ret.first); } @@ -734,6 +868,18 @@ int static EraseOrphanTx(uint256 hash) EXCLUSIVE_LOCKS_REQUIRED(g_cs_orphans) if (itPrev->second.empty()) mapOrphanTransactionsByPrev.erase(itPrev); } + + size_t old_pos = it->second.list_pos; + assert(g_orphan_list[old_pos] == it); + if (old_pos + 1 != g_orphan_list.size()) { + // Unless we're deleting the last entry in g_orphan_list, move the last + // entry to the position we're deleting. + auto it_last = g_orphan_list.back(); + g_orphan_list[old_pos] = it_last; + it_last->second.list_pos = old_pos; + } + g_orphan_list.pop_back(); + mapOrphanTransactions.erase(it); return 1; } @@ -784,11 +930,8 @@ unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans) while (mapOrphanTransactions.size() > nMaxOrphans) { // Evict a random orphan: - uint256 randomhash = rng.rand256(); - std::map<uint256, COrphanTx>::iterator it = mapOrphanTransactions.lower_bound(randomhash); - if (it == mapOrphanTransactions.end()) - it = mapOrphanTransactions.begin(); - EraseOrphanTx(it->first); + size_t randompos = rng.randrange(g_orphan_list.size()); + EraseOrphanTx(g_orphan_list[randompos]->first); ++nEvicted; } return nEvicted; @@ -1945,6 +2088,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr LOCK(cs_main); uint32_t nFetchFlags = GetFetchFlags(pfrom); + int64_t nNow = GetTimeMicros(); for (CInv &inv : vInv) { @@ -1976,7 +2120,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr if (fBlocksOnly) { LogPrint(BCLog::NET, "transaction (%s) inv sent in violation of protocol peer=%d\n", inv.hash.ToString(), pfrom->GetId()); } else if (!fAlreadyHave && !fImporting && !fReindex && !IsInitialBlockDownload()) { - pfrom->AskFor(inv); + RequestTx(State(pfrom->GetId()), inv.hash, nNow); } } } @@ -2211,8 +2355,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr bool fMissingInputs = false; CValidationState state; - pfrom->setAskFor.erase(inv.hash); - mapAlreadyAskedFor.erase(inv.hash); + CNodeState* nodestate = State(pfrom->GetId()); + nodestate->m_tx_download.m_tx_announced.erase(inv.hash); + nodestate->m_tx_download.m_tx_in_flight.erase(inv.hash); + EraseTxRequest(inv.hash); std::list<CTransactionRef> lRemovedTxn; @@ -2303,10 +2449,12 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr } if (!fRejectedParents) { uint32_t nFetchFlags = GetFetchFlags(pfrom); + int64_t nNow = GetTimeMicros(); + for (const CTxIn& txin : tx.vin) { CInv _inv(MSG_TX | nFetchFlags, txin.prevout.hash); pfrom->AddInventoryKnown(_inv); - if (!AlreadyHave(_inv)) pfrom->AskFor(_inv); + if (!AlreadyHave(_inv)) RequestTx(State(pfrom->GetId()), _inv.hash, nNow); } AddOrphanTx(ptx, pfrom->GetId()); @@ -3731,24 +3879,39 @@ bool PeerLogicValidation::SendMessages(CNode* pto) // // Message: getdata (non-blocks) // - while (!pto->mapAskFor.empty() && (*pto->mapAskFor.begin()).first <= nNow) - { - const CInv& inv = (*pto->mapAskFor.begin()).second; - if (!AlreadyHave(inv)) - { - LogPrint(BCLog::NET, "Requesting %s peer=%d\n", inv.ToString(), pto->GetId()); - vGetData.push_back(inv); - if (vGetData.size() >= 1000) - { - connman->PushMessage(pto, msgMaker.Make(NetMsgType::GETDATA, vGetData)); - vGetData.clear(); + auto& tx_process_time = state.m_tx_download.m_tx_process_time; + while (!tx_process_time.empty() && tx_process_time.begin()->first <= nNow && state.m_tx_download.m_tx_in_flight.size() < MAX_PEER_TX_IN_FLIGHT) { + const uint256& txid = tx_process_time.begin()->second; + CInv inv(MSG_TX | GetFetchFlags(pto), txid); + if (!AlreadyHave(inv)) { + // If this transaction was last requested more than 1 minute ago, + // then request. + int64_t last_request_time = GetTxRequestTime(inv.hash); + if (last_request_time <= nNow - GETDATA_TX_INTERVAL) { + LogPrint(BCLog::NET, "Requesting %s peer=%d\n", inv.ToString(), pto->GetId()); + vGetData.push_back(inv); + if (vGetData.size() >= MAX_GETDATA_SZ) { + connman->PushMessage(pto, msgMaker.Make(NetMsgType::GETDATA, vGetData)); + vGetData.clear(); + } + UpdateTxRequestTime(inv.hash, nNow); + state.m_tx_download.m_tx_in_flight.insert(inv.hash); + } else { + // This transaction is in flight from someone else; queue + // up processing to happen after the download times out + // (with a slight delay for inbound peers, to prefer + // requests to outbound peers). + RequestTx(&state, txid, nNow); } } else { - //If we're not going to ask, don't expect a response. - pto->setAskFor.erase(inv.hash); + // We have already seen this transaction, no need to download. + state.m_tx_download.m_tx_announced.erase(inv.hash); + state.m_tx_download.m_tx_in_flight.erase(inv.hash); } - pto->mapAskFor.erase(pto->mapAskFor.begin()); + tx_process_time.erase(tx_process_time.begin()); } + + if (!vGetData.empty()) connman->PushMessage(pto, msgMaker.Make(NetMsgType::GETDATA, vGetData)); diff --git a/src/netaddress.cpp b/src/netaddress.cpp index a0c7f8e3c2..58e45c2c02 100644 --- a/src/netaddress.cpp +++ b/src/netaddress.cpp @@ -182,16 +182,16 @@ bool CNetAddr::IsTor() const bool CNetAddr::IsLocal() const { - // IPv4 loopback - if (IsIPv4() && (GetByte(3) == 127 || GetByte(3) == 0)) - return true; + // IPv4 loopback (127.0.0.0/8 or 0.0.0.0/8) + if (IsIPv4() && (GetByte(3) == 127 || GetByte(3) == 0)) + return true; - // IPv6 loopback (::1/128) - static const unsigned char pchLocal[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}; - if (memcmp(ip, pchLocal, 16) == 0) - return true; + // IPv6 loopback (::1/128) + static const unsigned char pchLocal[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}; + if (memcmp(ip, pchLocal, 16) == 0) + return true; - return false; + return false; } bool CNetAddr::IsValid() const diff --git a/src/netbase.cpp b/src/netbase.cpp index 355e21d4e6..6c386a9ade 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -80,11 +80,7 @@ bool static LookupIntern(const char *pszName, std::vector<CNetAddr>& vIP, unsign aiHint.ai_socktype = SOCK_STREAM; aiHint.ai_protocol = IPPROTO_TCP; aiHint.ai_family = AF_UNSPEC; -#ifdef WIN32 - aiHint.ai_flags = fAllowLookup ? 0 : AI_NUMERICHOST; -#else aiHint.ai_flags = fAllowLookup ? AI_ADDRCONFIG : AI_NUMERICHOST; -#endif struct addrinfo *aiRes = nullptr; int nErr = getaddrinfo(pszName, nullptr, &aiHint, &aiRes); if (nErr) diff --git a/src/node/transaction.cpp b/src/node/transaction.cpp new file mode 100644 index 0000000000..7b9b4310e7 --- /dev/null +++ b/src/node/transaction.cpp @@ -0,0 +1,103 @@ +// Copyright (c) 2010 Satoshi Nakamoto +// Copyright (c) 2009-2018 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include <consensus/validation.h> +#include <net.h> +#include <txmempool.h> +#include <validation.h> +#include <validationinterface.h> +#include <node/transaction.h> + +#include <future> + +std::string TransactionErrorString(const TransactionError err) +{ + switch (err) { + case TransactionError::OK: + return "No error"; + case TransactionError::MISSING_INPUTS: + return "Missing inputs"; + case TransactionError::ALREADY_IN_CHAIN: + return "Transaction already in block chain"; + case TransactionError::P2P_DISABLED: + return "Peer-to-peer functionality missing or disabled"; + case TransactionError::MEMPOOL_REJECTED: + return "Transaction rejected by AcceptToMemoryPool"; + case TransactionError::MEMPOOL_ERROR: + return "AcceptToMemoryPool failed"; + case TransactionError::INVALID_PSBT: + return "PSBT is not sane"; + case TransactionError::PSBT_MISMATCH: + return "PSBTs not compatible (different transactions)"; + case TransactionError::SIGHASH_MISMATCH: + return "Specified sighash value does not match existing value"; + // no default case, so the compiler can warn about missing cases + } + assert(false); +} + +TransactionError BroadcastTransaction(const CTransactionRef tx, uint256& hashTx, std::string& err_string, const CAmount& highfee) +{ + std::promise<void> promise; + hashTx = tx->GetHash(); + + { // cs_main scope + LOCK(cs_main); + CCoinsViewCache &view = *pcoinsTip; + bool fHaveChain = false; + for (size_t o = 0; !fHaveChain && o < tx->vout.size(); o++) { + const Coin& existingCoin = view.AccessCoin(COutPoint(hashTx, o)); + fHaveChain = !existingCoin.IsSpent(); + } + bool fHaveMempool = mempool.exists(hashTx); + if (!fHaveMempool && !fHaveChain) { + // push to local node and sync with wallets + CValidationState state; + bool fMissingInputs; + if (!AcceptToMemoryPool(mempool, state, std::move(tx), &fMissingInputs, + nullptr /* plTxnReplaced */, false /* bypass_limits */, highfee)) { + if (state.IsInvalid()) { + err_string = FormatStateMessage(state); + return TransactionError::MEMPOOL_REJECTED; + } else { + if (fMissingInputs) { + return TransactionError::MISSING_INPUTS; + } + err_string = FormatStateMessage(state); + return TransactionError::MEMPOOL_ERROR; + } + } else { + // If wallet is enabled, ensure that the wallet has been made aware + // of the new transaction prior to returning. This prevents a race + // where a user might call sendrawtransaction with a transaction + // to/from their wallet, immediately call some wallet RPC, and get + // a stale result because callbacks have not yet been processed. + CallFunctionInValidationInterfaceQueue([&promise] { + promise.set_value(); + }); + } + } else if (fHaveChain) { + return TransactionError::ALREADY_IN_CHAIN; + } else { + // Make sure we don't block forever if re-sending + // a transaction already in mempool. + promise.set_value(); + } + + } // cs_main + + promise.get_future().wait(); + + if (!g_connman) { + return TransactionError::P2P_DISABLED; + } + + CInv inv(MSG_TX, hashTx); + g_connman->ForEachNode([&inv](CNode* pnode) { + pnode->PushInventory(inv); + }); + + return TransactionError::OK; +} diff --git a/src/node/transaction.h b/src/node/transaction.h new file mode 100644 index 0000000000..3457ececa4 --- /dev/null +++ b/src/node/transaction.h @@ -0,0 +1,37 @@ +// Copyright (c) 2017-2019 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_NODE_TRANSACTION_H +#define BITCOIN_NODE_TRANSACTION_H + +#include <attributes.h> +#include <primitives/transaction.h> +#include <uint256.h> + +enum class TransactionError { + OK, //!< No error + MISSING_INPUTS, + ALREADY_IN_CHAIN, + P2P_DISABLED, + MEMPOOL_REJECTED, + MEMPOOL_ERROR, + INVALID_PSBT, + PSBT_MISMATCH, + SIGHASH_MISMATCH, +}; + +std::string TransactionErrorString(const TransactionError error); + +/** + * Broadcast a transaction + * + * @param[in] tx the transaction to broadcast + * @param[out] &txid the txid of the transaction, if successfully broadcast + * @param[out] &err_string reference to std::string to fill with error string if available + * @param[in] highfee Reject txs with fees higher than this (if 0, accept any fee) + * return error + */ +NODISCARD TransactionError BroadcastTransaction(CTransactionRef tx, uint256& txid, std::string& err_string, const CAmount& highfee); + +#endif // BITCOIN_NODE_TRANSACTION_H diff --git a/src/psbt.cpp b/src/psbt.cpp new file mode 100644 index 0000000000..0fb7d49d7d --- /dev/null +++ b/src/psbt.cpp @@ -0,0 +1,327 @@ +// Copyright (c) 2009-2018 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include <psbt.h> +#include <util/strencodings.h> + +PartiallySignedTransaction::PartiallySignedTransaction(const CMutableTransaction& tx) : tx(tx) +{ + inputs.resize(tx.vin.size()); + outputs.resize(tx.vout.size()); +} + +bool PartiallySignedTransaction::IsNull() const +{ + return !tx && inputs.empty() && outputs.empty() && unknown.empty(); +} + +bool PartiallySignedTransaction::Merge(const PartiallySignedTransaction& psbt) +{ + // Prohibited to merge two PSBTs over different transactions + if (tx->GetHash() != psbt.tx->GetHash()) { + return false; + } + + for (unsigned int i = 0; i < inputs.size(); ++i) { + inputs[i].Merge(psbt.inputs[i]); + } + for (unsigned int i = 0; i < outputs.size(); ++i) { + outputs[i].Merge(psbt.outputs[i]); + } + unknown.insert(psbt.unknown.begin(), psbt.unknown.end()); + + return true; +} + +bool PartiallySignedTransaction::IsSane() const +{ + for (PSBTInput input : inputs) { + if (!input.IsSane()) return false; + } + return true; +} + +bool PartiallySignedTransaction::AddInput(const CTxIn& txin, PSBTInput& psbtin) +{ + if (std::find(tx->vin.begin(), tx->vin.end(), txin) != tx->vin.end()) { + return false; + } + tx->vin.push_back(txin); + psbtin.partial_sigs.clear(); + psbtin.final_script_sig.clear(); + psbtin.final_script_witness.SetNull(); + inputs.push_back(psbtin); + return true; +} + +bool PartiallySignedTransaction::AddOutput(const CTxOut& txout, const PSBTOutput& psbtout) +{ + tx->vout.push_back(txout); + outputs.push_back(psbtout); + return true; +} + +bool PartiallySignedTransaction::GetInputUTXO(CTxOut& utxo, int input_index) const +{ + PSBTInput input = inputs[input_index]; + int prevout_index = tx->vin[input_index].prevout.n; + if (input.non_witness_utxo) { + utxo = input.non_witness_utxo->vout[prevout_index]; + } else if (!input.witness_utxo.IsNull()) { + utxo = input.witness_utxo; + } else { + return false; + } + return true; +} + +bool PSBTInput::IsNull() const +{ + return !non_witness_utxo && witness_utxo.IsNull() && partial_sigs.empty() && unknown.empty() && hd_keypaths.empty() && redeem_script.empty() && witness_script.empty(); +} + +void PSBTInput::FillSignatureData(SignatureData& sigdata) const +{ + if (!final_script_sig.empty()) { + sigdata.scriptSig = final_script_sig; + sigdata.complete = true; + } + if (!final_script_witness.IsNull()) { + sigdata.scriptWitness = final_script_witness; + sigdata.complete = true; + } + if (sigdata.complete) { + return; + } + + sigdata.signatures.insert(partial_sigs.begin(), partial_sigs.end()); + if (!redeem_script.empty()) { + sigdata.redeem_script = redeem_script; + } + if (!witness_script.empty()) { + sigdata.witness_script = witness_script; + } + for (const auto& key_pair : hd_keypaths) { + sigdata.misc_pubkeys.emplace(key_pair.first.GetID(), key_pair); + } +} + +void PSBTInput::FromSignatureData(const SignatureData& sigdata) +{ + if (sigdata.complete) { + partial_sigs.clear(); + hd_keypaths.clear(); + redeem_script.clear(); + witness_script.clear(); + + if (!sigdata.scriptSig.empty()) { + final_script_sig = sigdata.scriptSig; + } + if (!sigdata.scriptWitness.IsNull()) { + final_script_witness = sigdata.scriptWitness; + } + return; + } + + partial_sigs.insert(sigdata.signatures.begin(), sigdata.signatures.end()); + if (redeem_script.empty() && !sigdata.redeem_script.empty()) { + redeem_script = sigdata.redeem_script; + } + if (witness_script.empty() && !sigdata.witness_script.empty()) { + witness_script = sigdata.witness_script; + } + for (const auto& entry : sigdata.misc_pubkeys) { + hd_keypaths.emplace(entry.second); + } +} + +void PSBTInput::Merge(const PSBTInput& input) +{ + if (!non_witness_utxo && input.non_witness_utxo) non_witness_utxo = input.non_witness_utxo; + if (witness_utxo.IsNull() && !input.witness_utxo.IsNull()) { + witness_utxo = input.witness_utxo; + non_witness_utxo = nullptr; // Clear out any non-witness utxo when we set a witness one. + } + + partial_sigs.insert(input.partial_sigs.begin(), input.partial_sigs.end()); + hd_keypaths.insert(input.hd_keypaths.begin(), input.hd_keypaths.end()); + unknown.insert(input.unknown.begin(), input.unknown.end()); + + if (redeem_script.empty() && !input.redeem_script.empty()) redeem_script = input.redeem_script; + if (witness_script.empty() && !input.witness_script.empty()) witness_script = input.witness_script; + if (final_script_sig.empty() && !input.final_script_sig.empty()) final_script_sig = input.final_script_sig; + if (final_script_witness.IsNull() && !input.final_script_witness.IsNull()) final_script_witness = input.final_script_witness; +} + +bool PSBTInput::IsSane() const +{ + // Cannot have both witness and non-witness utxos + if (!witness_utxo.IsNull() && non_witness_utxo) return false; + + // If we have a witness_script or a scriptWitness, we must also have a witness utxo + if (!witness_script.empty() && witness_utxo.IsNull()) return false; + if (!final_script_witness.IsNull() && witness_utxo.IsNull()) return false; + + return true; +} + +void PSBTOutput::FillSignatureData(SignatureData& sigdata) const +{ + if (!redeem_script.empty()) { + sigdata.redeem_script = redeem_script; + } + if (!witness_script.empty()) { + sigdata.witness_script = witness_script; + } + for (const auto& key_pair : hd_keypaths) { + sigdata.misc_pubkeys.emplace(key_pair.first.GetID(), key_pair); + } +} + +void PSBTOutput::FromSignatureData(const SignatureData& sigdata) +{ + if (redeem_script.empty() && !sigdata.redeem_script.empty()) { + redeem_script = sigdata.redeem_script; + } + if (witness_script.empty() && !sigdata.witness_script.empty()) { + witness_script = sigdata.witness_script; + } + for (const auto& entry : sigdata.misc_pubkeys) { + hd_keypaths.emplace(entry.second); + } +} + +bool PSBTOutput::IsNull() const +{ + return redeem_script.empty() && witness_script.empty() && hd_keypaths.empty() && unknown.empty(); +} + +void PSBTOutput::Merge(const PSBTOutput& output) +{ + hd_keypaths.insert(output.hd_keypaths.begin(), output.hd_keypaths.end()); + unknown.insert(output.unknown.begin(), output.unknown.end()); + + if (redeem_script.empty() && !output.redeem_script.empty()) redeem_script = output.redeem_script; + if (witness_script.empty() && !output.witness_script.empty()) witness_script = output.witness_script; +} +bool PSBTInputSigned(PSBTInput& input) +{ + return !input.final_script_sig.empty() || !input.final_script_witness.IsNull(); +} + +bool SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction& psbt, int index, int sighash, SignatureData* out_sigdata, bool use_dummy) +{ + PSBTInput& input = psbt.inputs.at(index); + const CMutableTransaction& tx = *psbt.tx; + + if (PSBTInputSigned(input)) { + return true; + } + + // Fill SignatureData with input info + SignatureData sigdata; + input.FillSignatureData(sigdata); + + // Get UTXO + bool require_witness_sig = false; + CTxOut utxo; + + // Verify input sanity, which checks that at most one of witness or non-witness utxos is provided. + if (!input.IsSane()) { + return false; + } + + if (input.non_witness_utxo) { + // If we're taking our information from a non-witness UTXO, verify that it matches the prevout. + COutPoint prevout = tx.vin[index].prevout; + if (input.non_witness_utxo->GetHash() != prevout.hash) { + return false; + } + utxo = input.non_witness_utxo->vout[prevout.n]; + } else if (!input.witness_utxo.IsNull()) { + utxo = input.witness_utxo; + // When we're taking our information from a witness UTXO, we can't verify it is actually data from + // the output being spent. This is safe in case a witness signature is produced (which includes this + // information directly in the hash), but not for non-witness signatures. Remember that we require + // a witness signature in this situation. + require_witness_sig = true; + } else { + return false; + } + + sigdata.witness = false; + bool sig_complete; + if (use_dummy) { + sig_complete = ProduceSignature(provider, DUMMY_SIGNATURE_CREATOR, utxo.scriptPubKey, sigdata); + } else { + MutableTransactionSignatureCreator creator(&tx, index, utxo.nValue, sighash); + sig_complete = ProduceSignature(provider, creator, utxo.scriptPubKey, sigdata); + } + // Verify that a witness signature was produced in case one was required. + if (require_witness_sig && !sigdata.witness) return false; + input.FromSignatureData(sigdata); + + // If we have a witness signature, use the smaller witness UTXO. + if (sigdata.witness) { + input.witness_utxo = utxo; + input.non_witness_utxo = nullptr; + } + + // Fill in the missing info + if (out_sigdata) { + out_sigdata->missing_pubkeys = sigdata.missing_pubkeys; + out_sigdata->missing_sigs = sigdata.missing_sigs; + out_sigdata->missing_redeem_script = sigdata.missing_redeem_script; + out_sigdata->missing_witness_script = sigdata.missing_witness_script; + } + + return sig_complete; +} + +bool FinalizePSBT(PartiallySignedTransaction& psbtx) +{ + // Finalize input signatures -- in case we have partial signatures that add up to a complete + // signature, but have not combined them yet (e.g. because the combiner that created this + // PartiallySignedTransaction did not understand them), this will combine them into a final + // script. + bool complete = true; + for (unsigned int i = 0; i < psbtx.tx->vin.size(); ++i) { + complete &= SignPSBTInput(DUMMY_SIGNING_PROVIDER, psbtx, i, SIGHASH_ALL); + } + + return complete; +} + +bool FinalizeAndExtractPSBT(PartiallySignedTransaction& psbtx, CMutableTransaction& result) +{ + // It's not safe to extract a PSBT that isn't finalized, and there's no easy way to check + // whether a PSBT is finalized without finalizing it, so we just do this. + if (!FinalizePSBT(psbtx)) { + return false; + } + + result = *psbtx.tx; + for (unsigned int i = 0; i < result.vin.size(); ++i) { + result.vin[i].scriptSig = psbtx.inputs[i].final_script_sig; + result.vin[i].scriptWitness = psbtx.inputs[i].final_script_witness; + } + return true; +} + +TransactionError CombinePSBTs(PartiallySignedTransaction& out, const std::vector<PartiallySignedTransaction>& psbtxs) +{ + out = psbtxs[0]; // Copy the first one + + // Merge + for (auto it = std::next(psbtxs.begin()); it != psbtxs.end(); ++it) { + if (!out.Merge(*it)) { + return TransactionError::PSBT_MISMATCH; + } + } + if (!out.IsSane()) { + return TransactionError::INVALID_PSBT; + } + + return TransactionError::OK; +} diff --git a/src/psbt.h b/src/psbt.h new file mode 100644 index 0000000000..c889dad361 --- /dev/null +++ b/src/psbt.h @@ -0,0 +1,583 @@ +// Copyright (c) 2009-2019 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_PSBT_H +#define BITCOIN_PSBT_H + +#include <attributes.h> +#include <node/transaction.h> +#include <primitives/transaction.h> +#include <pubkey.h> +#include <script/sign.h> + +// Magic bytes +static constexpr uint8_t PSBT_MAGIC_BYTES[5] = {'p', 's', 'b', 't', 0xff}; + +// Global types +static constexpr uint8_t PSBT_GLOBAL_UNSIGNED_TX = 0x00; + +// Input types +static constexpr uint8_t PSBT_IN_NON_WITNESS_UTXO = 0x00; +static constexpr uint8_t PSBT_IN_WITNESS_UTXO = 0x01; +static constexpr uint8_t PSBT_IN_PARTIAL_SIG = 0x02; +static constexpr uint8_t PSBT_IN_SIGHASH = 0x03; +static constexpr uint8_t PSBT_IN_REDEEMSCRIPT = 0x04; +static constexpr uint8_t PSBT_IN_WITNESSSCRIPT = 0x05; +static constexpr uint8_t PSBT_IN_BIP32_DERIVATION = 0x06; +static constexpr uint8_t PSBT_IN_SCRIPTSIG = 0x07; +static constexpr uint8_t PSBT_IN_SCRIPTWITNESS = 0x08; + +// Output types +static constexpr uint8_t PSBT_OUT_REDEEMSCRIPT = 0x00; +static constexpr uint8_t PSBT_OUT_WITNESSSCRIPT = 0x01; +static constexpr uint8_t PSBT_OUT_BIP32_DERIVATION = 0x02; + +// The separator is 0x00. Reading this in means that the unserializer can interpret it +// as a 0 length key which indicates that this is the separator. The separator has no value. +static constexpr uint8_t PSBT_SEPARATOR = 0x00; + +/** A structure for PSBTs which contain per-input information */ +struct PSBTInput +{ + CTransactionRef non_witness_utxo; + CTxOut witness_utxo; + CScript redeem_script; + CScript witness_script; + CScript final_script_sig; + CScriptWitness final_script_witness; + std::map<CPubKey, KeyOriginInfo> hd_keypaths; + std::map<CKeyID, SigPair> partial_sigs; + std::map<std::vector<unsigned char>, std::vector<unsigned char>> unknown; + int sighash_type = 0; + + bool IsNull() const; + void FillSignatureData(SignatureData& sigdata) const; + void FromSignatureData(const SignatureData& sigdata); + void Merge(const PSBTInput& input); + bool IsSane() const; + PSBTInput() {} + + template <typename Stream> + inline void Serialize(Stream& s) const { + // Write the utxo + // If there is a non-witness utxo, then don't add the witness one. + if (non_witness_utxo) { + SerializeToVector(s, PSBT_IN_NON_WITNESS_UTXO); + OverrideStream<Stream> os(&s, s.GetType(), s.GetVersion() | SERIALIZE_TRANSACTION_NO_WITNESS); + SerializeToVector(os, non_witness_utxo); + } else if (!witness_utxo.IsNull()) { + SerializeToVector(s, PSBT_IN_WITNESS_UTXO); + SerializeToVector(s, witness_utxo); + } + + if (final_script_sig.empty() && final_script_witness.IsNull()) { + // Write any partial signatures + for (auto sig_pair : partial_sigs) { + SerializeToVector(s, PSBT_IN_PARTIAL_SIG, MakeSpan(sig_pair.second.first)); + s << sig_pair.second.second; + } + + // Write the sighash type + if (sighash_type > 0) { + SerializeToVector(s, PSBT_IN_SIGHASH); + SerializeToVector(s, sighash_type); + } + + // Write the redeem script + if (!redeem_script.empty()) { + SerializeToVector(s, PSBT_IN_REDEEMSCRIPT); + s << redeem_script; + } + + // Write the witness script + if (!witness_script.empty()) { + SerializeToVector(s, PSBT_IN_WITNESSSCRIPT); + s << witness_script; + } + + // Write any hd keypaths + SerializeHDKeypaths(s, hd_keypaths, PSBT_IN_BIP32_DERIVATION); + } + + // Write script sig + if (!final_script_sig.empty()) { + SerializeToVector(s, PSBT_IN_SCRIPTSIG); + s << final_script_sig; + } + // write script witness + if (!final_script_witness.IsNull()) { + SerializeToVector(s, PSBT_IN_SCRIPTWITNESS); + SerializeToVector(s, final_script_witness.stack); + } + + // Write unknown things + for (auto& entry : unknown) { + s << entry.first; + s << entry.second; + } + + s << PSBT_SEPARATOR; + } + + + template <typename Stream> + inline void Unserialize(Stream& s) { + // Read loop + bool found_sep = false; + while(!s.empty()) { + // Read + std::vector<unsigned char> key; + s >> key; + + // the key is empty if that was actually a separator byte + // This is a special case for key lengths 0 as those are not allowed (except for separator) + if (key.empty()) { + found_sep = true; + break; + } + + // First byte of key is the type + unsigned char type = key[0]; + + // Do stuff based on type + switch(type) { + case PSBT_IN_NON_WITNESS_UTXO: + { + if (non_witness_utxo) { + throw std::ios_base::failure("Duplicate Key, input non-witness utxo already provided"); + } else if (key.size() != 1) { + throw std::ios_base::failure("Non-witness utxo key is more than one byte type"); + } + // Set the stream to unserialize with witness since this is always a valid network transaction + OverrideStream<Stream> os(&s, s.GetType(), s.GetVersion() & ~SERIALIZE_TRANSACTION_NO_WITNESS); + UnserializeFromVector(os, non_witness_utxo); + break; + } + case PSBT_IN_WITNESS_UTXO: + if (!witness_utxo.IsNull()) { + throw std::ios_base::failure("Duplicate Key, input witness utxo already provided"); + } else if (key.size() != 1) { + throw std::ios_base::failure("Witness utxo key is more than one byte type"); + } + UnserializeFromVector(s, witness_utxo); + break; + case PSBT_IN_PARTIAL_SIG: + { + // Make sure that the key is the size of pubkey + 1 + if (key.size() != CPubKey::PUBLIC_KEY_SIZE + 1 && key.size() != CPubKey::COMPRESSED_PUBLIC_KEY_SIZE + 1) { + throw std::ios_base::failure("Size of key was not the expected size for the type partial signature pubkey"); + } + // Read in the pubkey from key + CPubKey pubkey(key.begin() + 1, key.end()); + if (!pubkey.IsFullyValid()) { + throw std::ios_base::failure("Invalid pubkey"); + } + if (partial_sigs.count(pubkey.GetID()) > 0) { + throw std::ios_base::failure("Duplicate Key, input partial signature for pubkey already provided"); + } + + // Read in the signature from value + std::vector<unsigned char> sig; + s >> sig; + + // Add to list + partial_sigs.emplace(pubkey.GetID(), SigPair(pubkey, std::move(sig))); + break; + } + case PSBT_IN_SIGHASH: + if (sighash_type > 0) { + throw std::ios_base::failure("Duplicate Key, input sighash type already provided"); + } else if (key.size() != 1) { + throw std::ios_base::failure("Sighash type key is more than one byte type"); + } + UnserializeFromVector(s, sighash_type); + break; + case PSBT_IN_REDEEMSCRIPT: + { + if (!redeem_script.empty()) { + throw std::ios_base::failure("Duplicate Key, input redeemScript already provided"); + } else if (key.size() != 1) { + throw std::ios_base::failure("Input redeemScript key is more than one byte type"); + } + s >> redeem_script; + break; + } + case PSBT_IN_WITNESSSCRIPT: + { + if (!witness_script.empty()) { + throw std::ios_base::failure("Duplicate Key, input witnessScript already provided"); + } else if (key.size() != 1) { + throw std::ios_base::failure("Input witnessScript key is more than one byte type"); + } + s >> witness_script; + break; + } + case PSBT_IN_BIP32_DERIVATION: + { + DeserializeHDKeypaths(s, key, hd_keypaths); + break; + } + case PSBT_IN_SCRIPTSIG: + { + if (!final_script_sig.empty()) { + throw std::ios_base::failure("Duplicate Key, input final scriptSig already provided"); + } else if (key.size() != 1) { + throw std::ios_base::failure("Final scriptSig key is more than one byte type"); + } + s >> final_script_sig; + break; + } + case PSBT_IN_SCRIPTWITNESS: + { + if (!final_script_witness.IsNull()) { + throw std::ios_base::failure("Duplicate Key, input final scriptWitness already provided"); + } else if (key.size() != 1) { + throw std::ios_base::failure("Final scriptWitness key is more than one byte type"); + } + UnserializeFromVector(s, final_script_witness.stack); + break; + } + // Unknown stuff + default: + if (unknown.count(key) > 0) { + throw std::ios_base::failure("Duplicate Key, key for unknown value already provided"); + } + // Read in the value + std::vector<unsigned char> val_bytes; + s >> val_bytes; + unknown.emplace(std::move(key), std::move(val_bytes)); + break; + } + } + + if (!found_sep) { + throw std::ios_base::failure("Separator is missing at the end of an input map"); + } + } + + template <typename Stream> + PSBTInput(deserialize_type, Stream& s) { + Unserialize(s); + } +}; + +/** A structure for PSBTs which contains per output information */ +struct PSBTOutput +{ + CScript redeem_script; + CScript witness_script; + std::map<CPubKey, KeyOriginInfo> hd_keypaths; + std::map<std::vector<unsigned char>, std::vector<unsigned char>> unknown; + + bool IsNull() const; + void FillSignatureData(SignatureData& sigdata) const; + void FromSignatureData(const SignatureData& sigdata); + void Merge(const PSBTOutput& output); + bool IsSane() const; + PSBTOutput() {} + + template <typename Stream> + inline void Serialize(Stream& s) const { + // Write the redeem script + if (!redeem_script.empty()) { + SerializeToVector(s, PSBT_OUT_REDEEMSCRIPT); + s << redeem_script; + } + + // Write the witness script + if (!witness_script.empty()) { + SerializeToVector(s, PSBT_OUT_WITNESSSCRIPT); + s << witness_script; + } + + // Write any hd keypaths + SerializeHDKeypaths(s, hd_keypaths, PSBT_OUT_BIP32_DERIVATION); + + // Write unknown things + for (auto& entry : unknown) { + s << entry.first; + s << entry.second; + } + + s << PSBT_SEPARATOR; + } + + + template <typename Stream> + inline void Unserialize(Stream& s) { + // Read loop + bool found_sep = false; + while(!s.empty()) { + // Read + std::vector<unsigned char> key; + s >> key; + + // the key is empty if that was actually a separator byte + // This is a special case for key lengths 0 as those are not allowed (except for separator) + if (key.empty()) { + found_sep = true; + break; + } + + // First byte of key is the type + unsigned char type = key[0]; + + // Do stuff based on type + switch(type) { + case PSBT_OUT_REDEEMSCRIPT: + { + if (!redeem_script.empty()) { + throw std::ios_base::failure("Duplicate Key, output redeemScript already provided"); + } else if (key.size() != 1) { + throw std::ios_base::failure("Output redeemScript key is more than one byte type"); + } + s >> redeem_script; + break; + } + case PSBT_OUT_WITNESSSCRIPT: + { + if (!witness_script.empty()) { + throw std::ios_base::failure("Duplicate Key, output witnessScript already provided"); + } else if (key.size() != 1) { + throw std::ios_base::failure("Output witnessScript key is more than one byte type"); + } + s >> witness_script; + break; + } + case PSBT_OUT_BIP32_DERIVATION: + { + DeserializeHDKeypaths(s, key, hd_keypaths); + break; + } + // Unknown stuff + default: { + if (unknown.count(key) > 0) { + throw std::ios_base::failure("Duplicate Key, key for unknown value already provided"); + } + // Read in the value + std::vector<unsigned char> val_bytes; + s >> val_bytes; + unknown.emplace(std::move(key), std::move(val_bytes)); + break; + } + } + } + + if (!found_sep) { + throw std::ios_base::failure("Separator is missing at the end of an output map"); + } + } + + template <typename Stream> + PSBTOutput(deserialize_type, Stream& s) { + Unserialize(s); + } +}; + +/** A version of CTransaction with the PSBT format*/ +struct PartiallySignedTransaction +{ + boost::optional<CMutableTransaction> tx; + std::vector<PSBTInput> inputs; + std::vector<PSBTOutput> outputs; + std::map<std::vector<unsigned char>, std::vector<unsigned char>> unknown; + + bool IsNull() const; + + /** Merge psbt into this. The two psbts must have the same underlying CTransaction (i.e. the + * same actual Bitcoin transaction.) Returns true if the merge succeeded, false otherwise. */ + NODISCARD bool Merge(const PartiallySignedTransaction& psbt); + bool IsSane() const; + bool AddInput(const CTxIn& txin, PSBTInput& psbtin); + bool AddOutput(const CTxOut& txout, const PSBTOutput& psbtout); + PartiallySignedTransaction() {} + PartiallySignedTransaction(const PartiallySignedTransaction& psbt_in) : tx(psbt_in.tx), inputs(psbt_in.inputs), outputs(psbt_in.outputs), unknown(psbt_in.unknown) {} + explicit PartiallySignedTransaction(const CMutableTransaction& tx); + /** + * Finds the UTXO for a given input index + * + * @param[out] utxo The UTXO of the input if found + * @param[in] input_index Index of the input to retrieve the UTXO of + * @return Whether the UTXO for the specified input was found + */ + bool GetInputUTXO(CTxOut& utxo, int input_index) const; + + template <typename Stream> + inline void Serialize(Stream& s) const { + + // magic bytes + s << PSBT_MAGIC_BYTES; + + // unsigned tx flag + SerializeToVector(s, PSBT_GLOBAL_UNSIGNED_TX); + + // Write serialized tx to a stream + OverrideStream<Stream> os(&s, s.GetType(), s.GetVersion() | SERIALIZE_TRANSACTION_NO_WITNESS); + SerializeToVector(os, *tx); + + // Write the unknown things + for (auto& entry : unknown) { + s << entry.first; + s << entry.second; + } + + // Separator + s << PSBT_SEPARATOR; + + // Write inputs + for (const PSBTInput& input : inputs) { + s << input; + } + // Write outputs + for (const PSBTOutput& output : outputs) { + s << output; + } + } + + + template <typename Stream> + inline void Unserialize(Stream& s) { + // Read the magic bytes + uint8_t magic[5]; + s >> magic; + if (!std::equal(magic, magic + 5, PSBT_MAGIC_BYTES)) { + throw std::ios_base::failure("Invalid PSBT magic bytes"); + } + + // Read global data + bool found_sep = false; + while(!s.empty()) { + // Read + std::vector<unsigned char> key; + s >> key; + + // the key is empty if that was actually a separator byte + // This is a special case for key lengths 0 as those are not allowed (except for separator) + if (key.empty()) { + found_sep = true; + break; + } + + // First byte of key is the type + unsigned char type = key[0]; + + // Do stuff based on type + switch(type) { + case PSBT_GLOBAL_UNSIGNED_TX: + { + if (tx) { + throw std::ios_base::failure("Duplicate Key, unsigned tx already provided"); + } else if (key.size() != 1) { + throw std::ios_base::failure("Global unsigned tx key is more than one byte type"); + } + CMutableTransaction mtx; + // Set the stream to serialize with non-witness since this should always be non-witness + OverrideStream<Stream> os(&s, s.GetType(), s.GetVersion() | SERIALIZE_TRANSACTION_NO_WITNESS); + UnserializeFromVector(os, mtx); + tx = std::move(mtx); + // Make sure that all scriptSigs and scriptWitnesses are empty + for (const CTxIn& txin : tx->vin) { + if (!txin.scriptSig.empty() || !txin.scriptWitness.IsNull()) { + throw std::ios_base::failure("Unsigned tx does not have empty scriptSigs and scriptWitnesses."); + } + } + break; + } + // Unknown stuff + default: { + if (unknown.count(key) > 0) { + throw std::ios_base::failure("Duplicate Key, key for unknown value already provided"); + } + // Read in the value + std::vector<unsigned char> val_bytes; + s >> val_bytes; + unknown.emplace(std::move(key), std::move(val_bytes)); + } + } + } + + if (!found_sep) { + throw std::ios_base::failure("Separator is missing at the end of the global map"); + } + + // Make sure that we got an unsigned tx + if (!tx) { + throw std::ios_base::failure("No unsigned transcation was provided"); + } + + // Read input data + unsigned int i = 0; + while (!s.empty() && i < tx->vin.size()) { + PSBTInput input; + s >> input; + inputs.push_back(input); + + // Make sure the non-witness utxo matches the outpoint + if (input.non_witness_utxo && input.non_witness_utxo->GetHash() != tx->vin[i].prevout.hash) { + throw std::ios_base::failure("Non-witness UTXO does not match outpoint hash"); + } + ++i; + } + // Make sure that the number of inputs matches the number of inputs in the transaction + if (inputs.size() != tx->vin.size()) { + throw std::ios_base::failure("Inputs provided does not match the number of inputs in transaction."); + } + + // Read output data + i = 0; + while (!s.empty() && i < tx->vout.size()) { + PSBTOutput output; + s >> output; + outputs.push_back(output); + ++i; + } + // Make sure that the number of outputs matches the number of outputs in the transaction + if (outputs.size() != tx->vout.size()) { + throw std::ios_base::failure("Outputs provided does not match the number of outputs in transaction."); + } + // Sanity check + if (!IsSane()) { + throw std::ios_base::failure("PSBT is not sane."); + } + } + + template <typename Stream> + PartiallySignedTransaction(deserialize_type, Stream& s) { + Unserialize(s); + } +}; + +/** Checks whether a PSBTInput is already signed. */ +bool PSBTInputSigned(PSBTInput& input); + +/** Signs a PSBTInput, verifying that all provided data matches what is being signed. */ +bool SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction& psbt, int index, int sighash = SIGHASH_ALL, SignatureData* out_sigdata = nullptr, bool use_dummy = false); + +/** + * Finalizes a PSBT if possible, combining partial signatures. + * + * @param[in,out] &psbtx reference to PartiallySignedTransaction to finalize + * return True if the PSBT is now complete, false otherwise + */ +bool FinalizePSBT(PartiallySignedTransaction& psbtx); + +/** + * Finalizes a PSBT if possible, and extracts it to a CMutableTransaction if it could be finalized. + * + * @param[in] &psbtx reference to PartiallySignedTransaction + * @param[out] result CMutableTransaction representing the complete transaction, if successful + * @return True if we successfully extracted the transaction, false otherwise + */ +bool FinalizeAndExtractPSBT(PartiallySignedTransaction& psbtx, CMutableTransaction& result); + +/** + * Combines PSBTs with the same underlying transaction, resulting in a single PSBT with all partial signatures from each input. + * + * @param[out] &out the combined PSBT, if successful + * @param[in] psbtxs the PSBTs to combine + * @return error (OK if we successfully combined the transactions, other error if they were not compatible) + */ +NODISCARD TransactionError CombinePSBTs(PartiallySignedTransaction& out, const std::vector<PartiallySignedTransaction>& psbtxs); + +#endif // BITCOIN_PSBT_H diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index ca26131b95..1b063771ef 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -55,9 +55,6 @@ #if defined(QT_STATICPLUGIN) #include <QtPlugin> -#if QT_VERSION < 0x050400 -Q_IMPORT_PLUGIN(AccessibleFactory) -#endif #if defined(QT_QPA_PLATFORM_XCB) Q_IMPORT_PLUGIN(QXcbIntegrationPlugin); #elif defined(QT_QPA_PLATFORM_WINDOWS) @@ -218,6 +215,8 @@ BitcoinApplication::~BitcoinApplication() #ifdef ENABLE_WALLET delete paymentServer; paymentServer = nullptr; + delete m_wallet_controller; + m_wallet_controller = nullptr; #endif delete optionsModel; optionsModel = nullptr; @@ -307,18 +306,20 @@ void BitcoinApplication::requestShutdown() qDebug() << __func__ << ": Requesting shutdown"; startThread(); window->hide(); + // Must disconnect node signals otherwise current thread can deadlock since + // no event loop is running. + window->unsubscribeFromCoreSignals(); + // Request node shutdown, which can interrupt long operations, like + // rescanning a wallet. + m_node.startShutdown(); + // Unsetting the client model can cause the current thread to wait for node + // to complete an operation, like wait for a RPC execution to complate. window->setClientModel(nullptr); pollShutdownTimer->stop(); -#ifdef ENABLE_WALLET - delete m_wallet_controller; - m_wallet_controller = nullptr; -#endif delete clientModel; clientModel = nullptr; - m_node.startShutdown(); - // Request shutdown from core thread Q_EMIT requestedShutdown(); } @@ -452,7 +453,7 @@ int GuiMain(int argc, char* argv[]) // IMPORTANT if it is no longer a typedef use the normal variant above qRegisterMetaType< CAmount >("CAmount"); qRegisterMetaType< std::function<void()> >("std::function<void()>"); - + qRegisterMetaType<QMessageBox::Icon>("QMessageBox::Icon"); /// 2. Parse command-line options. We do this after qt in order to show an error if there are problems parsing these // Command-line options take precedence: node->setupServerArgs(); diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index ba7e8c7daf..abf9136eee 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -334,6 +334,13 @@ void BitcoinGUI::createActions() openAction = new QAction(platformStyle->TextColorIcon(":/icons/open"), tr("Open &URI..."), this); openAction->setStatusTip(tr("Open a bitcoin: URI or payment request")); + m_open_wallet_action = new QAction(tr("Open Wallet"), this); + m_open_wallet_action->setMenu(new QMenu(this)); + m_open_wallet_action->setStatusTip(tr("Open a wallet")); + + m_close_wallet_action = new QAction(tr("Close Wallet..."), this); + m_close_wallet_action->setStatusTip(tr("Close wallet")); + showHelpMessageAction = new QAction(platformStyle->TextColorIcon(":/icons/info"), tr("&Command-line options"), this); showHelpMessageAction->setMenuRole(QAction::NoRole); showHelpMessageAction->setStatusTip(tr("Show the %1 help message to get a list with possible Bitcoin command-line options").arg(tr(PACKAGE_NAME))); @@ -361,6 +368,42 @@ void BitcoinGUI::createActions() connect(usedSendingAddressesAction, &QAction::triggered, walletFrame, &WalletFrame::usedSendingAddresses); connect(usedReceivingAddressesAction, &QAction::triggered, walletFrame, &WalletFrame::usedReceivingAddresses); connect(openAction, &QAction::triggered, this, &BitcoinGUI::openClicked); + connect(m_open_wallet_action->menu(), &QMenu::aboutToShow, [this] { + m_open_wallet_action->menu()->clear(); + for (std::string path : m_wallet_controller->getWalletsAvailableToOpen()) { + QString name = path.empty() ? QString("["+tr("default wallet")+"]") : QString::fromStdString(path); + QAction* action = m_open_wallet_action->menu()->addAction(name); + connect(action, &QAction::triggered, [this, name, path] { + OpenWalletActivity* activity = m_wallet_controller->openWallet(path); + + QProgressDialog* dialog = new QProgressDialog(this); + dialog->setLabelText(tr("Opening Wallet <b>%1</b>...").arg(name.toHtmlEscaped())); + dialog->setRange(0, 0); + dialog->setCancelButton(nullptr); + dialog->setWindowModality(Qt::ApplicationModal); + dialog->show(); + + connect(activity, &OpenWalletActivity::message, this, [this] (QMessageBox::Icon icon, QString text) { + QMessageBox box; + box.setIcon(icon); + box.setText(tr("Open Wallet Failed")); + box.setInformativeText(text); + box.setStandardButtons(QMessageBox::Ok); + box.setDefaultButton(QMessageBox::Ok); + connect(this, &QObject::destroyed, &box, &QDialog::accept); + box.exec(); + }); + connect(activity, &OpenWalletActivity::opened, this, &BitcoinGUI::setCurrentWallet); + connect(activity, &OpenWalletActivity::finished, activity, &QObject::deleteLater); + connect(activity, &OpenWalletActivity::finished, dialog, &QObject::deleteLater); + bool invoked = QMetaObject::invokeMethod(activity, "open"); + assert(invoked); + }); + } + }); + connect(m_close_wallet_action, &QAction::triggered, [this] { + m_wallet_controller->closeWallet(walletFrame->currentWalletModel(), this); + }); } #endif // ENABLE_WALLET @@ -382,6 +425,9 @@ void BitcoinGUI::createMenuBar() QMenu *file = appMenuBar->addMenu(tr("&File")); if(walletFrame) { + file->addAction(m_open_wallet_action); + file->addAction(m_close_wallet_action); + file->addSeparator(); file->addAction(openAction); file->addAction(backupWalletAction); file->addAction(signMessageAction); @@ -656,6 +702,7 @@ void BitcoinGUI::setWalletActionsEnabled(bool enabled) usedSendingAddressesAction->setEnabled(enabled); usedReceivingAddressesAction->setEnabled(enabled); openAction->setEnabled(enabled); + m_close_wallet_action->setEnabled(enabled); } void BitcoinGUI::createTrayIcon() diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index f1b76a6b64..b58ccbb455 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -95,6 +95,9 @@ public: */ bool hasTrayIcon() const { return trayIcon; } + /** Disconnect core signals from GUI client */ + void unsubscribeFromCoreSignals(); + protected: void changeEvent(QEvent *e); void closeEvent(QCloseEvent *event); @@ -144,6 +147,8 @@ private: QAction* openRPCConsoleAction = nullptr; QAction* openAction = nullptr; QAction* showHelpMessageAction = nullptr; + QAction* m_open_wallet_action{nullptr}; + QAction* m_close_wallet_action{nullptr}; QAction* m_wallet_selector_label_action = nullptr; QAction* m_wallet_selector_action = nullptr; @@ -184,8 +189,6 @@ private: /** Connect core signals to GUI client */ void subscribeToCoreSignals(); - /** Disconnect core signals from GUI client */ - void unsubscribeFromCoreSignals(); /** Update UI with latest network info from model. */ void updateNetworkState(); diff --git a/src/qt/bitcoinstrings.cpp b/src/qt/bitcoinstrings.cpp index de60b30dfe..dc997e96cc 100644 --- a/src/qt/bitcoinstrings.cpp +++ b/src/qt/bitcoinstrings.cpp @@ -30,8 +30,6 @@ QT_TRANSLATE_NOOP("bitcoin-core", "" "Distributed under the MIT software license, see the accompanying file %s or " "%s"), QT_TRANSLATE_NOOP("bitcoin-core", "" -"Error loading %s: You can't enable HD on an already existing non-HD wallet"), -QT_TRANSLATE_NOOP("bitcoin-core", "" "Error reading %s! All keys read correctly, but transaction data or address " "book entries might be missing or incorrect."), QT_TRANSLATE_NOOP("bitcoin-core", "" @@ -40,12 +38,6 @@ QT_TRANSLATE_NOOP("bitcoin-core", "" "Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -" "fallbackfee."), QT_TRANSLATE_NOOP("bitcoin-core", "" -"Group outputs by address, selecting all or none, instead of selecting on a " -"per-output basis. Privacy is improved as an address is only used once " -"(unless someone sends to it after spending from it), but may result in " -"slightly higher fees as suboptimal coin selection may result due to the " -"added limitation (default: %u)"), -QT_TRANSLATE_NOOP("bitcoin-core", "" "Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay " "fee of %s to prevent stuck transactions)"), QT_TRANSLATE_NOOP("bitcoin-core", "" @@ -91,12 +83,6 @@ QT_TRANSLATE_NOOP("bitcoin-core", "" "Unable to rewind the database to a pre-fork state. You will need to " "redownload the blockchain"), QT_TRANSLATE_NOOP("bitcoin-core", "" -"Unsupported argument -socks found. Setting SOCKS version isn't possible " -"anymore, only SOCKS5 proxies are supported."), -QT_TRANSLATE_NOOP("bitcoin-core", "" -"Unsupported argument -whitelistalwaysrelay ignored, use -whitelistrelay and/" -"or -whitelistforcerelay."), -QT_TRANSLATE_NOOP("bitcoin-core", "" "Warning: Private keys detected in wallet {%s} with disabled private keys"), QT_TRANSLATE_NOOP("bitcoin-core", "" "Warning: The network does not appear to fully agree! Some miners appear to " @@ -122,18 +108,17 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Cannot downgrade wallet"), QT_TRANSLATE_NOOP("bitcoin-core", "Cannot resolve -%s address: '%s'"), QT_TRANSLATE_NOOP("bitcoin-core", "Cannot write to data directory '%s'; check permissions."), QT_TRANSLATE_NOOP("bitcoin-core", "Change index out of range"), +QT_TRANSLATE_NOOP("bitcoin-core", "Config setting for %s only applied on %s network when in [%s] section."), QT_TRANSLATE_NOOP("bitcoin-core", "Copyright (C) %i-%i"), QT_TRANSLATE_NOOP("bitcoin-core", "Corrupted block database detected"), QT_TRANSLATE_NOOP("bitcoin-core", "Do you want to rebuild the block database now?"), QT_TRANSLATE_NOOP("bitcoin-core", "Done loading"), -QT_TRANSLATE_NOOP("bitcoin-core", "Error creating %s: You can't create non-HD wallets with this version."), QT_TRANSLATE_NOOP("bitcoin-core", "Error initializing block database"), QT_TRANSLATE_NOOP("bitcoin-core", "Error initializing wallet database environment %s!"), QT_TRANSLATE_NOOP("bitcoin-core", "Error loading %s"), QT_TRANSLATE_NOOP("bitcoin-core", "Error loading %s: Private keys can only be disabled during creation"), QT_TRANSLATE_NOOP("bitcoin-core", "Error loading %s: Wallet corrupted"), QT_TRANSLATE_NOOP("bitcoin-core", "Error loading %s: Wallet requires newer version of %s"), -QT_TRANSLATE_NOOP("bitcoin-core", "Error loading %s: You can't disable HD on an already existing HD wallet"), QT_TRANSLATE_NOOP("bitcoin-core", "Error loading block database"), QT_TRANSLATE_NOOP("bitcoin-core", "Error loading wallet %s. Duplicate -wallet filename specified."), QT_TRANSLATE_NOOP("bitcoin-core", "Error opening block database"), @@ -141,6 +126,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Error reading from database, shutting down.") QT_TRANSLATE_NOOP("bitcoin-core", "Error upgrading chainstate database"), QT_TRANSLATE_NOOP("bitcoin-core", "Error"), QT_TRANSLATE_NOOP("bitcoin-core", "Error: A fatal internal error occurred, see debug.log for details"), +QT_TRANSLATE_NOOP("bitcoin-core", "Error: Disk space is low for %s"), QT_TRANSLATE_NOOP("bitcoin-core", "Error: Disk space is low!"), QT_TRANSLATE_NOOP("bitcoin-core", "Failed to listen on any port. Use -listen=0 if you want this."), QT_TRANSLATE_NOOP("bitcoin-core", "Failed to rescan the wallet during initialization"), @@ -170,6 +156,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Reducing -maxconnections from %d to %d, becau QT_TRANSLATE_NOOP("bitcoin-core", "Replaying blocks..."), QT_TRANSLATE_NOOP("bitcoin-core", "Rescanning..."), QT_TRANSLATE_NOOP("bitcoin-core", "Rewinding blocks..."), +QT_TRANSLATE_NOOP("bitcoin-core", "Section [%s] is not recognized."), QT_TRANSLATE_NOOP("bitcoin-core", "Signing transaction failed"), QT_TRANSLATE_NOOP("bitcoin-core", "Specified -walletdir \"%s\" does not exist"), QT_TRANSLATE_NOOP("bitcoin-core", "Specified -walletdir \"%s\" is a relative path"), @@ -177,6 +164,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Specified -walletdir \"%s\" is not a director QT_TRANSLATE_NOOP("bitcoin-core", "Specified blocks directory \"%s\" does not exist."), QT_TRANSLATE_NOOP("bitcoin-core", "Starting network threads..."), QT_TRANSLATE_NOOP("bitcoin-core", "The source code is available from %s."), +QT_TRANSLATE_NOOP("bitcoin-core", "The specified config file %s does not exist\n"), QT_TRANSLATE_NOOP("bitcoin-core", "The transaction amount is too small to pay the fee"), QT_TRANSLATE_NOOP("bitcoin-core", "The wallet will avoid paying less than the minimum relay fee."), QT_TRANSLATE_NOOP("bitcoin-core", "This is experimental software."), @@ -195,9 +183,6 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Unable to generate initial keys"), QT_TRANSLATE_NOOP("bitcoin-core", "Unable to generate keys"), QT_TRANSLATE_NOOP("bitcoin-core", "Unable to start HTTP server. See debug log for details."), QT_TRANSLATE_NOOP("bitcoin-core", "Unknown network specified in -onlynet: '%s'"), -QT_TRANSLATE_NOOP("bitcoin-core", "Unsupported argument -benchmark ignored, use -debug=bench."), -QT_TRANSLATE_NOOP("bitcoin-core", "Unsupported argument -debugnet ignored, use -debug=net."), -QT_TRANSLATE_NOOP("bitcoin-core", "Unsupported argument -tor found, use -onion."), QT_TRANSLATE_NOOP("bitcoin-core", "Unsupported logging category %s=%s."), QT_TRANSLATE_NOOP("bitcoin-core", "Upgrading UTXO database"), QT_TRANSLATE_NOOP("bitcoin-core", "Upgrading txindex database"), diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index 30d9e977b8..27b4c182f9 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -237,8 +237,8 @@ static void BlockTipChanged(ClientModel *clientmodel, bool initialSync, int heig clientmodel->cachedBestHeaderHeight = height; clientmodel->cachedBestHeaderTime = blockTime; } - // if we are in-sync, update the UI regardless of last update time - if (!initialSync || now - nLastUpdateNotification > MODEL_UPDATE_DELAY) { + // if we are in-sync or if we notify a header update, update the UI regardless of last update time + if (fHeader || !initialSync || now - nLastUpdateNotification > MODEL_UPDATE_DELAY) { //pass an async signal to the UI thread QMetaObject::invokeMethod(clientmodel, "numBlocksChanged", Qt::QueuedConnection, Q_ARG(int, height), diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index 71e987c8f4..ba0a5abdf3 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -21,10 +21,6 @@ #include <util/system.h> #ifdef WIN32 -#ifdef _WIN32_WINNT -#undef _WIN32_WINNT -#endif -#define _WIN32_WINNT 0x0501 #ifdef _WIN32_IE #undef _WIN32_IE #endif diff --git a/src/qt/locale/bitcoin_af.ts b/src/qt/locale/bitcoin_af.ts index bff2db1d6a..c7e7fdd56a 100644 --- a/src/qt/locale/bitcoin_af.ts +++ b/src/qt/locale/bitcoin_af.ts @@ -1205,6 +1205,10 @@ </context> <context> <name>QRImageWidget</name> + <message> + <source>&Save Image...</source> + <translation>&Stoor beeld</translation> + </message> </context> <context> <name>RPCConsole</name> @@ -1364,6 +1368,10 @@ <translation>&Boodslap:</translation> </message> <message> + <source>Clear all fields of the form.</source> + <translation>Vee alle velde op die vorm skoon</translation> + </message> + <message> <source>Clear</source> <translation>Skoonmaak</translation> </message> @@ -1399,10 +1407,18 @@ <translation>QR Kode</translation> </message> <message> + <source>Copy &URI</source> + <translation>Kopieer &URI</translation> + </message> + <message> <source>Copy &Address</source> <translation>Kopieer &Address</translation> </message> <message> + <source>&Save Image...</source> + <translation>&Stoor beeld</translation> + </message> + <message> <source>Request payment to %1</source> <translation>Versoek betaling van %1</translation> </message> @@ -1434,7 +1450,15 @@ <source>Wallet</source> <translation>Beursie</translation> </message> - </context> + <message> + <source>Resulting URI too long, try to reduce the text for label / message.</source> + <translation>Gevolglike URI te lank, probeer teks verkort vir etiket/boodskap</translation> + </message> + <message> + <source>Error encoding URI into QR Code.</source> + <translation>Fout met enkodering van URI na QR kode</translation> + </message> +</context> <context> <name>RecentRequestsTableModel</name> <message> @@ -1521,6 +1545,20 @@ <translation>Kies...</translation> </message> <message> + <source>Using the fallbackfee can result in sending a transaction that will take several hours or days (or never) to confirm. Consider choosing your fee manually or wait until you have validated the complete chain.</source> + <translation>Die verstekfooi kan veroorsaak dat 'n transaksie gestuur word wat +etlike ure of dae (of nooit) sal neem om te bevestig. Oorweeg om +'n fooi met die hand te kies, of wag tot jy die hele ketting bevestig het.</translation> + </message> + <message> + <source>Warning: Fee estimation is currently not possible.</source> + <translation>Waarskuwing: fooiskatting is tans onbeskikbaar</translation> + </message> + <message> + <source>collapse fee-settings</source> + <translation>Vou fooi-nistellings in</translation> + </message> + <message> <source>per kilobyte</source> <translation>per kilogreep</translation> </message> @@ -1529,6 +1567,13 @@ <translation>Versteek</translation> </message> <message> + <source>Paying only the minimum fee is just fine as long as there is less transaction volume than space in the blocks. But be aware that this can end up in a never confirming transaction once there is more demand for bitcoin transactions than the network can process.</source> + <translation>Om die minimumfooi te betaal is in die haak, mits daar minder transaksievolume +as ruimte in die blok is. Wees bewus dat de gevolg kan wees dat 'n transaksie nooit +bevestig nie indien daar meer aanvraag vir bitcoin transaksies is as wat die netwerk kan +verwerk.</translation> + </message> + <message> <source>Recommended:</source> <translation>Aanbeveel:</translation> </message> @@ -1537,14 +1582,40 @@ <translation>Aangepaste:</translation> </message> <message> + <source>(Smart fee not initialized yet. This usually takes a few blocks...)</source> + <translation>(Slimfooi nog nie opgestel nie. Dit neem gewoonlik 'n paar blokke...)</translation> + </message> + <message> + <source>Send to multiple recipients at once</source> + <translation>Stuur aan veelvuldige ontvangers tegelyk</translation> + </message> + <message> <source>Add &Recipient</source> <translation>Voeg by &Ontvanger</translation> </message> <message> + <source>Clear all fields of the form.</source> + <translation>Vee alle velde op die vorm skoon</translation> + </message> + <message> <source>Dust:</source> <translation>Stof:</translation> </message> <message> + <source>Confirmation time target:</source> + <translation>Bevestigingstyd teiken:</translation> + </message> + <message> + <source>Enable Replace-By-Fee</source> + <translation>Bemontlik vervang-deur-fooi</translation> + </message> + <message> + <source>With Replace-By-Fee (BIP-125) you can increase a transaction's fee after it is sent. Without this, a higher fee may be recommended to compensate for increased transaction delay risk.</source> + <translation>Met Vervang-Met-Fooi (BIP-125) kan jy 'n transaskiefooi verhoog nadat dit gestuur is. +Daarsonder mag 'n hoër fooi dalk aanbeveel word om te kompenseer vir 'n verhoogde +transaksievertragingsrisiko.</translation> + </message> + <message> <source>Clear &All</source> <translation>Maak skoon &Alles</translation> </message> @@ -1553,6 +1624,10 @@ <translation>Balans:</translation> </message> <message> + <source>Confirm the send action</source> + <translation>Bevestig stuuraksie</translation> + </message> + <message> <source>S&end</source> <translation>S&tuur</translation> </message> @@ -1593,14 +1668,80 @@ <translation>%1 tot %2</translation> </message> <message> + <source>Are you sure you want to send?</source> + <translation>Is u seker u wil verstuur?</translation> + </message> + <message> + <source>or</source> + <translation>of</translation> + </message> + <message> + <source>You can increase the fee later (signals Replace-By-Fee, BIP-125).</source> + <translation>U kan die fooi later verhoog (sein Vervang-met-Fooi, BIP-125)</translation> + </message> + <message> <source>Transaction fee</source> <translation>Transaksie fooi</translation> </message> <message> + <source>Not signalling Replace-By-Fee, BIP-125.</source> + <translation>Sein nie Vervang-Met-Fooi nie, BIP-25</translation> + </message> + <message> + <source>Confirm send coins</source> + <translation>Bevestig versending van munte</translation> + </message> + <message> + <source>The recipient address is not valid. Please recheck.</source> + <translation>Die ontvangeradres is ongeldig. Kyk asseblief weer mooi.</translation> + </message> + <message> + <source>The amount to pay must be larger than 0.</source> + <translation>Bedrag moet groter as nul wees</translation> + </message> + <message> + <source>The amount exceeds your balance.</source> + <translation>Die bedrag oorskry jou saldo</translation> + </message> + <message> + <source>The total exceeds your balance when the %1 transaction fee is included.</source> + <translation>Die somtotaal oorskry jou saldo as die %1 transaksiefooi ingereken word</translation> + </message> + <message> + <source>Duplicate address found: addresses should only be used once each.</source> + <translation>Duplikaatadres: adresse behoort slegs eenkeer gebruik te word</translation> + </message> + <message> + <source>Transaction creation failed!</source> + <translation>Transaksieopstelling het gefaal</translation> + </message> + <message> + <source>The transaction was rejected with the following reason: %1</source> + <translation>Die transaksie is afgekeur met die volgende rede: %1</translation> + </message> + <message> + <source>A fee higher than %1 is considered an absurdly high fee.</source> + <translation>'n Fooi hoër as %1 word as buitensporig beskou</translation> + </message> + <message> <source>Payment request expired.</source> <translation>Betalings versoek verstryk.</translation> </message> <message> + <source>Pay only the required fee of %1</source> + <translation>Betaal slegs die verlangde fooi van %1</translation> + </message> + <message> + <source>Warning: Invalid Bitcoin address</source> + <translation>Waarskuwing: Ongeldige Bitcoinadres</translation> + </message> + <message> + <source>The address you selected for change is not part of this wallet. Any or all funds in your wallet may be sent to this address. Are you sure?</source> + <translation>Die adres wat u gekies het vir verandering is nie deel van hierdie +beursie nie. Enige of alle fondse mag dalk daarheen gestuur word. +Is u seker?</translation> + </message> + <message> <source>(no label)</source> <translation>(geen etiket)</translation> </message> @@ -1616,14 +1757,57 @@ <translation>&Etiket:</translation> </message> <message> + <source>Choose previously used address</source> + <translation>Kies voorhen gebruikte adres</translation> + </message> + <message> + <source>This is a normal payment.</source> + <translation>Hierdie is 'n gewone betaling</translation> + </message> + <message> + <source>The Bitcoin address to send the payment to</source> + <translation>Die Bitcoinadres waarheen die betaling gestuur word</translation> + </message> + <message> <source>Alt+A</source> <translation>Alt+A</translation> </message> <message> + <source>Paste address from clipboard</source> + <translation>Plak adres van aanknipbord af</translation> + </message> + <message> + <source>Remove this entry</source> + <translation>Verwyder hierdie inskrywing</translation> + </message> + <message> + <source>The fee will be deducted from the amount being sent. The recipient will receive less bitcoins than you enter in the amount field. If multiple recipients are selected, the fee is split equally.</source> + <translation>De fooi word afgetrek van die gestuurde bedrag. +Die ontvanger sal minder ontvang as wat u in die +bedrag opgee. As daar meer as een ontvanger is, +word die fooi eweredig verdeel.</translation> + </message> + <message> + <source>S&ubtract fee from amount</source> + <translation>Bedrag &Sonder fooi </translation> + </message> + <message> + <source>Use available balance</source> + <translation>Gebruik beskikbare saldo</translation> + </message> + <message> <source>Message:</source> <translation>Boodskap:</translation> </message> <message> + <source>This is an unauthenticated payment request.</source> + <translation>Hierdie is 'n ongemagtigde uitbetalingsversoek</translation> + </message> + <message> + <source>This is an authenticated payment request.</source> + <translation>Hierdie is 'n gemagtigde uitbetalingsversoek</translation> + </message> + <message> <source>Pay To:</source> <translation>Betaal Vir:</translation> </message> @@ -1645,10 +1829,18 @@ <translation>&Teken Boodskap</translation> </message> <message> + <source>Choose previously used address</source> + <translation>Kies voorhen gebruikte adres</translation> + </message> + <message> <source>Alt+A</source> <translation>Alt+A</translation> </message> <message> + <source>Paste address from clipboard</source> + <translation>Plak adres van aanknipbord af</translation> + </message> + <message> <source>Signature</source> <translation>Handtekening</translation> </message> @@ -1978,4 +2170,4 @@ <translation>Fout</translation> </message> </context> -</TS>
\ No newline at end of file +</TS> diff --git a/src/qt/locale/bitcoin_af_ZA.ts b/src/qt/locale/bitcoin_af_ZA.ts index b3e9acca9d..4f31d4cd62 100644 --- a/src/qt/locale/bitcoin_af_ZA.ts +++ b/src/qt/locale/bitcoin_af_ZA.ts @@ -227,6 +227,10 @@ <context> <name>BanTableModel</name> <message> + <source>IP/Netmask</source> + <translation>IP/Netmasker</translation> + </message> + <message> <source>Banned Until</source> <translation>Verban Tot</translation> </message> @@ -330,6 +334,14 @@ <translation>Klik om netwerk aktiwiteit weer aan te skakel.</translation> </message> <message> + <source>Syncing Headers (%1%)...</source> + <translation>Sinkroniseer tans Hoofde (%1%)...</translation> + </message> + <message> + <source>Reindexing blocks on disk...</source> + <translation>Herindekseer blokke op skyf...</translation> + </message> + <message> <source>Send coins to a Bitcoin address</source> <translation>Stuur muntstukke na 'n Bitcoin adres</translation> </message> @@ -346,6 +358,10 @@ <translation>&Ontfoutvenster</translation> </message> <message> + <source>Open debugging and diagnostic console</source> + <translation>Open ontfouting en diagnostiese konsole</translation> + </message> + <message> <source>&Verify message...</source> <translation>&Verifieer boodskap...</translation> </message> @@ -414,10 +430,22 @@ <translation>Wys die lys van gebruikte ontvangsadresse en etikette</translation> </message> <message> + <source>Open a bitcoin: URI or payment request</source> + <translation>Open 'n bitcoin: URI of betalingsversoek</translation> + </message> + <message> <source>&Command-line options</source> <translation>&Opdrag lys opsies</translation> </message> <message> + <source>Indexing blocks on disk...</source> + <translation>Indekseer tans blokke op skyf...</translation> + </message> + <message> + <source>Processing blocks on disk...</source> + <translation>Prosesseer tans blokke op skyf...</translation> + </message> + <message> <source>%1 behind</source> <translation>%1 agter</translation> </message> @@ -426,6 +454,10 @@ <translation>Ontvangs van laaste blok is %1 terug.</translation> </message> <message> + <source>Transactions after this will not yet be visible.</source> + <translation>Opvolgende transaksies sal nog nie sigbaar wees nie.</translation> + </message> + <message> <source>Error</source> <translation>Fout</translation> </message> @@ -442,10 +474,18 @@ <translation>Op datum</translation> </message> <message> + <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source> + <translation>Wys die %1 hulpboodskap om 'n lys met moontlike Bitcoin bevel-lyn opsies te verkry</translation> + </message> + <message> <source>%1 client</source> <translation>%1 klient</translation> </message> <message> + <source>Connecting to peers...</source> + <translation>Verbind tans aan eweknieë...</translation> + </message> + <message> <source>Catching up...</source> <translation>Besig om op te vang...</translation> </message> @@ -468,12 +508,22 @@ </translation> </message> <message> + <source>Label: %1 +</source> + <translation>Etiket: %1 +</translation> + </message> + <message> <source>Address: %1 </source> <translation>Adres: %1 </translation> </message> <message> + <source>Sent transaction</source> + <translation>Gestuurde transaksie</translation> + </message> + <message> <source>Incoming transaction</source> <translation>Inkomende transaksie</translation> </message> @@ -493,7 +543,11 @@ <source>Wallet is <b>encrypted</b> and currently <b>locked</b></source> <translation>Beursie is <b>versleutel</b> en is tans <b>gesluit</b></translation> </message> - </context> + <message> + <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source> + <translation>'n Noodlottige fout het voorgekom. Bitcoin kan nie langer voortgaan nie en sal afsluit.</translation> + </message> +</context> <context> <name>CoinControlDialog</name> <message> @@ -521,10 +575,18 @@ <translation>Stof:</translation> </message> <message> + <source>After Fee:</source> + <translation>Na Fooi:</translation> + </message> + <message> <source>Change:</source> <translation>Verander:</translation> </message> <message> + <source>(un)select all</source> + <translation>(on)selekteer alles</translation> + </message> + <message> <source>Tree mode</source> <translation>Boom wyse</translation> </message> @@ -617,6 +679,14 @@ <translation>nee</translation> </message> <message> + <source>This label turns red if any recipient receives an amount smaller than the current dust threshold.</source> + <translation>Hierdie etiket verander na rooi as enige ontvanger 'n bedrag kleiner as die huidige stof drempelwaarde ontvang.</translation> + </message> + <message> + <source>Can vary +/- %1 satoshi(s) per input.</source> + <translation>Kan wissel met +/- %1 satoshi(s) per inset.</translation> + </message> + <message> <source>(no label)</source> <translation>(geen etiket)</translation> </message> @@ -640,6 +710,14 @@ <translation>&Etiket</translation> </message> <message> + <source>The label associated with this address list entry</source> + <translation>Die etiket geassosieer met hierdie adreslys inskrywing</translation> + </message> + <message> + <source>The address associated with this address list entry. This can only be modified for sending addresses.</source> + <translation>Die adres geassosieer met hierdie adreslys inskrywing. Dié kan slegs gewysig word vir stuur-adresse.</translation> + </message> + <message> <source>&Address</source> <translation>&Adres</translation> </message> @@ -656,6 +734,10 @@ <translation>Wysig stuurende adres</translation> </message> <message> + <source>The entered address "%1" is not a valid Bitcoin address.</source> + <translation>Die ingeskrewe adres "%1" is nie 'n geldige Bitcoin adres nie.</translation> + </message> + <message> <source>Could not unlock wallet.</source> <translation>Kon nie die beursie oopsluit nie.</translation> </message> @@ -679,6 +761,10 @@ <translation>Lêer bestaan reeds. Voeg %1 indien u van plan is om n nuwe lêer hier te skep.</translation> </message> <message> + <source>Path already exists, and is not a directory.</source> + <translation>Pad bestaan reeds en is nie 'n lêergids nie.</translation> + </message> + <message> <source>Cannot create data directory here.</source> <translation>Kan nie data gids hier skep nie.</translation> </message> @@ -971,6 +1057,10 @@ <translation>Fooi:</translation> </message> <message> + <source>After Fee:</source> + <translation>Na Fooi:</translation> + </message> + <message> <source>Change:</source> <translation>Verander:</translation> </message> diff --git a/src/qt/locale/bitcoin_am.ts b/src/qt/locale/bitcoin_am.ts new file mode 100644 index 0000000000..46942066e2 --- /dev/null +++ b/src/qt/locale/bitcoin_am.ts @@ -0,0 +1,451 @@ +<TS language="am" version="2.1"> +<context> + <name>AddressBookPage</name> + <message> + <source>Right-click to edit address or label</source> + <translation>አድራሻ ወይም መለያ ስም ለመቀየር ቀኙን ጠቅ ያድርጉ</translation> + </message> + <message> + <source>Create a new address</source> + <translation>አዲስ አድራሻ ፍጠር</translation> + </message> + <message> + <source>&New</source> + <translation>&አዲስ</translation> + </message> + <message> + <source>Copy the currently selected address to the system clipboard</source> + <translation>አሁን የተመረጠውን አድራሻ ወደ ሲስተሙ ቅንጥብ ሰሌዳ ቅዳ</translation> + </message> + <message> + <source>&Copy</source> + <translation>&ቅዳ</translation> + </message> + <message> + <source>C&lose</source> + <translation>ዝጋ</translation> + </message> + <message> + <source>Delete the currently selected address from the list</source> + <translation>አሁን የተመረጠውን አድራሻ ከዝርዝሩ ውስጥ ሰርዝ</translation> + </message> + <message> + <source>Export the data in the current tab to a file</source> + <translation>በአሁኑ ማውጫ ውስጥ ያለውን መረጃ ወደ አንድ ፋይል ላክ</translation> + </message> + <message> + <source>&Export</source> + <translation>&ላክ</translation> + </message> + <message> + <source>&Delete</source> + <translation>&ሰርዝ</translation> + </message> + <message> + <source>Choose the address to send coins to</source> + <translation>ገንዘብ/ኮይኖች የሚልኩለትን አድራሻ ይምረጡ</translation> + </message> + <message> + <source>Choose the address to receive coins with</source> + <translation>ገንዘብ/ኮይኖች የሚቀበሉበትን አድራሻ ይምረጡ</translation> + </message> + <message> + <source>C&hoose</source> + <translation>ምረጥ</translation> + </message> + <message> + <source>Sending addresses</source> + <translation>የመላኪያ አድራሻዎች</translation> + </message> + <message> + <source>Receiving addresses</source> + <translation>የመቀበያ አድራሻዎች</translation> + </message> + <message> + <source>These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins.</source> + <translation>እነኚ የቢትኮይን ክፍያ የመላኪያ አድራሻዎችዎ ናቸው:: ገንዘብ/ኮይኖች ከመላክዎ በፊት መጠኑን እና የመቀበያ አድራሻውን ሁልጊዜ ያረጋግጡ::</translation> + </message> + <message> + <source>These are your Bitcoin addresses for receiving payments. It is recommended to use a new receiving address for each transaction.</source> + <translation>እነኚ የቢትኮይን ክፍያ የመቀበያ አድራሻዎችዎ ናቸው:: ለእያንዳንዱ ግብይት አዲስ የመቀበያ አድራሻ እንዲጠቀሙ ይመከራል:: </translation> + </message> + <message> + <source>&Copy Address</source> + <translation>&አድራሻ ቅዳ</translation> + </message> + <message> + <source>Copy &Label</source> + <translation>ቅዳ &መለያ ስም</translation> + </message> + <message> + <source>&Edit</source> + <translation> &ቀይር</translation> + </message> + <message> + <source>Export Address List</source> + <translation>የአድራሻ ዝርዝር ላክ</translation> + </message> + <message> + <source>Comma separated file (*.csv)</source> + <translation>ኮማ ሴፓሬትድ ፋይል (*.csv)</translation> + </message> + <message> + <source>Exporting Failed</source> + <translation>ወደ ውጪ መላክ አልተሳካም</translation> + </message> + <message> + <source>There was an error trying to save the address list to %1. Please try again.</source> + <translation>የአድራሻ ዝርዝሩን ወደ %1 ለማስቀመጥ ሲሞከር ስህተት አጋጥሟል:: እባክዎ መልሰው ይሞክሩ::</translation> + </message> +</context> +<context> + <name>AddressTableModel</name> + <message> + <source>Label</source> + <translation>መለያ ስም</translation> + </message> + <message> + <source>Address</source> + <translation>አድራሻ</translation> + </message> + <message> + <source>(no label)</source> + <translation>(መለያ ስም የለም)</translation> + </message> +</context> +<context> + <name>AskPassphraseDialog</name> + <message> + <source>Passphrase Dialog</source> + <translation>የይለፍ-ሐረግ ንግግር</translation> + </message> + <message> + <source>Enter passphrase</source> + <translation>የይለፍ-ሐረግዎን ያስገቡ</translation> + </message> + <message> + <source>New passphrase</source> + <translation>አዲስ የይለፍ-ሐረግ</translation> + </message> + <message> + <source>Repeat new passphrase</source> + <translation>አዲስ የይለፍ-ሐረጉን ይድገሙት</translation> + </message> + <message> + <source>Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>.</source> + <translation>አዲስ የይለፍ ሐረግዎን ወደ ቢትኮይን ቦርሳዎ ያስገቡ:: <br/>እባክዎ ለየይለፍ ሐረግዎ<b>አስር ወይም ከዚያ በላይ የዘፈቀደ ዓይነተ-ፊደላት</b>, ወይም<b>ስምንት ወይም ከዚያ በላይ ቃላት</b> ይጠቀሙ ::</translation> + </message> + <message> + <source>Encrypt wallet</source> + <translation>የቢትኮይን ቦርሳውን አመስጥር</translation> + </message> + <message> + <source>This operation needs your wallet passphrase to unlock the wallet.</source> + <translation>ይህ ክንዋኔ የቢትኮይን ቦርሳዎን ለመክፈት የቦርሳዎ ይለፍ-ሐረግ ያስፈልገዋል::</translation> + </message> + <message> + <source>Unlock wallet</source> + <translation>የቢትኮይን ቦርሳውን ክፈት</translation> + </message> + <message> + <source>This operation needs your wallet passphrase to decrypt the wallet.</source> + <translation>ይህ ክንዋኔ የቢትኮይን ቦርሳዎን ለመፍታት የቦርሳዎ ይለፍ-ሐረግ ያስፈልገዋል::</translation> + </message> + <message> + <source>Decrypt wallet</source> + <translation>የቢትኮይን ቦርሳውን ፍታ</translation> + </message> + <message> + <source>Change passphrase</source> + <translation>ይለፍ-ሐረግ ለውጥ</translation> + </message> + <message> + <source>Enter the old passphrase and new passphrase to the wallet.</source> + <translation>የድሮውን የይለፍ-ሐረግ እና አዲሱን የይለፍ-ሐረግ ወደ ቢትኮይን ቦርሳዎ ያስገቡ::</translation> + </message> + <message> + <source>Confirm wallet encryption</source> + <translation>የቢትኮይን ቦርሳዎን ማመስጠር ያረጋግጡ</translation> + </message> + <message> + <source>Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>!</source> + <translation>ማስጠንቀቂያ: የቢትኮይን ቦርሳዎን አመስጥረው የይለፍ-ሐረግዎን ካጡት<b>ቢትኮይኖቾን በሙሉ ያጣሉ</b>!</translation> + </message> + <message> + <source>Are you sure you wish to encrypt your wallet?</source> + <translation>እርግጠኛ ነዎት ቦርሳዎን ማመስጠር ይፈልጋሉ?</translation> + </message> + <message> + <source>Wallet encrypted</source> + <translation>ቦርሳዎ ምስጢር ተደርጓል</translation> + </message> + <message> + <source>%1 will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source> + <translation>%1 የማመስጠር ሂደቱን ለመጨረስ አሁን ይዘጋል:: ያስታውሱ፣ ኮምፒተርዎ በተንኮል አዘል ሶፍትዌር ከተበከለ ቦርሳዎን ማመስጠር ቢትኮይኖቾን ሙሉበሙሉ እንዳይሰረቁ ሊከላከል አይችልም::</translation> + </message> + <message> + <source>IMPORTANT: Any previous backups you have made of your wallet file should be replaced with the newly generated, encrypted wallet file. For security reasons, previous backups of the unencrypted wallet file will become useless as soon as you start using the new, encrypted wallet.</source> + <translation>አስፈላጊ: ከ ቦርሳ ፋይልዎ ያከናወኗቸው ቀደም ያሉ ምትኬዎች በአዲስ በተፈጠረ የማመስጠሪያ ፋይል ውስጥ መተካት አለባቸው. ለደህንነት ሲባል, አዲሱን የተመሰጠ የቦርሳ ፋይል መጠቀም ሲጀመሩ ወዲያውኑ ቀደም ሲል ያልተመሰጠሩ የቦርሳ ፋይል ቅጂዎች ዋጋ ቢስ ይሆናሉ::</translation> + </message> + <message> + <source>Wallet encryption failed</source> + <translation>የቦርሳ ማመስጠር አልተሳካም</translation> + </message> + <message> + <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source> + <translation>የቦርሳ ማመስጠር በውስጣዊ ስህተት ምክንያት አልተሳካም:: ቦርሳዎ አልተመሰጠረም::</translation> + </message> + <message> + <source>The supplied passphrases do not match.</source> + <translation>የተሰጡት የይለፍ-ሐረግዎች አይዛመዱም::</translation> + </message> + <message> + <source>Wallet unlock failed</source> + <translation>ቦርሳ መክፈት አልተሳካም</translation> + </message> + <message> + <source>The passphrase entered for the wallet decryption was incorrect.</source> + <translation>ቦርሳ ለመፍታት ያስገቡት የይለፍ-ሐረግ ትክክል አልነበረም::</translation> + </message> + <message> + <source>Wallet decryption failed</source> + <translation>ቦርሳ መፍታት አልተሳካም </translation> + </message> + <message> + <source>Wallet passphrase was successfully changed.</source> + <translation>የቦርሳ የይለፍ-ሐረግ በተሳካ ሁኔታ ተቀይሯል.</translation> + </message> + <message> + <source>Warning: The Caps Lock key is on!</source> + <translation>ማስጠንቀቂያ: የ "Caps Lock" ቁልፍ በርቷል!</translation> + </message> +</context> +<context> + <name>BanTableModel</name> + <message> + <source>IP/Netmask</source> + <translation>አይፒ/ኔትማስክ IP/Netmask</translation> + </message> + <message> + <source>Banned Until</source> + <translation>ታግደዋል እስከ</translation> + </message> +</context> +<context> + <name>BitcoinGUI</name> + <message> + <source>Sign &message...</source> + <translation>ምልክትና መልእክት...</translation> + </message> + <message> + <source>Synchronizing with network...</source> + <translation>ከኔትወርክ ጋራ በማመሳሰል ላይ ነው...</translation> + </message> + <message> + <source>&Overview</source> + <translation>&አጠቃላይ እይታ</translation> + </message> + <message> + <source>Node</source> + <translation>እትር</translation> + </message> + <message> + <source>Show general overview of wallet</source> + <translation>የቦርሳ አጠቃላይ እይታ ኣሳይ</translation> + </message> + <message> + <source>&Transactions</source> + <translation>&ግብይቶች</translation> + </message> + <message> + <source>Browse transaction history</source> + <translation>የግብይት ታሪክ ያስሱ</translation> + </message> + <message> + <source>E&xit</source> + <translation>ውጣ</translation> + </message> + <message> + <source>Quit application</source> + <translation>አፕሊኬሽኑን አቁም</translation> + </message> + <message> + <source>&About %1</source> + <translation>&ስለ %1</translation> + </message> + <message> + <source>Show information about %1</source> + <translation>ስለ %1 መረጃ አሳይ</translation> + </message> + <message> + <source>About &Qt</source> + <translation>ስለ &Qt</translation> + </message> + <message> + <source>Show information about Qt</source> + <translation>ስለ Qt መረጃ አሳይ</translation> + </message> + <message> + <source>&Options...</source> + <translation>&አማራጮች...</translation> + </message> + </context> +<context> + <name>CoinControlDialog</name> + <message> + <source>(no label)</source> + <translation>(መለያ ስም የለም)</translation> + </message> + </context> +<context> + <name>EditAddressDialog</name> + </context> +<context> + <name>FreespaceChecker</name> + </context> +<context> + <name>HelpMessageDialog</name> + </context> +<context> + <name>Intro</name> + </context> +<context> + <name>ModalOverlay</name> + </context> +<context> + <name>OpenURIDialog</name> + </context> +<context> + <name>OptionsDialog</name> + </context> +<context> + <name>OverviewPage</name> + </context> +<context> + <name>PaymentServer</name> + </context> +<context> + <name>PeerTableModel</name> + </context> +<context> + <name>QObject</name> + </context> +<context> + <name>QObject::QObject</name> + </context> +<context> + <name>QRImageWidget</name> + </context> +<context> + <name>RPCConsole</name> + </context> +<context> + <name>ReceiveCoinsDialog</name> + </context> +<context> + <name>ReceiveRequestDialog</name> + <message> + <source>Address</source> + <translation>አድራሻ</translation> + </message> + <message> + <source>Label</source> + <translation>መለያ ስም</translation> + </message> + </context> +<context> + <name>RecentRequestsTableModel</name> + <message> + <source>Label</source> + <translation>መለያ ስም</translation> + </message> + <message> + <source>(no label)</source> + <translation>(መለያ ስም የለም)</translation> + </message> + </context> +<context> + <name>SendCoinsDialog</name> + <message> + <source>(no label)</source> + <translation>(መለያ ስም የለም)</translation> + </message> +</context> +<context> + <name>SendCoinsEntry</name> + </context> +<context> + <name>SendConfirmationDialog</name> + </context> +<context> + <name>ShutdownWindow</name> + </context> +<context> + <name>SignVerifyMessageDialog</name> + </context> +<context> + <name>SplashScreen</name> + </context> +<context> + <name>TrafficGraphWidget</name> + </context> +<context> + <name>TransactionDesc</name> + </context> +<context> + <name>TransactionDescDialog</name> + </context> +<context> + <name>TransactionTableModel</name> + <message> + <source>Label</source> + <translation>መለያ ስም</translation> + </message> + <message> + <source>(no label)</source> + <translation>(መለያ ስም የለም)</translation> + </message> + </context> +<context> + <name>TransactionView</name> + <message> + <source>Comma separated file (*.csv)</source> + <translation>ኮማ ሴፓሬትድ ፋይል (*.csv)</translation> + </message> + <message> + <source>Label</source> + <translation>መለያ ስም</translation> + </message> + <message> + <source>Address</source> + <translation>አድራሻ</translation> + </message> + <message> + <source>Exporting Failed</source> + <translation>ወደ ውጪ መላክ አልተሳካም</translation> + </message> + </context> +<context> + <name>UnitDisplayStatusBarControl</name> + </context> +<context> + <name>WalletFrame</name> + </context> +<context> + <name>WalletModel</name> + </context> +<context> + <name>WalletView</name> + <message> + <source>&Export</source> + <translation>&ላክ</translation> + </message> + <message> + <source>Export the data in the current tab to a file</source> + <translation>በአሁኑ ማውጫ ውስጥ ያለውን መረጃ ወደ አንድ ፋይል ላክ</translation> + </message> + </context> +<context> + <name>bitcoin-core</name> + </context> +</TS>
\ No newline at end of file diff --git a/src/qt/locale/bitcoin_ar.ts b/src/qt/locale/bitcoin_ar.ts index 481e02c60e..d176505ac3 100644 --- a/src/qt/locale/bitcoin_ar.ts +++ b/src/qt/locale/bitcoin_ar.ts @@ -2936,6 +2936,11 @@ <translation>يرجى المساهمة إذا وجدت %s مفيداً. تفضل بزيارة %s لمزيد من المعلومات حول البرنامج.</translation> </message> <message> + <source>%s corrupt, salvage failed</source> + <translation> +%s تالف, فشل الانقاذ.</translation> + </message> + <message> <source>Change index out of range</source> <translation>فهرس الفكة خارج النطاق</translation> </message> @@ -2960,6 +2965,18 @@ <translation>خطأ في تحميل %s</translation> </message> <message> + <source>Error loading %s: Private keys can only be disabled during creation</source> + <translation>خطأ في تحميل %s: لا يمكن تعطيل المفاتيح الخاصة إلا أثناء الإنشاء.</translation> + </message> + <message> + <source>Error loading %s: Wallet corrupted</source> + <translation>خطأ في التحميل %s: المحفظة تالفة.</translation> + </message> + <message> + <source>Error loading %s: Wallet requires newer version of %s</source> + <translation>خطا تحميل %s: المحفظة تتطلب النسخة الجديدة من %s.</translation> + </message> + <message> <source>Error loading block database</source> <translation>خطأ في تحميل قاعدة بيانات الكتل</translation> </message> @@ -2976,6 +2993,10 @@ <translation>فشل في الاستماع على أي منفذ. استخدام الاستماع = 0 إذا كنت تريد هذا.</translation> </message> <message> + <source>Failed to rescan the wallet during initialization</source> + <translation>فشل في اعادة مسح المحفظة خلال عملية التهيئة.</translation> + </message> + <message> <source>Importing...</source> <translation>استيراد...</translation> </message> @@ -3020,6 +3041,10 @@ <translation>شفرة المصدر متاحة من %s.</translation> </message> <message> + <source>Unable to generate keys</source> + <translation> غير قادر على توليد مفاتيح.</translation> + </message> + <message> <source>Unsupported argument -tor found, use -onion.</source> <translation>تم العثور على وسيطة غير مدعومة -tor ، استخدم -onion.</translation> </message> @@ -3128,6 +3153,10 @@ <translation>يجب ألا تكون قيمة المعاملة سلبية</translation> </message> <message> + <source>Transaction has too long of a mempool chain</source> + <translation>المعاملات طويلة جداً على حجم سلسلة الذاكرة </translation> + </message> + <message> <source>Transaction must have at least one recipient</source> <translation>يجب أن تحتوي المعاملة على مستلم واحد على الأقل</translation> </message> @@ -3136,6 +3165,10 @@ <translation>اموال غير كافية</translation> </message> <message> + <source>Cannot write to data directory '%s'; check permissions.</source> + <translation>لايمكن الكتابة على دليل البيانات '%s'؛ تحقق من السماحيات.</translation> + </message> + <message> <source>Loading block index...</source> <translation>تحميل مؤشر الكتلة</translation> </message> diff --git a/src/qt/locale/bitcoin_bg.ts b/src/qt/locale/bitcoin_bg.ts index be7fed59a1..c9d33ed6bb 100644 --- a/src/qt/locale/bitcoin_bg.ts +++ b/src/qt/locale/bitcoin_bg.ts @@ -136,6 +136,10 @@ <translation>Въведете новата парола повторно</translation> </message> <message> + <source>Show password</source> + <translation>Покажи парола</translation> + </message> + <message> <source>Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>.</source> <translation>Въведете новата парола към портфейла.<br/>Моля ползвайте парола съставена от <b>десет или повече произволни символа</b>, или <b>осем или повече думи</b>.</translation> </message> @@ -318,6 +322,14 @@ <translation>Отвори &URI...</translation> </message> <message> + <source>Wallet:</source> + <translation>Портфейл</translation> + </message> + <message> + <source>default wallet</source> + <translation>Портфейл по подразбиране</translation> + </message> + <message> <source>Click to disable network activity.</source> <translation>Натиснете за деактивиране на мрежата</translation> </message> @@ -330,6 +342,10 @@ <translation>Натиснете за повторно активиране на мрежата.</translation> </message> <message> + <source>Syncing Headers (%1%)...</source> + <translation>Синхронизиране на хедъри (%1%)</translation> + </message> + <message> <source>Reindexing blocks on disk...</source> <translation>Повторно индексиране на блоковете на диска...</translation> </message> @@ -876,6 +892,10 @@ <translation>&Мрежа</translation> </message> <message> + <source>GB</source> + <translation>ГБ</translation> + </message> + <message> <source>W&allet</source> <translation>По&ртфейл</translation> </message> @@ -900,6 +920,14 @@ <translation>Отваряне на входящия порт чрез &UPnP</translation> </message> <message> + <source>Accept connections from outside.</source> + <translation>Позволи външни връзки</translation> + </message> + <message> + <source>Allow incomin&g connections</source> + <translation>Позволи входящи връзки</translation> + </message> + <message> <source>Connect to the Bitcoin network through a SOCKS5 proxy.</source> <translation>Свързване с Биткойн мрежата чрез SOCKS5 прокси.</translation> </message> @@ -920,6 +948,10 @@ <translation>Порт на прокси сървъра (пр. 9050)</translation> </message> <message> + <source>Tor</source> + <translation>Тор</translation> + </message> + <message> <source>&Window</source> <translation>&Прозорец</translation> </message> @@ -980,6 +1012,10 @@ <translation>Изисква се рестартиране на клиента за активиране на извършените промени.</translation> </message> <message> + <source>Client will be shut down. Do you want to proceed?</source> + <translation>Клиентът ще бъде изключен. Искате ли да продължите?</translation> + </message> + <message> <source>Error</source> <translation>Грешка</translation> </message> @@ -1349,6 +1385,10 @@ <translation>Изчисти конзолата</translation> </message> <message> + <source>default wallet</source> + <translation>Портфейл по подразбиране</translation> + </message> + <message> <source>via %1</source> <translation>посредством %1</translation> </message> diff --git a/src/qt/locale/bitcoin_cs.ts b/src/qt/locale/bitcoin_cs.ts index 260d79b766..a08cc960da 100644 --- a/src/qt/locale/bitcoin_cs.ts +++ b/src/qt/locale/bitcoin_cs.ts @@ -354,6 +354,10 @@ <translation>Vytvářím nový index bloků na disku...</translation> </message> <message> + <source>Proxy is <b>enabled</b>: %1</source> + <translation>Proxy je <b>zapnutá</b>: %1</translation> + </message> + <message> <source>Send coins to a Bitcoin address</source> <translation>Pošli mince na bitcoinovou adresu</translation> </message> @@ -522,6 +526,12 @@ </translation> </message> <message> + <source>Wallet: %1 +</source> + <translation>Peněženka: %1 +</translation> + </message> + <message> <source>Type: %1 </source> <translation>Typ: %1 @@ -758,6 +768,14 @@ <translation>Zadaná adresa „%1“ není platná bitcoinová adresa.</translation> </message> <message> + <source>Address "%1" already exists as a receiving address with label "%2" and so cannot be added as a sending address.</source> + <translation>Adresa "%1" již existuje jako přijímací adresa s označením "%2" a proto nemůže být přidána jako odesílací adresa.</translation> + </message> + <message> + <source>The entered address "%1" is already in the address book with label "%2".</source> + <translation>Zadaná adresa „%1“ už v adresáři je s označením "%2".</translation> + </message> + <message> <source>Could not unlock wallet.</source> <translation>Nemohu odemknout peněženku.</translation> </message> @@ -1036,6 +1054,22 @@ <translation>&Síť</translation> </message> <message> + <source>Disables some advanced features but all blocks will still be fully validated. Reverting this setting requires re-downloading the entire blockchain. Actual disk usage may be somewhat higher.</source> + <translation>Zakáže některé pokročilé funkce, ale všechny bloky budou stále plně otevřené. Obnovení tohoto nastavení vyžaduje opětovné převzetí celého blockchainu. Skutečné využít disku může být o něco vyšší.</translation> + </message> + <message> + <source>Prune &block storage to</source> + <translation>Redukovat prostor pro &bloky na</translation> + </message> + <message> + <source>GB</source> + <translation>GB</translation> + </message> + <message> + <source>Reverting this setting requires re-downloading the entire blockchain.</source> + <translation>Obnovení tohoto nastavení vyžaduje opětovné převzetí celého blockchainu.</translation> + </message> + <message> <source>(0 = auto, <0 = leave that many cores free)</source> <translation>(0 = automaticky, <0 = nechat daný počet jader volný, výchozí: 0)</translation> </message> @@ -1503,10 +1537,18 @@ <context> <name>QObject::QObject</name> <message> + <source>Error parsing command line arguments: %1.</source> + <translation>Chyba při zpracování argumentů příkazového řádku: %1.</translation> + </message> + <message> <source>Error: Specified data directory "%1" does not exist.</source> <translation>Chyba: Zadaný adresář pro data „%1“ neexistuje.</translation> </message> <message> + <source>Error: Cannot parse configuration file: %1.</source> + <translation>Chyba: Konfigurační soubor se nedá zpracovat: %1.</translation> + </message> + <message> <source>Error: %1</source> <translation>Chyba: %1</translation> </message> @@ -1597,6 +1639,14 @@ <translation>Obsazenost paměti</translation> </message> <message> + <source>Wallet: </source> + <translation>Peněženka:</translation> + </message> + <message> + <source>(none)</source> + <translation>(žádné)</translation> + </message> + <message> <source>&Reset</source> <translation>&Vynulovat</translation> </message> @@ -1777,6 +1827,14 @@ <translation>V historii se pohybuješ šipkami nahoru a dolů a pomocí %1 čistíš obrazovku.</translation> </message> <message> + <source>Type %1 for an overview of available commands.</source> + <translation>Napiš %1 pro přehled dostupných příkazů.</translation> + </message> + <message> + <source>For more information on using this console type %1.</source> + <translation>Pro více informací jak používat tuto konzoli napište %1.</translation> + </message> + <message> <source>WARNING: Scammers have been active, telling users to type commands here, stealing their wallet contents. Do not use this console without fully understanding the ramifications of a command.</source> <translation>UPOZORNĚNÍ: Podvodníci jsou aktivní a říkají uživatelům, aby sem zadávali příkazy, kterými jim pak ale vykradou jejich peněženky. Nepoužívej tuhle konzoli, pokud úplně neznáš důsledky jednotlivých příkazů.</translation> </message> @@ -1785,6 +1843,14 @@ <translation>Síť je vypnutá</translation> </message> <message> + <source>Executing command without any wallet</source> + <translation>Spouštění příkazu bez jakékoliv peněženky</translation> + </message> + <message> + <source>Executing command using "%1" wallet</source> + <translation>Příkaz se vykonává s použitím peněženky "%1"</translation> + </message> + <message> <source>(node id: %1)</source> <translation>(id uzlu: %1)</translation> </message> @@ -1856,6 +1922,14 @@ <translation>Vyčistit</translation> </message> <message> + <source>Native segwit addresses (aka Bech32 or BIP-173) reduce your transaction fees later on and offer better protection against typos, but old wallets don't support them. When unchecked, an address compatible with older wallets will be created instead.</source> + <translation>Nativní segwit adresy (Bech32 nebo BIP-173) snižují Vaše budoucí transakční poplatky a nabízejí lepší ochranu před překlepy, avšak staré peněženky je nepodporují. Pokud je toto pole nezaškrtnuté, bude vytvořena adresa kompatibilní se staršími peněženkami.</translation> + </message> + <message> + <source>Generate native segwit (Bech32) address</source> + <translation>Generovat nativní segwit adresu (Bench32)</translation> + </message> + <message> <source>Requested payments history</source> <translation>Historie vyžádaných plateb</translation> </message> @@ -2061,6 +2135,14 @@ <translation>sbal nastavení poplatků</translation> </message> <message> + <source>Specify a custom fee per kB (1,000 bytes) of the transaction's virtual size. + +Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis per kB" for a transaction size of 500 bytes (half of 1 kB) would ultimately yield a fee of only 50 satoshis.</source> + <translation>Specifikujte vlastní poplatek za kB (1000 bajtů) virtuální velikosti transakce. + +Poznámka: Jelikož je poplatek počítaný za bajt, poplatek o hodnotě "100 satoshi za kB" a velikost transakce 500 bajtů (polovina z 1 kB) by stál jen 50 satoshi.</translation> + </message> + <message> <source>per kilobyte</source> <translation>za kilobajt</translation> </message> @@ -2113,6 +2195,10 @@ <translation>Povolit možnost dodatečně transakci navýšit poplatek (tzv. „replace-by-fee“)</translation> </message> <message> + <source>With Replace-By-Fee (BIP-125) you can increase a transaction's fee after it is sent. Without this, a higher fee may be recommended to compensate for increased transaction delay risk.</source> + <translation>S dodatečným navýšením poplatku (BIP-125, tzv. „Replace-By-Fee“) můžete zvýšit poplatek i po odeslání. Bez dodatečného navýšení bude navrhnut vyšší transakční poplatek, tak aby kompenzoval zvýšené riziko prodlení transakce.</translation> + </message> + <message> <source>Clear &All</source> <translation>Všechno s&maž</translation> </message> @@ -2173,10 +2259,30 @@ <translation>nebo</translation> </message> <message> + <source>You can increase the fee later (signals Replace-By-Fee, BIP-125).</source> + <translation>Poplatek můžete navýšit později (vysílá se "Replace-By-Fee" - nahrazení poplatkem, BIP-125).</translation> + </message> + <message> + <source>from wallet %1</source> + <translation>z peněženky %1</translation> + </message> + <message> + <source>Please, review your transaction.</source> + <translation>Prosím, zkontrolujte vaši transakci.</translation> + </message> + <message> <source>Transaction fee</source> <translation>Transakční poplatek</translation> </message> <message> + <source>Not signalling Replace-By-Fee, BIP-125.</source> + <translation>Nevysílá se "Replace-By-Fee" - nahrazení poplatkem, BIP-125.</translation> + </message> + <message> + <source>Total Amount</source> + <translation>Celková částka</translation> + </message> + <message> <source>Confirm send coins</source> <translation>Potvrď odeslání mincí</translation> </message> @@ -2296,6 +2402,10 @@ <translation>Od&ečíst poplatek od částky</translation> </message> <message> + <source>Use available balance</source> + <translation>Použít dostupný zůstatek</translation> + </message> + <message> <source>Message:</source> <translation>Zpráva:</translation> </message> @@ -2626,6 +2736,10 @@ <translation>Celková velikost transakce</translation> </message> <message> + <source>Transaction virtual size</source> + <translation>Virtuální velikost transakce</translation> + </message> + <message> <source>Output index</source> <translation>Pořadí výstupu</translation> </message> @@ -3030,7 +3144,11 @@ <source>The wallet data was successfully saved to %1.</source> <translation>Data z peněženky byla v pořádku uložena do %1.</translation> </message> - </context> + <message> + <source>Cancel</source> + <translation>Zrušit</translation> + </message> +</context> <context> <name>bitcoin-core</name> <message> @@ -3082,6 +3200,10 @@ <translation>Nastala chyba při čtení souboru %s! Všechny klíče se přečetly správně, ale data o transakcích nebo záznamy v adresáři mohou chybět či být nesprávné.</translation> </message> <message> + <source>Group outputs by address, selecting all or none, instead of selecting on a per-output basis. Privacy is improved as an address is only used once (unless someone sends to it after spending from it), but may result in slightly higher fees as suboptimal coin selection may result due to the added limitation (default: %u)</source> + <translation>Seskupení výstupů podle adresy, při výběru všech nebo žádných, namísto výběru báze za výstup. Zvýšena ochrana soukromí, protože je adresa použita pouze jednou (pokud nikdo na tuto adresu již nic po minutě nepošle). Může být spojeno s vyššími poplatky, jelikož neoptimalizovaný výběr mincí může vyústit v přidané omezení (předvolené: %u)</translation> + </message> + <message> <source>Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly.</source> <translation>Zkontroluj, že máš v počítači správně nastavený datum a čas! Pokud jsou nastaveny špatně, %s nebude fungovat správně.</translation> </message> @@ -3166,6 +3288,10 @@ <translation>Chyba při načítání %s</translation> </message> <message> + <source>Error loading %s: Private keys can only be disabled during creation</source> + <translation>Chyba při načítání %s: Soukromé klíče můžou být zakázané jen v průběhu vytváření.</translation> + </message> + <message> <source>Error loading %s: Wallet corrupted</source> <translation>Chyba při načítání %s: peněženka je poškozená</translation> </message> @@ -3190,6 +3316,10 @@ <translation>Nepodařilo se naslouchat na žádném portu. Použij -listen=0, pokud to byl tvůj záměr.</translation> </message> <message> + <source>Failed to rescan the wallet during initialization</source> + <translation>Během inicializace se nepodařilo proskenovat peněženku</translation> + </message> + <message> <source>Importing...</source> <translation>Importuji...</translation> </message> @@ -3214,6 +3344,14 @@ <translation>Neplatná částka pro -fallbackfee=<částka>: '%s'</translation> </message> <message> + <source>Specified blocks directory "%s" does not exist.</source> + <translation>Zadaný adresář bloků "%s" neexistuje.</translation> + </message> + <message> + <source>Upgrading txindex database</source> + <translation>Aktualizuje se txindex databáze</translation> + </message> + <message> <source>Loading P2P addresses...</source> <translation>Načítám P2P adresy…</translation> </message> @@ -3254,6 +3392,10 @@ <translation>Nedaří se mi připojit na %s na tomhle počítači. %s už pravděpodobně jednou běží.</translation> </message> <message> + <source>Unable to generate keys</source> + <translation>Nepodařilo se vygenerovat klíče</translation> + </message> + <message> <source>Unsupported argument -benchmark ignored, use -debug=bench.</source> <translation>Nepodporovaný argument -benchmark se ignoruje, použij -debug=bench.</translation> </message> @@ -3346,6 +3488,18 @@ <translation>Nepodařilo se podepsat transakci</translation> </message> <message> + <source>Specified -walletdir "%s" does not exist</source> + <translation>Uvedená -walletdir "%s" neexistuje</translation> + </message> + <message> + <source>Specified -walletdir "%s" is a relative path</source> + <translation>Uvedená -walletdir "%s" je relatívna cesta</translation> + </message> + <message> + <source>Specified -walletdir "%s" is not a directory</source> + <translation>Uvedená -walletdir "%s" není složkou</translation> + </message> + <message> <source>The transaction amount is too small to pay the fee</source> <translation>Částka v transakci je příliš malá na pokrytí poplatku</translation> </message> @@ -3378,6 +3532,10 @@ <translation>Kontroluji peněženku/y…</translation> </message> <message> + <source>Wallet %s resides outside wallet directory %s</source> + <translation>Peněženka %s se nachází mimo adresář pro peněženky %s</translation> + </message> + <message> <source>Warning</source> <translation>Upozornění</translation> </message> @@ -3474,6 +3632,22 @@ <translation>Nedostatek prostředků</translation> </message> <message> + <source>Can't generate a change-address key. Private keys are disabled for this wallet.</source> + <translation>Není možné vygenerovat klíč na změnu adresy. Soukromé klíče jsou pro tuto peněženku zakázané.</translation> + </message> + <message> + <source>Cannot upgrade a non HD split wallet without upgrading to support pre split keypool. Please use -upgradewallet=169900 or -upgradewallet with no version specified.</source> + <translation>Není možné vylepšit peněženku bez HD bez aktualizace, která podporuje dělení keypoolu. Použijte prosím -upgradewallet=169900 nebo -upgradewallet bez specifikované verze.</translation> + </message> + <message> + <source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source> + <translation>Odhad poplatku se nepodařil. Fallbackfee je zakázaný. Počkejte několik bloků nebo povolte -fallbackfee.</translation> + </message> + <message> + <source>Warning: Private keys detected in wallet {%s} with disabled private keys</source> + <translation>Upozornění: Byly zjištěné soukromé klíče v peněžence {%s} se zakázanými soukromými klíči.</translation> + </message> + <message> <source>Loading block index...</source> <translation>Načítám index bloků...</translation> </message> diff --git a/src/qt/locale/bitcoin_da.ts b/src/qt/locale/bitcoin_da.ts index 21dc7831c3..c7a2422c8a 100644 --- a/src/qt/locale/bitcoin_da.ts +++ b/src/qt/locale/bitcoin_da.ts @@ -3200,6 +3200,10 @@ Note: Siden gebyret er kalkuleret på en per-byte basis, et gebyr på "100 satos <translation>Fejl under læsning af %s! Alle nøgler blev læst korrekt, men transaktionsdata eller indgange i adressebogen kan mangle eller være ukorrekte.</translation> </message> <message> + <source>Group outputs by address, selecting all or none, instead of selecting on a per-output basis. Privacy is improved as an address is only used once (unless someone sends to it after spending from it), but may result in slightly higher fees as suboptimal coin selection may result due to the added limitation (default: %u)</source> + <translation>Gruppér output efter adresse og vælg alle eller ingen, i stedet for at vælge på per-output-basis. Højere sikring af privatliv, da en adresse kun bruges én gang (med mindre nogen sender til en adresse efter den er brugt), men kan resultere i en anelse højere gebyrer, da ikke-optimal valg af output-adresser kan forekomme på grund af den tilføjede begrænsning (standard: %u)</translation> + </message> + <message> <source>Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly.</source> <translation>Undersøg venligst at din computers dato og klokkeslet er korrekt indstillet! Hvis der er fejl i disse, vil %s ikke fungere korrekt.</translation> </message> @@ -3340,6 +3344,10 @@ Note: Siden gebyret er kalkuleret på en per-byte basis, et gebyr på "100 satos <translation>Ugyldigt beløb for -fallbackfee=<beløb>: “%s”</translation> </message> <message> + <source>Specified blocks directory "%s" does not exist.</source> + <translation>Angivet blokmappe “%s” eksisterer ikke.</translation> + </message> + <message> <source>Upgrading txindex database</source> <translation>Opgraderer txindex database</translation> </message> @@ -3480,12 +3488,6 @@ Note: Siden gebyret er kalkuleret på en per-byte basis, et gebyr på "100 satos <translation>Signering af transaktion mislykkedes</translation> </message> <message> - <source>Specified blocks directory "%s" does not exist. -</source> - <translation>Specificeret blokke mappe "%s" eksisterer ikke. -</translation> - </message> - <message> <source>The transaction amount is too small to pay the fee</source> <translation>Transaktionsbeløbet er for lille til at betale gebyret</translation> </message> diff --git a/src/qt/locale/bitcoin_de.ts b/src/qt/locale/bitcoin_de.ts index 45d09655c4..31feaf114f 100644 --- a/src/qt/locale/bitcoin_de.ts +++ b/src/qt/locale/bitcoin_de.ts @@ -145,7 +145,7 @@ </message> <message> <source>Encrypt wallet</source> - <translation>Wallet verschlüsseln</translation> + <translation>Brieftasche verschlüsseln</translation> </message> <message> <source>This operation needs your wallet passphrase to unlock the wallet.</source> @@ -161,7 +161,7 @@ </message> <message> <source>Decrypt wallet</source> - <translation>Brieftasche entschlüsseln</translation> + <translation>Wallet entschlüsseln</translation> </message> <message> <source>Change passphrase</source> @@ -3196,6 +3196,10 @@ Hinweis: Eine Gebühr von "100 Satoshis pro kB" bei einer Größe der Transaktio <translation>Lesen von %s fehlgeschlagen! Alle Schlüssel wurden korrekt gelesen, Transaktionsdaten bzw. Adressbucheinträge fehlen aber möglicherweise oder sind inkorrekt.</translation> </message> <message> + <source>Group outputs by address, selecting all or none, instead of selecting on a per-output basis. Privacy is improved as an address is only used once (unless someone sends to it after spending from it), but may result in slightly higher fees as suboptimal coin selection may result due to the added limitation (default: %u)</source> + <translation>Gruppiere Outputs mit der Auswahl von allen oder keinen Adressen, anstatt alle pro Output auszuwählen. Die Privatsphäre wurde verbessert, da eine Adresse nur einmal verwendet wird (ausser jemand sendet Coins nachdem von der Adresse ausgegeben wurde). Durch diese hinzugefügte Limitierung kann es allerdings zu leicht erhöhten Transaktionskosten kommen, da eine suboptimale Coinselektierung bei Transaktionen stattfinden kann. (Standardeinstellung: %u)</translation> + </message> + <message> <source>Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly.</source> <translation>Bitte korrigieren Sie die Datums- und Uhrzeiteinstellungen Ihres Computers, da %s ansonsten nicht ordnungsgemäß funktionieren wird.</translation> </message> @@ -3337,6 +3341,10 @@ Hinweis: Eine Gebühr von "100 Satoshis pro kB" bei einer Größe der Transaktio <translation>Ungültiger Betrag für -fallbackfee=<amount>: '%s'</translation> </message> <message> + <source>Specified blocks directory "%s" does not exist.</source> + <translation>Angegebener Blöcke-Ordner "%s" existiert nicht.</translation> + </message> + <message> <source>Upgrading txindex database</source> <translation>Erneuern der txindex Datenbank</translation> </message> @@ -3485,12 +3493,6 @@ Hinweis: Eine Gebühr von "100 Satoshis pro kB" bei einer Größe der Transaktio <translation>Angegebenes Verzeichniss "%s" ist kein Verzeichniss</translation> </message> <message> - <source>Specified blocks directory "%s" does not exist. -</source> - <translation>Angegebenes 'blocks'-Verzeichnis "%s" existiert nicht. -</translation> - </message> - <message> <source>The transaction amount is too small to pay the fee</source> <translation>Der Transaktionsbetrag ist zu niedrig, um die Gebühr zu bezahlen.</translation> </message> diff --git a/src/qt/locale/bitcoin_el_GR.ts b/src/qt/locale/bitcoin_el_GR.ts index 4557fd85aa..85d5c62c91 100644 --- a/src/qt/locale/bitcoin_el_GR.ts +++ b/src/qt/locale/bitcoin_el_GR.ts @@ -234,7 +234,11 @@ <source>IP/Netmask</source> <translation>IP/Netmask</translation> </message> - </context> + <message> + <source>Banned Until</source> + <translation>Απαγορευμένο έως</translation> + </message> +</context> <context> <name>BitcoinGUI</name> <message> @@ -326,6 +330,10 @@ <translation>Πορτοφόλι</translation> </message> <message> + <source>default wallet</source> + <translation>Προεπιλεγμένο πορτοφόλι</translation> + </message> + <message> <source>Click to disable network activity.</source> <translation>Κάντε κλικ για να απενεργοποιήσετε το δίκτυο.</translation> </message> @@ -338,6 +346,10 @@ <translation>Κάντε κλικ για να ενεργοποιήσετε τo δίκτυο ξανά.</translation> </message> <message> + <source>Syncing Headers (%1%)...</source> + <translation>Συγχρονισμός Επικεφαλίδων (%1%)...</translation> + </message> + <message> <source>Reindexing blocks on disk...</source> <translation>Φόρτωση ευρετηρίου μπλοκ στον σκληρό δίσκο...</translation> </message> @@ -490,6 +502,12 @@ </translation> </message> <message> + <source>Wallet: %1 +</source> + <translation>Πορτοφόλι: %1 +</translation> + </message> + <message> <source>Type: %1 </source> <translation>Τύπος: %1 @@ -611,6 +629,14 @@ <translation>Αντιγραφή ταυτότητας συναλλαγής</translation> </message> <message> + <source>Copy quantity</source> + <translation>Αντιγραφή ποσότητας</translation> + </message> + <message> + <source>Copy fee</source> + <translation>Αντιγραφή τελών</translation> + </message> + <message> <source>yes</source> <translation>ναι</translation> </message> @@ -661,7 +687,27 @@ <source>Edit sending address</source> <translation> Επεξεργασία διεύθυνσης αποστολής</translation> </message> - </context> + <message> + <source>The entered address "%1" is not a valid Bitcoin address.</source> + <translation>Η διεύθυνση "%1" δεν είναι έγκυρη Bitcoin διεύθυνση.</translation> + </message> + <message> + <source>Address "%1" already exists as a receiving address with label "%2" and so cannot be added as a sending address.</source> + <translation>Η διεύθυνση "%1" υπάρχει ήδη ως διεύθυνσης λήψης με ετικέτα "%2" και γιαυτό τον λόγο δεν μπορεί να προστεθεί ως διεύθυνση αποστολής.</translation> + </message> + <message> + <source>The entered address "%1" is already in the address book with label "%2".</source> + <translation>Η διεύθυνση "%1" βρίσκεται ήδη στο βιβλίο διευθύνσεων με ετικέτα "%2".</translation> + </message> + <message> + <source>Could not unlock wallet.</source> + <translation>Δεν είναι δυνατό το ξεκλείδωμα του πορτοφολιού.</translation> + </message> + <message> + <source>New key generation failed.</source> + <translation>Η δημιουργία νέου κλειδιού απέτυχε.</translation> + </message> +</context> <context> <name>FreespaceChecker</name> <message> @@ -696,6 +742,10 @@ <translation>(%1-bit)</translation> </message> <message> + <source>About %1</source> + <translation>Σχετικά %1</translation> + </message> + <message> <source>Command-line options</source> <translation>Επιλογές γραμμής εντολών</translation> </message> @@ -828,6 +878,10 @@ <translation>&Δίκτυο</translation> </message> <message> + <source>GB</source> + <translation>GB</translation> + </message> + <message> <source>(0 = auto, <0 = leave that many cores free)</source> <translation>(0 = αυτόματο, <0 = ελεύθεροι πυρήνες)</translation> </message> @@ -880,6 +934,18 @@ <translation>Θύρα διαμεσολαβητή</translation> </message> <message> + <source>IPv4</source> + <translation>IPv4</translation> + </message> + <message> + <source>IPv6</source> + <translation>IPv6</translation> + </message> + <message> + <source>Tor</source> + <translation>Tor</translation> + </message> + <message> <source>&Window</source> <translation>&Παράθυρο</translation> </message> @@ -1181,6 +1247,10 @@ <translation>Τρέχον αριθμός μπλοκ</translation> </message> <message> + <source>Memory usage</source> + <translation>χρήση Μνήμης</translation> + </message> + <message> <source>Received</source> <translation>Παραλήφθησαν</translation> </message> @@ -1201,6 +1271,14 @@ <translation>Έκδοση</translation> </message> <message> + <source>Decrease font size</source> + <translation>Μείωση μεγέθους γραμματοσειράς</translation> + </message> + <message> + <source>Increase font size</source> + <translation>Αύξηση μεγέθους γραμματοσειράς</translation> + </message> + <message> <source>Services</source> <translation>Υπηρεσίες</translation> </message> @@ -1261,6 +1339,26 @@ <translation>Καθαρισμός κονσόλας</translation> </message> <message> + <source>1 &hour</source> + <translation>1 &ώρα</translation> + </message> + <message> + <source>1 &day</source> + <translation>1 &μέρα</translation> + </message> + <message> + <source>1 &week</source> + <translation>1 &εβδομάδα</translation> + </message> + <message> + <source>1 &year</source> + <translation>1 &χρόνος</translation> + </message> + <message> + <source>default wallet</source> + <translation>Προεπιλεγμένο πορτοφόλι</translation> + </message> + <message> <source>via %1</source> <translation>μέσω %1</translation> </message> @@ -1277,6 +1375,14 @@ <translation>Εξερχόμενα</translation> </message> <message> + <source>Yes</source> + <translation>Ναι</translation> + </message> + <message> + <source>No</source> + <translation>Όχι</translation> + </message> + <message> <source>Unknown</source> <translation>Άγνωστο(α)</translation> </message> @@ -1328,6 +1434,10 @@ <translation>Αντιγραφή ετικέτας</translation> </message> <message> + <source>Copy message</source> + <translation>Αντιγραφή μηνύματος</translation> + </message> + <message> <source>Copy amount</source> <translation>Αντιγραφή ποσού</translation> </message> @@ -1351,14 +1461,26 @@ <translation>&Αποθήκευση εικόνας...</translation> </message> <message> + <source>Payment information</source> + <translation>Πληροφορίες πληρωμής</translation> + </message> + <message> <source>Address</source> <translation>Διεύθυνση</translation> </message> <message> + <source>Amount</source> + <translation>Ποσό</translation> + </message> + <message> <source>Label</source> <translation>Ετικέτα</translation> </message> <message> + <source>Message</source> + <translation>Μήνυμα</translation> + </message> + <message> <source>Wallet</source> <translation>Πορτοφόλι</translation> </message> @@ -1374,6 +1496,10 @@ <translation>Ετικέτα</translation> </message> <message> + <source>Message</source> + <translation>Μήνυμα</translation> + </message> + <message> <source>(no label)</source> <translation>(χωρίς ετικέτα)</translation> </message> @@ -1489,10 +1615,22 @@ <translation>Αποστολή</translation> </message> <message> + <source>Copy quantity</source> + <translation>Αντιγραφή ποσότητας</translation> + </message> + <message> <source>Copy amount</source> <translation>Αντιγραφή ποσού</translation> </message> <message> + <source>Copy fee</source> + <translation>Αντιγραφή τελών</translation> + </message> + <message> + <source>or</source> + <translation>ή</translation> + </message> + <message> <source>Transaction fee</source> <translation>Κόστος συναλλαγής</translation> </message> @@ -1562,7 +1700,11 @@ </context> <context> <name>SendConfirmationDialog</name> - </context> + <message> + <source>Yes</source> + <translation>Ναι</translation> + </message> +</context> <context> <name>ShutdownWindow</name> <message> @@ -1725,6 +1867,14 @@ <source>Transaction fee</source> <translation>Κόστος συναλλαγής</translation> </message> + <message> + <source>Message</source> + <translation>Μήνυμα</translation> + </message> + <message> + <source>Amount</source> + <translation>Ποσό</translation> + </message> </context> <context> <name>TransactionDescDialog</name> @@ -1815,10 +1965,18 @@ </context> <context> <name>WalletModel</name> + <message> + <source>Increase:</source> + <translation>Αύξηση:</translation> + </message> </context> <context> <name>WalletView</name> - </context> + <message> + <source>Cancel</source> + <translation>Ακύρωση</translation> + </message> +</context> <context> <name>bitcoin-core</name> <message> diff --git a/src/qt/locale/bitcoin_en.ts b/src/qt/locale/bitcoin_en.ts index fbff2d36a0..c6ecbc3f87 100644 --- a/src/qt/locale/bitcoin_en.ts +++ b/src/qt/locale/bitcoin_en.ts @@ -237,7 +237,7 @@ </message> <message> <location line="-56"/> - <source>%1 will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source> + <source>Your wallet is now encrypted. Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source> <translation type="unfinished"></translation> </message> <message> @@ -246,32 +246,33 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+9"/> + <location line="+8"/> <location line="+7"/> - <location line="+42"/> + <location line="+43"/> <location line="+6"/> <source>Wallet encryption failed</source> <translation type="unfinished"></translation> </message> <message> - <location line="-54"/> + <location line="-55"/> <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source> <translation type="unfinished"></translation> </message> <message> <location line="+7"/> - <location line="+48"/> + <location line="+49"/> <source>The supplied passphrases do not match.</source> <translation type="unfinished"></translation> </message> <message> - <location line="-37"/> + <location line="-38"/> + <location line="+6"/> <source>Wallet unlock failed</source> <translation type="unfinished"></translation> </message> <message> - <location line="+1"/> - <location line="+11"/> + <location line="-5"/> + <location line="+12"/> <location line="+19"/> <source>The passphrase entered for the wallet decryption was incorrect.</source> <translation type="unfinished"></translation> @@ -309,27 +310,22 @@ <context> <name>BitcoinGUI</name> <message> - <location filename="../bitcoingui.cpp" line="+307"/> + <location filename="../bitcoingui.cpp" line="+318"/> <source>Sign &message...</source> <translation>Sign &message...</translation> </message> <message> - <location line="+483"/> + <location line="+574"/> <source>Synchronizing with network...</source> <translation>Synchronizing with network...</translation> </message> <message> - <location line="-561"/> + <location line="-652"/> <source>&Overview</source> <translation>&Overview</translation> </message> <message> - <location line="-140"/> - <source>Node</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+141"/> + <location line="+1"/> <source>Show general overview of wallet</source> <translation>Show general overview of wallet</translation> </message> @@ -399,32 +395,17 @@ <translation>&Change Passphrase...</translation> </message> <message> - <location line="+12"/> - <source>&Sending addresses...</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+2"/> - <source>&Receiving addresses...</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+3"/> + <location line="+18"/> <source>Open &URI...</source> <translation type="unfinished"></translation> </message> <message> - <location line="+104"/> + <location line="+157"/> <source>Wallet:</source> <translation type="unfinished"></translation> </message> <message> - <location line="+83"/> - <source>default wallet</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+226"/> + <location line="+330"/> <source>Click to disable network activity.</source> <translation type="unfinished"></translation> </message> @@ -444,17 +425,17 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+37"/> + <location line="+53"/> <source>Reindexing blocks on disk...</source> <translation>Reindexing blocks on disk...</translation> </message> <message> - <location line="+316"/> + <location line="+315"/> <source>Proxy is <b>enabled</b>: %1</source> <translation type="unfinished"></translation> </message> <message> - <location line="-880"/> + <location line="-970"/> <source>Send coins to a Bitcoin address</source> <translation>Send coins to a Bitcoin address</translation> </message> @@ -484,17 +465,12 @@ <translation>&Verify message...</translation> </message> <message> - <location line="+570"/> + <location line="+660"/> <source>Bitcoin</source> <translation>Bitcoin</translation> </message> <message> - <location line="-792"/> - <source>Wallet</source> - <translation>Wallet</translation> - </message> - <message> - <location line="+149"/> + <location line="-733"/> <source>&Send</source> <translation>&Send</translation> </message> @@ -529,32 +505,32 @@ <translation>Verify messages to ensure they were signed with specified Bitcoin addresses</translation> </message> <message> - <location line="+58"/> + <location line="+61"/> <source>&File</source> <translation>&File</translation> </message> <message> - <location line="+14"/> + <location line="+11"/> <source>&Settings</source> <translation>&Settings</translation> </message> <message> - <location line="+9"/> + <location line="+66"/> <source>&Help</source> <translation>&Help</translation> </message> <message> - <location line="+15"/> + <location line="+11"/> <source>Tabs toolbar</source> <translation>Tabs toolbar</translation> </message> <message> - <location line="-158"/> + <location line="-211"/> <source>Request payments (generates QR codes and bitcoin: URIs)</source> <translation type="unfinished"></translation> </message> <message> - <location line="+70"/> + <location line="+71"/> <source>Show the list of used sending addresses and labels</source> <translation type="unfinished"></translation> </message> @@ -574,7 +550,7 @@ <translation type="unfinished"></translation> </message> <message numerus="yes"> - <location line="+410"/> + <location line="+484"/> <source>%n active connection(s) to Bitcoin network</source> <translation> <numerusform>%n active connection to Bitcoin network</numerusform> @@ -582,7 +558,7 @@ </translation> </message> <message> - <location line="+60"/> + <location line="+76"/> <source>Indexing blocks on disk...</source> <translation type="unfinished"></translation> </message> @@ -600,7 +576,7 @@ </translation> </message> <message> - <location line="+24"/> + <location line="+23"/> <source>%1 behind</source> <translation>%1 behind</translation> </message> @@ -635,22 +611,57 @@ <translation>Up to date</translation> </message> <message> - <location line="-494"/> + <location line="-593"/> + <source>&Sending addresses</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>&Receiving addresses</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+8"/> <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source> <translation type="unfinished"></translation> </message> <message> - <location line="+253"/> + <location line="+63"/> + <source>&Window</source> + <translation type="unfinished">&Window</translation> + </message> + <message> + <location line="+2"/> + <source>Minimize</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+10"/> + <source>Zoom</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+14"/> + <source>Restore</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+12"/> + <source>Main Window</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+228"/> <source>%1 client</source> <translation type="unfinished"></translation> </message> <message> - <location line="+227"/> + <location line="+241"/> <source>Connecting to peers...</source> <translation type="unfinished"></translation> </message> <message> - <location line="+38"/> + <location line="+37"/> <source>Catching up...</source> <translation>Catching up...</translation> </message> @@ -711,6 +722,11 @@ <translation type="unfinished"></translation> </message> <message> + <location line="+0"/> + <source>Private key <b>disabled</b></source> + <translation type="unfinished"></translation> + </message> + <message> <location line="+19"/> <source>Wallet is <b>encrypted</b> and currently <b>unlocked</b></source> <translation>Wallet is <b>encrypted</b> and currently <b>unlocked</b></translation> @@ -721,7 +737,7 @@ <translation>Wallet is <b>encrypted</b> and currently <b>locked</b></translation> </message> <message> - <location filename="../bitcoin.cpp" line="+529"/> + <location filename="../bitcoin.cpp" line="+395"/> <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source> <translation type="unfinished"></translation> </message> @@ -814,7 +830,7 @@ <translation type="unfinished">Confirmed</translation> </message> <message> - <location filename="../coincontroldialog.cpp" line="+53"/> + <location filename="../coincontroldialog.cpp" line="+58"/> <source>Copy address</source> <translation type="unfinished"></translation> </message> @@ -875,7 +891,7 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+315"/> + <location line="+313"/> <source>(%1 locked)</source> <translation type="unfinished"></translation> </message> @@ -987,7 +1003,7 @@ <context> <name>FreespaceChecker</name> <message> - <location filename="../intro.cpp" line="+77"/> + <location filename="../intro.cpp" line="+73"/> <source>A new data directory will be created.</source> <translation>A new data directory will be created.</translation> </message> @@ -1015,7 +1031,7 @@ <context> <name>HelpMessageDialog</name> <message> - <location filename="../utilitydialog.cpp" line="+41"/> + <location filename="../utilitydialog.cpp" line="+44"/> <source>version</source> <translation type="unfinished">version</translation> </message> @@ -1079,7 +1095,7 @@ <translation>Use a custom data directory:</translation> </message> <message> - <location filename="../intro.cpp" line="+20"/> + <location filename="../intro.cpp" line="+22"/> <source>Bitcoin</source> <translation type="unfinished">Bitcoin</translation> </message> @@ -1104,7 +1120,7 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+73"/> + <location line="+80"/> <source>Error: Specified data directory "%1" cannot be created.</source> <translation type="unfinished"></translation> </message> @@ -1252,12 +1268,7 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+16"/> - <source>MB</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+27"/> + <location line="+43"/> <source>Number of script &verification threads</source> <translation type="unfinished"></translation> </message> @@ -1301,12 +1312,7 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+31"/> - <source>Active command-line options that override above options:</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+45"/> + <location line="+76"/> <source>Open the %1 configuration file from the working directory.</source> <translation type="unfinished"></translation> </message> @@ -1351,7 +1357,12 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+68"/> + <location line="+28"/> + <source>MiB</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+40"/> <source>(0 = auto, <0 = leave that many cores free)</source> <translation type="unfinished"></translation> </message> @@ -1509,7 +1520,12 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+182"/> + <location line="+41"/> + <source>Options set in this dialog are overridden by the command line or in the configuration file:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+141"/> <source>&OK</source> <translation>&OK</translation> </message> @@ -1519,17 +1535,17 @@ <translation>&Cancel</translation> </message> <message> - <location filename="../optionsdialog.cpp" line="+92"/> + <location filename="../optionsdialog.cpp" line="+96"/> <source>default</source> <translation>default</translation> </message> <message> - <location line="+56"/> + <location line="+63"/> <source>none</source> <translation type="unfinished"></translation> </message> <message> - <location line="+77"/> + <location line="+93"/> <source>Confirm options reset</source> <translation>Confirm options reset</translation> </message> @@ -1672,8 +1688,8 @@ <context> <name>PaymentServer</name> <message> - <location filename="../paymentserver.cpp" line="+317"/> - <location line="+215"/> + <location filename="../paymentserver.cpp" line="+226"/> + <location line="+338"/> <location line="+42"/> <location line="+110"/> <location line="+14"/> @@ -1682,30 +1698,42 @@ <translation type="unfinished"></translation> </message> <message> - <location line="-398"/> + <location line="-521"/> <source>Cannot start bitcoin: click-to-pay handler</source> <translation type="unfinished"></translation> </message> <message> - <location line="+82"/> - <location line="+21"/> - <location line="+13"/> + <location line="+62"/> + <location line="+9"/> + <location line="+16"/> + <location line="+5"/> + <location line="+12"/> <location line="+7"/> <source>URI handling</source> <translation type="unfinished"></translation> </message> <message> - <location line="-41"/> + <location line="-49"/> <source>'bitcoin://' is not a valid URI. Use 'bitcoin:' instead.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+22"/> + <location line="+10"/> + <source>You are using a BIP70 URL which will be unsupported in the future.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+16"/> <source>Payment request fetch URL is invalid: %1</source> <translation type="unfinished"></translation> </message> <message> - <location line="+12"/> + <location line="+5"/> + <source>Cannot process payment request because BIP70 support was not compiled in.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+11"/> <source>Invalid payment address %1</source> <translation type="unfinished"></translation> </message> @@ -1715,7 +1743,7 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+13"/> + <location line="+14"/> <source>Payment request file handling</source> <translation type="unfinished"></translation> </message> @@ -1725,7 +1753,7 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+61"/> + <location line="+195"/> <location line="+9"/> <location line="+31"/> <location line="+10"/> @@ -1796,7 +1824,7 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+11"/> + <location line="+6"/> <source>Payment acknowledged</source> <translation type="unfinished"></translation> </message> @@ -1842,12 +1870,12 @@ <translation type="unfinished">Amount</translation> </message> <message> - <location filename="../guiutil.cpp" line="+115"/> + <location filename="../guiutil.cpp" line="+111"/> <source>Enter a Bitcoin address (e.g. %1)</source> <translation type="unfinished"></translation> </message> <message> - <location line="+686"/> + <location line="+687"/> <source>%1 d</source> <translation type="unfinished"></translation> </message> @@ -1957,7 +1985,7 @@ <translation type="unfinished"></translation> </message> <message> - <location filename="../bitcoin.cpp" line="+192"/> + <location filename="../bitcoin.cpp" line="+185"/> <source>%1 didn't yet exit safely...</source> <translation type="unfinished"></translation> </message> @@ -1970,12 +1998,12 @@ <context> <name>QObject::QObject</name> <message> - <location filename="../bitcoin.cpp" line="-117"/> + <location filename="../bitcoin.cpp" line="-113"/> <source>Error parsing command line arguments: %1.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+38"/> + <location line="+37"/> <source>Error: Specified data directory "%1" does not exist.</source> <translation type="unfinished"></translation> </message> @@ -2019,7 +2047,8 @@ <location filename="../forms/debugwindow.ui" line="+56"/> <location line="+26"/> <location line="+26"/> - <location line="+23"/> + <location line="+26"/> + <location line="+29"/> <location line="+26"/> <location line="+36"/> <location line="+23"/> @@ -2027,7 +2056,7 @@ <location line="+23"/> <location line="+36"/> <location line="+23"/> - <location line="+679"/> + <location line="+713"/> <location line="+23"/> <location line="+23"/> <location line="+23"/> @@ -2049,7 +2078,7 @@ <translation>N/A</translation> </message> <message> - <location line="-1361"/> + <location line="-1427"/> <source>Client version</source> <translation>Client version</translation> </message> @@ -2079,7 +2108,22 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+26"/> + <location line="+10"/> + <source>To specify a non-default location of the data directory use the '%1' option.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+19"/> + <source>Blocksdir</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+10"/> + <source>To specify a non-default location of the blocks directory use the '%1' option.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+19"/> <source>Startup time</source> <translation>Startup time</translation> </message> @@ -2129,7 +2173,7 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+8"/> + <location line="+11"/> <source>(none)</source> <translation type="unfinished"></translation> </message> @@ -2140,35 +2184,35 @@ </message> <message> <location line="+80"/> - <location line="+558"/> + <location line="+589"/> <source>Received</source> <translation type="unfinished"></translation> </message> <message> - <location line="-478"/> - <location line="+455"/> + <location line="-509"/> + <location line="+486"/> <source>Sent</source> <translation type="unfinished"></translation> </message> <message> - <location line="-414"/> + <location line="-445"/> <source>&Peers</source> <translation type="unfinished"></translation> </message> <message> - <location line="+53"/> + <location line="+67"/> <source>Banned peers</source> <translation type="unfinished"></translation> </message> <message> - <location line="+60"/> - <location filename="../rpcconsole.cpp" line="+502"/> - <location line="+760"/> + <location line="+65"/> + <location filename="../rpcconsole.cpp" line="+501"/> + <location line="+754"/> <source>Select a peer to view detailed information.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+25"/> + <location line="+37"/> <source>Whitelisted</source> <translation type="unfinished"></translation> </message> @@ -2198,18 +2242,18 @@ <translation type="unfinished"></translation> </message> <message> - <location line="-1095"/> - <location line="+1003"/> + <location line="-1161"/> + <location line="+1069"/> <source>User Agent</source> <translation type="unfinished"></translation> </message> <message> - <location line="-700"/> + <location line="-734"/> <source>Open the %1 debug log file from the current data directory. This can take a few seconds for large log files.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+84"/> + <location line="+87"/> <source>Decrease font size</source> <translation type="unfinished"></translation> </message> @@ -2219,7 +2263,7 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+610"/> + <location line="+641"/> <source>Services</source> <translation type="unfinished"></translation> </message> @@ -2269,7 +2313,7 @@ <translation type="unfinished"></translation> </message> <message> - <location line="-1132"/> + <location line="-1166"/> <source>Last block time</source> <translation>Last block time</translation> </message> @@ -2284,7 +2328,7 @@ <translation>&Console</translation> </message> <message> - <location line="+211"/> + <location line="+214"/> <source>&Network Traffic</source> <translation type="unfinished"></translation> </message> @@ -2294,7 +2338,7 @@ <translation type="unfinished"></translation> </message> <message> - <location filename="../rpcconsole.cpp" line="-414"/> + <location filename="../rpcconsole.cpp" line="-411"/> <source>In:</source> <translation type="unfinished"></translation> </message> @@ -2304,17 +2348,17 @@ <translation type="unfinished"></translation> </message> <message> - <location filename="../forms/debugwindow.ui" line="-315"/> + <location filename="../forms/debugwindow.ui" line="-318"/> <source>Debug log file</source> <translation>Debug log file</translation> </message> <message> - <location line="+152"/> + <location line="+155"/> <source>Clear console</source> <translation>Clear console</translation> </message> <message> - <location filename="../rpcconsole.cpp" line="-253"/> + <location filename="../rpcconsole.cpp" line="-249"/> <source>1 &hour</source> <translation type="unfinished"></translation> </message> @@ -2347,17 +2391,12 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+48"/> + <location line="+47"/> <source>&Unban</source> <translation type="unfinished"></translation> </message> <message> - <location line="+54"/> - <source>default wallet</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+110"/> + <location line="+161"/> <source>Welcome to the %1 RPC console.</source> <translation type="unfinished"></translation> </message> @@ -2387,17 +2426,17 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+68"/> + <location line="+70"/> <source>Executing command without any wallet</source> <translation type="unfinished"></translation> </message> <message> - <location line="+2"/> + <location line="-2"/> <source>Executing command using "%1" wallet</source> <translation type="unfinished"></translation> </message> <message> - <location line="+190"/> + <location line="+189"/> <source>(node id: %1)</source> <translation type="unfinished"></translation> </message> @@ -2626,7 +2665,7 @@ <context> <name>RecentRequestsTableModel</name> <message> - <location filename="../recentrequeststablemodel.cpp" line="+27"/> + <location filename="../recentrequeststablemodel.cpp" line="+25"/> <source>Date</source> <translation type="unfinished">Date</translation> </message> @@ -2665,7 +2704,7 @@ <name>SendCoinsDialog</name> <message> <location filename="../forms/sendcoinsdialog.ui" line="+14"/> - <location filename="../sendcoinsdialog.cpp" line="+588"/> + <location filename="../sendcoinsdialog.cpp" line="+593"/> <source>Send Coins</source> <translation>Send Coins</translation> </message> @@ -2772,18 +2811,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <translation type="unfinished"></translation> </message> <message> - <location line="+80"/> - <location line="+13"/> - <source>Paying only the minimum fee is just fine as long as there is less transaction volume than space in the blocks. But be aware that this can end up in a never confirming transaction once there is more demand for bitcoin transactions than the network can process.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+3"/> - <source>(read the tooltip)</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+29"/> + <location line="+112"/> <source>Recommended:</source> <translation type="unfinished"></translation> </message> @@ -2793,12 +2821,12 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <translation type="unfinished"></translation> </message> <message> - <location line="+52"/> + <location line="+49"/> <source>(Smart fee not initialized yet. This usually takes a few blocks...)</source> <translation type="unfinished"></translation> </message> <message> - <location line="+185"/> + <location line="+166"/> <source>Send to multiple recipients at once</source> <translation>Send to multiple recipients at once</translation> </message> @@ -2813,17 +2841,27 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <translation type="unfinished"></translation> </message> <message> - <location line="-835"/> + <location line="-800"/> <source>Dust:</source> <translation type="unfinished"></translation> </message> <message> - <location line="+696"/> + <location line="+543"/> + <source>When there is less transaction volume than space in the blocks, miners as well as relaying nodes may enforce a minimum fee. Paying only this minimum fee is just fine, but be aware that this can result in a never confirming transaction once there is more demand for bitcoin transactions than the network can process.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>A too low fee might result in a never confirming transaction (read the tooltip)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+131"/> <source>Confirmation time target:</source> <translation type="unfinished"></translation> </message> <message> - <location line="+74"/> + <location line="+58"/> <source>Enable Replace-By-Fee</source> <translation type="unfinished"></translation> </message> @@ -2853,7 +2891,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <translation>S&end</translation> </message> <message> - <location filename="../sendcoinsdialog.cpp" line="-504"/> + <location filename="../sendcoinsdialog.cpp" line="-505"/> <source>Copy quantity</source> <translation type="unfinished"></translation> </message> @@ -2888,20 +2926,20 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <translation type="unfinished"></translation> </message> <message> - <location line="+76"/> + <location line="+74"/> <source>%1 (%2 blocks)</source> <translation type="unfinished"></translation> </message> <message> - <location line="+131"/> - <location line="+5"/> + <location line="+133"/> <location line="+5"/> + <location line="+6"/> <location line="+4"/> <source>%1 to %2</source> <translation type="unfinished"></translation> </message> <message> - <location line="+6"/> + <location line="+7"/> <source>Are you sure you want to send?</source> <translation type="unfinished"></translation> </message> @@ -2916,12 +2954,12 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <translation type="unfinished"></translation> </message> <message> - <location line="-57"/> + <location line="-61"/> <source>from wallet %1</source> <translation type="unfinished"></translation> </message> <message> - <location line="+36"/> + <location line="+40"/> <source>Please, review your transaction.</source> <translation type="unfinished"></translation> </message> @@ -2946,7 +2984,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <translation type="unfinished"></translation> </message> <message> - <location line="+192"/> + <location line="+191"/> <source>The recipient address is not valid. Please recheck.</source> <translation type="unfinished"></translation> </message> @@ -2990,13 +3028,8 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <source>Payment request expired.</source> <translation type="unfinished"></translation> </message> - <message> - <location line="+91"/> - <source>Pay only the required fee of %1</source> - <translation type="unfinished"></translation> - </message> <message numerus="yes"> - <location line="+43"/> + <location line="+120"/> <source>Estimated to begin confirmation within %n block(s).</source> <translation> <numerusform>Estimated to begin confirmation within %n block.</numerusform> @@ -3138,7 +3171,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <translation type="unfinished"></translation> </message> <message> - <location filename="../sendcoinsentry.cpp" line="+35"/> + <location filename="../sendcoinsentry.cpp" line="+39"/> <source>Enter a label for this address to add it to your address book</source> <translation type="unfinished"></translation> </message> @@ -3366,7 +3399,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <context> <name>TransactionDesc</name> <message numerus="yes"> - <location filename="../transactiondesc.cpp" line="+31"/> + <location filename="../transactiondesc.cpp" line="+35"/> <source>Open for %n more block(s)</source> <translation> <numerusform>Open for %n more block</numerusform> @@ -3414,7 +3447,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <translation type="unfinished"></translation> </message> <message> - <location line="+23"/> + <location line="+22"/> <source>Status</source> <translation type="unfinished"></translation> </message> @@ -3473,12 +3506,12 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <location line="+12"/> <location line="+54"/> <location line="+30"/> - <location line="+58"/> + <location line="+60"/> <source>Credit</source> <translation type="unfinished"></translation> </message> <message numerus="yes"> - <location line="-152"/> + <location line="-154"/> <source>matures in %n more block(s)</source> <translation> <numerusform>matures in %n more block</numerusform> @@ -3493,12 +3526,12 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <message> <location line="+60"/> <location line="+26"/> - <location line="+61"/> + <location line="+63"/> <source>Debit</source> <translation type="unfinished"></translation> </message> <message> - <location line="-77"/> + <location line="-79"/> <source>Total debit</source> <translation type="unfinished"></translation> </message> @@ -3549,12 +3582,12 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <translation type="unfinished"></translation> </message> <message> - <location line="+18"/> + <location line="+19"/> <source>Merchant</source> <translation type="unfinished"></translation> </message> <message> - <location line="+7"/> + <location line="+8"/> <source>Generated coins must mature %1 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, its state will change to "not accepted" and it won't be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.</source> <translation type="unfinished"></translation> </message> @@ -3607,7 +3640,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <context> <name>TransactionTableModel</name> <message> - <location filename="../transactiontablemodel.cpp" line="+226"/> + <location filename="../transactiontablemodel.cpp" line="+227"/> <source>Date</source> <translation type="unfinished">Date</translation> </message> @@ -3743,7 +3776,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <context> <name>TransactionView</name> <message> - <location filename="../transactionview.cpp" line="+70"/> + <location filename="../transactionview.cpp" line="+71"/> <location line="+16"/> <source>All</source> <translation type="unfinished"></translation> @@ -3814,7 +3847,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <translation type="unfinished"></translation> </message> <message> - <location line="+47"/> + <location line="+51"/> <source>Abandon transaction</source> <translation type="unfinished"></translation> </message> @@ -3864,7 +3897,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <translation type="unfinished"></translation> </message> <message> - <location line="+193"/> + <location line="+199"/> <source>Export Transaction History</source> <translation type="unfinished"></translation> </message> @@ -3929,7 +3962,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <translation type="unfinished"></translation> </message> <message> - <location line="+166"/> + <location line="+171"/> <source>Range:</source> <translation type="unfinished"></translation> </message> @@ -3942,7 +3975,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <context> <name>UnitDisplayStatusBarControl</name> <message> - <location filename="../bitcoingui.cpp" line="+159"/> + <location filename="../bitcoingui.cpp" line="+154"/> <source>Unit to show amounts in. Click to select another unit.</source> <translation type="unfinished"></translation> </message> @@ -3958,19 +3991,19 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <context> <name>WalletModel</name> <message> - <location filename="../walletmodel.cpp" line="+215"/> + <location filename="../walletmodel.cpp" line="+219"/> <source>Send Coins</source> <translation type="unfinished">Send Coins</translation> </message> <message> - <location line="+289"/> + <location line="+301"/> <location line="+39"/> - <location line="+6"/> + <location line="+5"/> <source>Fee bump error</source> <translation type="unfinished"></translation> </message> <message> - <location line="-45"/> + <location line="-44"/> <source>Increasing transaction fee failed</source> <translation type="unfinished"></translation> </message> @@ -4005,10 +4038,15 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <translation type="unfinished"></translation> </message> <message> - <location line="+6"/> + <location line="+5"/> <source>Could not commit transaction</source> <translation type="unfinished"></translation> </message> + <message> + <location line="+35"/> + <source>default wallet</source> + <translation type="unfinished"></translation> + </message> </context> <context> <name>WalletView</name> @@ -4023,7 +4061,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <translation type="unfinished">Export the data in the current tab to a file</translation> </message> <message> - <location line="+207"/> + <location line="+206"/> <source>Backup Wallet</source> <translation type="unfinished"></translation> </message> @@ -4053,7 +4091,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <translation type="unfinished"></translation> </message> <message> - <location line="+54"/> + <location line="+44"/> <source>Cancel</source> <translation type="unfinished"></translation> </message> @@ -4066,7 +4104,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <translation type="unfinished"></translation> </message> <message> - <location line="+28"/> + <location line="+20"/> <source>Prune configured below the minimum of %d MiB. Please use a higher number.</source> <translation type="unfinished"></translation> </message> @@ -4081,22 +4119,22 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <translation type="unfinished"></translation> </message> <message> - <location line="+81"/> + <location line="+74"/> <source>Error: A fatal internal error occurred, see debug.log for details</source> <translation type="unfinished"></translation> </message> <message> - <location line="+25"/> + <location line="+26"/> <source>Pruning blockstore...</source> <translation type="unfinished"></translation> </message> <message> - <location line="+28"/> + <location line="+30"/> <source>Unable to start HTTP server. See debug log for details.</source> <translation type="unfinished"></translation> </message> <message> - <location line="-184"/> + <location line="-172"/> <source>Bitcoin Core</source> <translation type="unfinished">Bitcoin Core</translation> </message> @@ -4116,17 +4154,12 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <translation type="unfinished"></translation> </message> <message> - <location line="+12"/> + <location line="+10"/> <source>Error reading %s! All keys read correctly, but transaction data or address book entries might be missing or incorrect.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+8"/> - <source>Group outputs by address, selecting all or none, instead of selecting on a per-output basis. Privacy is improved as an address is only used once (unless someone sends to it after spending from it), but may result in slightly higher fees as suboptimal coin selection may result due to the added limitation (default: %u)</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+9"/> + <location line="+11"/> <source>Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly.</source> <translation type="unfinished"></translation> </message> @@ -4161,7 +4194,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <translation type="unfinished"></translation> </message> <message> - <location line="+11"/> + <location line="+5"/> <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source> <translation type="unfinished"></translation> </message> @@ -4197,6 +4230,11 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos </message> <message> <location line="+1"/> + <source>Config setting for %s only applied on %s network when in [%s] section.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> <source>Copyright (C) %i-%i</source> <translation type="unfinished"></translation> </message> @@ -4212,11 +4250,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos </message> <message> <location line="+2"/> - <source>Error creating %s: You can't create non-HD wallets with this version.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+1"/> <source>Error initializing block database</source> <translation>Error initializing block database</translation> </message> @@ -4246,7 +4279,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <translation type="unfinished"></translation> </message> <message> - <location line="+2"/> + <location line="+1"/> <source>Error loading block database</source> <translation>Error loading block database</translation> </message> @@ -4256,7 +4289,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <translation>Error opening block database</translation> </message> <message> - <location line="+5"/> + <location line="+6"/> <source>Error: Disk space is low!</source> <translation>Error: Disk space is low!</translation> </message> @@ -4301,17 +4334,17 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <translation type="unfinished"></translation> </message> <message> - <location line="+21"/> + <location line="+22"/> <source>Specified blocks directory "%s" does not exist.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+26"/> + <location line="+24"/> <source>Upgrading txindex database</source> <translation type="unfinished"></translation> </message> <message> - <location line="-43"/> + <location line="-42"/> <source>Loading P2P addresses...</source> <translation type="unfinished"></translation> </message> @@ -4346,12 +4379,12 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <translation type="unfinished"></translation> </message> <message> - <location line="+7"/> + <location line="+8"/> <source>The source code is available from %s.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+8"/> + <location line="+9"/> <source>Transaction fee and change calculation failed</source> <translation type="unfinished"></translation> </message> @@ -4367,21 +4400,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos </message> <message> <location line="+3"/> - <source>Unsupported argument -benchmark ignored, use -debug=bench.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+1"/> - <source>Unsupported argument -debugnet ignored, use -debug=net.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+1"/> - <source>Unsupported argument -tor found, use -onion.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+1"/> <source>Unsupported logging category %s=%s.</source> <translation type="unfinished"></translation> </message> @@ -4406,12 +4424,12 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <translation type="unfinished"></translation> </message> <message> - <location line="-171"/> + <location line="-158"/> <source>Error: Listening for incoming connections failed (listen returned error %s)</source> <translation type="unfinished"></translation> </message> <message> - <location line="+11"/> + <location line="+5"/> <source>Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)</source> <translation type="unfinished"></translation> </message> @@ -4421,17 +4439,12 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <translation type="unfinished"></translation> </message> <message> - <location line="+44"/> + <location line="+38"/> <source>You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain</source> <translation type="unfinished"></translation> </message> <message> - <location line="+22"/> - <source>Error loading %s: You can't disable HD on an already existing HD wallet</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+4"/> + <location line="+25"/> <source>Error reading from database, shutting down.</source> <translation type="unfinished"></translation> </message> @@ -4441,7 +4454,12 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <translation type="unfinished"></translation> </message> <message> - <location line="+8"/> + <location line="+3"/> + <source>Error: Disk space is low for %s</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+6"/> <source>Information</source> <translation>Information</translation> </message> @@ -4477,6 +4495,11 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos </message> <message> <location line="+4"/> + <source>Section [%s] is not recognized.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> <source>Signing transaction failed</source> <translation>Signing transaction failed</translation> </message> @@ -4497,6 +4520,12 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos </message> <message> <location line="+4"/> + <source>The specified config file %s does not exist +</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> <source>The transaction amount is too small to pay the fee</source> <translation type="unfinished"></translation> </message> @@ -4531,7 +4560,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <translation type="unfinished"></translation> </message> <message> - <location line="+12"/> + <location line="+9"/> <source>Verifying wallet(s)...</source> <translation type="unfinished"></translation> </message> @@ -4556,17 +4585,12 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <translation type="unfinished"></translation> </message> <message> - <location line="-197"/> + <location line="-182"/> <source>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+18"/> - <source>Error loading %s: You can't enable HD on an already existing non-HD wallet</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+46"/> + <location line="+56"/> <source>This is the transaction fee you may pay when fee estimates are not available.</source> <translation type="unfinished"></translation> </message> @@ -4581,17 +4605,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <translation type="unfinished"></translation> </message> <message> - <location line="+9"/> - <source>Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+3"/> - <source>Unsupported argument -whitelistalwaysrelay ignored, use -whitelistrelay and/or -whitelistforcerelay.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+8"/> + <location line="+14"/> <source>Warning: Unknown block versions being mined! It's possible unknown rules are in effect</source> <translation type="unfinished"></translation> </message> @@ -4606,22 +4620,22 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <translation type="unfinished"></translation> </message> <message> - <location line="+19"/> + <location line="+18"/> <source>Error loading wallet %s. Duplicate -wallet filename specified.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+21"/> + <location line="+22"/> <source>Keypool ran out, please call keypoolrefill first</source> <translation type="unfinished"></translation> </message> <message> - <location line="+19"/> + <location line="+20"/> <source>Starting network threads...</source> <translation type="unfinished"></translation> </message> <message> - <location line="+3"/> + <location line="+4"/> <source>The wallet will avoid paying less than the minimum relay fee.</source> <translation type="unfinished"></translation> </message> @@ -4656,12 +4670,12 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <translation>Unknown network specified in -onlynet: '%s'</translation> </message> <message> - <location line="-46"/> + <location line="-48"/> <source>Insufficient funds</source> <translation>Insufficient funds</translation> </message> <message> - <location line="-134"/> + <location line="-120"/> <source>Can't generate a change-address key. Private keys are disabled for this wallet.</source> <translation type="unfinished"></translation> </message> @@ -4671,12 +4685,12 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <translation type="unfinished"></translation> </message> <message> - <location line="+14"/> + <location line="+12"/> <source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+60"/> + <location line="+48"/> <source>Warning: Private keys detected in wallet {%s} with disabled private keys</source> <translation type="unfinished"></translation> </message> @@ -4706,12 +4720,12 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <translation>Rescanning...</translation> </message> <message> - <location line="-43"/> + <location line="-42"/> <source>Done loading</source> <translation>Done loading</translation> </message> <message> - <location line="+14"/> + <location line="+12"/> <source>Error</source> <translation>Error</translation> </message> diff --git a/src/qt/locale/bitcoin_en_GB.ts b/src/qt/locale/bitcoin_en_GB.ts index 7da223f52e..92a08280d7 100644 --- a/src/qt/locale/bitcoin_en_GB.ts +++ b/src/qt/locale/bitcoin_en_GB.ts @@ -330,6 +330,10 @@ <translation>Wallet:</translation> </message> <message> + <source>default wallet</source> + <translation>default wallet</translation> + </message> + <message> <source>Click to disable network activity.</source> <translation>Click to disable network activity.</translation> </message> @@ -350,6 +354,10 @@ <translation>Reindexing blocks on disk...</translation> </message> <message> + <source>Proxy is <b>enabled</b>: %1</source> + <translation>Proxy is <b>enabled</b>: %1</translation> + </message> + <message> <source>Send coins to a Bitcoin address</source> <translation>Send coins to a Bitcoin address</translation> </message> @@ -760,6 +768,14 @@ <translation>The entered address "%1" is not a valid Bitcoin address.</translation> </message> <message> + <source>Address "%1" already exists as a receiving address with label "%2" and so cannot be added as a sending address.</source> + <translation>Address "%1" already exists as a receiving address with label "%2" and so cannot be added as a sending address.</translation> + </message> + <message> + <source>The entered address "%1" is already in the address book with label "%2".</source> + <translation>The entered address "%1" is already in the address book with label "%2".</translation> + </message> + <message> <source>Could not unlock wallet.</source> <translation>Could not unlock wallet.</translation> </message> @@ -834,7 +850,7 @@ </message> <message> <source>If you have chosen to limit block chain storage (pruning), the historical data must still be downloaded and processed, but will be deleted afterward to keep your disk usage low.</source> - <translation>If you have chosen to limit block chain storage (pruning), the historical data must still be downloaded and processed, but will be deleted afterward to keep your disk usage low.</translation> + <translation>If you have chosen to limit block chain storage (pruning), the historical data must still be downloaded and processed, but will be deleted afterwards to keep your disk usage low.</translation> </message> <message> <source>Use the default data directory</source> @@ -1038,10 +1054,22 @@ <translation>&Network</translation> </message> <message> + <source>Disables some advanced features but all blocks will still be fully validated. Reverting this setting requires re-downloading the entire blockchain. Actual disk usage may be somewhat higher.</source> + <translation>Disables some advanced features but all blocks will still be fully validated. Reverting this setting requires re-downloading the entire blockchain. Actual disk usage may be somewhat higher.</translation> + </message> + <message> + <source>Prune &block storage to</source> + <translation>Prune &block storage to</translation> + </message> + <message> <source>GB</source> <translation>GB</translation> </message> <message> + <source>Reverting this setting requires re-downloading the entire blockchain.</source> + <translation>Reverting this setting requires re-downloading the entire blockchain.</translation> + </message> + <message> <source>(0 = auto, <0 = leave that many cores free)</source> <translation>(0 = auto, <0 = leave that many cores free)</translation> </message> @@ -1308,6 +1336,10 @@ <translation>URI handling</translation> </message> <message> + <source>'bitcoin://' is not a valid URI. Use 'bitcoin:' instead.</source> + <translation>'bitcoin://' is not a valid URI. Use 'bitcoin:' instead.</translation> + </message> + <message> <source>Payment request fetch URL is invalid: %1</source> <translation>Payment request fetch URL is invalid: %1</translation> </message> @@ -1505,10 +1537,18 @@ <context> <name>QObject::QObject</name> <message> + <source>Error parsing command line arguments: %1.</source> + <translation>Error parsing command line arguments: %1.</translation> + </message> + <message> <source>Error: Specified data directory "%1" does not exist.</source> <translation>Error: Specified data directory "%1" does not exist.</translation> </message> <message> + <source>Error: Cannot parse configuration file: %1.</source> + <translation>Error: Cannot parse configuration file: %1.</translation> + </message> + <message> <source>Error: %1</source> <translation>Error: %1</translation> </message> @@ -1564,7 +1604,7 @@ </message> <message> <source>Startup time</source> - <translation>Startup time</translation> + <translation>Start up time</translation> </message> <message> <source>Network</source> @@ -1775,6 +1815,10 @@ <translation>&Unban</translation> </message> <message> + <source>default wallet</source> + <translation>default wallet</translation> + </message> + <message> <source>Welcome to the %1 RPC console.</source> <translation>Welcome to the %1 RPC console.</translation> </message> @@ -1799,6 +1843,14 @@ <translation>Network activity disabled</translation> </message> <message> + <source>Executing command without any wallet</source> + <translation>Executing command without any wallet</translation> + </message> + <message> + <source>Executing command using "%1" wallet</source> + <translation>Executing command using "%1" wallet</translation> + </message> + <message> <source>(node id: %1)</source> <translation>(node id: %1)</translation> </message> @@ -1870,6 +1922,14 @@ <translation>Clear</translation> </message> <message> + <source>Native segwit addresses (aka Bech32 or BIP-173) reduce your transaction fees later on and offer better protection against typos, but old wallets don't support them. When unchecked, an address compatible with older wallets will be created instead.</source> + <translation>Native segwit addresses (aka Bech32 or BIP-173) reduce your transaction fees later on and offer better protection against typos, but old wallets don't support them. When unchecked, an address compatible with older wallets will be created instead.</translation> + </message> + <message> + <source>Generate native segwit (Bech32) address</source> + <translation>Generate native segwit (Bech32) address</translation> + </message> + <message> <source>Requested payments history</source> <translation>Requested payments history</translation> </message> @@ -2075,6 +2135,14 @@ <translation>collapse fee-settings</translation> </message> <message> + <source>Specify a custom fee per kB (1,000 bytes) of the transaction's virtual size. + +Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis per kB" for a transaction size of 500 bytes (half of 1 kB) would ultimately yield a fee of only 50 satoshis.</source> + <translation>Specify a custom fee per kB (1,000 bytes) of the transaction's virtual size. + +Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis per kB" for a transaction size of 500 bytes (half of 1 kB) would ultimately yield a fee of only 50 satoshis.</translation> + </message> + <message> <source>per kilobyte</source> <translation>per kilobyte</translation> </message> @@ -2195,6 +2263,14 @@ <translation>You can increase the fee later (signals Replace-By-Fee, BIP-125).</translation> </message> <message> + <source>from wallet %1</source> + <translation>from wallet %1</translation> + </message> + <message> + <source>Please, review your transaction.</source> + <translation>Please, review your transaction.</translation> + </message> + <message> <source>Transaction fee</source> <translation>Transaction fee</translation> </message> @@ -2203,6 +2279,10 @@ <translation>Not signalling Replace-By-Fee, BIP-125.</translation> </message> <message> + <source>Total Amount</source> + <translation>Total Amount</translation> + </message> + <message> <source>Confirm send coins</source> <translation>Confirm send coins</translation> </message> @@ -2656,6 +2736,10 @@ <translation>Transaction total size</translation> </message> <message> + <source>Transaction virtual size</source> + <translation>Transaction virtual size</translation> + </message> + <message> <source>Output index</source> <translation>Output index</translation> </message> @@ -3116,6 +3200,10 @@ <translation>Error reading %s! All keys read correctly, but transaction data or address book entries might be missing or incorrect.</translation> </message> <message> + <source>Group outputs by address, selecting all or none, instead of selecting on a per-output basis. Privacy is improved as an address is only used once (unless someone sends to it after spending from it), but may result in slightly higher fees as suboptimal coin selection may result due to the added limitation (default: %u)</source> + <translation>Group outputs by address, selecting all or none, instead of selecting on a per-output basis. Privacy is improved as an address is only used once (unless someone sends to it after spending from it), but may result in slightly higher fees as suboptimal coin selection may result due to the added limitation (default: %u)</translation> + </message> + <message> <source>Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly.</source> <translation>Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly.</translation> </message> @@ -3200,6 +3288,10 @@ <translation>Error loading %s</translation> </message> <message> + <source>Error loading %s: Private keys can only be disabled during creation</source> + <translation>Error loading %s: Private keys can only be disabled during creation</translation> + </message> + <message> <source>Error loading %s: Wallet corrupted</source> <translation>Error loading %s: Wallet corrupted</translation> </message> @@ -3252,6 +3344,14 @@ <translation>Invalid amount for -fallbackfee=<amount>: '%s'</translation> </message> <message> + <source>Specified blocks directory "%s" does not exist.</source> + <translation>Specified blocks directory "%s" does not exist.</translation> + </message> + <message> + <source>Upgrading txindex database</source> + <translation>Upgrading txindex database</translation> + </message> + <message> <source>Loading P2P addresses...</source> <translation>Loading P2P addresses...</translation> </message> @@ -3292,6 +3392,10 @@ <translation>Unable to bind to %s on this computer. %s is probably already running.</translation> </message> <message> + <source>Unable to generate keys</source> + <translation>Unable to generate keys</translation> + </message> + <message> <source>Unsupported argument -benchmark ignored, use -debug=bench.</source> <translation>Unsupported argument -benchmark ignored, use -debug=bench.</translation> </message> @@ -3465,7 +3569,7 @@ </message> <message> <source>Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported.</source> - <translation>Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported.</translation> + <translation>Unsupported argument -socks found. Setting SOCKS version isn't possible any more, only SOCKS5 proxies are supported.</translation> </message> <message> <source>Unsupported argument -whitelistalwaysrelay ignored, use -whitelistrelay and/or -whitelistforcerelay.</source> @@ -3528,6 +3632,26 @@ <translation>Insufficient funds</translation> </message> <message> + <source>Can't generate a change-address key. Private keys are disabled for this wallet.</source> + <translation>Can't generate a change-address key. Private keys are disabled for this wallet.</translation> + </message> + <message> + <source>Cannot upgrade a non HD split wallet without upgrading to support pre split keypool. Please use -upgradewallet=169900 or -upgradewallet with no version specified.</source> + <translation>Cannot upgrade a non HD split wallet without upgrading to support pre split keypool. Please use -upgradewallet=169900 or -upgradewallet with no version specified.</translation> + </message> + <message> + <source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source> + <translation>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</translation> + </message> + <message> + <source>Warning: Private keys detected in wallet {%s} with disabled private keys</source> + <translation>Warning: Private keys detected in wallet {%s} with disabled private keys</translation> + </message> + <message> + <source>Cannot write to data directory '%s'; check permissions.</source> + <translation>Cannot write to data directory '%s'; check permissions.</translation> + </message> + <message> <source>Loading block index...</source> <translation>Loading block index...</translation> </message> diff --git a/src/qt/locale/bitcoin_es.ts b/src/qt/locale/bitcoin_es.ts index 0ae126eb33..7b07380606 100644 --- a/src/qt/locale/bitcoin_es.ts +++ b/src/qt/locale/bitcoin_es.ts @@ -3199,6 +3199,10 @@ Nota: Dado que la comisión se calcula por byte, una comisión de "100 satoshis <translation>Error leyendo %s!. Todas las claves se han leido correctamente, pero los datos de transacciones o la libreta de direcciones pueden faltar o ser incorrectos.</translation> </message> <message> + <source>Group outputs by address, selecting all or none, instead of selecting on a per-output basis. Privacy is improved as an address is only used once (unless someone sends to it after spending from it), but may result in slightly higher fees as suboptimal coin selection may result due to the added limitation (default: %u)</source> + <translation>Grupo de salida por dirección, seleccionando todo o nada, en lugar de seleccionar en una base para salida. La privacidad se mejora como una dirección utilizada una sola vez (a menos que alguien lo envíe después de gastarlo), a menos que alguien envíe una solicitud, pero puede resultar en tarifas ligeramente más altas ya que la selección de la moneda puede ser inferior a la óptima debido a la limitación adicional después de gastarla. (por defecto, predeterminado %u)</translation> + </message> + <message> <source>Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly.</source> <translation>Por favor, compruebe si la fecha y hora en su computadora son correctas! Si su reloj esta mal, %s no trabajara correctamente. </translation> </message> @@ -3339,6 +3343,10 @@ Nota: Dado que la comisión se calcula por byte, una comisión de "100 satoshis <translation>Cantidad inválida para -fallbackfee=<amount>: '%s'</translation> </message> <message> + <source>Specified blocks directory "%s" does not exist.</source> + <translation>El directorio de bloques «%s» especificado no existe.</translation> + </message> + <message> <source>Upgrading txindex database</source> <translation>Actualización de la base de datos txindex</translation> </message> @@ -3491,12 +3499,6 @@ Nota: Dado que la comisión se calcula por byte, una comisión de "100 satoshis <translation>El -walletdir "%s" indicado no es un directorio</translation> </message> <message> - <source>Specified blocks directory "%s" does not exist. -</source> - <translation>El directorio de bloques especificado "%s" no existe. -</translation> - </message> - <message> <source>The transaction amount is too small to pay the fee</source> <translation>Cantidad de la transacción demasiado pequeña para pagar la comisión</translation> </message> diff --git a/src/qt/locale/bitcoin_es_VE.ts b/src/qt/locale/bitcoin_es_VE.ts index 9c7fb2e2a0..b500c16352 100644 --- a/src/qt/locale/bitcoin_es_VE.ts +++ b/src/qt/locale/bitcoin_es_VE.ts @@ -50,6 +50,10 @@ <translation>Elige la dirección para recibir monedas</translation> </message> <message> + <source>C&hoose</source> + <translation>Escoger</translation> + </message> + <message> <source>Sending addresses</source> <translation>Envío de direcciones</translation> </message> @@ -66,6 +70,10 @@ <translation>Estas son tus direcciones Bitcoin para recibir pagos. Es recomendable usar una nueva dirección de recibo para cada transacción.</translation> </message> <message> + <source>&Copy Address</source> + <translation>Copiar dirección</translation> + </message> + <message> <source>Copy &Label</source> <translation>Copiar &Etiqueta</translation> </message> @@ -77,10 +85,30 @@ <source>Export Address List</source> <translation>Exportar lista de direcciones</translation> </message> - </context> + <message> + <source>Comma separated file (*.csv)</source> + <translation>Separar los archivos con comas (*.csv)</translation> + </message> + <message> + <source>Exporting Failed</source> + <translation>Error al exportar</translation> + </message> + <message> + <source>There was an error trying to save the address list to %1. Please try again.</source> + <translation>Tuvimos un problema al guardar la dirección en la lista %1. Intenta de Nuevo.</translation> + </message> +</context> <context> <name>AddressTableModel</name> <message> + <source>Label</source> + <translation>Nombre</translation> + </message> + <message> + <source>Address</source> + <translation>Direccion</translation> + </message> + <message> <source>(no label)</source> <translation>(sin etiqueta)</translation> </message> @@ -103,6 +131,40 @@ <source>Repeat new passphrase</source> <translation>Repetir nueva frase de contraseña</translation> </message> + <message> + <source>Show password</source> + <translation>Mostrar contraseña</translation> + </message> + <message> + <source>Encrypt wallet</source> + <translation>Cifrar monedero</translation> + </message> + <message> + <source>This operation needs your wallet passphrase to unlock the wallet.</source> + <translation>Esta operación necesita su frase de contraseña de la billetera para desbloquearla. +</translation> + </message> + <message> + <source>Unlock wallet</source> + <translation>Desbloquear monedero</translation> + </message> + <message> + <source>This operation needs your wallet passphrase to decrypt the wallet.</source> + <translation>Esta operación necesita su frase de contraseña de la billetera para descifrar la billetera. +</translation> + </message> + <message> + <source>Decrypt wallet</source> + <translation>Descifrar monedero</translation> + </message> + <message> + <source>Change passphrase</source> + <translation>Cambiar frase secreta</translation> + </message> + <message> + <source>Confirm wallet encryption</source> + <translation>Confirmar cifrado de billetera</translation> + </message> </context> <context> <name>BanTableModel</name> @@ -577,6 +639,14 @@ <translation>&Copiar Dirección</translation> </message> <message> + <source>Address</source> + <translation>Direccion</translation> + </message> + <message> + <source>Label</source> + <translation>Nombre</translation> + </message> + <message> <source>Wallet</source> <translation>Billetera</translation> </message> @@ -584,6 +654,10 @@ <context> <name>RecentRequestsTableModel</name> <message> + <source>Label</source> + <translation>Nombre</translation> + </message> + <message> <source>(no label)</source> <translation>(sin etiqueta)</translation> </message> @@ -670,12 +744,32 @@ <context> <name>TransactionTableModel</name> <message> + <source>Label</source> + <translation>Nombre</translation> + </message> + <message> <source>(no label)</source> <translation>(sin etiqueta)</translation> </message> </context> <context> <name>TransactionView</name> + <message> + <source>Comma separated file (*.csv)</source> + <translation>Separar los archivos con comas (*.csv)</translation> + </message> + <message> + <source>Label</source> + <translation>Nombre</translation> + </message> + <message> + <source>Address</source> + <translation>Direccion</translation> + </message> + <message> + <source>Exporting Failed</source> + <translation>Error al exportar</translation> + </message> </context> <context> <name>UnitDisplayStatusBarControl</name> diff --git a/src/qt/locale/bitcoin_eu_ES.ts b/src/qt/locale/bitcoin_eu_ES.ts index 1abc55acce..e266621d16 100644 --- a/src/qt/locale/bitcoin_eu_ES.ts +++ b/src/qt/locale/bitcoin_eu_ES.ts @@ -3,7 +3,7 @@ <name>AddressBookPage</name> <message> <source>Right-click to edit address or label</source> - <translation>Klikatu eskuinean helbidea edo etiketa aldatzeko</translation> + <translation>Klikatu eskuinarekin helbidea edo etiketa aldatzeko</translation> </message> <message> <source>Create a new address</source> @@ -136,6 +136,14 @@ <translation>Pasahitz berria errepiikatu</translation> </message> <message> + <source>Show password</source> + <translation>Erakutsi pasahitza</translation> + </message> + <message> + <source>Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>.</source> + <translation>Sartu pasaesaldi bat diru-zorrorako. Mesedez erabili ausazko hamar edo gehiago karaktere edo zortzi edo gehiago hitz.</translation> + </message> + <message> <source>Encrypt wallet</source> <translation>Diruzorroa enkriptatu</translation> </message> @@ -274,6 +282,10 @@ <translation>Fitxen tresna-barra</translation> </message> <message> + <source>Error</source> + <translation>Akatsa</translation> + </message> + <message> <source>Up to date</source> <translation>Eguneratua</translation> </message> @@ -368,6 +380,10 @@ </context> <context> <name>Intro</name> + <message> + <source>Error</source> + <translation>Akatsa</translation> + </message> </context> <context> <name>ModalOverlay</name> @@ -385,6 +401,10 @@ <source>Options</source> <translation>Aukerak</translation> </message> + <message> + <source>Error</source> + <translation>Akatsa</translation> + </message> </context> <context> <name>OverviewPage</name> @@ -808,6 +828,10 @@ <context> <name>bitcoin-core</name> <message> + <source>Loading wallet...</source> + <translation>Diru-zorroa kargatzen</translation> + </message> + <message> <source>Rescanning...</source> <translation>Birbilatzen...</translation> </message> @@ -815,5 +839,9 @@ <source>Done loading</source> <translation>Zamaketa amaitua</translation> </message> - </context> + <message> + <source>Error</source> + <translation>Akatsa</translation> + </message> +</context> </TS>
\ No newline at end of file diff --git a/src/qt/locale/bitcoin_fa.ts b/src/qt/locale/bitcoin_fa.ts index 1fa0d9fb44..c2f2930a08 100644 --- a/src/qt/locale/bitcoin_fa.ts +++ b/src/qt/locale/bitcoin_fa.ts @@ -997,6 +997,10 @@ <context> <name>PeerTableModel</name> <message> + <source>Ping</source> + <translation>پینگ</translation> + </message> + <message> <source>Sent</source> <translation>ارسال شده</translation> </message> @@ -1811,10 +1815,30 @@ </context> <context> <name>WalletModel</name> + <message> + <source>Send Coins</source> + <translation>فرستادن سکه ها</translation> + </message> + <message> + <source>Current fee:</source> + <translation>دستمزد فعلی</translation> + </message> + <message> + <source>Increase:</source> + <translation>افزایش</translation> + </message> + <message> + <source>New fee:</source> + <translation>تعرفه جدید</translation> + </message> </context> <context> <name>WalletView</name> <message> + <source>&Export</source> + <translation>و صدور</translation> + </message> + <message> <source>Export the data in the current tab to a file</source> <translation>صدور دادههای برگهٔ فعلی به یک پرونده</translation> </message> diff --git a/src/qt/locale/bitcoin_fa_IR.ts b/src/qt/locale/bitcoin_fa_IR.ts index 7912f43582..be00b00656 100644 --- a/src/qt/locale/bitcoin_fa_IR.ts +++ b/src/qt/locale/bitcoin_fa_IR.ts @@ -231,6 +231,10 @@ <context> <name>BanTableModel</name> <message> + <source>IP/Netmask</source> + <translation>آی پی/نت ماسک</translation> + </message> + <message> <source>Banned Until</source> <translation>مسدودشده تا</translation> </message> @@ -239,7 +243,7 @@ <name>BitcoinGUI</name> <message> <source>Sign &message...</source> - <translation>امضا و پیام</translation> + <translation>ثبت &پیام</translation> </message> <message> <source>Synchronizing with network...</source> @@ -318,6 +322,10 @@ <translation>دریافت آدرس ها</translation> </message> <message> + <source>Open &URI...</source> + <translation>بازکردن آدرس...</translation> + </message> + <message> <source>Wallet:</source> <translation>کیف پول:</translation> </message> @@ -362,6 +370,10 @@ <translation>پنجره دیباگ</translation> </message> <message> + <source>Open debugging and diagnostic console</source> + <translation>باز کردن کنسول دی باگ و تشخیص</translation> + </message> + <message> <source>&Verify message...</source> <translation>تایید پیام</translation> </message> @@ -433,6 +445,10 @@ <source>Open a bitcoin: URI or payment request</source> <translation>بازکردن بیتکوین: آدرس یا درخواست پرداخت</translation> </message> + <message> + <source>&Command-line options</source> + <translation>گزینه های خط فرمان</translation> + </message> <message numerus="yes"> <source>%n active connection(s) to Bitcoin network</source> <translation><numerusform>%n ارتباط فعال به شبکه بیتکوین</numerusform><numerusform>%n ارتباط فعال به شبکه بیتکوین</numerusform></translation> @@ -474,6 +490,10 @@ <translation>به روز</translation> </message> <message> + <source>Connecting to peers...</source> + <translation>در حال اتصال به همتاهای شبکه...</translation> + </message> + <message> <source>Catching up...</source> <translation>در حال روزآمد سازی..</translation> </message> @@ -505,7 +525,11 @@ <source>Wallet is <b>encrypted</b> and currently <b>locked</b></source> <translation>wallet رمزگذاری شد و در حال حاضر قفل است</translation> </message> - </context> + <message> + <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source> + <translation>خطای بحرانی رخ داده است. بیتکوین دیگر به صورت ایمن قادر به ادامه دادن نمیباشد و خارج خواهد شد.</translation> + </message> +</context> <context> <name>CoinControlDialog</name> <message> @@ -517,6 +541,10 @@ <translation>مقدار</translation> </message> <message> + <source>Bytes:</source> + <translation>بایت ها:</translation> + </message> + <message> <source>Amount:</source> <translation>میزان وجه:</translation> </message> @@ -525,6 +553,14 @@ <translation>هزینه</translation> </message> <message> + <source>Dust:</source> + <translation>گرد و غبار با داست:</translation> + </message> + <message> + <source>After Fee:</source> + <translation>بعد از احتساب کارمزد</translation> + </message> + <message> <source>Change:</source> <translation>تغییر</translation> </message> @@ -589,6 +625,22 @@ <translation>کپی هزینه</translation> </message> <message> + <source>Copy after fee</source> + <translation>کپی کردن بعد از احتساب کارمزد</translation> + </message> + <message> + <source>Copy bytes</source> + <translation>کپی کردن بایت ها</translation> + </message> + <message> + <source>Copy dust</source> + <translation>کپی کردن داست:</translation> + </message> + <message> + <source>Copy change</source> + <translation>کپی کردن تغییر</translation> + </message> + <message> <source>yes</source> <translation>بله</translation> </message> @@ -600,7 +652,11 @@ <source>(no label)</source> <translation>(برچسب ندارد)</translation> </message> - </context> + <message> + <source>(change)</source> + <translation>(تغییر)</translation> + </message> +</context> <context> <name>EditAddressDialog</name> <message> @@ -631,21 +687,41 @@ <source>The entered address "%1" is not a valid Bitcoin address.</source> <translation>آدرس وارد شده "%1" آدرس معتبر بیت کوین نیست.</translation> </message> - </context> + <message> + <source>Could not unlock wallet.</source> + <translation>نمیتوان کیف پول را باز کرد.</translation> + </message> + <message> + <source>New key generation failed.</source> + <translation>تولید کلید جدید به خطا انجامید.</translation> + </message> +</context> <context> <name>FreespaceChecker</name> <message> + <source>A new data directory will be created.</source> + <translation>پوشه داده جدید ساخته خواهد شد</translation> + </message> + <message> <source>name</source> <translation>نام</translation> </message> - </context> + <message> + <source>Cannot create data directory here.</source> + <translation>نمیتوان در اینجا پوشه داده ساخت.</translation> + </message> +</context> <context> <name>HelpMessageDialog</name> <message> <source>version</source> <translation>نسخه</translation> </message> - </context> + <message> + <source>Command-line options</source> + <translation>گزینه های خط-فرمان </translation> + </message> +</context> <context> <name>Intro</name> <message> @@ -657,6 +733,14 @@ <translation>به %1 خوش آمدید.</translation> </message> <message> + <source>Use the default data directory</source> + <translation>استفاده کردن از پوشه داده پیشفرض</translation> + </message> + <message> + <source>Use a custom data directory:</source> + <translation>استفاده کردن از پوشه داده مخصوص:</translation> + </message> + <message> <source>Bitcoin</source> <translation>بیت کوین</translation> </message> @@ -692,6 +776,10 @@ <translation>پیشرفت</translation> </message> <message> + <source>Progress increase per hour</source> + <translation>سرعت افزایش پیشرفت بر ساعت</translation> + </message> + <message> <source>calculating...</source> <translation>در حال محاسبه...</translation> </message> @@ -702,7 +790,27 @@ </context> <context> <name>OpenURIDialog</name> - </context> + <message> + <source>Open URI</source> + <translation>باز کردن آدرس URL</translation> + </message> + <message> + <source>Open payment request from URI or file</source> + <translation>بازکردن درخواست پرداخت از آدرس URL یا فایل</translation> + </message> + <message> + <source>URI:</source> + <translation>آدرس:</translation> + </message> + <message> + <source>Select payment request file</source> + <translation>انتخاب فایل درخواست وجه (Payment Request)</translation> + </message> + <message> + <source>Select payment request file to open</source> + <translation>انتخاب فایل درحواست وجه برای باز کردن</translation> + </message> +</context> <context> <name>OptionsDialog</name> <message> @@ -710,10 +818,26 @@ <translation>گزینه ها</translation> </message> <message> + <source>&Main</source> + <translation>&اصلی</translation> + </message> + <message> + <source>Size of &database cache</source> + <translation>اندازه کش پایگاه داده.</translation> + </message> + <message> <source>MB</source> <translation>مگابایت</translation> </message> <message> + <source>Open Configuration File</source> + <translation>بازکردن فایل پیکربندی</translation> + </message> + <message> + <source>Reset all client options to default.</source> + <translation>ریست تمامی تنظیمات کلاینت به پیشفرض</translation> + </message> + <message> <source>&Reset Options</source> <translation>تنظیم مجدد گزینه ها</translation> </message> @@ -722,14 +846,50 @@ <translation>شبکه</translation> </message> <message> + <source>GB</source> + <translation>گیگابایت</translation> + </message> + <message> <source>W&allet</source> <translation>کیف پول</translation> </message> <message> + <source>Expert</source> + <translation>حرفهای</translation> + </message> + <message> + <source>Accept connections from outside.</source> + <translation>پذیرفتن اتصال شدن از بیرون</translation> + </message> + <message> + <source>Allow incomin&g connections</source> + <translation>اجازه دادن به ارتباطات ورودی</translation> + </message> + <message> + <source>Proxy &IP:</source> + <translation>پراکسی و آیپی:</translation> + </message> + <message> <source>&Port:</source> <translation>پورت:</translation> </message> <message> + <source>IPv4</source> + <translation>IPv4</translation> + </message> + <message> + <source>IPv6</source> + <translation>IPv6</translation> + </message> + <message> + <source>Tor</source> + <translation>شبکه Tor</translation> + </message> + <message> + <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services.</source> + <translation>اتصال به شبکه بیت کوین با استفاده از پراکسی SOCKS5 برای استفاده از سرویس مخفی تور</translation> + </message> + <message> <source>&Window</source> <translation>پنجره</translation> </message> @@ -738,6 +898,18 @@ <translation>نمایش</translation> </message> <message> + <source>User Interface &language:</source> + <translation>زبان واسط کاربری:</translation> + </message> + <message> + <source>&Unit to show amounts in:</source> + <translation>واحد نمایشگر مقادیر:</translation> + </message> + <message> + <source>&Third party transaction URLs</source> + <translation>URLهای تراکنش شخص ثالث</translation> + </message> + <message> <source>&OK</source> <translation>تایید</translation> </message> @@ -750,10 +922,42 @@ <translation>پیش فرض</translation> </message> <message> + <source>none</source> + <translation>خالی</translation> + </message> + <message> + <source>Confirm options reset</source> + <translation>تایید ریست تنظیمات</translation> + </message> + <message> + <source>Client restart required to activate changes.</source> + <translation>کلاینت نیازمند ریست شدن است برای فعال کردن تغییرات</translation> + </message> + <message> + <source>Client will be shut down. Do you want to proceed?</source> + <translation>کلاینت خاموش خواهد شد.آیا میخواهید ادامه دهید؟</translation> + </message> + <message> + <source>Configuration options</source> + <translation>تنظیمات پیکربندی</translation> + </message> + <message> <source>Error</source> <translation>خطا</translation> </message> - </context> + <message> + <source>The configuration file could not be opened.</source> + <translation>فایل پیکربندی قادر به بازشدن نبود.</translation> + </message> + <message> + <source>This change would require a client restart.</source> + <translation>تغییرات منوط به ریست کاربر است.</translation> + </message> + <message> + <source>The supplied proxy address is invalid.</source> + <translation>آدرس پراکسی ارائه شده نامعتبر است.</translation> + </message> +</context> <context> <name>OverviewPage</name> <message> @@ -765,18 +969,46 @@ <translation>اطلاعات نمایش داده شده ممکن است روزآمد نباشد. wallet شما به صورت خودکار بعد از برقراری اتصال با شبکه bitcoin به روز می شود اما این فرایند هنوز تکمیل نشده است.</translation> </message> <message> + <source>Watch-only:</source> + <translation>فقط قابل-مشاهده:</translation> + </message> + <message> <source>Available:</source> <translation>در دسترس:</translation> </message> <message> + <source>Your current spendable balance</source> + <translation>موجودی قابل خرج در الان</translation> + </message> + <message> <source>Pending:</source> <translation>در حال انتظار:</translation> </message> <message> + <source>Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance</source> + <translation>تعداد تراکنشهایی که نیاز به تایید دارند و هنوز در مانده حساب جاری شما به حساب نیامده اند</translation> + </message> + <message> + <source>Mined balance that has not yet matured</source> + <translation>موجودی استخراج شده هنوز کامل نشده است</translation> + </message> + <message> + <source>Balances</source> + <translation>موجودی ها</translation> + </message> + <message> <source>Total:</source> <translation>کل:</translation> </message> <message> + <source>Your current total balance</source> + <translation>موجودی شما در همین لحظه</translation> + </message> + <message> + <source>Your current balance in watch-only addresses</source> + <translation>موجودی شما در همین لحظه در آدرس های Watch only Addresses </translation> + </message> + <message> <source>Spendable:</source> <translation>قابل مصرف:</translation> </message> @@ -784,13 +1016,65 @@ <source>Recent transactions</source> <translation>تراکنش های اخیر</translation> </message> + <message> + <source>Unconfirmed transactions to watch-only addresses</source> + <translation>تراکنش های تایید نشده به آدرس های فقط قابل مشاهده watch-only</translation> + </message> + <message> + <source>Mined balance in watch-only addresses that has not yet matured</source> + <translation>موجودی استخراج شده در آدرس های فقط قابل مشاهده هنوز کامل نشده است</translation> + </message> </context> <context> <name>PaymentServer</name> + <message> + <source>Payment request error</source> + <translation>درخواست پرداخت با خطا مواجه شد</translation> + </message> + <message> + <source>Payment request rejected</source> + <translation>درخواست پرداخت رد شد</translation> + </message> + <message> + <source>Payment request expired.</source> + <translation>درخواست پرداخت منقضی شد یا تاریخ آن گذشت.</translation> + </message> + <message> + <source>Payment request is not initialized.</source> + <translation>درخواست پرداخت, با مقداردهی اولیه یکسان نبود.</translation> + </message> + <message> + <source>Invalid payment request.</source> + <translation>درخواست پرداخت نامعتبر بود.</translation> + </message> + <message> + <source>Network request error</source> + <translation>درخواست از شبکه با خطا مواجه شد</translation> + </message> </context> <context> <name>PeerTableModel</name> - </context> + <message> + <source>Node/Service</source> + <translation>گره/خدمت</translation> + </message> + <message> + <source>NodeId</source> + <translation>شناسه گره</translation> + </message> + <message> + <source>Ping</source> + <translation>پینگ</translation> + </message> + <message> + <source>Sent</source> + <translation>فرستاده شد</translation> + </message> + <message> + <source>Received</source> + <translation>دریافت شد</translation> + </message> +</context> <context> <name>QObject</name> <message> @@ -798,6 +1082,14 @@ <translation>میزان</translation> </message> <message> + <source>None</source> + <translation>هیچ کدام</translation> + </message> + <message> + <source>N/A</source> + <translation>موجود نیست</translation> + </message> + <message> <source>unknown</source> <translation>ناشناس</translation> </message> @@ -807,18 +1099,58 @@ </context> <context> <name>QRImageWidget</name> - </context> + <message> + <source>&Save Image...</source> + <translation>&ذخیره کردن Image...</translation> + </message> + <message> + <source>&Copy Image</source> + <translation>&کپی کردن image</translation> + </message> + <message> + <source>Save QR Code</source> + <translation>ذحیره کردن Qr Code</translation> + </message> + <message> + <source>PNG Image (*.png)</source> + <translation>تصویر با فرمت PNG انتخاب(*.png)</translation> + </message> +</context> <context> <name>RPCConsole</name> <message> + <source>N/A</source> + <translation>موجود نیست</translation> + </message> + <message> <source>Client version</source> <translation>ویرایش کنسول RPC</translation> </message> <message> + <source>&Information</source> + <translation>&اطلاعات</translation> + </message> + <message> + <source>Debug window</source> + <translation>پنجره یا صفحه دی باگ</translation> + </message> + <message> + <source>General</source> + <translation>عمومی</translation> + </message> + <message> + <source>Datadir</source> + <translation>پوشه داده Datadir</translation> + </message> + <message> <source>Network</source> <translation>شبکه</translation> </message> <message> + <source>Name</source> + <translation>نام</translation> + </message> + <message> <source>Number of connections</source> <translation>تعداد اتصال</translation> </message> @@ -831,14 +1163,174 @@ <translation>تعداد زنجیره های حاضر</translation> </message> <message> + <source>Current number of transactions</source> + <translation>تعداد تراکنش ها در حال حاضر</translation> + </message> + <message> + <source>Memory usage</source> + <translation>حافظه استفاده شده</translation> + </message> + <message> + <source>Wallet: </source> + <translation>کیف پول:</translation> + </message> + <message> + <source>(none)</source> + <translation>(هیچ کدام)</translation> + </message> + <message> + <source>&Reset</source> + <translation>&ریست کردن</translation> + </message> + <message> + <source>Received</source> + <translation>دریافت شد</translation> + </message> + <message> + <source>Sent</source> + <translation>فرستاده شد</translation> + </message> + <message> + <source>&Peers</source> + <translation>&همتاها</translation> + </message> + <message> + <source>Banned peers</source> + <translation>همتاهای بن شده</translation> + </message> + <message> + <source>Select a peer to view detailed information.</source> + <translation>انتخاب همتا یا جفت برای جزییات اطلاعات</translation> + </message> + <message> + <source>Whitelisted</source> + <translation>لیست سفید شده یا لیست سالم WhiteList</translation> + </message> + <message> + <source>Direction</source> + <translation>مسیر</translation> + </message> + <message> + <source>Version</source> + <translation>نسخه</translation> + </message> + <message> + <source>Decrease font size</source> + <translation>کاهش دادن اندازه فونت</translation> + </message> + <message> + <source>Increase font size</source> + <translation>افزایش دادن اندازه فونت</translation> + </message> + <message> + <source>Services</source> + <translation>خدمات</translation> + </message> + <message> + <source>Connection Time</source> + <translation>زمان اتصال</translation> + </message> + <message> + <source>Last Send</source> + <translation>آخرین ارسال</translation> + </message> + <message> + <source>Last Receive</source> + <translation>آخرین دریافت</translation> + </message> + <message> + <source>Ping Time</source> + <translation>مدت زمان پینگ</translation> + </message> + <message> + <source>Ping Wait</source> + <translation>انتظار پینگ</translation> + </message> + <message> + <source>Min Ping</source> + <translation>حداقل پینگ</translation> + </message> + <message> <source>Last block time</source> <translation>زمان آخرین بلوک</translation> </message> <message> + <source>&Open</source> + <translation>&بازکردن</translation> + </message> + <message> + <source>&Network Traffic</source> + <translation>&شلوغی شبکه</translation> + </message> + <message> + <source>Totals</source> + <translation>جمع کل ها</translation> + </message> + <message> + <source>In:</source> + <translation>به یا داخل:</translation> + </message> + <message> + <source>Out:</source> + <translation>خارج شده:</translation> + </message> + <message> + <source>Clear console</source> + <translation>پاک کردن کنسول</translation> + </message> + <message> + <source>1 &hour</source> + <translation>1 &ساعت</translation> + </message> + <message> + <source>1 &day</source> + <translation>1 &روز</translation> + </message> + <message> + <source>1 &week</source> + <translation>1 &هفته</translation> + </message> + <message> + <source>1 &year</source> + <translation>1 &سال</translation> + </message> + <message> + <source>&Disconnect</source> + <translation>&قطع شدن</translation> + </message> + <message> + <source>Ban for</source> + <translation>بن یا بن شده برای</translation> + </message> + <message> + <source>&Unban</source> + <translation>&خارج کردن از بن</translation> + </message> + <message> <source>default wallet</source> <translation>کیف پول پیشفرض</translation> </message> - </context> + <message> + <source>Network activity disabled</source> + <translation>فعالیت شبکه غیر فعال شد</translation> + </message> + <message> + <source>never</source> + <translation>هیچ وقت</translation> + </message> + <message> + <source>Yes</source> + <translation>بله</translation> + </message> + <message> + <source>No</source> + <translation>خیر</translation> + </message> + <message> + <source>Unknown</source> + <translation>ناشناس یا نامعلوم</translation> + </message> +</context> <context> <name>ReceiveCoinsDialog</name> <message> @@ -854,14 +1346,46 @@ <translation>پیام:</translation> </message> <message> + <source>Use this form to request payments. All fields are <b>optional</b>.</source> + <translation>از این فرم استفاده کنید برای درخواست پرداخت ها.تمامی گزینه ها <b>اختیاری</b>هستند.</translation> + </message> + <message> + <source>Clear all fields of the form.</source> + <translation>پاک کردن تمامی گزینه های این فرم</translation> + </message> + <message> + <source>Clear</source> + <translation>پاک کردن</translation> + </message> + <message> + <source>Requested payments history</source> + <translation>تاریخچه پرداخت های درخواست شده</translation> + </message> + <message> + <source>&Request payment</source> + <translation>&درخواست پرداخت</translation> + </message> + <message> + <source>Show</source> + <translation>نمایش</translation> + </message> + <message> <source>Remove</source> <translation>حذف</translation> </message> <message> + <source>Copy URI</source> + <translation>کپی کردن آدرس URL</translation> + </message> + <message> <source>Copy label</source> <translation>کپی برچسب</translation> </message> <message> + <source>Copy message</source> + <translation>کپی کردن پیام</translation> + </message> + <message> <source>Copy amount</source> <translation>کپی مقدار</translation> </message> @@ -869,18 +1393,46 @@ <context> <name>ReceiveRequestDialog</name> <message> + <source>QR Code</source> + <translation>کی یو آر کد Qr Code</translation> + </message> + <message> + <source>Copy &URI</source> + <translation>کپی کردن &آدرس URL</translation> + </message> + <message> <source>Copy &Address</source> <translation>کپی آدرس</translation> </message> <message> + <source>&Save Image...</source> + <translation>&ذخیره کردن تصویر...</translation> + </message> + <message> + <source>Payment information</source> + <translation>اطلاعات پرداخت</translation> + </message> + <message> + <source>URI</source> + <translation>آدرس URL</translation> + </message> + <message> <source>Address</source> <translation>آدرس</translation> </message> <message> + <source>Amount</source> + <translation>میزان وجه:</translation> + </message> + <message> <source>Label</source> <translation>برچسب</translation> </message> <message> + <source>Message</source> + <translation>پیام</translation> + </message> + <message> <source>Wallet</source> <translation>کیف پول</translation> </message> @@ -888,14 +1440,34 @@ <context> <name>RecentRequestsTableModel</name> <message> + <source>Date</source> + <translation>تاریخ</translation> + </message> + <message> <source>Label</source> <translation>برچسب</translation> </message> <message> + <source>Message</source> + <translation>پیام</translation> + </message> + <message> <source>(no label)</source> <translation>(برچسب ندارد)</translation> </message> - </context> + <message> + <source>(no message)</source> + <translation>(بدون پیام)</translation> + </message> + <message> + <source>(no amount requested)</source> + <translation>(هیچ درخواست پرداخت وجود ندارد)</translation> + </message> + <message> + <source>Requested</source> + <translation>درخواست شده</translation> + </message> +</context> <context> <name>SendCoinsDialog</name> <message> @@ -903,6 +1475,14 @@ <translation>سکه های ارسالی</translation> </message> <message> + <source>Coin Control Features</source> + <translation>قابلیت های کنترل کوین</translation> + </message> + <message> + <source>automatically selected</source> + <translation>به صورت خودکار انتخاب شده</translation> + </message> + <message> <source>Insufficient funds!</source> <translation>وجوه ناکافی</translation> </message> @@ -911,6 +1491,10 @@ <translation>مقدار</translation> </message> <message> + <source>Bytes:</source> + <translation>بایت ها:</translation> + </message> + <message> <source>Amount:</source> <translation>میزان وجه:</translation> </message> @@ -919,18 +1503,86 @@ <translation>هزینه</translation> </message> <message> + <source>After Fee:</source> + <translation>بعد از احتساب کارمزد</translation> + </message> + <message> <source>Change:</source> <translation>تغییر</translation> </message> <message> + <source>Custom change address</source> + <translation>تغییر آدرس مخصوص</translation> + </message> + <message> + <source>Transaction Fee:</source> + <translation>کارمزد تراکنش:</translation> + </message> + <message> + <source>Choose...</source> + <translation>انتخاب...</translation> + </message> + <message> + <source>Warning: Fee estimation is currently not possible.</source> + <translation>هشدار:تخمین کارمزد در حال حاضر امکان پذیر نیست.</translation> + </message> + <message> + <source>collapse fee-settings</source> + <translation>تنظیمات کاهش کارمزد</translation> + </message> + <message> + <source>Specify a custom fee per kB (1,000 bytes) of the transaction's virtual size. + +Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis per kB" for a transaction size of 500 bytes (half of 1 kB) would ultimately yield a fee of only 50 satoshis.</source> + <translation>مشخص کردن هزینه کارمزد مخصوص به ازاری کیلوبایت(1,000 بایت) حجم مجازی تراکنش + +توجه: از آن جایی که کارمزد بر اساس هر بایت محاسبه میشود,هزینه کارمزد"100 ساتوشی بر کیلو بایت"برای تراکنش با حجم 500 بایت(نصف 1 کیلوبایت) کارمزد فقط اندازه 50 ساتوشی خواهد بود.</translation> + </message> + <message> + <source>per kilobyte</source> + <translation>به ازای هر کیلوبایت</translation> + </message> + <message> <source>Hide</source> <translation>پنهان کردن</translation> </message> <message> + <source>Recommended:</source> + <translation>پیشنهاد شده:</translation> + </message> + <message> + <source>Custom:</source> + <translation>سفارشی:</translation> + </message> + <message> + <source>(Smart fee not initialized yet. This usually takes a few blocks...)</source> + <translation>(مقداردهی کارمزد هوشمند هنوز مشخص نشده است.این کارمزد معمولا به اندازه چند بلاک طول میکشد...) </translation> + </message> + <message> <source>Send to multiple recipients at once</source> <translation>ارسال همزمان به گیرنده های متعدد</translation> </message> <message> + <source>Add &Recipient</source> + <translation>اضافه کردن &گیرنده</translation> + </message> + <message> + <source>Clear all fields of the form.</source> + <translation>پاک کردن تمامی گزینه های این فرم</translation> + </message> + <message> + <source>Dust:</source> + <translation>گرد و غبار یا داست:</translation> + </message> + <message> + <source>Confirmation time target:</source> + <translation>هدف زمانی تایید شدن:</translation> + </message> + <message> + <source>Enable Replace-By-Fee</source> + <translation>فعال کردن جایگذاری دوباره از کارمزد</translation> + </message> + <message> <source>Clear &All</source> <translation>پاک کردن همه</translation> </message> @@ -959,6 +1611,90 @@ <translation>کپی هزینه</translation> </message> <message> + <source>Copy after fee</source> + <translation>کپی کردن بعد از احتساب کارمزد</translation> + </message> + <message> + <source>Copy bytes</source> + <translation>کپی کردن بایت ها</translation> + </message> + <message> + <source>Copy dust</source> + <translation>کپی کردن داست:</translation> + </message> + <message> + <source>Copy change</source> + <translation>کپی کردن تغییر</translation> + </message> + <message> + <source>Are you sure you want to send?</source> + <translation>آیا برای ارسال کردن یا فرستادن مطمئن هستید؟</translation> + </message> + <message> + <source>or</source> + <translation>یا</translation> + </message> + <message> + <source>You can increase the fee later (signals Replace-By-Fee, BIP-125).</source> + <translation>تو میتوانی بعدا هزینه کارمزد را افزایش بدی(signals Replace-By-Fee, BIP-125)</translation> + </message> + <message> + <source>Please, review your transaction.</source> + <translation>لطفا,تراکنش خود را بازبینی کنید.</translation> + </message> + <message> + <source>Transaction fee</source> + <translation>کارمزد تراکنش</translation> + </message> + <message> + <source>Total Amount</source> + <translation>میزان کل</translation> + </message> + <message> + <source>Confirm send coins</source> + <translation>تایید کردن ارسال کوین ها</translation> + </message> + <message> + <source>The recipient address is not valid. Please recheck.</source> + <translation>آدرس گیرنده نامعتبر است.لطفا دوباره چک یا بررسی کنید.</translation> + </message> + <message> + <source>The amount to pay must be larger than 0.</source> + <translation>میزان پولی کخ پرداخت می کنید باید بزرگتر از 0 باشد.</translation> + </message> + <message> + <source>The amount exceeds your balance.</source> + <translation>این میزان پول بیشتر از موجودی شما است.</translation> + </message> + <message> + <source>Duplicate address found: addresses should only be used once each.</source> + <translation>آدرس تکراری یافت شد:آدرس ها باید فقط یک بار استفاده شوند.</translation> + </message> + <message> + <source>Transaction creation failed!</source> + <translation>ایجاد تراکنش با خطا مواجه شد!</translation> + </message> + <message> + <source>Payment request expired.</source> + <translation>درخواست پرداخت منقضی شد یا تاریخ آن گذشت.</translation> + </message> + <message> + <source>Warning: Invalid Bitcoin address</source> + <translation>هشدار: آدرس بیت کوین نامعتبر</translation> + </message> + <message> + <source>Warning: Unknown change address</source> + <translation>هشدار:تغییر آدرس نامعلوم</translation> + </message> + <message> + <source>Confirm custom change address</source> + <translation>تایید کردن تغییر آدرس سفارشی</translation> + </message> + <message> + <source>The address you selected for change is not part of this wallet. Any or all funds in your wallet may be sent to this address. Are you sure?</source> + <translation>این آدرس که شما انتخاب کرده اید بخشی از کیف پول شما نیست.هر یا همه دارایی های شما در این کیف پول به این آدرس ارسال خواهد شد.آیا مطمئن هستید؟</translation> + </message> + <message> <source>(no label)</source> <translation>(برچسب ندارد)</translation> </message> @@ -978,10 +1714,38 @@ <translation>برچسب:</translation> </message> <message> + <source>Choose previously used address</source> + <translation>انتخاب آدرس قبلا استفاده شده</translation> + </message> + <message> + <source>This is a normal payment.</source> + <translation>این پرداحت,عادی هست.</translation> + </message> + <message> + <source>The Bitcoin address to send the payment to</source> + <translation>آدرس بیت کوین برای ارسال پرداحت به آن</translation> + </message> + <message> + <source>Alt+A</source> + <translation>Alt+A</translation> + </message> + <message> <source>Paste address from clipboard</source> <translation>استفاده از آدرس کلیپ بورد</translation> </message> <message> + <source>Alt+P</source> + <translation>Alt+P</translation> + </message> + <message> + <source>Remove this entry</source> + <translation>پاک کردن این ورودی</translation> + </message> + <message> + <source>Use available balance</source> + <translation>استفاده از موجودی حساب</translation> + </message> + <message> <source>Message:</source> <translation>پیام:</translation> </message> @@ -996,7 +1760,11 @@ </context> <context> <name>SendConfirmationDialog</name> - </context> + <message> + <source>Yes</source> + <translation>بله</translation> + </message> +</context> <context> <name>ShutdownWindow</name> <message> @@ -1007,14 +1775,30 @@ <context> <name>SignVerifyMessageDialog</name> <message> + <source>Signatures - Sign / Verify a Message</source> + <translation>امضاها -ثبت/تایید پیام</translation> + </message> + <message> <source>&Sign Message</source> - <translation>امضای پیام </translation> + <translation>&ثبت پیام </translation> + </message> + <message> + <source>Choose previously used address</source> + <translation>انتخاب آدرس قبلا استفاده شده</translation> + </message> + <message> + <source>Alt+A</source> + <translation>Alt+A</translation> </message> <message> <source>Paste address from clipboard</source> <translation>آدرس را بر کلیپ بورد کپی کنید</translation> </message> <message> + <source>Alt+P</source> + <translation>Alt+P</translation> + </message> + <message> <source>Enter the message you want to sign here</source> <translation>پیامی که می خواهید امضا کنید را اینجا وارد کنید</translation> </message> @@ -1024,7 +1808,7 @@ </message> <message> <source>Sign &Message</source> - <translation>امضای پیام </translation> + <translation>ثبت &پیام</translation> </message> <message> <source>Clear &All</source> @@ -1039,10 +1823,30 @@ <translation>تایید پیام</translation> </message> <message> + <source>Click "Sign Message" to generate signature</source> + <translation>برای تولید امضا "Sign Message" و یا "ثبت پیام" را کلیک کنید</translation> + </message> + <message> <source>The entered address is invalid.</source> <translation>آدرس وارد شده نامعتبر است.</translation> </message> - </context> + <message> + <source>Message signed.</source> + <translation>پیام ثبت شده</translation> + </message> + <message> + <source>The signature did not match the message digest.</source> + <translation>این امضا با حرفو پیام همخوانی ندارد</translation> + </message> + <message> + <source>Message verification failed.</source> + <translation>پیام شما با خطا مواجه شد</translation> + </message> + <message> + <source>Message verified.</source> + <translation>پیام شما تایید شد</translation> + </message> +</context> <context> <name>SplashScreen</name> <message> @@ -1052,7 +1856,11 @@ </context> <context> <name>TrafficGraphWidget</name> - </context> + <message> + <source>KB/s</source> + <translation>کیلو بایت بر ثانیه</translation> + </message> +</context> <context> <name>TransactionDesc</name> <message> @@ -1060,6 +1868,10 @@ <translation>وضعیت</translation> </message> <message> + <source>Date</source> + <translation>تاریخ</translation> + </message> + <message> <source>Source</source> <translation>منبع</translation> </message> @@ -1072,10 +1884,86 @@ <translation>از</translation> </message> <message> + <source>unknown</source> + <translation>ناشناس</translation> + </message> + <message> <source>To</source> <translation>به</translation> </message> - </context> + <message> + <source>own address</source> + <translation>آدرس خود</translation> + </message> + <message> + <source>watch-only</source> + <translation>فقط-با قابلیت دیدن</translation> + </message> + <message> + <source>label</source> + <translation>برچسب</translation> + </message> + <message> + <source>Credit</source> + <translation>اعتبار</translation> + </message> + <message> + <source>not accepted</source> + <translation>قبول نشده</translation> + </message> + <message> + <source>Total credit</source> + <translation>تمامی اعتبار</translation> + </message> + <message> + <source>Transaction fee</source> + <translation>کارمزد تراکنش</translation> + </message> + <message> + <source>Net amount</source> + <translation>میزان وجه دقیق</translation> + </message> + <message> + <source>Message</source> + <translation>پیام</translation> + </message> + <message> + <source>Comment</source> + <translation>کامنت</translation> + </message> + <message> + <source>Transaction ID</source> + <translation>شناسه تراکنش</translation> + </message> + <message> + <source>Transaction total size</source> + <translation>حجم کل تراکنش</translation> + </message> + <message> + <source>Debug information</source> + <translation>اطلاعات دی باگ Debug</translation> + </message> + <message> + <source>Transaction</source> + <translation>تراکنش</translation> + </message> + <message> + <source>Inputs</source> + <translation>ورودی ها</translation> + </message> + <message> + <source>Amount</source> + <translation>میزان وجه:</translation> + </message> + <message> + <source>true</source> + <translation>درست</translation> + </message> + <message> + <source>false</source> + <translation>نادرست</translation> + </message> +</context> <context> <name>TransactionDescDialog</name> <message> @@ -1086,6 +1974,14 @@ <context> <name>TransactionTableModel</name> <message> + <source>Date</source> + <translation>تاریخ</translation> + </message> + <message> + <source>Type</source> + <translation>نوع</translation> + </message> + <message> <source>Label</source> <translation>برچسب</translation> </message> @@ -1094,6 +1990,14 @@ <translation>تایید نشده</translation> </message> <message> + <source>Generated but not accepted</source> + <translation>تولید شده ولی هنوز قبول نشده است</translation> + </message> + <message> + <source>Received with</source> + <translation>دریافت شده با</translation> + </message> + <message> <source>Received from</source> <translation>دریافت شده از</translation> </message> @@ -1102,25 +2006,101 @@ <translation>ارسال شده به</translation> </message> <message> + <source>Payment to yourself</source> + <translation>پرداخت به خود</translation> + </message> + <message> <source>Mined</source> <translation>استخراج شده</translation> </message> <message> + <source>watch-only</source> + <translation>فقط-با قابلیت دیدن</translation> + </message> + <message> + <source>(n/a)</source> + <translation>(موجود نیست)</translation> + </message> + <message> <source>(no label)</source> <translation>(برچسب ندارد)</translation> </message> - </context> + <message> + <source>Date and time that the transaction was received.</source> + <translation>تاریخ و زمان تراکنش دریافت شده است</translation> + </message> + <message> + <source>Type of transaction.</source> + <translation>نوع تراکنش.</translation> + </message> + <message> + <source>Amount removed from or added to balance.</source> + <translation> میزان وجه کم شده یا اضافه شده به حساب</translation> + </message> +</context> <context> <name>TransactionView</name> <message> + <source>All</source> + <translation>همه</translation> + </message> + <message> + <source>Today</source> + <translation>امروز</translation> + </message> + <message> + <source>This week</source> + <translation>این هفته</translation> + </message> + <message> + <source>This month</source> + <translation>این ماه</translation> + </message> + <message> + <source>Last month</source> + <translation>ماه گذشته</translation> + </message> + <message> + <source>This year</source> + <translation>امسال یا این سال</translation> + </message> + <message> + <source>Range...</source> + <translation>دامنه...</translation> + </message> + <message> + <source>Received with</source> + <translation>گرفته شده با</translation> + </message> + <message> <source>Sent to</source> <translation>ارسال شده به</translation> </message> <message> + <source>To yourself</source> + <translation>به خودت</translation> + </message> + <message> <source>Mined</source> <translation>استخراج شده</translation> </message> <message> + <source>Other</source> + <translation>بقیه</translation> + </message> + <message> + <source>Enter address, transaction id, or label to search</source> + <translation>وارد کردن آدرس,شناسه تراکنش, یا برچسب برای جست و جو</translation> + </message> + <message> + <source>Min amount</source> + <translation>حداقل میزان وجه</translation> + </message> + <message> + <source>Increase transaction fee</source> + <translation>افزایش کارمزد تراکنش</translation> + </message> + <message> <source>Copy address</source> <translation>کپی آدرس</translation> </message> @@ -1137,10 +2117,38 @@ <translation>کپی شناسه تراکنش</translation> </message> <message> + <source>Copy full transaction details</source> + <translation>کپی کردن تمامی اطلاعات تراکنش</translation> + </message> + <message> + <source>Edit label</source> + <translation>ویرایش کردن برچسب</translation> + </message> + <message> + <source>Show transaction details</source> + <translation>نشان دادن جرییات تراکنش</translation> + </message> + <message> + <source>Export Transaction History</source> + <translation>خارج کردن یا بالا بردن سابقه تراکنش ها</translation> + </message> + <message> <source>Comma separated file (*.csv)</source> <translation>فایل سی اس وی (*.csv)</translation> </message> <message> + <source>Confirmed</source> + <translation>تایید شده</translation> + </message> + <message> + <source>Date</source> + <translation>تاریخ</translation> + </message> + <message> + <source>Type</source> + <translation>نوع</translation> + </message> + <message> <source>Label</source> <translation>برچسب</translation> </message> @@ -1149,10 +2157,26 @@ <translation>آدرس</translation> </message> <message> + <source>ID</source> + <translation>شناسه</translation> + </message> + <message> <source>Exporting Failed</source> <translation>گرفتن خروجی به مشکل خورد</translation> </message> - </context> + <message> + <source>Exporting Successful</source> + <translation>خارج کردن موفقیت آمیز بود Exporting</translation> + </message> + <message> + <source>Range:</source> + <translation>دامنه:</translation> + </message> + <message> + <source>to</source> + <translation>به</translation> + </message> +</context> <context> <name>UnitDisplayStatusBarControl</name> </context> @@ -1161,29 +2185,209 @@ </context> <context> <name>WalletModel</name> + <message> + <source>Send Coins</source> + <translation>ارسال کوین ها یا سکه ها</translation> + </message> + <message> + <source>Increasing transaction fee failed</source> + <translation>افزایش کارمزد تراکنش با خطا مواجه شد</translation> + </message> + <message> + <source>Do you want to increase the fee?</source> + <translation>آیا میخواهید اندازه کارمزد را افزایش دهید؟</translation> + </message> + <message> + <source>Current fee:</source> + <translation>کارمزد الان:</translation> + </message> + <message> + <source>Increase:</source> + <translation>افزایش دادن:</translation> + </message> + <message> + <source>New fee:</source> + <translation>کارمزد جدید:</translation> + </message> + <message> + <source>Can't sign transaction.</source> + <translation>نمیتوان تراکنش را ثبت کرد</translation> + </message> </context> <context> <name>WalletView</name> - </context> + <message> + <source>&Export</source> + <translation>&صدور</translation> + </message> + <message> + <source>Backup Wallet</source> + <translation>بازیابی یا پشتیبان گیری کیف پول</translation> + </message> + <message> + <source>Backup Failed</source> + <translation>بازیابی یا پشتیبان گیری با خطا مواجه شد</translation> + </message> + <message> + <source>Backup Successful</source> + <translation>بازیابی یا پشتیبان گیری موفقیت آمیز بود.</translation> + </message> + <message> + <source>Cancel</source> + <translation>لغو</translation> + </message> +</context> <context> <name>bitcoin-core</name> <message> + <source>Bitcoin Core</source> + <translation>هسته بیت کوین</translation> + </message> + <message> + <source>Change index out of range</source> + <translation>تغییر دادن اندیس خارج از دامنه</translation> + </message> + <message> + <source>Copyright (C) %i-%i</source> + <translation>کپی رایت (C) %i-%i</translation> + </message> + <message> + <source>Do you want to rebuild the block database now?</source> + <translation>آیا میخواهید الان پایگاه داده بلاک را بازسازی کنید؟</translation> + </message> + <message> + <source>Error loading block database</source> + <translation>خطا در بارگذاری پایگاه داده بلاک block</translation> + </message> + <message> + <source>Error opening block database</source> + <translation>خطا در بازکردن پایگاه داده بلاک block</translation> + </message> + <message> + <source>Error: Disk space is low!</source> + <translation>حطا:فضای دیسک کم است!</translation> + </message> + <message> + <source>Importing...</source> + <translation>در حال وارد کردن...</translation> + </message> + <message> + <source>Invalid amount for -%s=<amount>: '%s'</source> + <translation>میزان نامعتبر برای -%s=<amount>: '%s'</translation> + </message> + <message> + <source>Upgrading txindex database</source> + <translation>ارتقا دادن پایگاه داده اندیس تراکنش ها یا txindex</translation> + </message> + <message> + <source>Loading P2P addresses...</source> + <translation>در حال بارگذاری آدرس های همتا-به-همتا یا P2P</translation> + </message> + <message> + <source>Loading banlist...</source> + <translation>در حال بارگذاری لیست بن...</translation> + </message> + <message> + <source>Unable to generate keys</source> + <translation>نمیتوان کلید ها را تولید کرد</translation> + </message> + <message> + <source>Upgrading UTXO database</source> + <translation>ارتقا دادن پایگاه داده UTXO</translation> + </message> + <message> + <source>Verifying blocks...</source> + <translation>در حال تایید کردن بلاک ها...</translation> + </message> + <message> <source>The transaction amount is too small to send after the fee has been deducted</source> <translation>مبلغ تراکنش کمتر از آن است که پس از کسر هزینه تراکنش قابل ارسال باشد</translation> </message> <message> + <source>Error reading from database, shutting down.</source> + <translation>خواندن از پایگاه داده با خطا مواجه شد,در حال خاموش شدن.</translation> + </message> + <message> <source>Information</source> <translation>اطلاعات</translation> </message> <message> + <source>Signing transaction failed</source> + <translation>ثبت تراکنش با خطا مواجه شد</translation> + </message> + <message> + <source>The transaction amount is too small to pay the fee</source> + <translation>حجم تراکنش بسیار کم است برای پرداخت کارمزد</translation> + </message> + <message> + <source>This is experimental software.</source> + <translation>این یک نرم افزار تجربی است.</translation> + </message> + <message> + <source>Transaction amount too small</source> + <translation>حجم تراکنش خیلی کم است</translation> + </message> + <message> + <source>Transaction too large for fee policy</source> + <translation>حجم تراکنش خیلی زیاد است به خاطر سیاست های کارمزدی بیت کوین</translation> + </message> + <message> + <source>Transaction too large</source> + <translation>حجم تراکنش خیلی زیاد است</translation> + </message> + <message> + <source>Unable to generate initial keys</source> + <translation>نمیتوان کلید های اولیه را تولید کرد.</translation> + </message> + <message> + <source>Verifying wallet(s)...</source> + <translation>در حال تایید شدن کیف پول(ها)...</translation> + </message> + <message> <source>Warning</source> <translation>هشدار</translation> </message> <message> + <source>This is the transaction fee you may pay when fee estimates are not available.</source> + <translation>این هزینه تراکنشی است که در صورت عدم وجود هزینه تخمینی، پرداخت می کنید.</translation> + </message> + <message> + <source>Warning: Unknown block versions being mined! It's possible unknown rules are in effect</source> + <translation>هشدار:یک بلاک از یک نسخه ناشناس در حال ماین شدن است.در این اتفاق ممکن است قوانین ناشناسی اثرات نامعلوم بگذارند.</translation> + </message> + <message> + <source>%s is set very high!</source> + <translation>%s بسیار بزرگ انتخاب شده است.</translation> + </message> + <message> + <source>Keypool ran out, please call keypoolrefill first</source> + <translation>کلید استخر تمام شده است، لطفاً درخواست کلید استخر را پرنمایید.</translation> + </message> + <message> + <source>Starting network threads...</source> + <translation>ایجاد نخهای شبکه ...</translation> + </message> + <message> + <source>This is the minimum transaction fee you pay on every transaction.</source> + <translation>این کمترین فی تراکنش است که در هر تراکنش پرداخت مینمایید.</translation> + </message> + <message> + <source>Transaction amounts must not be negative</source> + <translation>مقدار تراکنش نمیتواند منفی باشد.</translation> + </message> + <message> + <source>Transaction must have at least one recipient</source> + <translation>تراکنش باید حداقل یک دریافت کننده داشته باشد</translation> + </message> + <message> <source>Insufficient funds</source> <translation>وجوه ناکافی</translation> </message> <message> + <source>Can't generate a change-address key. Private keys are disabled for this wallet.</source> + <translation>نمیتوان تغییر-آدرس کلید را تولید کرد.کلید های خصوصی در این کیف پول غیر فعال شده اند.</translation> + </message> + <message> <source>Loading block index...</source> <translation>لود شدن نمایه بلاکها..</translation> </message> diff --git a/src/qt/locale/bitcoin_fi.ts b/src/qt/locale/bitcoin_fi.ts index ea97d48b10..71832200df 100644 --- a/src/qt/locale/bitcoin_fi.ts +++ b/src/qt/locale/bitcoin_fi.ts @@ -326,6 +326,14 @@ <translation>Avaa &URI...</translation> </message> <message> + <source>Wallet:</source> + <translation>Lompakko:</translation> + </message> + <message> + <source>default wallet</source> + <translation>oletuslompakko</translation> + </message> + <message> <source>Click to disable network activity.</source> <translation>Paina poistaaksesi verkkoyhteysilmaisin käytöstä.</translation> </message> @@ -346,6 +354,10 @@ <translation>Ladataan lohkoindeksiä...</translation> </message> <message> + <source>Proxy is <b>enabled</b>: %1</source> + <translation>Välipalvelin on <b>käytössä</b>: %1</translation> + </message> + <message> <source>Send coins to a Bitcoin address</source> <translation>Lähetä kolikoita Bitcoin-osoitteeseen</translation> </message> @@ -441,6 +453,10 @@ <source>&Command-line options</source> <translation>&Komentorivin valinnat</translation> </message> + <message numerus="yes"> + <source>%n active connection(s) to Bitcoin network</source> + <translation><numerusform>%n aktiivinen yhteys Bitcoin-verkkoon</numerusform><numerusform>%n aktiivista yhteyttä Bitcoin-verkkoon</numerusform></translation> + </message> <message> <source>Indexing blocks on disk...</source> <translation>Ladataan lohkoindeksiä...</translation> @@ -449,6 +465,10 @@ <source>Processing blocks on disk...</source> <translation>Käsitellään lohkoja levyllä...</translation> </message> + <message numerus="yes"> + <source>Processed %n block(s) of transaction history.</source> + <translation><numerusform>Käsitelty %n lohko rahansiirtohistoriasta.</numerusform><numerusform>Käsitelty %n lohkoa rahansiirtohistoriasta.</numerusform></translation> + </message> <message> <source>%1 behind</source> <translation>%1 jäljessä</translation> @@ -742,6 +762,14 @@ <translation>Antamasi osoite "%1" ei ole kelvollinen Bitcoin-osoite.</translation> </message> <message> + <source>Address "%1" already exists as a receiving address with label "%2" and so cannot be added as a sending address.</source> + <translation>Osoite "%1" on jo vastaanotto-osoitteena nimellä "%2", joten sitä ei voi lisätä lähetysosoitteeksi.</translation> + </message> + <message> + <source>The entered address "%1" is already in the address book with label "%2".</source> + <translation>Syötetty osoite "%1" on jo osoitekirjassa nimellä "%2".</translation> + </message> + <message> <source>Could not unlock wallet.</source> <translation>Lompakkoa ei voitu avata.</translation> </message> @@ -854,7 +882,15 @@ <source>Error</source> <translation>Virhe</translation> </message> - </context> + <message numerus="yes"> + <source>%n GB of free space available</source> + <translation><numerusform>%n GB tilaa vapaana</numerusform><numerusform>%n GB tilaa vapaana</numerusform></translation> + </message> + <message numerus="yes"> + <source>(of %n GB needed)</source> + <translation><numerusform>(tarvitaan %n GB)</numerusform><numerusform>(tarvitaan %n GB)</numerusform></translation> + </message> +</context> <context> <name>ModalOverlay</name> <message> @@ -957,7 +993,7 @@ </message> <message> <source>Number of script &verification threads</source> - <translation>Script &varmistuksen threadien määrä</translation> + <translation>Säikeiden määrä skriptien &varmistuksessa</translation> </message> <message> <source>IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1)</source> @@ -968,6 +1004,10 @@ <translation>Ilmoittaa, mikäli oletetettua SOCKS5-välityspalvelinta käytetään vertaisten tavoittamiseen tämän verkkotyypin kautta.</translation> </message> <message> + <source>Use separate SOCKS&5 proxy to reach peers via Tor hidden services:</source> + <translation>Käytä SOCKS&5-välityspalvelinta tavoittamaan Tor-verkon piilotetut palvelut:</translation> + </message> + <message> <source>Hide the icon from the system tray.</source> <translation>Piilota kuvake järjestelmäpalkista.</translation> </message> @@ -1008,6 +1048,18 @@ <translation>&Verkko</translation> </message> <message> + <source>Disables some advanced features but all blocks will still be fully validated. Reverting this setting requires re-downloading the entire blockchain. Actual disk usage may be somewhat higher.</source> + <translation>Jättää pois joitain edistyneitä ominaisuuksia, mutta silti varmistaa kaikki lohkot kokonaan. Tämän asetuksen muutto vaatii koko lohkoketjun uudelleen lataamisen. Levyn käyttöaste saattaa olla hiukan suurempaa.</translation> + </message> + <message> + <source>Prune &block storage to</source> + <translation>Karsi lohkovaraston kooksi</translation> + </message> + <message> + <source>Reverting this setting requires re-downloading the entire blockchain.</source> + <translation>Tämän asetuksen muuttaminen vaatii koko lohkoketjun uudelleenlataamista.</translation> + </message> + <message> <source>(0 = auto, <0 = leave that many cores free)</source> <translation>(0 = auto, <0 = jätä näin monta ydintä vapaaksi)</translation> </message> @@ -1274,6 +1326,10 @@ <translation>URI käsittely</translation> </message> <message> + <source>'bitcoin://' is not a valid URI. Use 'bitcoin:' instead.</source> + <translation>'bitcoin://' ei ole kelvollinen URI. Käytä 'bitcoin:' sen sijaan.</translation> + </message> + <message> <source>Payment request fetch URL is invalid: %1</source> <translation>Maksupyynnön haku URL on virheellinen: %1</translation> </message> @@ -1447,10 +1503,18 @@ <context> <name>QObject::QObject</name> <message> + <source>Error parsing command line arguments: %1.</source> + <translation>Virhe käsitellessä komentorivin valintaa: %1.</translation> + </message> + <message> <source>Error: Specified data directory "%1" does not exist.</source> <translation>Virhe: Annettua data-hakemistoa "%1" ei ole olemassa.</translation> </message> <message> + <source>Error: Cannot parse configuration file: %1.</source> + <translation>Virhe: Asetustiedostoa ei voida käsitellä: %1.</translation> + </message> + <message> <source>Error: %1</source> <translation>Virhe: %1</translation> </message> @@ -1709,6 +1773,10 @@ <translation>&Poista esto</translation> </message> <message> + <source>default wallet</source> + <translation>oletuslompakko</translation> + </message> + <message> <source>Welcome to the %1 RPC console.</source> <translation>Tervetuloa %1 RPC-konsoliin.</translation> </message> @@ -1800,6 +1868,10 @@ <translation>Tyhjennä</translation> </message> <message> + <source>Generate native segwit (Bech32) address</source> + <translation>Luo natiivi segwit (Bech32) -osoite</translation> + </message> + <message> <source>Requested payments history</source> <translation>Pyydettyjen maksujen historia</translation> </message> @@ -2013,6 +2085,10 @@ <translation>Piilota</translation> </message> <message> + <source>Paying only the minimum fee is just fine as long as there is less transaction volume than space in the blocks. But be aware that this can end up in a never confirming transaction once there is more demand for bitcoin transactions than the network can process.</source> + <translation>Vähimmäispalkkion maksaminen käy hyvin, kunhan verkossa on vähemmän siirtotapahtumia kuin lohkoissa on tilaa. Huomaa, että tämä saattaa johtaa ei-koskaan-vahvistuvaan siirtoon, jos verkon käsittelykyky ylittyy.</translation> + </message> + <message> <source>(read the tooltip)</source> <translation>(lue työkaluvinkki)</translation> </message> @@ -2053,6 +2129,10 @@ <translation>Käytä Replace-By-Fee:tä</translation> </message> <message> + <source>With Replace-By-Fee (BIP-125) you can increase a transaction's fee after it is sent. Without this, a higher fee may be recommended to compensate for increased transaction delay risk.</source> + <translation>Replace-By-Fee:tä (BIP-125) käyttämällä voit korottaa siirtotapahtuman palkkiota sen lähettämisen jälkeen. Ilman tätä saatetaan suositella käyttämään suurempaa palkkiota kompensoimaan viiveen kasvamisen riskiä.</translation> + </message> + <message> <source>Clear &All</source> <translation>&Tyhjennnä Kaikki</translation> </message> @@ -2113,6 +2193,14 @@ <translation>tai</translation> </message> <message> + <source>You can increase the fee later (signals Replace-By-Fee, BIP-125).</source> + <translation>Voit korottaa palkkiota myöhemmin (osoittaa Replace-By-Fee:tä, BIP-125).</translation> + </message> + <message> + <source>Please, review your transaction.</source> + <translation>Tarkistathan siirtosi.</translation> + </message> + <message> <source>Transaction fee</source> <translation>Siirtokulu</translation> </message> @@ -2160,6 +2248,10 @@ <source>Pay only the required fee of %1</source> <translation>Maksa vain vaadittu kulu %1 </translation> </message> + <message numerus="yes"> + <source>Estimated to begin confirmation within %n block(s).</source> + <translation><numerusform>Vahvistuminen alkaa arviolta %n lohkon sisällä.</numerusform><numerusform>Vahvistuminen alkaa arviolta %n lohkon sisällä.</numerusform></translation> + </message> <message> <source>Warning: Invalid Bitcoin address</source> <translation>Varoitus: Virheellinen Bitcoin-osoite </translation> @@ -2441,6 +2533,10 @@ </context> <context> <name>TransactionDesc</name> + <message numerus="yes"> + <source>Open for %n more block(s)</source> + <translation><numerusform>Avoinna vielä %n lohkon ajan</numerusform><numerusform>Avoinna vielä %n lohkon ajan</numerusform></translation> + </message> <message> <source>Open until %1</source> <translation>Avoinna %1 asti</translation> @@ -2615,6 +2711,10 @@ <source>Label</source> <translation>Nimike</translation> </message> + <message numerus="yes"> + <source>Open for %n more block(s)</source> + <translation><numerusform>Avoinna vielä %n lohkon ajan</numerusform><numerusform>Avoinna vielä %n lohkon ajan</numerusform></translation> + </message> <message> <source>Open until %1</source> <translation>Avoinna %1 asti</translation> @@ -2884,6 +2984,10 @@ <translation>Lähetä kolikoita</translation> </message> <message> + <source>Fee bump error</source> + <translation>Virhe nostaessa palkkiota.</translation> + </message> + <message> <source>Increasing transaction fee failed</source> <translation>Siirtokulun nosto epäonnistui</translation> </message> @@ -2950,7 +3054,11 @@ <source>The wallet data was successfully saved to %1.</source> <translation>Lompakko tallennettiin onnistuneesti tiedostoon %1.</translation> </message> - </context> + <message> + <source>Cancel</source> + <translation>Peruuta</translation> + </message> +</context> <context> <name>bitcoin-core</name> <message> @@ -3122,6 +3230,14 @@ <translation>Virheellinen määrä -fallbackfee=<amount>: '%s'</translation> </message> <message> + <source>Specified blocks directory "%s" does not exist.</source> + <translation>Määrättyä lohkohakemistoa "%s" ei ole olemassa.</translation> + </message> + <message> + <source>Upgrading txindex database</source> + <translation>Päivitetään txindex -tietokantaa</translation> + </message> + <message> <source>Loading P2P addresses...</source> <translation>Ladataan P2P-vertaisten osoitteita...</translation> </message> @@ -3142,6 +3258,10 @@ <translation>Karsittu tila ei ole yhteensopiva -txindex:n kanssa.</translation> </message> <message> + <source>Replaying blocks...</source> + <translation>Tarkastetaan lohkoja..</translation> + </message> + <message> <source>Rewinding blocks...</source> <translation>Varmistetaan lohkoja...</translation> </message> @@ -3158,6 +3278,10 @@ <translation>Kytkeytyminen kohteeseen %s ei onnistu tällä tietokoneella. %s on luultavasti jo käynnissä.</translation> </message> <message> + <source>Unable to generate keys</source> + <translation>Avaimia ei voitu luoda</translation> + </message> + <message> <source>Unsupported argument -benchmark ignored, use -debug=bench.</source> <translation>Argumenttia -benchmark ei tueta, käytä -debug=bench.</translation> </message> @@ -3206,6 +3330,10 @@ <translation>Virheitä tietokantaa luettaessa, ohjelma pysäytetään.</translation> </message> <message> + <source>Error upgrading chainstate database</source> + <translation>Virhe päivittäessä chainstate-tietokantaa</translation> + </message> + <message> <source>Information</source> <translation>Tietoa</translation> </message> @@ -3238,6 +3366,14 @@ <translation>Siirron vahvistus epäonnistui</translation> </message> <message> + <source>Specified -walletdir "%s" does not exist</source> + <translation>Määriteltyä lompakon hakemistoa "%s" ei ole olemassa.</translation> + </message> + <message> + <source>Specified -walletdir "%s" is a relative path</source> + <translation>Määritelty lompakkohakemisto "%s" sijaitsee suhteellisessa polussa</translation> + </message> + <message> <source>The transaction amount is too small to pay the fee</source> <translation>Rahansiirron määrä on liian pieni kattaakseen maksukulun</translation> </message> @@ -3266,6 +3402,10 @@ <translation>Varmistetaan lompakko(ja)...</translation> </message> <message> + <source>Wallet %s resides outside wallet directory %s</source> + <translation>Lompakko %s sijaitsee lompakkohakemiston %s ulkopuolella.</translation> + </message> + <message> <source>Warning</source> <translation>Varoitus</translation> </message> @@ -3286,6 +3426,10 @@ <translation>Virhe ladattaessa %s: Et voi ottaa HD:ta käyttöön jo olemassa olevalle ei-HD -lompakolle.</translation> </message> <message> + <source>This is the transaction fee you may pay when fee estimates are not available.</source> + <translation>Tämän siirtomaksun maksat, kun siirtomaksun arviointi ei ole käytettävissä.</translation> + </message> + <message> <source>Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported.</source> <translation>Ei tuettu argumentti -socks löytynyt. SOCKS -version asetusta ei enää tueta, ainoastaan SOCKS5 -välityspalvelimet on tuettu.</translation> </message> @@ -3314,6 +3458,10 @@ <translation>Käynnistetään verkkoa...</translation> </message> <message> + <source>The wallet will avoid paying less than the minimum relay fee.</source> + <translation>Lompakko välttää maksamasta alle vähimmäisen välityskulun.</translation> + </message> + <message> <source>This is the minimum transaction fee you pay on every transaction.</source> <translation>Tämä on jokaisesta siirrosta maksettava vähimmäismaksu.</translation> </message> @@ -3342,6 +3490,14 @@ <translation>Lompakon saldo ei riitä</translation> </message> <message> + <source>Can't generate a change-address key. Private keys are disabled for this wallet.</source> + <translation>Vaihtorahaosoitetteen avainta ei voitu luoda. Yksityisavaimet on poistettu käytöstä tässä lompakossa.</translation> + </message> + <message> + <source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source> + <translation>Siirtomaksun arviointi epäonnistui. Odota muutama lohko tai käytä -fallbackfee -valintaa..</translation> + </message> + <message> <source>Loading block index...</source> <translation>Ladataan lohkoindeksiä...</translation> </message> diff --git a/src/qt/locale/bitcoin_fr.ts b/src/qt/locale/bitcoin_fr.ts index 52e7bda368..046972360e 100644 --- a/src/qt/locale/bitcoin_fr.ts +++ b/src/qt/locale/bitcoin_fr.ts @@ -842,7 +842,7 @@ </message> <message> <source>When you click OK, %1 will begin to download and process the full %4 block chain (%2GB) starting with the earliest transactions in %3 when %4 initially launched.</source> - <translation>Lorsque vous cliquez sur OK, %1 commence à télécharger et à traiter l’intégralité de la chaîne de blocs %4 (%2 Go) en débutant avec les transactions les plus anciennes de %3, quand %4 a été lancé initialement.</translation> + <translation>Quand vous cliquerez sur Valider, %1 commencera à télécharger et à traiter l’intégralité de la chaîne de blocs %4 (%2 Go) en débutant avec les transactions les plus anciennes de %3, quand %4 a été lancé initialement.</translation> </message> <message> <source>This initial synchronisation is very demanding, and may expose hardware problems with your computer that had previously gone unnoticed. Each time you run %1, it will continue downloading where it left off.</source> @@ -1195,7 +1195,7 @@ </message> <message> <source>&OK</source> - <translation>&OK</translation> + <translation>&Valider</translation> </message> <message> <source>&Cancel</source> @@ -1254,7 +1254,7 @@ </message> <message> <source>The displayed information may be out of date. Your wallet automatically synchronizes with the Bitcoin network after a connection is established, but this process has not completed yet.</source> - <translation>Les informations affichées peuvent être obsolètes. Votre porte-monnaie est automatiquement synchronisé avec le réseau Bitcoin lorsque la connexion s’établit, or ce processus n’est pas encore terminé.</translation> + <translation>Les informations affichées peuvent être obsolètes. Votre porte-monnaie se synchronise automatiquement avec le réseau Bitcoin dès qu’une connexion est établie, mais ce processus n’est pas encore achevé.</translation> </message> <message> <source>Watch-only:</source> @@ -2300,7 +2300,7 @@ Note : Les frais étant calculés par octet, des frais de « 100 satoshis par </message> <message> <source>The total exceeds your balance when the %1 transaction fee is included.</source> - <translation>Le montant dépasse votre solde lorsque les frais de transaction de %1 sont inclus.</translation> + <translation>Le montant dépasse votre solde quand les frais de transaction de %1 sont inclus.</translation> </message> <message> <source>Duplicate address found: addresses should only be used once each.</source> @@ -2741,7 +2741,7 @@ Note : Les frais étant calculés par octet, des frais de « 100 satoshis par </message> <message> <source>Output index</source> - <translation>Index de sorties</translation> + <translation>Index des sorties</translation> </message> <message> <source>Merchant</source> @@ -2749,7 +2749,7 @@ Note : Les frais étant calculés par octet, des frais de « 100 satoshis par </message> <message> <source>Generated coins must mature %1 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, its state will change to "not accepted" and it won't be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.</source> - <translation>Les pièces générées doivent mûrir pendant %1 blocs avant de pouvoir être dépensées. Lorsque ce bloc a été généré, il a été diffusé sur le réseau pour être ajouté à la chaîne de blocs. Si son intégration à la chaîne échoue, son état sera modifié en « refusée » et il ne sera pas possible de le dépenser. Cela peut arriver occasionnellement si un autre nœud génère un bloc à quelques secondes du vôtre.</translation> + <translation>Les pièces générées doivent mûrir pendant %1 blocs avant de pouvoir être dépensées. Quand vous avez généré ce bloc, il a été diffusé sur le réseau pour être ajouté à la chaîne de blocs. Si son intégration à la chaîne échoue, son état sera modifié en « refusée » et il ne sera pas possible de le dépenser. Cela peut arriver occasionnellement si un autre nœud génère un bloc à quelques secondes du vôtre.</translation> </message> <message> <source>Debug information</source> @@ -3200,6 +3200,10 @@ Note : Les frais étant calculés par octet, des frais de « 100 satoshis par <translation>Erreur de lecture de %s ! Toutes les clés ont été lues correctement, mais les données transactionnelles ou les entrées du carnet d’adresses sont peut-être manquantes ou incorrectes.</translation> </message> <message> + <source>Group outputs by address, selecting all or none, instead of selecting on a per-output basis. Privacy is improved as an address is only used once (unless someone sends to it after spending from it), but may result in slightly higher fees as suboptimal coin selection may result due to the added limitation (default: %u)</source> + <translation>Grouper les sorties par adresse, les sélectionnant toutes ou n’en sélectionnant aucune, au lieu d’une sélection par sortie. La confidentialité est améliorée dans la mesure où une adresse n’est utilisée qu’une fois (à moins que quelqu’un envoie à adresse après l’avoir utilisée pour une dépense). Cela pourrait entraîner des frais légèrement plus élevés, car une sélection sous-optimale des pièces pourrait en résulter en raison de la restriction supplémentaire (par défaut : %u)</translation> + </message> + <message> <source>Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly.</source> <translation>Veuillez vérifier que l’heure et la date de votre ordinateur sont justes ! Si votre horloge n’est pas à l’heure, %s ne fonctionnera pas correctement.</translation> </message> @@ -3340,6 +3344,10 @@ Note : Les frais étant calculés par octet, des frais de « 100 satoshis par <translation>Montant invalide pour -fallbackfee=<amount> : « %s »</translation> </message> <message> + <source>Specified blocks directory "%s" does not exist.</source> + <translation>Le répertoire des blocs indiqué « %s » n’existe pas.</translation> + </message> + <message> <source>Upgrading txindex database</source> <translation>Mise à niveau de la base de données txindex</translation> </message> @@ -3480,12 +3488,6 @@ Note : Les frais étant calculés par octet, des frais de « 100 satoshis par <translation>Échec de signature de la transaction</translation> </message> <message> - <source>Specified blocks directory "%s" does not exist. -</source> - <translation>Le répertoire de blocs indiqué « %s » n’existe pas. -</translation> - </message> - <message> <source>The transaction amount is too small to pay the fee</source> <translation>Le montant de la transaction est trop bas pour que les frais soient payés</translation> </message> diff --git a/src/qt/locale/bitcoin_he.ts b/src/qt/locale/bitcoin_he.ts index cf884f0fc7..c8088da4e2 100644 --- a/src/qt/locale/bitcoin_he.ts +++ b/src/qt/locale/bitcoin_he.ts @@ -3,7 +3,7 @@ <name>AddressBookPage</name> <message> <source>Right-click to edit address or label</source> - <translation>יש ללחוץ על הכפתור הימני כדי לערוך כתובת או תווית</translation> + <translation>לחץ על הכפתור הימני בעכבר כדי לערוך את הכתובת או התווית</translation> </message> <message> <source>Create a new address</source> @@ -279,19 +279,19 @@ </message> <message> <source>&About %1</source> - <translation>על &אודות %1</translation> + <translation>&אודות %1</translation> </message> <message> <source>Show information about %1</source> - <translation>הצגת מידע על %1</translation> + <translation>הצג מידע על %1</translation> </message> <message> <source>About &Qt</source> - <translation>על אודות Qt</translation> + <translation>אודות &Qt</translation> </message> <message> <source>Show information about Qt</source> - <translation>הצגת מידע על Qt</translation> + <translation>הצג מידע על Qt</translation> </message> <message> <source>&Options...</source> @@ -815,7 +815,7 @@ </message> <message> <source>About %1</source> - <translation>על אודות %1</translation> + <translation>אודות %1</translation> </message> <message> <source>Command-line options</source> @@ -1002,6 +1002,14 @@ <translation>כתובת ה־IP של המתווך (לדוגמה IPv4: 127.0.0.1 / IPv6: ::1)</translation> </message> <message> + <source>Shows if the supplied default SOCKS5 proxy is used to reach peers via this network type.</source> + <translation>מראה אם פרוקסי SOCKS5 המסופק כבררת מחדל משמש להתקשרות עם עמיתים באמצעות סוג רשת זה.</translation> + </message> + <message> + <source>Use separate SOCKS&5 proxy to reach peers via Tor hidden services:</source> + <translation>השתמשו בפרוקסי SOCKS&5 נפרד כדי להתקשר עם עמיתים באמצעות שירותים חבויים ברשת Tor:</translation> + </message> + <message> <source>Hide the icon from the system tray.</source> <translation>הסתר את סמל מגש המערכת</translation> </message> @@ -1556,7 +1564,7 @@ </message> <message> <source>Client version</source> - <translation>גרסת מנשק</translation> + <translation>גרסה</translation> </message> <message> <source>&Information</source> @@ -1572,7 +1580,7 @@ </message> <message> <source>Using BerkeleyDB version</source> - <translation>שימוש ב־BerkeleyDB גרסה</translation> + <translation>גרסת BerkeleyDB</translation> </message> <message> <source>Datadir</source> @@ -1675,6 +1683,10 @@ <translation>סוכן משתמש</translation> </message> <message> + <source>Open the %1 debug log file from the current data directory. This can take a few seconds for large log files.</source> + <translation>פתחו את לוג ניפוי השגיאות ה%1 מתיקיית הנתונים הנוכחית. עבור קבצי לוג גדולים ייתכן זמן המתנה של מספר שניות.</translation> + </message> + <message> <source>Decrease font size</source> <translation>הקטן גודל גופן</translation> </message> @@ -2203,6 +2215,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>העתקת השינוי</translation> </message> <message> + <source>%1 (%2 blocks)</source> + <translation>%1 (%2 בלוקים)</translation> + </message> + <message> <source>Are you sure you want to send?</source> <translation>לשלוח?</translation> </message> diff --git a/src/qt/locale/bitcoin_hi_IN.ts b/src/qt/locale/bitcoin_hi_IN.ts index 51d6770b1a..cf969b67db 100644 --- a/src/qt/locale/bitcoin_hi_IN.ts +++ b/src/qt/locale/bitcoin_hi_IN.ts @@ -18,6 +18,14 @@ <translation>चुनिन्दा पते को सिस्टम क्लिपबोर्ड पर कापी करे !</translation> </message> <message> + <source>&Copy</source> + <translation>&कॉपी </translation> + </message> + <message> + <source>C&lose</source> + <translation>सी&लूज़ </translation> + </message> + <message> <source>Delete the currently selected address from the list</source> <translation>सूची से वर्तमान में चयनित पता हटाएं</translation> </message> @@ -61,13 +69,49 @@ <source>These are your Bitcoin addresses for receiving payments. It is recommended to use a new receiving address for each transaction.</source> <translation>भुगतान प्राप्त करने के लिए ये आपके बीटकोइन पते हैं प्रत्येक लेनदेन के लिए एक नया प्राप्त पता उपयोग करने की सिफारिश की जाती है।</translation> </message> + <message> + <source>&Copy Address</source> + <translation>&पता कॉपी करें </translation> + </message> + <message> + <source>&Edit</source> + <translation>&संशोधित करें </translation> + </message> + <message> + <source>Export Address List</source> + <translation>निर्यात पता सूची</translation> + </message> + <message> + <source>Comma separated file (*.csv)</source> + <translation>कोमा द्वारा अलग की गई फ़ाइल (* .csv)</translation> + </message> + <message> + <source>Exporting Failed</source> + <translation>निर्यात विफल रहा</translation> + </message> </context> <context> <name>AddressTableModel</name> - </context> + <message> + <source>Label</source> + <translation>परचा</translation> + </message> + <message> + <source>Address</source> + <translation>पता </translation> + </message> + <message> + <source>(no label)</source> + <translation>(कोई परचा नहीं )</translation> + </message> +</context> <context> <name>AskPassphraseDialog</name> <message> + <source>Passphrase Dialog</source> + <translation>पासफ़्रेज़ डायलॉग</translation> + </message> + <message> <source>Enter passphrase</source> <translation>पहचान शब्द/अक्षर डालिए !</translation> </message> @@ -79,6 +123,18 @@ <source>Repeat new passphrase</source> <translation>दोबारा नया पहचान शब्द/अक्षर डालिए !</translation> </message> + <message> + <source>Show password</source> + <translation>पासवर्ड दिखाए</translation> + </message> + <message> + <source>Encrypt wallet</source> + <translation>वॉलेट एन्क्रिप्ट करें</translation> + </message> + <message> + <source>Change passphrase</source> + <translation>पासफ़्रेज़ बदलें</translation> + </message> </context> <context> <name>BanTableModel</name> @@ -205,6 +261,10 @@ <source>Confirmed</source> <translation>पक्का</translation> </message> + <message> + <source>(no label)</source> + <translation>(कोई परचा नहीं )</translation> + </message> </context> <context> <name>EditAddressDialog</name> @@ -340,12 +400,28 @@ <translation>&पता कॉपी करे</translation> </message> <message> + <source>Address</source> + <translation>पता </translation> + </message> + <message> + <source>Label</source> + <translation>परचा</translation> + </message> + <message> <source>Wallet</source> <translation>वॉलेट</translation> </message> </context> <context> <name>RecentRequestsTableModel</name> + <message> + <source>Label</source> + <translation>परचा</translation> + </message> + <message> + <source>(no label)</source> + <translation>(कोई परचा नहीं )</translation> + </message> </context> <context> <name>SendCoinsDialog</name> @@ -369,7 +445,11 @@ <source>Confirm the send action</source> <translation>भेजने की पुष्टि करें</translation> </message> - </context> + <message> + <source>(no label)</source> + <translation>(कोई परचा नहीं )</translation> + </message> +</context> <context> <name>SendCoinsEntry</name> <message> @@ -448,9 +528,33 @@ </context> <context> <name>TransactionTableModel</name> + <message> + <source>Label</source> + <translation>परचा</translation> + </message> + <message> + <source>(no label)</source> + <translation>(कोई परचा नहीं )</translation> + </message> </context> <context> <name>TransactionView</name> + <message> + <source>Comma separated file (*.csv)</source> + <translation>कोमा द्वारा अलग की गई फ़ाइल (* .csv)</translation> + </message> + <message> + <source>Label</source> + <translation>परचा</translation> + </message> + <message> + <source>Address</source> + <translation>पता </translation> + </message> + <message> + <source>Exporting Failed</source> + <translation>निर्यात विफल रहा</translation> + </message> </context> <context> <name>UnitDisplayStatusBarControl</name> diff --git a/src/qt/locale/bitcoin_hr.ts b/src/qt/locale/bitcoin_hr.ts index 2bd6c7df03..381c99946b 100644 --- a/src/qt/locale/bitcoin_hr.ts +++ b/src/qt/locale/bitcoin_hr.ts @@ -3,7 +3,7 @@ <name>AddressBookPage</name> <message> <source>Right-click to edit address or label</source> - <translation>Desni klik za uređivanje adresa i oznaka</translation> + <translation>Desni klik za uređivanje adrese ili oznake</translation> </message> <message> <source>Create a new address</source> @@ -15,19 +15,19 @@ </message> <message> <source>Copy the currently selected address to the system clipboard</source> - <translation>Kopiraj trenutno odabranu adresu u međuspremnik</translation> + <translation>Kopirajte trenutno odabranu adresu u međuspremnik</translation> </message> <message> <source>&Copy</source> - <translation>&Kopiraj</translation> + <translation>&Kopirajte</translation> </message> <message> <source>C&lose</source> - <translation>&Zatvori</translation> + <translation>&Zatvorite</translation> </message> <message> <source>Delete the currently selected address from the list</source> - <translation>Brisanje trenutno odabrane adrese s popisa.</translation> + <translation>Obrišite trenutno odabranu adresu s popisa.</translation> </message> <message> <source>Enter address or label to search</source> @@ -35,35 +35,35 @@ </message> <message> <source>Export the data in the current tab to a file</source> - <translation>Izvoz podataka iz trenutnog lista u datoteku</translation> + <translation>Izvezite podatke iz trenutne kartice u datoteku</translation> </message> <message> <source>&Export</source> - <translation>&Izvozi</translation> + <translation>&Izvezite</translation> </message> <message> <source>&Delete</source> - <translation>Iz&briši</translation> + <translation>Iz&brišite</translation> </message> <message> <source>Choose the address to send coins to</source> - <translation>Odaberi adresu na koju šalješ novac</translation> + <translation>Odaberite adresu na koju ćete poslati novac</translation> </message> <message> <source>Choose the address to receive coins with</source> - <translation>Odaberi adresu na koju primaš novac</translation> + <translation>Odaberite adresu na koju ćete primiti novac</translation> </message> <message> <source>C&hoose</source> - <translation>&Odaberi</translation> + <translation>&Odaberite</translation> </message> <message> <source>Sending addresses</source> - <translation>Adresa pošiljatelja</translation> + <translation>Adrese pošiljatelja</translation> </message> <message> <source>Receiving addresses</source> - <translation>Adresa primatelja</translation> + <translation>Adrese primatelja</translation> </message> <message> <source>These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins.</source> @@ -71,23 +71,23 @@ </message> <message> <source>These are your Bitcoin addresses for receiving payments. It is recommended to use a new receiving address for each transaction.</source> - <translation>Ovo su vaše Bitcoin adrese za primanje novca. Preporučamo da koristite novu adresu za primanje za svaku transakciju.</translation> + <translation>Ovo su vaše Bitcoin adrese za primanje novca. Preporučeno je da koristite novu primateljsku adresu za svaku transakciju.</translation> </message> <message> <source>&Copy Address</source> - <translation>&Kopiraj adresu</translation> + <translation>&Kopirajte adresu</translation> </message> <message> <source>Copy &Label</source> - <translation>Kopiraj i označi</translation> + <translation>Kopirajte &oznaku</translation> </message> <message> <source>&Edit</source> - <translation>Uredi</translation> + <translation>&Uredite</translation> </message> <message> <source>Export Address List</source> - <translation>Izvezi listu adresa</translation> + <translation>Izvezite listu adresa</translation> </message> <message> <source>Comma separated file (*.csv)</source> @@ -136,12 +136,16 @@ <translation>Ponovite novu lozinku</translation> </message> <message> + <source>Show password</source> + <translation>Prikažite lozinku</translation> + </message> + <message> <source>Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>.</source> - <translation>Unesite novu lozinku za novčanik. <br/>Molimo Vas da koristite zaporku od <b>deset ili više slučajnih znakova</b>, ili <b>osam ili više riječi.</b></translation> + <translation>Unesite novu lozinku za novčanik. <br/>Molimo vas da koristite zaporku od <b>deset ili više slučajnih znakova</b>, ili <b>osam ili više riječi.</b></translation> </message> <message> <source>Encrypt wallet</source> - <translation>Šifriranje novčanika</translation> + <translation>Šifrirajte novčanik</translation> </message> <message> <source>This operation needs your wallet passphrase to unlock the wallet.</source> @@ -149,7 +153,7 @@ </message> <message> <source>Unlock wallet</source> - <translation>Otključaj novčanik</translation> + <translation>Otključajte novčanik</translation> </message> <message> <source>This operation needs your wallet passphrase to decrypt the wallet.</source> @@ -157,11 +161,11 @@ </message> <message> <source>Decrypt wallet</source> - <translation>Dešifriranje novčanika.</translation> + <translation>Dešifrirajte novčanik</translation> </message> <message> <source>Change passphrase</source> - <translation>Promjena lozinke</translation> + <translation>Promijenite lozinku</translation> </message> <message> <source>Enter the old passphrase and new passphrase to the wallet.</source> @@ -169,7 +173,7 @@ </message> <message> <source>Confirm wallet encryption</source> - <translation>Potvrdi šifriranje novčanika</translation> + <translation>Potvrdite šifriranje novčanika</translation> </message> <message> <source>Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>!</source> @@ -184,6 +188,10 @@ <translation>Novčanik šifriran</translation> </message> <message> + <source>%1 will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source> + <translation>%1 će se sada zatvoriti kako bi dovršio postupak šifriranja. Zapamtite da šifriranje vašeg novčanika ne može u potpunosti zaštititi vaše bitcoine od krađe preko zloćudnog softvera koji bi bio na vašem računalu.</translation> + </message> + <message> <source>IMPORTANT: Any previous backups you have made of your wallet file should be replaced with the newly generated, encrypted wallet file. For security reasons, previous backups of the unencrypted wallet file will become useless as soon as you start using the new, encrypted wallet.</source> <translation>VAŽNO: Sve prethodne pričuve vašeg novčanika trebale bi biti zamijenjene novo stvorenom, šifriranom datotekom novčanika. Zbog sigurnosnih razloga, prethodne pričuve nešifriranog novčanika će postati beskorisne čim počnete koristiti novi, šifrirani novčanik.</translation> </message> @@ -222,7 +230,15 @@ </context> <context> <name>BanTableModel</name> - </context> + <message> + <source>IP/Netmask</source> + <translation>IP/Mrežna maska</translation> + </message> + <message> + <source>Banned Until</source> + <translation>Zabranjen do</translation> + </message> +</context> <context> <name>BitcoinGUI</name> <message> @@ -231,7 +247,7 @@ </message> <message> <source>Synchronizing with network...</source> - <translation>Usklađivanje s mrežom ...</translation> + <translation>Sinkronizira se s mrežom...</translation> </message> <message> <source>&Overview</source> @@ -251,7 +267,7 @@ </message> <message> <source>Browse transaction history</source> - <translation>Pretraži povijest transakcija</translation> + <translation>Pretražite povijest transakcija</translation> </message> <message> <source>E&xit</source> @@ -259,35 +275,43 @@ </message> <message> <source>Quit application</source> - <translation>Izlazak iz programa</translation> + <translation>Zatvorite aplikaciju</translation> </message> <message> <source>&About %1</source> <translation>&Više o %1</translation> </message> <message> + <source>Show information about %1</source> + <translation>Prikažite informacije o programu %1</translation> + </message> + <message> <source>About &Qt</source> <translation>Više o &Qt</translation> </message> <message> <source>Show information about Qt</source> - <translation>Prikaži informacije o Qt</translation> + <translation>Prikažite informacije o Qt</translation> </message> <message> <source>&Options...</source> <translation>Pos&tavke...</translation> </message> <message> + <source>Modify configuration options for %1</source> + <translation>Promijenite postavke za %1</translation> + </message> + <message> <source>&Encrypt Wallet...</source> - <translation>Ši&friraj novčanik...</translation> + <translation>Ši&frirajte novčanik...</translation> </message> <message> <source>&Backup Wallet...</source> - <translation>Spremi &kopiju novčanika...</translation> + <translation>Spremite &kopiju novčanika...</translation> </message> <message> <source>&Change Passphrase...</source> - <translation>Promjena &lozinke...</translation> + <translation>Promijenite &lozinku...</translation> </message> <message> <source>&Sending addresses...</source> @@ -299,15 +323,43 @@ </message> <message> <source>Open &URI...</source> - <translation>Otvori &URI...</translation> + <translation>Otvorite &URI...</translation> + </message> + <message> + <source>Wallet:</source> + <translation>Novčanik:</translation> + </message> + <message> + <source>default wallet</source> + <translation>uobičajeni novčanik</translation> + </message> + <message> + <source>Click to disable network activity.</source> + <translation>Kliknite da isključite mrežnu aktivnost.</translation> + </message> + <message> + <source>Network activity disabled.</source> + <translation>Mrežna aktivnost isključena.</translation> + </message> + <message> + <source>Click to enable network activity again.</source> + <translation>Kliknite da ponovo uključite mrežnu aktivnost.</translation> + </message> + <message> + <source>Syncing Headers (%1%)...</source> + <translation>Sinkroniziraju se zaglavlja (%1%)...</translation> </message> <message> <source>Reindexing blocks on disk...</source> <translation>Re-indeksiranje blokova na disku...</translation> </message> <message> + <source>Proxy is <b>enabled</b>: %1</source> + <translation>Proxy je <b>uključen</b>: %1</translation> + </message> + <message> <source>Send coins to a Bitcoin address</source> - <translation>Slanje novca na bitcoin adresu</translation> + <translation>Pošaljite novac na Bitcoin adresu</translation> </message> <message> <source>Backup wallet to another location</source> @@ -323,7 +375,7 @@ </message> <message> <source>Open debugging and diagnostic console</source> - <translation>Otvori konzolu za dijagnostiku</translation> + <translation>Otvorite konzolu za dijagnostiku</translation> </message> <message> <source>&Verify message...</source> @@ -339,31 +391,31 @@ </message> <message> <source>&Send</source> - <translation>&Pošalji</translation> + <translation>&Pošaljite</translation> </message> <message> <source>&Receive</source> - <translation>Pri&mi</translation> + <translation>Pri&mite</translation> </message> <message> <source>&Show / Hide</source> - <translation>Po&kaži / Sakrij</translation> + <translation>Po&kažite / Sakrijte</translation> </message> <message> <source>Show or hide the main Window</source> - <translation>Prikaži ili sakrij glavni prozor</translation> + <translation>Prikažite ili sakrijte glavni prozor</translation> </message> <message> <source>Encrypt the private keys that belong to your wallet</source> - <translation>Šifriranje privatnih ključeva koji u novčaniku</translation> + <translation>Šifrirajte privatne ključeve u novčaniku</translation> </message> <message> <source>Sign messages with your Bitcoin addresses to prove you own them</source> - <translation>Poruku potpišemo s bitcoin adresom, kako bi dokazali vlasništvo nad tom adresom</translation> + <translation>Poruku potpišemo s Bitcoin adresom, kako bi dokazali vlasništvo nad tom adresom</translation> </message> <message> <source>Verify messages to ensure they were signed with specified Bitcoin addresses</source> - <translation>Provjeravanje poruke, kao dokaz, da je potpisana navedenom bitcoin adresom</translation> + <translation>Provjerite poruku da je potpisana s navedenom Bitcoin adresom</translation> </message> <message> <source>&File</source> @@ -383,19 +435,19 @@ </message> <message> <source>Request payments (generates QR codes and bitcoin: URIs)</source> - <translation>Zatraži uplatu (stvara QR kod i bitcoin: URI adresu)</translation> + <translation>Zatražite uplatu (stvara QR kod i bitcoin: URI adresu)</translation> </message> <message> <source>Show the list of used sending addresses and labels</source> - <translation>Prikaži popis korištenih adresa i oznaka za slanje novca</translation> + <translation>Prikažite popis korištenih adresa i oznaka za slanje novca</translation> </message> <message> <source>Show the list of used receiving addresses and labels</source> - <translation>Prikaži popis korištenih adresa i oznaka za primanje novca</translation> + <translation>Prikažite popis korištenih adresa i oznaka za primanje novca</translation> </message> <message> <source>Open a bitcoin: URI or payment request</source> - <translation>Otvori bitcoin: URI adresu ili zahtjev za uplatu</translation> + <translation>Otvorite bitcoin: URI adresu ili zahtjev za uplatu</translation> </message> <message> <source>&Command-line options</source> @@ -407,17 +459,21 @@ </message> <message> <source>Indexing blocks on disk...</source> - <translation>Indeksiram blokove na disku...</translation> + <translation>Indeksiraju se blokovi na disku...</translation> </message> <message> <source>Processing blocks on disk...</source> - <translation>Procesiram blokove na disku...</translation> + <translation>Procesiraju se blokovi na disku...</translation> </message> <message numerus="yes"> <source>Processed %n block(s) of transaction history.</source> <translation><numerusform>Obrađen %n blok povijesti transakcije.</numerusform><numerusform>Obrađeno %n bloka povijesti transakcije.</numerusform><numerusform>Obrađeno %n blokova povijesti transakcije.</numerusform></translation> </message> <message> + <source>%1 behind</source> + <translation>%1 iza</translation> + </message> + <message> <source>Last received block was generated %1 ago.</source> <translation>Zadnji primljeni blok je bio ustvaren prije %1.</translation> </message> @@ -442,10 +498,18 @@ <translation>Ažurno</translation> </message> <message> + <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source> + <translation>Prikažite pomoć programa %1 kako biste ispisali moguće opcije preko terminala</translation> + </message> + <message> <source>%1 client</source> <translation>%1 klijent</translation> </message> <message> + <source>Connecting to peers...</source> + <translation>Spaja se na klijente...</translation> + </message> + <message> <source>Catching up...</source> <translation>Ažuriranje...</translation> </message> @@ -462,6 +526,11 @@ </translation> </message> <message> + <source>Wallet: %1 +</source> + <translation>Novčanik: %1</translation> + </message> + <message> <source>Type: %1 </source> <translation>Vrsta: %1 @@ -488,6 +557,14 @@ <translation>Dolazna transakcija</translation> </message> <message> + <source>HD key generation is <b>enabled</b></source> + <translation>Generiranje HD ključeva je <b>uključeno</b></translation> + </message> + <message> + <source>HD key generation is <b>disabled</b></source> + <translation>Generiranje HD ključeva je <b>isključeno</b></translation> + </message> + <message> <source>Wallet is <b>encrypted</b> and currently <b>unlocked</b></source> <translation>Novčanik je <b>šifriran</b> i trenutno <b>otključan</b></translation> </message> @@ -495,7 +572,11 @@ <source>Wallet is <b>encrypted</b> and currently <b>locked</b></source> <translation>Novčanik je <b>šifriran</b> i trenutno <b>zaključan</b></translation> </message> - </context> + <message> + <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source> + <translation>Dogodila se kobna greška. Bitcoin ne može više sigurno nastaviti te će se zatvoriti.</translation> + </message> +</context> <context> <name>CoinControlDialog</name> <message> @@ -520,7 +601,11 @@ </message> <message> <source>Dust:</source> - <translation>Prah:</translation> + <translation>Prašina:</translation> + </message> + <message> + <source>After Fee:</source> + <translation>Nakon naknade:</translation> </message> <message> <source>Change:</source> @@ -531,6 +616,14 @@ <translation>Izaberi sve/ništa</translation> </message> <message> + <source>Tree mode</source> + <translation>Prikažite kao stablo</translation> + </message> + <message> + <source>List mode</source> + <translation>Prikažite kao listu</translation> + </message> + <message> <source>Amount</source> <translation>Iznos</translation> </message> @@ -556,19 +649,55 @@ </message> <message> <source>Copy address</source> - <translation>Kopiraj adresu</translation> + <translation>Kopirajte adresu</translation> </message> <message> <source>Copy label</source> - <translation>Kopiraj oznaku</translation> + <translation>Kopirajte oznaku</translation> </message> <message> <source>Copy amount</source> - <translation>Kopiraj iznos</translation> + <translation>Kopirajte iznos</translation> </message> <message> <source>Copy transaction ID</source> - <translation>Kopiraj ID transakcije</translation> + <translation>Kopirajte ID transakcije</translation> + </message> + <message> + <source>Lock unspent</source> + <translation>Zaključajte nepotrošen input</translation> + </message> + <message> + <source>Unlock unspent</source> + <translation>Otključajte nepotrošen input</translation> + </message> + <message> + <source>Copy quantity</source> + <translation>Kopirajte iznos</translation> + </message> + <message> + <source>Copy fee</source> + <translation>Kopirajte naknadu</translation> + </message> + <message> + <source>Copy after fee</source> + <translation>Kopirajte iznos nakon naknade</translation> + </message> + <message> + <source>Copy bytes</source> + <translation>Kopirajte količinu bajtova</translation> + </message> + <message> + <source>Copy dust</source> + <translation>Kopirajte prašinu</translation> + </message> + <message> + <source>Copy change</source> + <translation>Kopirajte ostatak</translation> + </message> + <message> + <source>(%1 locked)</source> + <translation>(%1 zaključen)</translation> </message> <message> <source>yes</source> @@ -579,15 +708,31 @@ <translation>ne</translation> </message> <message> + <source>This label turns red if any recipient receives an amount smaller than the current dust threshold.</source> + <translation>Oznaka postane crvene boje ako bilo koji primatelj dobije iznos manji od trenutnog praga "prašine" (sićušnog iznosa).</translation> + </message> + <message> + <source>Can vary +/- %1 satoshi(s) per input.</source> + <translation>Može varirati +/- %1 satoši(ja) po inputu.</translation> + </message> + <message> <source>(no label)</source> <translation>(nema oznake)</translation> </message> - </context> + <message> + <source>change from %1 (%2)</source> + <translation>ostatak od %1 (%2)</translation> + </message> + <message> + <source>(change)</source> + <translation>(ostatak)</translation> + </message> +</context> <context> <name>EditAddressDialog</name> <message> <source>Edit Address</source> - <translation>Uredi adresu</translation> + <translation>Uredite adresu</translation> </message> <message> <source>&Label</source> @@ -595,11 +740,11 @@ </message> <message> <source>The label associated with this address list entry</source> - <translation>Oznaka bitcoin adrese</translation> + <translation>Oznaka ovog zapisa u adresaru</translation> </message> <message> <source>The address associated with this address list entry. This can only be modified for sending addresses.</source> - <translation>Bitcoin adresa. Izmjene adrese su moguće samo za adrese za slanje.</translation> + <translation>Adresa ovog zapisa u adresaru. Može se mijenjati samo kod adresa za slanje.</translation> </message> <message> <source>&Address</source> @@ -619,11 +764,19 @@ </message> <message> <source>The entered address "%1" is not a valid Bitcoin address.</source> - <translation>Upisana adresa "%1" nije valjana bitcoin adresa.</translation> + <translation>Upisana adresa "%1" nije valjana Bitcoin adresa.</translation> + </message> + <message> + <source>Address "%1" already exists as a receiving address with label "%2" and so cannot be added as a sending address.</source> + <translation>Adresa "%1" već postoji kao primateljska adresa s oznakom "%2" te se ne može dodati kao pošiljateljska adresa.</translation> + </message> + <message> + <source>The entered address "%1" is already in the address book with label "%2".</source> + <translation>Unesena adresa "%1" postoji već u imeniku pod oznakom "%2".</translation> </message> <message> <source>Could not unlock wallet.</source> - <translation>Ne mogu otključati novčanik.</translation> + <translation>Ne može se otključati novčanik.</translation> </message> <message> <source>New key generation failed.</source> @@ -634,13 +787,21 @@ <name>FreespaceChecker</name> <message> <source>A new data directory will be created.</source> - <translation>Stvoren će biti novi direktorij za podatke.</translation> + <translation>Bit će stvorena nova podatkovna mapa.</translation> </message> <message> <source>name</source> <translation>ime</translation> </message> <message> + <source>Directory already exists. Add %1 if you intend to create a new directory here.</source> + <translation>Mapa već postoji. Dodajte %1 ako namjeravate stvoriti novu mapu ovdje.</translation> + </message> + <message> + <source>Path already exists, and is not a directory.</source> + <translation>Put već postoji i nije mapa.</translation> + </message> + <message> <source>Cannot create data directory here.</source> <translation>Nije moguće stvoriti direktorij za podatke na tom mjestu.</translation> </message> @@ -656,6 +817,10 @@ <translation>(%1-bit)</translation> </message> <message> + <source>About %1</source> + <translation>O programu %1</translation> + </message> + <message> <source>Command-line options</source> <translation>Opcije programa u naredbenoj liniji</translation> </message> @@ -667,13 +832,65 @@ <translation>Dobrodošli</translation> </message> <message> + <source>Welcome to %1.</source> + <translation>Dobrodošli u %1.</translation> + </message> + <message> + <source>As this is the first time the program is launched, you can choose where %1 will store its data.</source> + <translation>Kako je ovo prvi put da je ova aplikacija pokrenuta, možete izabrati gdje će %1 spremati svoje podatke.</translation> + </message> + <message> + <source>When you click OK, %1 will begin to download and process the full %4 block chain (%2GB) starting with the earliest transactions in %3 when %4 initially launched.</source> + <translation>Kada kliknete OK, %1 počet će preuzimati i procesirati cijeli lanac blokova (%2GB) počevši s najranijim transakcijama u %3 kad je %4 prvi put pokrenut.</translation> + </message> + <message> + <source>This initial synchronisation is very demanding, and may expose hardware problems with your computer that had previously gone unnoticed. Each time you run %1, it will continue downloading where it left off.</source> + <translation>Početna sinkronizacija je vrlo zahtjevna i može otkriti hardverske probleme kod vašeg računala koji su prije prošli nezamijećeno. Svaki put kad pokrenete %1, nastavit će preuzimati odakle je stao.</translation> + </message> + <message> + <source>If you have chosen to limit block chain storage (pruning), the historical data must still be downloaded and processed, but will be deleted afterward to keep your disk usage low.</source> + <translation>Ako odlučite ograničiti spremanje lanca blokova pomoću pruninga (obrezivanja), treba preuzeti i procesirati povijesne podatke. Bit će obrisani naknadno kako bi se smanjila količina zauzetog prostora na disku.</translation> + </message> + <message> + <source>Use the default data directory</source> + <translation>Koristite uobičajenu podatkovnu mapu</translation> + </message> + <message> + <source>Use a custom data directory:</source> + <translation>Odaberite različitu podatkovnu mapu:</translation> + </message> + <message> <source>Bitcoin</source> <translation>Bitcoin</translation> </message> <message> + <source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source> + <translation>Bit će spremljeno barem %1 GB podataka u ovoj mapi te će se povećati tijekom vremena.</translation> + </message> + <message> + <source>Approximately %1 GB of data will be stored in this directory.</source> + <translation>Otprilike %1 GB podataka bit će spremljeno u ovoj mapi.</translation> + </message> + <message> + <source>%1 will download and store a copy of the Bitcoin block chain.</source> + <translation>%1 preuzet će i pohraniti kopiju Bitcoinovog lanca blokova.</translation> + </message> + <message> + <source>The wallet will also be stored in this directory.</source> + <translation>Novčanik bit će pohranjen u ovoj mapi.</translation> + </message> + <message> + <source>Error: Specified data directory "%1" cannot be created.</source> + <translation>Greška: Zadana podatkovna mapa "%1" ne može biti stvorena.</translation> + </message> + <message> <source>Error</source> <translation>Greška</translation> </message> + <message numerus="yes"> + <source>%n GB of free space available</source> + <translation><numerusform>Dostupno %n GB slobodnog prostora</numerusform><numerusform>Dostupno %n GB slobodnog prostora</numerusform><numerusform>Dostupno %n GB slobodnog prostora</numerusform></translation> + </message> </context> <context> <name>ModalOverlay</name> @@ -682,10 +899,50 @@ <translation>Oblik</translation> </message> <message> + <source>Recent transactions may not yet be visible, and therefore your wallet's balance might be incorrect. This information will be correct once your wallet has finished synchronizing with the bitcoin network, as detailed below.</source> + <translation>Nedavne transakcije možda još nisu vidljive pa vam stanje novčanika može biti netočno. Ove informacije bit će točne nakon što vaš novčanik dovrši sinkronizaciju s Bitcoinovom mrežom, kako je opisano dolje.</translation> + </message> + <message> + <source>Attempting to spend bitcoins that are affected by not-yet-displayed transactions will not be accepted by the network.</source> + <translation>Mreža neće prihvatiti pokušaje trošenja bitcoina koji su utjecani sa strane transakcija koje još nisu vidljive.</translation> + </message> + <message> + <source>Number of blocks left</source> + <translation>Broj preostalih blokova</translation> + </message> + <message> + <source>Unknown...</source> + <translation>Nepoznato...</translation> + </message> + <message> <source>Last block time</source> <translation>Posljednje vrijeme bloka</translation> </message> - </context> + <message> + <source>Progress</source> + <translation>Napredak</translation> + </message> + <message> + <source>Progress increase per hour</source> + <translation>Postotak povećanja napretka na sat</translation> + </message> + <message> + <source>calculating...</source> + <translation>računa...</translation> + </message> + <message> + <source>Estimated time left until synced</source> + <translation>Preostalo vrijeme do završetka sinkronizacije</translation> + </message> + <message> + <source>Hide</source> + <translation>Sakrijte</translation> + </message> + <message> + <source>Unknown. Syncing Headers (%1)...</source> + <translation>Nepoznato. Sinkroniziraju se zaglavlja (%1)...</translation> + </message> +</context> <context> <name>OpenURIDialog</name> <message> @@ -720,6 +977,14 @@ <translation>&Glavno</translation> </message> <message> + <source>Automatically start %1 after logging in to the system.</source> + <translation>Automatski pokrenite %1 nakon prijave u sustav.</translation> + </message> + <message> + <source>&Start %1 on system login</source> + <translation>&Pokrenite %1 kod prijave u sustav</translation> + </message> + <message> <source>Size of &database cache</source> <translation>Veličina predmemorije baze podataka</translation> </message> @@ -736,10 +1001,42 @@ <translation>IP adresa proxy servera (npr. IPv4: 127.0.0.1 / IPv6: ::1)</translation> </message> <message> + <source>Shows if the supplied default SOCKS5 proxy is used to reach peers via this network type.</source> + <translation>Prikazuje se ako je isporučeni uobičajeni SOCKS5 proxy korišten radi dohvaćanja klijenata preko ovog tipa mreže.</translation> + </message> + <message> + <source>Use separate SOCKS&5 proxy to reach peers via Tor hidden services:</source> + <translation>Koristite zaseban SOCKS&5 proxy kako biste dohvatili klijente preko Tora:</translation> + </message> + <message> + <source>Hide the icon from the system tray.</source> + <translation>Sakrijte ikonu sa sustavne trake.</translation> + </message> + <message> + <source>&Hide tray icon</source> + <translation>&Sakrijte ikonu</translation> + </message> + <message> <source>Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Exit in the menu.</source> <translation>Minimizirati aplikaciju umjesto zatvoriti, kada se zatvori prozor. Kada je ova opcija omogućena, aplikacija će biti zatvorena tek nakon odabira naredbe Izlaz u izborniku.</translation> </message> <message> + <source>Third party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items. %s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |.</source> + <translation>URL-ovi treće stranke (npr. preglednik blokova) koji se javljaju u kartici transakcija kao elementi kontekstnog izbornika. %s u URL-u zamijenjen je hashom transakcije. Višestruki URL-ovi su odvojeni vertikalnom crtom |.</translation> + </message> + <message> + <source>Active command-line options that override above options:</source> + <translation>Aktivne terminalne opcije koje poništavaju navedene opcije:</translation> + </message> + <message> + <source>Open the %1 configuration file from the working directory.</source> + <translation>Otvorite konfiguracijsku datoteku programa %1 s radne mape.</translation> + </message> + <message> + <source>Open Configuration File</source> + <translation>Otvorite konfiguracijsku datoteku</translation> + </message> + <message> <source>Reset all client options to default.</source> <translation>Nastavi sve postavke programa na početne vrijednosti.</translation> </message> @@ -752,10 +1049,42 @@ <translation>&Mreža</translation> </message> <message> + <source>Disables some advanced features but all blocks will still be fully validated. Reverting this setting requires re-downloading the entire blockchain. Actual disk usage may be somewhat higher.</source> + <translation>Isključuje napredne mogućnosti ali će svi blokovi ipak biti potpuno validirani. Vraćanje na prijašnje stanje zahtijeva ponovo preuzimanje cijelog lanca blokova. Realna količina zauzetog prostora na disku može biti ponešto veća.</translation> + </message> + <message> + <source>Prune &block storage to</source> + <translation>Obrezujte pohranu &blokova na</translation> + </message> + <message> + <source>GB</source> + <translation>GB</translation> + </message> + <message> + <source>Reverting this setting requires re-downloading the entire blockchain.</source> + <translation>Vraćanje na prijašnje stanje zahtijeva ponovo preuzimanje cijelog lanca blokova.</translation> + </message> + <message> + <source>(0 = auto, <0 = leave that many cores free)</source> + <translation>(0 = automatski odredite, <0 = ostavite slobodno upravo toliko jezgri)</translation> + </message> + <message> <source>W&allet</source> <translation>&Novčanik</translation> </message> <message> + <source>Expert</source> + <translation>Stručne postavke</translation> + </message> + <message> + <source>Enable coin &control features</source> + <translation>Uključite postavke kontroliranja inputa</translation> + </message> + <message> + <source>If you disable the spending of unconfirmed change, the change from a transaction cannot be used until that transaction has at least one confirmation. This also affects how your balance is computed.</source> + <translation>Ako isključite trošenje nepotvrđenog ostatka, ostatak transakcije ne može biti korišten dok ta transakcija ne dobije barem jednu potvrdu. Također utječe na to kako je vaše stanje računato.</translation> + </message> + <message> <source>&Spend unconfirmed change</source> <translation>&Trošenje nepotvrđenih vraćenih iznosa</translation> </message> @@ -768,6 +1097,22 @@ <translation>Mapiraj port koristeći &UPnP</translation> </message> <message> + <source>Accept connections from outside.</source> + <translation>Prihvatite veze izvana.</translation> + </message> + <message> + <source>Allow incomin&g connections</source> + <translation>Dozvolite dolazeće veze</translation> + </message> + <message> + <source>Connect to the Bitcoin network through a SOCKS5 proxy.</source> + <translation>Spojite se na Bitcoin mrežu kroz SOCKS5 proxy.</translation> + </message> + <message> + <source>&Connect through SOCKS5 proxy (default proxy):</source> + <translation>&Spojite se kroz SOCKS5 proxy (uobičajeni proxy)</translation> + </message> + <message> <source>Proxy &IP:</source> <translation>Proxy &IP:</translation> </message> @@ -780,6 +1125,26 @@ <translation>Proxy vrata (npr. 9050)</translation> </message> <message> + <source>Used for reaching peers via:</source> + <translation>Korišten za dohvaćanje klijenata preko:</translation> + </message> + <message> + <source>IPv4</source> + <translation>IPv4-a</translation> + </message> + <message> + <source>IPv6</source> + <translation>IPv6-a</translation> + </message> + <message> + <source>Tor</source> + <translation>Tora</translation> + </message> + <message> + <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services.</source> + <translation>Spojite se na Bitcoin mrežu kroz zaseban SOCKS5 proxy za povezivanje na Tor.</translation> + </message> + <message> <source>&Window</source> <translation>&Prozor</translation> </message> @@ -804,6 +1169,10 @@ <translation>Jezi&k sučelja:</translation> </message> <message> + <source>The user interface language can be set here. This setting will take effect after restarting %1.</source> + <translation>Jezik korisničkog sučelja može se postaviti ovdje. Postavka će vrijediti nakon ponovnog pokretanja programa %1.</translation> + </message> + <message> <source>&Unit to show amounts in:</source> <translation>&Jedinica za prikaz iznosa:</translation> </message> @@ -812,6 +1181,14 @@ <translation>Izaberite željeni najmanji dio bitcoina koji će biti prikazan u sučelju i koji će se koristiti za plaćanje.</translation> </message> <message> + <source>Whether to show coin control features or not.</source> + <translation>Ovisi želite li prikazati mogućnosti kontroliranja inputa ili ne.</translation> + </message> + <message> + <source>&Third party transaction URLs</source> + <translation>&URL-ovi treće stranke o transakciji</translation> + </message> + <message> <source>&OK</source> <translation>&U redu</translation> </message> @@ -824,10 +1201,42 @@ <translation>standardne vrijednosti</translation> </message> <message> + <source>none</source> + <translation>ništa</translation> + </message> + <message> + <source>Confirm options reset</source> + <translation>Potvrdite resetiranje opcija</translation> + </message> + <message> + <source>Client restart required to activate changes.</source> + <translation>Potrebno je ponovno pokretanje klijenta kako bi se promjene aktivirale.</translation> + </message> + <message> + <source>Client will be shut down. Do you want to proceed?</source> + <translation>Zatvorit će se klijent. Želite li nastaviti?</translation> + </message> + <message> + <source>Configuration options</source> + <translation>Konfiguracijske postavke</translation> + </message> + <message> + <source>The configuration file is used to specify advanced user options which override GUI settings. Additionally, any command-line options will override this configuration file.</source> + <translation>Ova konfiguracijska datoteka je korištena za specificiranje napredne korisničke opcije koje će poništiti postavke GUI-a. Također će bilo koje opcije navedene preko terminala poništiti ovu konfiguracijsku datoteku.</translation> + </message> + <message> <source>Error</source> <translation>Greška</translation> </message> <message> + <source>The configuration file could not be opened.</source> + <translation>Konfiguracijska datoteka nije se mogla otvoriti.</translation> + </message> + <message> + <source>This change would require a client restart.</source> + <translation>Ova promjena zahtijeva da se klijent ponovo pokrene.</translation> + </message> + <message> <source>The supplied proxy address is invalid.</source> <translation>Priložena proxy adresa je nevažeća.</translation> </message> @@ -843,20 +1252,184 @@ <translation>Prikazani podatci mogu biti zastarjeli. Vaš novčanik se automatski sinkronizira s Bitcoin mrežom kada je veza uspostavljena, ali taj proces još nije završen.</translation> </message> <message> + <source>Watch-only:</source> + <translation>Isključivno promatrane adrese:</translation> + </message> + <message> + <source>Available:</source> + <translation>Dostupno:</translation> + </message> + <message> + <source>Your current spendable balance</source> + <translation>Trenutno stanje koje možete trošiti</translation> + </message> + <message> + <source>Pending:</source> + <translation>Neriješeno:</translation> + </message> + <message> + <source>Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance</source> + <translation>Ukupan iznos transakcija koje se još moraju potvrditi te se ne računa kao stanje koje se može trošiti</translation> + </message> + <message> + <source>Immature:</source> + <translation>Nezrelo:</translation> + </message> + <message> + <source>Mined balance that has not yet matured</source> + <translation>Izrudareno stanje koje još nije dozrijevalo</translation> + </message> + <message> + <source>Balances</source> + <translation>Stanja</translation> + </message> + <message> <source>Total:</source> <translation>Ukupno:</translation> </message> - </context> + <message> + <source>Your current total balance</source> + <translation>Vaše trenutno svekupno stanje</translation> + </message> + <message> + <source>Your current balance in watch-only addresses</source> + <translation>Vaše trenutno stanje kod eksluzivno promatranih (watch-only) adresa</translation> + </message> + <message> + <source>Spendable:</source> + <translation>Stanje koje se može trošiti:</translation> + </message> + <message> + <source>Recent transactions</source> + <translation>Nedavne transakcije</translation> + </message> + <message> + <source>Unconfirmed transactions to watch-only addresses</source> + <translation>Nepotvrđene transakcije isključivo promatranim adresama</translation> + </message> + <message> + <source>Mined balance in watch-only addresses that has not yet matured</source> + <translation>Izrudareno stanje na isključivo promatranim adresama koje još nije dozrijevalo</translation> + </message> + <message> + <source>Current total balance in watch-only addresses</source> + <translation>Trenutno ukupno stanje na isključivo promatranim adresama</translation> + </message> +</context> <context> <name>PaymentServer</name> <message> + <source>Payment request error</source> + <translation>Greška kod zahtjeva za plaćanje</translation> + </message> + <message> + <source>Cannot start bitcoin: click-to-pay handler</source> + <translation>Ne može se pokrenuti klijent: rukovatelj "kliknite da platite"</translation> + </message> + <message> <source>URI handling</source> <translation>URI upravljanje</translation> </message> - </context> + <message> + <source>'bitcoin://' is not a valid URI. Use 'bitcoin:' instead.</source> + <translation>'bitcoin://' nije ispravan URI. Koristite 'bitcoin:' umjesto toga.</translation> + </message> + <message> + <source>Payment request fetch URL is invalid: %1</source> + <translation>URL za dohvatu zahtjeva za plaćanje neispravan: %1</translation> + </message> + <message> + <source>Invalid payment address %1</source> + <translation>Nevažeća adresa za plaćanje %1</translation> + </message> + <message> + <source>URI cannot be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters.</source> + <translation>Ne može se parsirati URI! Uzrok tomu može biti nevažeća Bitcoin adresa ili neispravni parametri kod URI-a.</translation> + </message> + <message> + <source>Payment request file handling</source> + <translation>Rukovanje datotekom zahtjeva za plaćanje</translation> + </message> + <message> + <source>Payment request file cannot be read! This can be caused by an invalid payment request file.</source> + <translation>Nije moguće iščitati datoteku zahtjeva za plaćanje! Uzrok tomu može biti nevažeća datoteka zahtjeva za plaćanje.</translation> + </message> + <message> + <source>Payment request rejected</source> + <translation>Zahtjev za plaćanje odbijen</translation> + </message> + <message> + <source>Payment request network doesn't match client network.</source> + <translation>Mreža zahtjeva za plaćanje ne poklapa se s mrežom klijenta.</translation> + </message> + <message> + <source>Payment request expired.</source> + <translation>Zahtjev za plaćanje istekao.</translation> + </message> + <message> + <source>Payment request is not initialized.</source> + <translation>Zahtjev za plaćanje nije inicijaliziran.</translation> + </message> + <message> + <source>Unverified payment requests to custom payment scripts are unsupported.</source> + <translation>Neprovjereni zahtjevi za plaćanje prilagođenim skriptima za plaćanje su nepodržani.</translation> + </message> + <message> + <source>Invalid payment request.</source> + <translation>Nevažeći zahtjev za plaćanje.</translation> + </message> + <message> + <source>Requested payment amount of %1 is too small (considered dust).</source> + <translation>Traženi iznos plaćanja %1 je premalen (smatra se "prašinom", sićušnim iznosom).</translation> + </message> + <message> + <source>Refund from %1</source> + <translation>Povrat iz %1</translation> + </message> + <message> + <source>Payment request %1 is too large (%2 bytes, allowed %3 bytes).</source> + <translation>Zahtjev za plaćanje %1 je prevelik (%2 bajt(ov)a, dozvoljeno %3 bajt(ov)a).</translation> + </message> + <message> + <source>Error communicating with %1: %2</source> + <translation>Greška kod komuniciranja s %1: %2</translation> + </message> + <message> + <source>Payment request cannot be parsed!</source> + <translation>Zahtjev za plaćanje ne može se parsirati!</translation> + </message> + <message> + <source>Bad response from server %1</source> + <translation>Neispravan odgovor sa strane servera %1</translation> + </message> + <message> + <source>Network request error</source> + <translation>Greška kod mrežnog zahtjeva</translation> + </message> + <message> + <source>Payment acknowledged</source> + <translation>Plaćanje priznato</translation> + </message> +</context> <context> <name>PeerTableModel</name> <message> + <source>User Agent</source> + <translation>Korisnički agent</translation> + </message> + <message> + <source>Node/Service</source> + <translation>Čvor/Servis</translation> + </message> + <message> + <source>NodeId</source> + <translation>NodeId (ID čvora)</translation> + </message> + <message> + <source>Ping</source> + <translation>Ping</translation> + </message> + <message> <source>Sent</source> <translation>Poslano</translation> </message> @@ -872,13 +1445,85 @@ <translation>Iznos</translation> </message> <message> + <source>Enter a Bitcoin address (e.g. %1)</source> + <translation>Unesite Bitcoin adresu (npr. %1)</translation> + </message> + <message> + <source>%1 d</source> + <translation>%1 d</translation> + </message> + <message> + <source>%1 h</source> + <translation>%1 h</translation> + </message> + <message> + <source>%1 m</source> + <translation>%1 m</translation> + </message> + <message> + <source>%1 s</source> + <translation>%1 s</translation> + </message> + <message> + <source>None</source> + <translation>Ništa</translation> + </message> + <message> <source>N/A</source> <translation>N/A</translation> </message> <message> + <source>%1 ms</source> + <translation>%1 ms</translation> + </message> + <message numerus="yes"> + <source>%n second(s)</source> + <translation><numerusform>%n sekund</numerusform><numerusform>%n sekundi</numerusform><numerusform>%n sekundi</numerusform></translation> + </message> + <message numerus="yes"> + <source>%n minute(s)</source> + <translation><numerusform>%n minut</numerusform><numerusform>%n minuta</numerusform><numerusform>%n minuta</numerusform></translation> + </message> + <message numerus="yes"> + <source>%n hour(s)</source> + <translation><numerusform>%n sat</numerusform><numerusform>%n sata</numerusform><numerusform>%n sati</numerusform></translation> + </message> + <message numerus="yes"> + <source>%n day(s)</source> + <translation><numerusform>%n dan</numerusform><numerusform>%n dana</numerusform><numerusform>%n dana</numerusform></translation> + </message> + <message numerus="yes"> + <source>%n week(s)</source> + <translation><numerusform>%n tjedan</numerusform><numerusform>%n tjedna</numerusform><numerusform>%n tjedana</numerusform></translation> + </message> + <message> <source>%1 and %2</source> <translation>%1 i %2</translation> </message> + <message numerus="yes"> + <source>%n year(s)</source> + <translation><numerusform>%n godina</numerusform><numerusform>%n godine</numerusform><numerusform>%n godina</numerusform></translation> + </message> + <message> + <source>%1 B</source> + <translation>%1 B</translation> + </message> + <message> + <source>%1 KB</source> + <translation>%1 KB</translation> + </message> + <message> + <source>%1 MB</source> + <translation>%1 MB</translation> + </message> + <message> + <source>%1 GB</source> + <translation>%1 GB</translation> + </message> + <message> + <source>%1 didn't yet exit safely...</source> + <translation>%1 se još nije sigurno zatvorio.</translation> + </message> <message> <source>unknown</source> <translation>nepoznato</translation> @@ -886,7 +1531,23 @@ </context> <context> <name>QObject::QObject</name> - </context> + <message> + <source>Error parsing command line arguments: %1.</source> + <translation>Greška kod parsiranja argumenata unesnih preko terminala: %1.</translation> + </message> + <message> + <source>Error: Specified data directory "%1" does not exist.</source> + <translation>Greška: Zadana podatkovna mapa "%1" ne postoji.</translation> + </message> + <message> + <source>Error: Cannot parse configuration file: %1.</source> + <translation>Greška: Ne može se parsirati konfiguracijska datoteka: %1.</translation> + </message> + <message> + <source>Error: %1</source> + <translation>Greška: %1</translation> + </message> +</context> <context> <name>QRImageWidget</name> <message> @@ -897,7 +1558,11 @@ <source>Save QR Code</source> <translation>Spremi QR kod</translation> </message> - </context> + <message> + <source>PNG Image (*.png)</source> + <translation>PNG slika (*.png)</translation> + </message> +</context> <context> <name>RPCConsole</name> <message> @@ -917,6 +1582,22 @@ <translation>Konzola za dijagnostiku</translation> </message> <message> + <source>General</source> + <translation>Općenito</translation> + </message> + <message> + <source>Using BerkeleyDB version</source> + <translation>Verzija BerkeleyDB-a</translation> + </message> + <message> + <source>Datadir</source> + <translation>Datadir (podatkovna mapa)</translation> + </message> + <message> + <source>Startup time</source> + <translation>Vrijeme pokretanja</translation> + </message> + <message> <source>Network</source> <translation>Mreža</translation> </message> @@ -937,6 +1618,30 @@ <translation>Trenutni broj blokova</translation> </message> <message> + <source>Memory Pool</source> + <translation>Memorijski bazen</translation> + </message> + <message> + <source>Current number of transactions</source> + <translation>Trenutan broj transakcija</translation> + </message> + <message> + <source>Memory usage</source> + <translation>Korištena memorija</translation> + </message> + <message> + <source>Wallet: </source> + <translation>Novčanik:</translation> + </message> + <message> + <source>(none)</source> + <translation>(ništa)</translation> + </message> + <message> + <source>&Reset</source> + <translation>&Resetirajte</translation> + </message> + <message> <source>Received</source> <translation>Primljeno</translation> </message> @@ -945,6 +1650,22 @@ <translation>Poslano</translation> </message> <message> + <source>&Peers</source> + <translation>&Klijenti</translation> + </message> + <message> + <source>Banned peers</source> + <translation>Zabranjeni klijenti</translation> + </message> + <message> + <source>Select a peer to view detailed information.</source> + <translation>Odaberite klijent kako biste vidjeli detaljne informacije.</translation> + </message> + <message> + <source>Whitelisted</source> + <translation>Na bijeloj listi</translation> + </message> + <message> <source>Direction</source> <translation>Smjer</translation> </message> @@ -953,10 +1674,74 @@ <translation>Verzija</translation> </message> <message> + <source>Starting Block</source> + <translation>Početni blok</translation> + </message> + <message> + <source>Synced Headers</source> + <translation>Broj sinkroniziranih zaglavlja</translation> + </message> + <message> + <source>Synced Blocks</source> + <translation>Broj sinkronizranih blokova</translation> + </message> + <message> + <source>User Agent</source> + <translation>Korisnički agent</translation> + </message> + <message> + <source>Open the %1 debug log file from the current data directory. This can take a few seconds for large log files.</source> + <translation>Otvorite datoteku zapisa programa %1 iz trenutne podatkovne mape. Može potrajati nekoliko sekundi za velike datoteke zapisa.</translation> + </message> + <message> + <source>Decrease font size</source> + <translation>Smanjite veličinu fonta</translation> + </message> + <message> + <source>Increase font size</source> + <translation>Povećajte veličinu fonta</translation> + </message> + <message> + <source>Services</source> + <translation>Usluge</translation> + </message> + <message> + <source>Ban Score</source> + <translation>Broj zabrana</translation> + </message> + <message> <source>Connection Time</source> <translation>Trajanje veze</translation> </message> <message> + <source>Last Send</source> + <translation>Zadnja pošiljka</translation> + </message> + <message> + <source>Last Receive</source> + <translation>Zadnji primitak</translation> + </message> + <message> + <source>Ping Time</source> + <translation>Vrijeme pinga</translation> + </message> + <message> + <source>The duration of a currently outstanding ping.</source> + <translation>Trajanje trenutno izvanrednog pinga</translation> + </message> + <message> + <source>Ping Wait</source> + <translation>Zakašnjenje pinga</translation> + </message> + <message> + <source>Min Ping</source> + <translation>Min ping</translation> + </message> + <message> + <source>Time Offset</source> + <translation>Vremenski ofset</translation> + </message> + <message> <source>Last block time</source> <translation>Posljednje vrijeme bloka</translation> </message> @@ -977,10 +1762,114 @@ <translation>Ukupno:</translation> </message> <message> + <source>In:</source> + <translation>Dolazne:</translation> + </message> + <message> + <source>Out:</source> + <translation>Izlazne:</translation> + </message> + <message> + <source>Debug log file</source> + <translation>Datoteka ispisa za debagiranje</translation> + </message> + <message> <source>Clear console</source> <translation>Očisti konzolu</translation> </message> <message> + <source>1 &hour</source> + <translation>1 &sat</translation> + </message> + <message> + <source>1 &day</source> + <translation>1 &dan</translation> + </message> + <message> + <source>1 &week</source> + <translation>1 &tjedan</translation> + </message> + <message> + <source>1 &year</source> + <translation>1 &godinu</translation> + </message> + <message> + <source>&Disconnect</source> + <translation>&Odspojite</translation> + </message> + <message> + <source>Ban for</source> + <translation>Zabranite za</translation> + </message> + <message> + <source>&Unban</source> + <translation>&Ukinite zabranu</translation> + </message> + <message> + <source>default wallet</source> + <translation>uobičajeni novčanik</translation> + </message> + <message> + <source>Welcome to the %1 RPC console.</source> + <translation>Dobrodošli u %1 RPC konzolu.</translation> + </message> + <message> + <source>Use up and down arrows to navigate history, and %1 to clear screen.</source> + <translation>Koristite tipke gore i dolje za izbor već korištenih naredbi. %1 kako biste očistili ekran i povijest naredbi.</translation> + </message> + <message> + <source>Type %1 for an overview of available commands.</source> + <translation>Utipkajte %1 za pregled dostupnih naredbi.</translation> + </message> + <message> + <source>For more information on using this console type %1.</source> + <translation>Za više informacija o korištenju ove konzole utipkajte %1.</translation> + </message> + <message> + <source>WARNING: Scammers have been active, telling users to type commands here, stealing their wallet contents. Do not use this console without fully understanding the ramifications of a command.</source> + <translation>UPOZORENJE: Prevaranti su aktivni i govore korisnicima da utipkaju naredbe ovdje kako bi ispraznili sadržaje njihovih novčanika. Ne koristite ovu konzolu bez da u potpunosti razumijete posljedice naredbe.</translation> + </message> + <message> + <source>Network activity disabled</source> + <translation>Mrežna aktivnost isključena</translation> + </message> + <message> + <source>Executing command without any wallet</source> + <translation>Izvršava se naredba bez bilo kakvog novčanika</translation> + </message> + <message> + <source>Executing command using "%1" wallet</source> + <translation>Izvršava se naredba koristeći novčanik "%1"</translation> + </message> + <message> + <source>(node id: %1)</source> + <translation>(ID čvora: %1)</translation> + </message> + <message> + <source>via %1</source> + <translation>preko %1</translation> + </message> + <message> + <source>never</source> + <translation>nikad</translation> + </message> + <message> + <source>Inbound</source> + <translation>Dolazni</translation> + </message> + <message> + <source>Outbound</source> + <translation>Izlazni</translation> + </message> + <message> + <source>Yes</source> + <translation>Da</translation> + </message> + <message> + <source>No</source> + <translation>Ne</translation> + </message> + <message> <source>Unknown</source> <translation>Nepoznato</translation> </message> @@ -1000,22 +1889,74 @@ <translation>&Poruka:</translation> </message> <message> + <source>An optional message to attach to the payment request, which will be displayed when the request is opened. Note: The message will not be sent with the payment over the Bitcoin network.</source> + <translation>Opcionalna poruka koja se može dodati kao privitak zahtjevu za plaćanje. Bit će prikazana kad je zahtjev otvoren. Napomena: Ova poruka neće biti poslana zajedno s uplatom preko Bitcoin mreže.</translation> + </message> + <message> + <source>An optional label to associate with the new receiving address.</source> + <translation>Opcionalna oznaka koja će se povezati s novom primateljskom adresom.</translation> + </message> + <message> + <source>Use this form to request payments. All fields are <b>optional</b>.</source> + <translation>Koristite ovaj formular kako biste zahtijevali uplate. Sva su polja <b>opcionalna</b>.</translation> + </message> + <message> + <source>An optional amount to request. Leave this empty or zero to not request a specific amount.</source> + <translation>Opcionalan iznos koji možete zahtijevati. Ostavite ovo prazno ili unesite nulu ako ne želite zahtijevati specifičan iznos.</translation> + </message> + <message> <source>Clear all fields of the form.</source> <translation>Obriši sva polja</translation> </message> <message> + <source>Clear</source> + <translation>Obrišite</translation> + </message> + <message> + <source>Native segwit addresses (aka Bech32 or BIP-173) reduce your transaction fees later on and offer better protection against typos, but old wallets don't support them. When unchecked, an address compatible with older wallets will be created instead.</source> + <translation>Izvorne SegWit adrese (tzv. Bech32 ili BIP-173) smanjuju vaše transakcijske naknade ubuduće i nude bolju zaštitu protiv tipfelera, ali stari novčanici ih ne podržavaju. Kada je ova opcija isključena, bit će umjesto toga stvorena adresa koja je kompatibilna sa starijim novčanicima.</translation> + </message> + <message> + <source>Generate native segwit (Bech32) address</source> + <translation>Generirajte izvornu SegWit (Bech32) adresu</translation> + </message> + <message> + <source>Requested payments history</source> + <translation>Povijest zahtjeva za plaćanje</translation> + </message> + <message> <source>&Request payment</source> <translation>&Zatraži plaćanje</translation> </message> <message> + <source>Show the selected request (does the same as double clicking an entry)</source> + <translation>Prikazuje izabran zahtjev (isto učini dvostruki klik na zapis)</translation> + </message> + <message> <source>Show</source> <translation>Pokaži</translation> </message> <message> + <source>Remove the selected entries from the list</source> + <translation>Uklonite odabrane zapise s popisa</translation> + </message> + <message> + <source>Remove</source> + <translation>Uklonite</translation> + </message> + <message> + <source>Copy URI</source> + <translation>Kopirajte URI</translation> + </message> + <message> <source>Copy label</source> <translation>Kopiraj oznaku</translation> </message> <message> + <source>Copy message</source> + <translation>Kopirajte poruku</translation> + </message> + <message> <source>Copy amount</source> <translation>Kopiraj iznos</translation> </message> @@ -1039,6 +1980,14 @@ <translation>&Spremi sliku...</translation> </message> <message> + <source>Request payment to %1</source> + <translation>&Zatražite plaćanje na adresu %1</translation> + </message> + <message> + <source>Payment information</source> + <translation>Informacije o uplati</translation> + </message> + <message> <source>URI</source> <translation>URI</translation> </message> @@ -1093,7 +2042,15 @@ <source>(no message)</source> <translation>(bez poruke)</translation> </message> - </context> + <message> + <source>(no amount requested)</source> + <translation>(nikakav iznos zahtijevan)</translation> + </message> + <message> + <source>Requested</source> + <translation>Zatraženo</translation> + </message> +</context> <context> <name>SendCoinsDialog</name> <message> @@ -1101,6 +2058,18 @@ <translation>Slanje novca</translation> </message> <message> + <source>Coin Control Features</source> + <translation>Mogućnosti kontroliranja inputa</translation> + </message> + <message> + <source>Inputs...</source> + <translation>Inputi...</translation> + </message> + <message> + <source>automatically selected</source> + <translation>automatski izabrano</translation> + </message> + <message> <source>Insufficient funds!</source> <translation>Nedovoljna sredstva</translation> </message> @@ -1121,14 +2090,78 @@ <translation>Naknada:</translation> </message> <message> + <source>After Fee:</source> + <translation>Nakon naknade:</translation> + </message> + <message> <source>Change:</source> <translation>Vraćeno:</translation> </message> <message> + <source>If this is activated, but the change address is empty or invalid, change will be sent to a newly generated address.</source> + <translation>Ako je ovo aktivirano, ali adresa u koju treba poslati ostatak je prazna ili nevažeća, onda će ostatak biti poslan u novo generiranu adresu.</translation> + </message> + <message> + <source>Custom change address</source> + <translation>Zadana adresa u koju će ostatak biti poslan</translation> + </message> + <message> <source>Transaction Fee:</source> <translation>Naknada za transakciju:</translation> </message> <message> + <source>Choose...</source> + <translation>Birajte...</translation> + </message> + <message> + <source>Using the fallbackfee can result in sending a transaction that will take several hours or days (or never) to confirm. Consider choosing your fee manually or wait until you have validated the complete chain.</source> + <translation>Korištenje rezervnu naknadu može rezultirati slanjem transakcije kojoj može trebati nekoliko sati ili dana (ili pak nikad) da se potvrdi. Uzmite u obzir ručno biranje naknade ili pričekajte da se cijeli lanac validira.</translation> + </message> + <message> + <source>Warning: Fee estimation is currently not possible.</source> + <translation>Upozorenje: Procjena naknada trenutno nije moguća.</translation> + </message> + <message> + <source>collapse fee-settings</source> + <translation>Sažimajte opcije naknade</translation> + </message> + <message> + <source>Specify a custom fee per kB (1,000 bytes) of the transaction's virtual size. + +Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis per kB" for a transaction size of 500 bytes (half of 1 kB) would ultimately yield a fee of only 50 satoshis.</source> + <translation>Zadajte prilagođeu naknadu po kB (1000 bajtova) virtualne veličine transakcije. + +Napomena: Budući da se naknada računa po bajtu, naknada od "100 satošija po kB" za transakciju veličine 500 bajtova (polovica od 1 kB) rezultirala bi ultimativno naknadom od samo 50 satošija.</translation> + </message> + <message> + <source>per kilobyte</source> + <translation>po kilobajtu</translation> + </message> + <message> + <source>Hide</source> + <translation>Sakrijte</translation> + </message> + <message> + <source>Paying only the minimum fee is just fine as long as there is less transaction volume than space in the blocks. But be aware that this can end up in a never confirming transaction once there is more demand for bitcoin transactions than the network can process.</source> + <translation>Plaćanje minimalnu naknadu je dovoljno ukoliko je volumen transakcija manja od prostora u blokovima. Budite svjesni da ovo može završiti tako da se transakcija nikad ne potvrdi ako je potražnja za Bitcoin transakcijama veća nego što mreža može procesirati.</translation> + </message> + <message> + <source>(read the tooltip)</source> + <translation>(pročitajte opis alata)</translation> + </message> + <message> + <source>Recommended:</source> + <translation>Preporučeno:</translation> + </message> + <message> + <source>Custom:</source> + <translation>Zadano:</translation> + </message> + <message> + <source>(Smart fee not initialized yet. This usually takes a few blocks...)</source> + <translation>(Pametna procjena naknada još nije inicijalizirana. Uobičajeno traje nekoliko blokova...)</translation> + </message> + <message> <source>Send to multiple recipients at once</source> <translation>Pošalji novce većem broju primatelja u jednoj transakciji</translation> </message> @@ -1145,6 +2178,18 @@ <translation>Prah:</translation> </message> <message> + <source>Confirmation time target:</source> + <translation>Ciljno vrijeme potvrde:</translation> + </message> + <message> + <source>Enable Replace-By-Fee</source> + <translation>Uključite Replace-By-Fee</translation> + </message> + <message> + <source>With Replace-By-Fee (BIP-125) you can increase a transaction's fee after it is sent. Without this, a higher fee may be recommended to compensate for increased transaction delay risk.</source> + <translation>Pomoću mogućnosti Replace-By-Fee (BIP-125) možete povećati naknadu transakcije nakon što je poslana. Bez ovoga može biti preporučena veća naknada kako bi nadoknadila povećani rizik zakašnjenja transakcije.</translation> + </message> + <message> <source>Clear &All</source> <translation>Obriši &sve</translation> </message> @@ -1161,22 +2206,82 @@ <translation>&Pošalji</translation> </message> <message> + <source>Copy quantity</source> + <translation>Kopiraj iznos</translation> + </message> + <message> <source>Copy amount</source> <translation>Kopiraj iznos</translation> </message> <message> + <source>Copy fee</source> + <translation>Kopirajte naknadu</translation> + </message> + <message> + <source>Copy after fee</source> + <translation>Kopirajte iznos nakon naknade</translation> + </message> + <message> + <source>Copy bytes</source> + <translation>Kopirajte količinu bajtova</translation> + </message> + <message> + <source>Copy dust</source> + <translation>Kopirajte sićušne iznose ("prašinu")</translation> + </message> + <message> + <source>Copy change</source> + <translation>Kopirajte ostatak</translation> + </message> + <message> + <source>%1 (%2 blocks)</source> + <translation>%1 (%2 blokova)</translation> + </message> + <message> + <source>%1 to %2</source> + <translation>%1 na %2</translation> + </message> + <message> + <source>Are you sure you want to send?</source> + <translation>Jeste li sigurni da želite poslati transakciju?</translation> + </message> + <message> <source>or</source> <translation>ili</translation> </message> <message> + <source>You can increase the fee later (signals Replace-By-Fee, BIP-125).</source> + <translation>Možete kasnije povećati naknadu (javlja Replace-By-Fee, BIP-125).</translation> + </message> + <message> + <source>from wallet %1</source> + <translation>iz novčanika %1</translation> + </message> + <message> + <source>Please, review your transaction.</source> + <translation>Molim vas, pregledajte svoju transakciju.</translation> + </message> + <message> <source>Transaction fee</source> <translation>Naknada za transakciju</translation> </message> <message> + <source>Not signalling Replace-By-Fee, BIP-125.</source> + <translation>Ne javlja Replace-By-Fee, BIP-125.</translation> + </message> + <message> + <source>Total Amount</source> + <translation>Ukupni iznos</translation> + </message> + <message> <source>Confirm send coins</source> <translation>Potvrdi slanje novca</translation> </message> <message> + <source>The recipient address is not valid. Please recheck.</source> + <translation>Adresa primatelja je nevažeća. Provjerite ponovno, molim vas.</translation> + </message> + <message> <source>The amount to pay must be larger than 0.</source> <translation>Iznos mora biti veći od 0.</translation> </message> @@ -1189,6 +2294,50 @@ <translation>Iznos je veći od stanja novčanika kad se doda naknada za transakcije od %1.</translation> </message> <message> + <source>Duplicate address found: addresses should only be used once each.</source> + <translation>Duplikatna adresa pronađena: adrese trebaju biti korištene samo jedanput.</translation> + </message> + <message> + <source>Transaction creation failed!</source> + <translation>Neuspješno stvorenje transakcije!</translation> + </message> + <message> + <source>The transaction was rejected with the following reason: %1</source> + <translation>Transakcija je bila odbijena zbog sljedećeg razloga: %1</translation> + </message> + <message> + <source>A fee higher than %1 is considered an absurdly high fee.</source> + <translation>Naknada veća od %1 smatra se apsurdno visokim naknadom.</translation> + </message> + <message> + <source>Payment request expired.</source> + <translation>Zahtjev za plaćanje istekao.</translation> + </message> + <message> + <source>Pay only the required fee of %1</source> + <translation>Platite samo potrebnu naknadu u iznosu od %1</translation> + </message> + <message numerus="yes"> + <source>Estimated to begin confirmation within %n block(s).</source> + <translation><numerusform>Procijenjeno je da će početi potvrđivanje unutar %n bloka.</numerusform><numerusform>Procijenjeno je da će početi potvrđivanje unutar %n bloka.</numerusform><numerusform>Procijenjeno je da će početi potvrđivanje unutar %n blokova.</numerusform></translation> + </message> + <message> + <source>Warning: Invalid Bitcoin address</source> + <translation>Upozorenje: Nevažeća Bitcoin adresa</translation> + </message> + <message> + <source>Warning: Unknown change address</source> + <translation>Upozorenje: Nepoznata adresa u koju će ostatak biti poslan</translation> + </message> + <message> + <source>Confirm custom change address</source> + <translation>Potvrdite zadanu adresu u koju će ostatak biti poslan</translation> + </message> + <message> + <source>The address you selected for change is not part of this wallet. Any or all funds in your wallet may be sent to this address. Are you sure?</source> + <translation>Adresa koju ste izabrali kamo ćete poslati ostatak nije dio ovog novčanika. Bilo koji iznosi u vašem novčaniku mogu biti poslani na ovu adresu. Jeste li sigurni?</translation> + </message> + <message> <source>(no label)</source> <translation>(nema oznake)</translation> </message> @@ -1208,6 +2357,18 @@ <translation>&Oznaka:</translation> </message> <message> + <source>Choose previously used address</source> + <translation>Odaberite prethodno korištenu adresu</translation> + </message> + <message> + <source>This is a normal payment.</source> + <translation>Ovo je normalna uplata.</translation> + </message> + <message> + <source>The Bitcoin address to send the payment to</source> + <translation>Bitcoin adresa na koju ćete poslati uplatu</translation> + </message> + <message> <source>Alt+A</source> <translation>Alt+A</translation> </message> @@ -1220,31 +2381,95 @@ <translation>Alt+P</translation> </message> <message> + <source>Remove this entry</source> + <translation>Obrišite ovaj zapis</translation> + </message> + <message> + <source>The fee will be deducted from the amount being sent. The recipient will receive less bitcoins than you enter in the amount field. If multiple recipients are selected, the fee is split equally.</source> + <translation>Naknada će biti oduzeta od poslanog iznosa. Primatelj će primiti manji iznos od onoga koji unesete u polje iznosa. Ako je odabrano više primatelja, onda će naknada biti podjednako raspodijeljena.</translation> + </message> + <message> + <source>S&ubtract fee from amount</source> + <translation>Oduzmite naknadu od iznosa</translation> + </message> + <message> + <source>Use available balance</source> + <translation>Koristite dostupno stanje</translation> + </message> + <message> <source>Message:</source> <translation>Poruka:</translation> </message> <message> + <source>This is an unauthenticated payment request.</source> + <translation>Ovo je neautenticiran zahtjev za plaćanje.</translation> + </message> + <message> + <source>This is an authenticated payment request.</source> + <translation>Ovo je autenticiran zahtjev za plaćanje.</translation> + </message> + <message> + <source>Enter a label for this address to add it to the list of used addresses</source> + <translation>Unesite oznaku za ovu adresu kako bi ju dodali u vaš adresar</translation> + </message> + <message> + <source>A message that was attached to the bitcoin: URI which will be stored with the transaction for your reference. Note: This message will not be sent over the Bitcoin network.</source> + <translation>Poruka koja je dodana uplati: URI koji će biti spremljen s transakcijom za referencu. Napomena: Ova poruka neće biti poslana preko Bitcoin mreže.</translation> + </message> + <message> <source>Pay To:</source> <translation>Primatelj plaćanja:</translation> </message> <message> + <source>Memo:</source> + <translation>Zapis:</translation> + </message> + <message> <source>Enter a label for this address to add it to your address book</source> <translation>Unesite oznaku za ovu adresu kako bi ju dodali u vaš adresar</translation> </message> </context> <context> <name>SendConfirmationDialog</name> - </context> + <message> + <source>Yes</source> + <translation>Da</translation> + </message> +</context> <context> <name>ShutdownWindow</name> - </context> + <message> + <source>%1 is shutting down...</source> + <translation>Zatvara se %1...</translation> + </message> + <message> + <source>Do not shut down the computer until this window disappears.</source> + <translation>Ne ugasite računalo dok ovaj prozor ne nestane.</translation> + </message> +</context> <context> <name>SignVerifyMessageDialog</name> <message> + <source>Signatures - Sign / Verify a Message</source> + <translation>Potpisi - Potpisujte / Provjerite poruku</translation> + </message> + <message> <source>&Sign Message</source> <translation>&Potpišite poruku</translation> </message> <message> + <source>You can sign messages/agreements with your addresses to prove you can receive bitcoins sent to them. Be careful not to sign anything vague or random, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to.</source> + <translation>Možete potpisati poruke/dogovore svojim adresama kako biste dokazali da možete pristupiti bitcoinima poslanim na te adrese. Budite oprezni da ne potpisujte ništa nejasno ili nasumično, jer napadi phishingom vas mogu prevariti da prepišite svoj identitet njima. Potpisujte samo detaljno objašnjene izjave s kojima se slažete.</translation> + </message> + <message> + <source>The Bitcoin address to sign the message with</source> + <translation>Bitcoin adresa pomoću koje ćete potpisati poruku</translation> + </message> + <message> + <source>Choose previously used address</source> + <translation>Odaberite prethodno korištenu adresu</translation> + </message> + <message> <source>Alt+A</source> <translation>Alt+A</translation> </message> @@ -1265,10 +2490,22 @@ <translation>Potpis</translation> </message> <message> + <source>Copy the current signature to the system clipboard</source> + <translation>Kopirajte trenutni potpis u međuspremnik</translation> + </message> + <message> + <source>Sign the message to prove you own this Bitcoin address</source> + <translation>Potpišite poruku kako biste dokazali da posjedujete ovu Bitcoin adresu</translation> + </message> + <message> <source>Sign &Message</source> <translation>&Potpišite poruku</translation> </message> <message> + <source>Reset all sign message fields</source> + <translation>Resetirajte sva polja formulara</translation> + </message> + <message> <source>Clear &All</source> <translation>Obriši &sve</translation> </message> @@ -1277,18 +2514,78 @@ <translation>&Potvrdite poruku</translation> </message> <message> + <source>Enter the receiver's address, message (ensure you copy line breaks, spaces, tabs, etc. exactly) and signature below to verify the message. Be careful not to read more into the signature than what is in the signed message itself, to avoid being tricked by a man-in-the-middle attack. Note that this only proves the signing party receives with the address, it cannot prove sendership of any transaction!</source> + <translation>Unesite primateljevu adresu, poruku (provjerite da kopirate prekide crta, razmake, tabove, itd. točno) i potpis ispod da provjerite poruku. Pazite da ne pridodate veće značenje potpisu nego što je sadržano u samoj poruci kako biste izbjegli napad posrednika (MITM attack). Primijetite da ovo samo dokazuje da stranka koja potpisuje prima na adresu. Ne može dokažati da je neka stranka poslala transakciju!</translation> + </message> + <message> + <source>The Bitcoin address the message was signed with</source> + <translation>Bitcoin adresa kojom je poruka potpisana</translation> + </message> + <message> + <source>Verify the message to ensure it was signed with the specified Bitcoin address</source> + <translation>Provjerite poruku da budete sigurni da je potpisana zadanom Bitcoin adresom</translation> + </message> + <message> <source>Verify &Message</source> <translation>&Potvrdite poruku</translation> </message> <message> + <source>Reset all verify message fields</source> + <translation>Resetirajte sva polja provjeravanja poruke</translation> + </message> + <message> + <source>Click "Sign Message" to generate signature</source> + <translation>Kliknite "Potpišite poruku" da generirate potpis</translation> + </message> + <message> + <source>The entered address is invalid.</source> + <translation>Unesena adresa je neispravna.</translation> + </message> + <message> + <source>Please check the address and try again.</source> + <translation>Molim provjerite adresu i pokušajte ponovo.</translation> + </message> + <message> + <source>The entered address does not refer to a key.</source> + <translation>Unesena adresa ne odnosi se na ključ.</translation> + </message> + <message> <source>Wallet unlock was cancelled.</source> <translation>Otključavanje novčanika je otkazano.</translation> </message> <message> + <source>Private key for the entered address is not available.</source> + <translation>Privatni ključ za unesenu adresu nije dostupan.</translation> + </message> + <message> + <source>Message signing failed.</source> + <translation>Potpisivanje poruke neuspješno.</translation> + </message> + <message> <source>Message signed.</source> <translation>Poruka je potpisana.</translation> </message> - </context> + <message> + <source>The signature could not be decoded.</source> + <translation>Potpis nije mogao biti dešifriran.</translation> + </message> + <message> + <source>Please check the signature and try again.</source> + <translation>Molim provjerite potpis i pokušajte ponovo.</translation> + </message> + <message> + <source>The signature did not match the message digest.</source> + <translation>Potpis se ne poklapa sa sažetkom poruke (message digest).</translation> + </message> + <message> + <source>Message verification failed.</source> + <translation>Provjera poruke neuspješna.</translation> + </message> + <message> + <source>Message verified.</source> + <translation>Poruka provjerena.</translation> + </message> +</context> <context> <name>SplashScreen</name> <message> @@ -1298,14 +2595,42 @@ </context> <context> <name>TrafficGraphWidget</name> - </context> + <message> + <source>KB/s</source> + <translation>KB/s</translation> + </message> +</context> <context> <name>TransactionDesc</name> + <message numerus="yes"> + <source>Open for %n more block(s)</source> + <translation><numerusform>Otvoren za još %n blok</numerusform><numerusform>Otvoren za još %n bloka</numerusform><numerusform>Otvoren za još %n blokova</numerusform></translation> + </message> <message> <source>Open until %1</source> <translation>Otvoren do %1</translation> </message> <message> + <source>conflicted with a transaction with %1 confirmations</source> + <translation>subokljen s transakcijom broja potvrde %1</translation> + </message> + <message> + <source>0/unconfirmed, %1</source> + <translation>0/nepotvrđeno, %1</translation> + </message> + <message> + <source>in memory pool</source> + <translation>u memorijskom bazenu</translation> + </message> + <message> + <source>not in memory pool</source> + <translation>nije u memorijskom bazenu</translation> + </message> + <message> + <source>abandoned</source> + <translation>napušteno</translation> + </message> + <message> <source>%1/unconfirmed</source> <translation>%1/nepotvrđeno</translation> </message> @@ -1346,6 +2671,10 @@ <translation>vlastita adresa</translation> </message> <message> + <source>watch-only</source> + <translation>isključivo promatrano</translation> + </message> + <message> <source>label</source> <translation>oznaka</translation> </message> @@ -1353,6 +2682,10 @@ <source>Credit</source> <translation>Uplaćeno</translation> </message> + <message numerus="yes"> + <source>matures in %n more block(s)</source> + <translation><numerusform>dozrije za još %n blok</numerusform><numerusform>dozrije za još %n bloka</numerusform><numerusform>dozrije za još %n blokova</numerusform></translation> + </message> <message> <source>not accepted</source> <translation>Nije prihvaćeno</translation> @@ -1362,6 +2695,14 @@ <translation>Zaduženje</translation> </message> <message> + <source>Total debit</source> + <translation>Ukupni debit</translation> + </message> + <message> + <source>Total credit</source> + <translation>Ukupni kredit</translation> + </message> + <message> <source>Transaction fee</source> <translation>Naknada za transakciju</translation> </message> @@ -1382,6 +2723,30 @@ <translation>ID transakcije</translation> </message> <message> + <source>Transaction total size</source> + <translation>Ukupna veličina transakcije</translation> + </message> + <message> + <source>Transaction virtual size</source> + <translation>Virtualna veličina transakcije</translation> + </message> + <message> + <source>Output index</source> + <translation>Indeks outputa</translation> + </message> + <message> + <source>Merchant</source> + <translation>Trgovac</translation> + </message> + <message> + <source>Generated coins must mature %1 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, its state will change to "not accepted" and it won't be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.</source> + <translation>Generirani novčići moraju dozrijeti %1 blokova prije nego što mogu biti potrošeni. Kada ste generirali ovaj blok, bio je emitiran na mreži kako bi bio dodan lancu blokova. Ako ne uspije ući u lanac, stanje će mu promijeniti na "neprihvaćeno" i neće se moći trošiti. Ovo se može dogoditi povremeno ako drugi čvor generira blok u roku od nekoliko sekundi od vas.</translation> + </message> + <message> + <source>Debug information</source> + <translation>Informacije za debugiranje</translation> + </message> + <message> <source>Transaction</source> <translation>Transakcija</translation> </message> @@ -1393,14 +2758,26 @@ <source>Amount</source> <translation>Iznos</translation> </message> - </context> + <message> + <source>true</source> + <translation>istina</translation> + </message> + <message> + <source>false</source> + <translation>laž</translation> + </message> +</context> <context> <name>TransactionDescDialog</name> <message> <source>This pane shows a detailed description of the transaction</source> <translation>Ovaj prozor prikazuje detaljni opis transakcije</translation> </message> - </context> + <message> + <source>Details for %1</source> + <translation>Detalji za %1</translation> + </message> +</context> <context> <name>TransactionTableModel</name> <message> @@ -1415,15 +2792,39 @@ <source>Label</source> <translation>Oznaka</translation> </message> + <message numerus="yes"> + <source>Open for %n more block(s)</source> + <translation><numerusform>Otvoren za još %n blok</numerusform><numerusform>Otvoren za još %n bloka</numerusform><numerusform>Otvoren za još %n blokova</numerusform></translation> + </message> <message> <source>Open until %1</source> <translation>Otvoren do %1</translation> </message> <message> + <source>Unconfirmed</source> + <translation>Nepotvrđeno</translation> + </message> + <message> + <source>Abandoned</source> + <translation>Napušteno</translation> + </message> + <message> + <source>Confirming (%1 of %2 recommended confirmations)</source> + <translation>Potvrđuje se (%1 od %2 preporučenih potvrda)</translation> + </message> + <message> <source>Confirmed (%1 confirmations)</source> <translation>Potvrđen (%1 potvrda)</translation> </message> <message> + <source>Conflicted</source> + <translation>Sukobljeno</translation> + </message> + <message> + <source>Immature (%1 confirmations, will be available after %2)</source> + <translation>Nezrelo (%1 potvrda/e, bit će dostupno nakon %2)</translation> + </message> + <message> <source>Generated but not accepted</source> <translation>Generirano, ali nije prihvaćeno</translation> </message> @@ -1448,6 +2849,10 @@ <translation>Rudareno</translation> </message> <message> + <source>watch-only</source> + <translation>isključivo promatrano</translation> + </message> + <message> <source>(n/a)</source> <translation>(n/d)</translation> </message> @@ -1468,6 +2873,14 @@ <translation>Vrsta transakcije.</translation> </message> <message> + <source>Whether or not a watch-only address is involved in this transaction.</source> + <translation>Ovisi je li isključivo promatrana adresa povezana s ovom transakcijom ili ne.</translation> + </message> + <message> + <source>User-defined intent/purpose of the transaction.</source> + <translation>Korisničko definirana namjera transakcije.</translation> + </message> + <message> <source>Amount removed from or added to balance.</source> <translation>Iznos odbijen od ili dodan k saldu.</translation> </message> @@ -1523,10 +2936,22 @@ <translation>Ostalo</translation> </message> <message> + <source>Enter address, transaction id, or label to search</source> + <translation>Unesite adresu, ID transakcije ili oznaku za pretragu</translation> + </message> + <message> <source>Min amount</source> <translation>Min iznos</translation> </message> <message> + <source>Abandon transaction</source> + <translation>Napustite transakciju</translation> + </message> + <message> + <source>Increase transaction fee</source> + <translation>Povećajte transakcijsku naknadu</translation> + </message> + <message> <source>Copy address</source> <translation>Kopiraj adresu</translation> </message> @@ -1543,6 +2968,14 @@ <translation>Kopiraj ID transakcije</translation> </message> <message> + <source>Copy raw transaction</source> + <translation>Kopirajte sirovu transakciju</translation> + </message> + <message> + <source>Copy full transaction details</source> + <translation>Kopirajte potpune transakcijske detalje</translation> + </message> + <message> <source>Edit label</source> <translation>Izmjeni oznaku</translation> </message> @@ -1551,6 +2984,10 @@ <translation>Prikaži detalje transakcije</translation> </message> <message> + <source>Export Transaction History</source> + <translation>Izvozite povijest transakcija</translation> + </message> + <message> <source>Comma separated file (*.csv)</source> <translation>Datoteka podataka odvojenih zarezima (*.csv)</translation> </message> @@ -1559,6 +2996,10 @@ <translation>Potvrđeno</translation> </message> <message> + <source>Watch-only</source> + <translation>Isključivo promatrano</translation> + </message> + <message> <source>Date</source> <translation>Datum</translation> </message> @@ -1583,6 +3024,18 @@ <translation>Izvoz neuspješan</translation> </message> <message> + <source>There was an error trying to save the transaction history to %1.</source> + <translation>Nastala je greška pokušavajući snimiti povijest transakcija na %1.</translation> + </message> + <message> + <source>Exporting Successful</source> + <translation>Izvoz uspješan</translation> + </message> + <message> + <source>The transaction history was successfully saved to %1.</source> + <translation>Povijest transakcija je bila uspješno snimljena na %1.</translation> + </message> + <message> <source>Range:</source> <translation>Raspon:</translation> </message> @@ -1593,17 +3046,61 @@ </context> <context> <name>UnitDisplayStatusBarControl</name> - </context> + <message> + <source>Unit to show amounts in. Click to select another unit.</source> + <translation>Jedinica u kojoj ćete prikazati iznose. Kliknite da izabrate drugu jedinicu.</translation> + </message> +</context> <context> <name>WalletFrame</name> - </context> + <message> + <source>No wallet has been loaded.</source> + <translation>Nije pokrenut nikakav novčanik.</translation> + </message> +</context> <context> <name>WalletModel</name> <message> <source>Send Coins</source> <translation>Slanje novca</translation> </message> - </context> + <message> + <source>Fee bump error</source> + <translation>Greška kod povećanja naknade</translation> + </message> + <message> + <source>Increasing transaction fee failed</source> + <translation>Povećavanje transakcijske naknade neuspješno</translation> + </message> + <message> + <source>Do you want to increase the fee?</source> + <translation>Želite li povećati naknadu?</translation> + </message> + <message> + <source>Current fee:</source> + <translation>Trenutna naknada:</translation> + </message> + <message> + <source>Increase:</source> + <translation>Povećanje:</translation> + </message> + <message> + <source>New fee:</source> + <translation>Nova naknada:</translation> + </message> + <message> + <source>Confirm fee bump</source> + <translation>Potvrdite povećanje naknade</translation> + </message> + <message> + <source>Can't sign transaction.</source> + <translation>Transakcija ne može biti potpisana.</translation> + </message> + <message> + <source>Could not commit transaction</source> + <translation>Transakcija ne može biti izvršena.</translation> + </message> +</context> <context> <name>WalletView</name> <message> @@ -1626,30 +3123,522 @@ <source>Backup Failed</source> <translation>Arhiviranje nije uspjelo</translation> </message> - </context> + <message> + <source>There was an error trying to save the wallet data to %1.</source> + <translation>Nastala je greška pokušavajući snimiti podatke novčanika na %1.</translation> + </message> + <message> + <source>Backup Successful</source> + <translation>Sigurnosna kopija uspješna</translation> + </message> + <message> + <source>The wallet data was successfully saved to %1.</source> + <translation>Podaci novčanika su bili uspješno snimljeni na %1.</translation> + </message> + <message> + <source>Cancel</source> + <translation>Odustanite</translation> + </message> +</context> <context> <name>bitcoin-core</name> <message> + <source>Distributed under the MIT software license, see the accompanying file %s or %s</source> + <translation>Distribuirano pod MIT licencom softvera. Vidite pripadajuću datoteku %s ili %s.</translation> + </message> + <message> + <source>Prune configured below the minimum of %d MiB. Please use a higher number.</source> + <translation>Obrezivanje postavljeno ispod minimuma od %d MiB. Molim koristite veći broj.</translation> + </message> + <message> + <source>Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)</source> + <translation>Obrezivanje: zadnja sinkronizacija novčanika ide dalje od obrezivanih podataka. Morate koristiti -reindex (ponovo preuzeti cijeli lanac blokova u slučaju obrezivanog čvora)</translation> + </message> + <message> + <source>Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.</source> + <translation>Ponovno skeniranje nije moguće u obrezanim načinu (pruned mode). Morat ćete koristiti -reindex, što će ponovno preuzeti cijeli lanac blokova.</translation> + </message> + <message> + <source>Error: A fatal internal error occurred, see debug.log for details</source> + <translation>Greška: Dogodila se kobna interna greška. Vidite debug.log za detalje</translation> + </message> + <message> + <source>Pruning blockstore...</source> + <translation>Obrezuje se blockstore...</translation> + </message> + <message> + <source>Unable to start HTTP server. See debug log for details.</source> + <translation>Ne može se pokrenuti HTTP server. Vidite debug.log za više detalja.</translation> + </message> + <message> <source>Bitcoin Core</source> <translation>Bitcoin Core</translation> </message> <message> + <source>The %s developers</source> + <translation>Ekipa %s</translation> + </message> + <message> + <source>Cannot obtain a lock on data directory %s. %s is probably already running.</source> + <translation>Program ne može pristupiti podatkovnoj mapi %s. %s je vjerojatno već pokrenut.</translation> + </message> + <message> + <source>Cannot provide specific connections and have addrman find outgoing connections at the same.</source> + <translation>Ne može ponuditi specifične veze i dati addrman da traži izlazne veze istovremeno.</translation> + </message> + <message> + <source>Error reading %s! All keys read correctly, but transaction data or address book entries might be missing or incorrect.</source> + <translation>Greška kod iščitanja %s! Svi ključevi su ispravno učitani, ali transakcijski podaci ili zapisi u adresaru mogu biti nepotpuni ili netočni.</translation> + </message> + <message> + <source>Group outputs by address, selecting all or none, instead of selecting on a per-output basis. Privacy is improved as an address is only used once (unless someone sends to it after spending from it), but may result in slightly higher fees as suboptimal coin selection may result due to the added limitation (default: %u)</source> + <translation>Grupirajte outpute po adresi, birajući sve ili ništa umjesto biranja po outputu. Privatnost je povećana jer je adresa korištena samo jedanput (osim ako netko šalje na tu adresu nakon trošenja iz nje), ali može rezultirati neznatno većim naknadama jer suboptimalno biranje novčića može nastati zbog dodanog ograničenja (uobičajeno: %u)</translation> + </message> + <message> + <source>Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly.</source> + <translation>Molimo provjerite jesu li datum i vrijeme na vašem računalu točni. Ako je vaš sat krivo namješten, %s neće raditi ispravno.</translation> + </message> + <message> + <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source> + <translation>Molimo vas da doprinijete programu %s ako ga smatrate korisnim. Posjetite %s za više informacija.</translation> + </message> + <message> + <source>The block database contains a block which appears to be from the future. This may be due to your computer's date and time being set incorrectly. Only rebuild the block database if you are sure that your computer's date and time are correct</source> + <translation>Baza blokova sadrži blok koji je naizgled iz budućnosti. Može to biti posljedica krivo namještenog datuma i vremena na vašem računalu. Obnovite bazu blokova samo ako ste sigurni da su točni datum i vrijeme na vašem računalu.</translation> + </message> + <message> + <source>This is a pre-release test build - use at your own risk - do not use for mining or merchant applications</source> + <translation>Ovo je eksperimentalna verzija za testiranje - koristite je na vlastitu odgovornost - ne koristite je za rudarenje ili trgovačke primjene</translation> + </message> + <message> + <source>This is the transaction fee you may discard if change is smaller than dust at this level</source> + <translation>Ovo je transakcijska naknada koju možete odbaciti ako je ostatak manji od "prašine" (sićušnih iznosa) po ovoj stopi</translation> + </message> + <message> + <source>Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate.</source> + <translation>Ne mogu se ponovo odigrati blokovi. Morat ćete ponovo složiti bazu koristeći -reindex-chainstate.</translation> + </message> + <message> + <source>Unable to rewind the database to a pre-fork state. You will need to redownload the blockchain</source> + <translation>Baza se ne može povratiti na stanje prije raskola. Morat ćete ponovno preuzeti lanac blokova</translation> + </message> + <message> + <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source> + <translation>Upozorenje: Čini se da se mreža ne slaže u potpunosti! Izgleda da su neki rudari suočeni s poteškoćama.</translation> + </message> + <message> + <source>Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.</source> + <translation>Upozorenje: Izgleda da se ne slažemo u potpunosti s našim klijentima! Možda ćete se vi ili ostali čvorovi morati ažurirati.</translation> + </message> + <message> + <source>%d of last 100 blocks have unexpected version</source> + <translation>%d od zadnjih 100 blokova ima neočekivanu verziju</translation> + </message> + <message> + <source>%s corrupt, salvage failed</source> + <translation>%s pokvaren, spašavanje neuspješno</translation> + </message> + <message> + <source>-maxmempool must be at least %d MB</source> + <translation>-maxmempool mora biti barem %d MB</translation> + </message> + <message> + <source>Cannot resolve -%s address: '%s'</source> + <translation>Ne može se razriješiti adresa -%s: '%s'</translation> + </message> + <message> + <source>Change index out of range</source> + <translation>Indeks ostatka izvan dosega</translation> + </message> + <message> + <source>Copyright (C) %i-%i</source> + <translation>Copyright (C) %i-%i</translation> + </message> + <message> + <source>Corrupted block database detected</source> + <translation>Pokvarena baza blokova otkrivena</translation> + </message> + <message> + <source>Do you want to rebuild the block database now?</source> + <translation>Želite li sada obnoviti bazu blokova?</translation> + </message> + <message> + <source>Error creating %s: You can't create non-HD wallets with this version.</source> + <translation>Greška kod stvaranja %s. S ovom verzijom ne možete stvoriti novčanike koji nisu HD.</translation> + </message> + <message> + <source>Error initializing block database</source> + <translation>Greška kod inicijaliziranja baze blokova</translation> + </message> + <message> + <source>Error initializing wallet database environment %s!</source> + <translation>Greška kod inicijaliziranja okoline baze novčanika %s!</translation> + </message> + <message> + <source>Error loading %s</source> + <translation>Greška kod pokretanja programa %s!</translation> + </message> + <message> + <source>Error loading %s: Private keys can only be disabled during creation</source> + <translation>Greška kod učitavanja %s: Privatni ključevi mogu biti isključeni samo tijekom stvaranja</translation> + </message> + <message> + <source>Error loading %s: Wallet corrupted</source> + <translation>Greška kod učitavanja %s: Novčanik pokvaren</translation> + </message> + <message> + <source>Error loading %s: Wallet requires newer version of %s</source> + <translation>Greška kod učitavanja %s: Novčanik zahtijeva noviju verziju softvera %s.</translation> + </message> + <message> + <source>Error loading block database</source> + <translation>Greška kod pokretanja baze blokova</translation> + </message> + <message> + <source>Error opening block database</source> + <translation>Greška kod otvaranja baze blokova</translation> + </message> + <message> <source>Error: Disk space is low!</source> <translation>Pogreška: Nema dovoljno prostora na disku!</translation> </message> <message> + <source>Failed to listen on any port. Use -listen=0 if you want this.</source> + <translation>Neuspješno slušanje na svim portovima. Koristite -listen=0 ako to želite.</translation> + </message> + <message> + <source>Failed to rescan the wallet during initialization</source> + <translation>Neuspješno ponovo skeniranje novčanika tijekom inicijalizacije</translation> + </message> + <message> + <source>Importing...</source> + <translation>Uvozi se...</translation> + </message> + <message> + <source>Incorrect or no genesis block found. Wrong datadir for network?</source> + <translation>Neispravan ili nepostojeći blok geneze. Možda je kriva podatkovna mapa za mrežu?</translation> + </message> + <message> + <source>Initialization sanity check failed. %s is shutting down.</source> + <translation>Brzinska provjera inicijalizacije neuspješna. %s se zatvara.</translation> + </message> + <message> + <source>Invalid amount for -%s=<amount>: '%s'</source> + <translation>Neispravan iznos za -%s=<amount>: '%s'</translation> + </message> + <message> + <source>Invalid amount for -discardfee=<amount>: '%s'</source> + <translation>Neispravan iznos za -discardfee=<amount>: '%s'</translation> + </message> + <message> + <source>Invalid amount for -fallbackfee=<amount>: '%s'</source> + <translation>Neispravan iznos za -fallbackfee=<amount>: '%s'</translation> + </message> + <message> + <source>Specified blocks directory "%s" does not exist.</source> + <translation>Zadana mapa blokova "%s" ne postoji.</translation> + </message> + <message> + <source>Upgrading txindex database</source> + <translation>Ažurira se txindex baza</translation> + </message> + <message> + <source>Loading P2P addresses...</source> + <translation>Pokreće se popis P2P adresa...</translation> + </message> + <message> + <source>Loading banlist...</source> + <translation>Pokreće se popis zabrana...</translation> + </message> + <message> + <source>Not enough file descriptors available.</source> + <translation>Nema dovoljno dostupnih datotečnih opisivača.</translation> + </message> + <message> + <source>Prune cannot be configured with a negative value.</source> + <translation>Obrezivanje (prune) ne može biti postavljeno na negativnu vrijednost.</translation> + </message> + <message> + <source>Prune mode is incompatible with -txindex.</source> + <translation>Način obreživanja (pruning) nekompatibilan je s parametrom -txindex.</translation> + </message> + <message> + <source>Replaying blocks...</source> + <translation>Odigraju se ponovno blokovi...</translation> + </message> + <message> + <source>Rewinding blocks...</source> + <translation>Premotavaju se blokovi...</translation> + </message> + <message> + <source>The source code is available from %s.</source> + <translation>Izvorni kod je dostupan na %s.</translation> + </message> + <message> + <source>Transaction fee and change calculation failed</source> + <translation>Neuspješno računanje ostatka i transakcijske naknade</translation> + </message> + <message> + <source>Unable to bind to %s on this computer. %s is probably already running.</source> + <translation>Ne može se povezati na %s na ovom računalu. %s je vjerojatno već pokrenut.</translation> + </message> + <message> + <source>Unable to generate keys</source> + <translation>Ne mogu se generirati ključevi</translation> + </message> + <message> + <source>Unsupported argument -benchmark ignored, use -debug=bench.</source> + <translation>Nepodržan argument -benchmark ignoriran. Koristite -debug=bench.</translation> + </message> + <message> + <source>Unsupported argument -debugnet ignored, use -debug=net.</source> + <translation>Nepodržan argument -debugnet ignoriran. Koristite -debug=net.</translation> + </message> + <message> + <source>Unsupported argument -tor found, use -onion.</source> + <translation>Nepodržan argument -tor pronađen. Koristite -onion.</translation> + </message> + <message> + <source>Unsupported logging category %s=%s.</source> + <translation>Nepodržana kategorija zapisa %s=%s.</translation> + </message> + <message> + <source>Upgrading UTXO database</source> + <translation>Ažurira se UTXO baza</translation> + </message> + <message> + <source>User Agent comment (%s) contains unsafe characters.</source> + <translation>Komentar pod "Korisnički agent" (%s) sadrži nesigurne znakove.</translation> + </message> + <message> + <source>Verifying blocks...</source> + <translation>Provjeravaju se blokovi...</translation> + </message> + <message> + <source>Wallet needed to be rewritten: restart %s to complete</source> + <translation>Novčanik je trebao prepravak: ponovo pokrenite %s</translation> + </message> + <message> + <source>Error: Listening for incoming connections failed (listen returned error %s)</source> + <translation>Greška: Neuspješno slušanje dolažećih veza (listen je izbacio grešku %s)</translation> + </message> + <message> + <source>Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)</source> + <translation>Neispravan iznos za -maxtxfee=<amount>: '%s' (mora biti barem minimalnu naknadu za proslijeđivanje od %s kako se ne bi zapela transakcija)</translation> + </message> + <message> + <source>The transaction amount is too small to send after the fee has been deducted</source> + <translation>Iznos transakcije je premalen za poslati nakon naknade</translation> + </message> + <message> + <source>You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain</source> + <translation>Morat ćete ponovno složiti bazu koristeći -reindex kako biste se vratili na neobrezivan način (unpruned mode). Ovo će ponovno preuzeti cijeli lanac blokova.</translation> + </message> + <message> + <source>Error loading %s: You can't disable HD on an already existing HD wallet</source> + <translation>Greška kod učitavanja %s: Ne možete isključiti HD na već postojećem HD novčaniku</translation> + </message> + <message> + <source>Error reading from database, shutting down.</source> + <translation>Greška kod iščitanja baze. Zatvara se klijent.</translation> + </message> + <message> + <source>Error upgrading chainstate database</source> + <translation>Greška kod ažuriranja baze stanja lanca</translation> + </message> + <message> <source>Information</source> <translation>Informacija</translation> </message> <message> + <source>Invalid -onion address or hostname: '%s'</source> + <translation>Neispravna -onion adresa ili ime računala: '%s'</translation> + </message> + <message> + <source>Invalid -proxy address or hostname: '%s'</source> + <translation>Neispravna -proxy adresa ili ime računala: '%s'</translation> + </message> + <message> + <source>Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s)</source> + <translation>Neispravan iznos za -paytxfee=<amount>: '%s' (mora biti barem %s)</translation> + </message> + <message> + <source>Invalid netmask specified in -whitelist: '%s'</source> + <translation>Neispravna mrežna maska zadana u -whitelist: '%s'</translation> + </message> + <message> + <source>Need to specify a port with -whitebind: '%s'</source> + <translation>Treba zadati port pomoću -whitebind: '%s'</translation> + </message> + <message> + <source>Reducing -maxconnections from %d to %d, because of system limitations.</source> + <translation>Smanjuje se -maxconnections sa %d na %d zbog sustavnih ograničenja.</translation> + </message> + <message> + <source>Signing transaction failed</source> + <translation>Potpisivanje transakcije neuspješno</translation> + </message> + <message> + <source>Specified -walletdir "%s" does not exist</source> + <translation>Zadan -walletdir "%s" ne postoji</translation> + </message> + <message> + <source>Specified -walletdir "%s" is a relative path</source> + <translation>Zadan -walletdir "%s" je relativan put</translation> + </message> + <message> + <source>Specified -walletdir "%s" is not a directory</source> + <translation>Zadan -walletdir "%s" nije mapa</translation> + </message> + <message> + <source>The transaction amount is too small to pay the fee</source> + <translation>Transakcijiski iznos je premalen da plati naknadu</translation> + </message> + <message> + <source>This is experimental software.</source> + <translation>Ovo je eksperimentalni softver.</translation> + </message> + <message> + <source>Transaction amount too small</source> + <translation>Transakcijski iznos premalen</translation> + </message> + <message> + <source>Transaction too large for fee policy</source> + <translation>Transakcija prevelika za politiku naknada</translation> + </message> + <message> + <source>Transaction too large</source> + <translation>Transakcija prevelika</translation> + </message> + <message> + <source>Unable to bind to %s on this computer (bind returned error %s)</source> + <translation>Ne može se povezati na %s na ovom računalu. (povezivanje je vratilo grešku %s)</translation> + </message> + <message> + <source>Unable to generate initial keys</source> + <translation>Ne mogu se generirati početni ključevi</translation> + </message> + <message> + <source>Verifying wallet(s)...</source> + <translation>Provjerava(ju) se novčanik/(ci)...</translation> + </message> + <message> + <source>Wallet %s resides outside wallet directory %s</source> + <translation>Novčanik %s nalazi se izvan mape novčanika %s</translation> + </message> + <message> <source>Warning</source> <translation>Upozorenje</translation> </message> <message> + <source>Warning: unknown new rules activated (versionbit %i)</source> + <translation>Upozorenje: nepoznata nova pravila aktivirana (versionbit %i)</translation> + </message> + <message> + <source>Zapping all transactions from wallet...</source> + <translation>Brišu se sve transakcije iz novčanika...</translation> + </message> + <message> + <source>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source> + <translation>-maxtxfee je postavljen preveliko. Naknade ove veličine će biti plaćene na individualnoj transakciji.</translation> + </message> + <message> + <source>Error loading %s: You can't enable HD on an already existing non-HD wallet</source> + <translation>Greška kod učitavanja %s: Ne možete uključiti HD na već postojećem novčaniku koji nije HD</translation> + </message> + <message> + <source>This is the transaction fee you may pay when fee estimates are not available.</source> + <translation>Ovo je transakcijska naknada koju ćete možda platiti kada su nedostupne procjene naknada.</translation> + </message> + <message> + <source>This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit %s and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard.</source> + <translation>Ovaj proizvod sadrži softver razvijen sa strane OpenSSL Projecta za upotrebu u OpenSSL Toolkitu %s, kriptografski softver koji je napisao Eric Young te UPnP softver koji je napisao Thomas Bernard.</translation> + </message> + <message> + <source>Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments.</source> + <translation>Ukupna duljina stringa verzije mreže (%i) prelazi maksimalnu duljinu (%i). Smanjite broj ili veličinu komentara o korisničkom agentu (uacomments).</translation> + </message> + <message> + <source>Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported.</source> + <translation>Nepodržan argument -socks pronađen. Postavljanje verziju SOCKS-a nije više moguće. Samo su SOCKS5 proxyji podržani.</translation> + </message> + <message> + <source>Unsupported argument -whitelistalwaysrelay ignored, use -whitelistrelay and/or -whitelistforcerelay.</source> + <translation>Nepodržan argument -whitelistalwaysrelay ignoriran. Koristite -whitelistelay i/ili -whitelistforcerelay.</translation> + </message> + <message> + <source>Warning: Unknown block versions being mined! It's possible unknown rules are in effect</source> + <translation>Upozorenje: Zbiva se rudarenje blokova nepoznatih verzija! Moguće je da su nepoznata pravila na snazi</translation> + </message> + <message> + <source>Warning: Wallet file corrupt, data salvaged! Original %s saved as %s in %s; if your balance or transactions are incorrect you should restore from a backup.</source> + <translation>Upozorenje: Datoteka novčanika je pokvarena, ali su podaci spašeni! Original %s snimljen je kao %s u %s; ako su transakcije ili stanje neispravni, onda biste trebali restorirati sa sigurnosne kopije (backupa).</translation> + </message> + <message> + <source>%s is set very high!</source> + <translation>%s je postavljen preveliko!</translation> + </message> + <message> + <source>Error loading wallet %s. Duplicate -wallet filename specified.</source> + <translation>Greška kod učitavanja novčanika %s. Duplikat imena novčanika zadan.</translation> + </message> + <message> + <source>Keypool ran out, please call keypoolrefill first</source> + <translation>Ispraznio se bazen ključeva. Molim pozovite keypoolrefill najprije</translation> + </message> + <message> + <source>Starting network threads...</source> + <translation>Pokreću se mrežne niti...</translation> + </message> + <message> + <source>The wallet will avoid paying less than the minimum relay fee.</source> + <translation>Ovaj novčanik će izbjegavati plaćanje manje od minimalne naknade prijenosa.</translation> + </message> + <message> + <source>This is the minimum transaction fee you pay on every transaction.</source> + <translation>Ovo je minimalna transakcijska naknada koju plaćate za svaku transakciju.</translation> + </message> + <message> + <source>This is the transaction fee you will pay if you send a transaction.</source> + <translation>Ovo je transakcijska naknada koju ćete platiti ako pošaljete transakciju.</translation> + </message> + <message> + <source>Transaction amounts must not be negative</source> + <translation>Iznosi transakcije ne smiju biti negativni</translation> + </message> + <message> + <source>Transaction has too long of a mempool chain</source> + <translation>Transakcija ima prevelik lanac memorijskog bazena</translation> + </message> + <message> + <source>Transaction must have at least one recipient</source> + <translation>Transakcija mora imati barem jednog primatelja</translation> + </message> + <message> + <source>Unknown network specified in -onlynet: '%s'</source> + <translation>Nepoznata mreža zadana kod -onlynet: '%s'</translation> + </message> + <message> <source>Insufficient funds</source> <translation>Nedovoljna sredstva</translation> </message> <message> + <source>Can't generate a change-address key. Private keys are disabled for this wallet.</source> + <translation>Ne može se generirati ključ adrese na koju će se poslati ostatak. Privatni ključevi su isključeni kod ovog novčanika.</translation> + </message> + <message> + <source>Cannot upgrade a non HD split wallet without upgrading to support pre split keypool. Please use -upgradewallet=169900 or -upgradewallet with no version specified.</source> + <translation>Ne može se ažurirati novčanik koji nije HD bez ažuriranja radi podrške za bazen ključeva prije raskola. Molim koristite -upgradewallet=169900 ili -upgradewallet bez zadane verzije.</translation> + </message> + <message> + <source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source> + <translation>Neuspješno procjenjivanje naknada. Fallbackfee je isključena. Pričekajte nekoliko blokova ili uključite -fallbackfee.</translation> + </message> + <message> + <source>Cannot write to data directory '%s'; check permissions.</source> + <translation>Nije moguće pisati u podatkovnu mapu '%s'; provjerite dozvole.</translation> + </message> + <message> <source>Loading block index...</source> <translation>Učitavanje indeksa blokova...</translation> </message> diff --git a/src/qt/locale/bitcoin_id.ts b/src/qt/locale/bitcoin_id.ts new file mode 100644 index 0000000000..1a4c7236d1 --- /dev/null +++ b/src/qt/locale/bitcoin_id.ts @@ -0,0 +1,969 @@ +<TS language="id" version="2.1"> +<context> + <name>AddressBookPage</name> + <message> + <source>Right-click to edit address or label</source> + <translation>Klik kanan untuk mengubah alamat atau label</translation> + </message> + <message> + <source>Create a new address</source> + <translation>Buat sebuah alamat baru</translation> + </message> + <message> + <source>&New</source> + <translation>&Baru</translation> + </message> + <message> + <source>Copy the currently selected address to the system clipboard</source> + <translation>Salin alamat yang dipilih ke dalam clipboard sistem</translation> + </message> + <message> + <source>&Copy</source> + <translation>&Salin</translation> + </message> + <message> + <source>C&lose</source> + <translation>&Tutup</translation> + </message> + <message> + <source>Delete the currently selected address from the list</source> + <translation>Hapus alamat yang dipilih dari daftar</translation> + </message> + <message> + <source>Enter address or label to search</source> + <translation>Masukkan alamat atau label untuk mencari</translation> + </message> + <message> + <source>Export the data in the current tab to a file</source> + <translation>Ekspor data dalam tab saat ini ke file</translation> + </message> + <message> + <source>&Export</source> + <translation>&Export</translation> + </message> + <message> + <source>&Delete</source> + <translation>&Hapus</translation> + </message> + <message> + <source>Choose the address to send coins to</source> + <translation>Pilih alamat untuk mengirim koin kepada</translation> + </message> + <message> + <source>Choose the address to receive coins with</source> + <translation>Pilih alamat untuk menerima koin</translation> + </message> + <message> + <source>C&hoose</source> + <translation>P&ilih</translation> + </message> + <message> + <source>Sending addresses</source> + <translation>Alamat mengirim</translation> + </message> + <message> + <source>Receiving addresses</source> + <translation>Alamat menerima</translation> + </message> + <message> + <source>These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins.</source> + <translation>Ini adalah alamat Bitcoin anda untuk mengirim pembayaran. Selalu periksa jumlah dan alamat penerima sebelum mengirim koin</translation> + </message> + <message> + <source>These are your Bitcoin addresses for receiving payments. It is recommended to use a new receiving address for each transaction.</source> + <translation>Ini adalah alamat Bitcoin anda untuk menerima pembayaran. Disarankan untuk menggunakan alamat penerimaan baru untuk setiap transaksi</translation> + </message> + <message> + <source>&Copy Address</source> + <translation>&Salin Alamat</translation> + </message> + <message> + <source>Copy &Label</source> + <translation>Copy &Label</translation> + </message> + <message> + <source>&Edit</source> + <translation>&Edit</translation> + </message> + <message> + <source>Export Address List</source> + <translation>Export Daftar Alamat</translation> + </message> + <message> + <source>Comma separated file (*.csv)</source> + <translation>File dipisahkan dengan Comma (*.csv)</translation> + </message> + <message> + <source>Exporting Failed</source> + <translation>Exporting Gagal</translation> + </message> + <message> + <source>There was an error trying to save the address list to %1. Please try again.</source> + <translation>Terjadi kesalahan saat menyimpan daftar alamat %1. Silahkan coba kembali.</translation> + </message> +</context> +<context> + <name>AddressTableModel</name> + <message> + <source>Label</source> + <translation>Label</translation> + </message> + <message> + <source>Address</source> + <translation>Alamat</translation> + </message> + <message> + <source>(no label)</source> + <translation>(tanpa label)</translation> + </message> +</context> +<context> + <name>AskPassphraseDialog</name> + <message> + <source>Passphrase Dialog</source> + <translation>Dialog passphrase</translation> + </message> + <message> + <source>Enter passphrase</source> + <translation>Masukan passphrase</translation> + </message> + <message> + <source>New passphrase</source> + <translation>Passphrase baru</translation> + </message> + <message> + <source>Repeat new passphrase</source> + <translation>Ulangi passphrase baru</translation> + </message> + <message> + <source>Show password</source> + <translation>Tampilkan kata sandi</translation> + </message> + <message> + <source>Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>.</source> + <translation>Masukkan passphrase baru ke dompet.<br/>Harap gunakan passphrase dari <b>sepuluh atau lebih karakter acak</b>, or <b>delapan atau lebih kata</b>.</translation> + </message> + <message> + <source>Encrypt wallet</source> + <translation>Enkripsi wallet</translation> + </message> + <message> + <source>This operation needs your wallet passphrase to unlock the wallet.</source> + <translation>Tindakan ini memerlukan passphrase untuk membuka wallet anda</translation> + </message> + <message> + <source>Unlock wallet</source> + <translation>Buka wallet</translation> + </message> + <message> + <source>This operation needs your wallet passphrase to decrypt the wallet.</source> + <translation>Tindakan ini memerlukan passphrase untuk mendekripsi wallet anda</translation> + </message> + <message> + <source>Decrypt wallet</source> + <translation>Dekripsi wallet</translation> + </message> + <message> + <source>Change passphrase</source> + <translation>Ganti passphrase</translation> + </message> + <message> + <source>Enter the old passphrase and new passphrase to the wallet.</source> + <translation>Masukan passphrase lama dan passphrase baru ke wallet</translation> + </message> + <message> + <source>Confirm wallet encryption</source> + <translation>Konfirmasi proses enkripsi wallet</translation> + </message> + <message> + <source>Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>!</source> + <translation>Peringatan: Jika anda mengenkripsi wallet anda dan lupa/hilang passphrase anda, anda akan <b> KEHILANGAN SEMUA BITCOIN ANDA </b>!</translation> + </message> + <message> + <source>Are you sure you wish to encrypt your wallet?</source> + <translation>Apa anda yakin ingin mengenkripsi wallet anda?</translation> + </message> + <message> + <source>Wallet encrypted</source> + <translation>Wallet terenkripsi</translation> + </message> + <message> + <source>%1 will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source> + <translation>%1 akan ditutup sekarang untuk menyelesaikan proses enkripsi. Ingat bahwa mengenkripsi dompet Anda tidak dapat sepenuhnya melindungi bitcoin Anda dari pencurian oleh malware yang menginfeksi komputer Anda.</translation> + </message> + <message> + <source>IMPORTANT: Any previous backups you have made of your wallet file should be replaced with the newly generated, encrypted wallet file. For security reasons, previous backups of the unencrypted wallet file will become useless as soon as you start using the new, encrypted wallet.</source> + <translation>PENTING: Semua cadangan sebelumnya yang Anda buat dari file dompet Anda harus diganti dengan file dompet terenkripsi yang baru dibuat. Untuk alasan keamanan, cadangan sebelumnya dari file dompet yang tidak terenkripsi akan menjadi tidak berguna segera setelah Anda mulai menggunakan dompet terenkripsi yang baru.</translation> + </message> + <message> + <source>Wallet encryption failed</source> + <translation>Enkripsi wallet gagal</translation> + </message> + <message> + <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source> + <translation>Enkripsi wallet gagal karena kesalahan internal. Wallet anda belum terenkripsi</translation> + </message> + <message> + <source>The supplied passphrases do not match.</source> + <translation>Passphrase yang dimasukan tidak cocok.</translation> + </message> + <message> + <source>Wallet unlock failed</source> + <translation>Gagal membuka wallet</translation> + </message> + <message> + <source>The passphrase entered for the wallet decryption was incorrect.</source> + <translation>Passphrase yang dimasukan untuk dekripsi wallet salah</translation> + </message> + <message> + <source>Wallet decryption failed</source> + <translation>Gagal mendekripsi wallet</translation> + </message> + <message> + <source>Wallet passphrase was successfully changed.</source> + <translation>Passphrase wallet berhasil diganti</translation> + </message> + <message> + <source>Warning: The Caps Lock key is on!</source> + <translation>Peringatan: Caps Lock key menyala!</translation> + </message> +</context> +<context> + <name>BanTableModel</name> + <message> + <source>IP/Netmask</source> + <translation>IP/Netmask</translation> + </message> + <message> + <source>Banned Until</source> + <translation>Dibanned hingga</translation> + </message> +</context> +<context> + <name>BitcoinGUI</name> + <message> + <source>Sign &message...</source> + <translation>&Verifikasi pesan...</translation> + </message> + <message> + <source>Synchronizing with network...</source> + <translation>Sedang sinkronisasi dengan jaringan</translation> + </message> + <message> + <source>&Overview</source> + <translation>&Overview</translation> + </message> + <message> + <source>Node</source> + <translation>Node</translation> + </message> + <message> + <source>Show general overview of wallet</source> + <translation>Tampilkan gambaran umum dompet</translation> + </message> + <message> + <source>&Transactions</source> + <translation>&Transaksi</translation> + </message> + <message> + <source>Browse transaction history</source> + <translation>Telusuri history transaksi</translation> + </message> + <message> + <source>E&xit</source> + <translation>&Keluar</translation> + </message> + <message> + <source>Quit application</source> + <translation>Tutup aplikasi</translation> + </message> + <message> + <source>&About %1</source> + <translation>&Tentang %1</translation> + </message> + <message> + <source>Show information about %1</source> + <translation>Tunjukan informasi tentang %1</translation> + </message> + <message> + <source>About &Qt</source> + <translation>Tentang &Qt</translation> + </message> + <message> + <source>Show information about Qt</source> + <translation>Tampilkan informasi tentang Qt</translation> + </message> + <message> + <source>&Options...</source> + <translation>&Pilihan...</translation> + </message> + <message> + <source>Modify configuration options for %1</source> + <translation>Ubah pilihan konfigurasi untuk %1</translation> + </message> + <message> + <source>&Encrypt Wallet...</source> + <translation>&Enkripsi wallet...</translation> + </message> + <message> + <source>&Backup Wallet...</source> + <translation>&Backup wallet</translation> + </message> + <message> + <source>&Change Passphrase...</source> + <translation>&Ganti Passphrase...</translation> + </message> + <message> + <source>&Sending addresses...</source> + <translation>&Mengirim alamat</translation> + </message> + <message> + <source>&Receiving addresses...</source> + <translation>&Menerima alamat...</translation> + </message> + <message> + <source>Open &URI...</source> + <translation>Buka &URI...</translation> + </message> + <message> + <source>Wallet:</source> + <translation>Dompet:</translation> + </message> + <message> + <source>Click to disable network activity.</source> + <translation>Klik untuk menonaktifkan aktifitas network</translation> + </message> + <message> + <source>Network activity disabled.</source> + <translation>Aktifitas network tidak aktif</translation> + </message> + <message> + <source>Click to enable network activity again.</source> + <translation>Klik untuk mengaktifkan kembali network</translation> + </message> + <message> + <source>Send coins to a Bitcoin address</source> + <translation>Kirim koin ke alamat Bitcoin</translation> + </message> + <message> + <source>Backup wallet to another location</source> + <translation>Backup wallet ke lokasi lain</translation> + </message> + <message> + <source>Change the passphrase used for wallet encryption</source> + <translation>Ganti passphrase yang digunakan untuk enkripsi wallet</translation> + </message> + <message> + <source>&Debug window</source> + <translation>&Debug window</translation> + </message> + <message> + <source>Open debugging and diagnostic console</source> + <translation>Buka debugging dan diagnostic console</translation> + </message> + <message> + <source>&Verify message...</source> + <translation>&Verifikasi pesan...</translation> + </message> + <message> + <source>Bitcoin</source> + <translation>Bitcoin</translation> + </message> + <message> + <source>Wallet</source> + <translation>Wallet</translation> + </message> + <message> + <source>&Send</source> + <translation>&Kirim</translation> + </message> + <message> + <source>&Receive</source> + <translation>&Terima</translation> + </message> + <message> + <source>&Show / Hide</source> + <translation>&Tampilkan/ Sembunyikan</translation> + </message> + <message> + <source>Show or hide the main Window</source> + <translation>Tampilkan atau sembunyikan tampilan utama</translation> + </message> + <message> + <source>Encrypt the private keys that belong to your wallet</source> + <translation>Enkripsi private keys wallet anda</translation> + </message> + <message> + <source>Sign messages with your Bitcoin addresses to prove you own them</source> + <translation>Tambahkan pesan di alamat Bitcoin untuk membuktikan bahwa anda pemiliknya</translation> + </message> + <message> + <source>Verify messages to ensure they were signed with specified Bitcoin addresses</source> + <translation>Verifikasi pesan untuk memastikan bahwa telah ditanda tangani dengan alamat Bitcoin tertentu</translation> + </message> + <message> + <source>&File</source> + <translation>&File</translation> + </message> + <message> + <source>&Settings</source> + <translation>&Pengaturan</translation> + </message> + <message> + <source>&Help</source> + <translation>&Bantuan</translation> + </message> + <message> + <source>Tabs toolbar</source> + <translation>Toolbar Tabs</translation> + </message> + <message> + <source>Show the list of used sending addresses and labels</source> + <translation>Tampilkan daftar alamat kirim yg telah digunakan dan label</translation> + </message> + <message> + <source>Error</source> + <translation>Error</translation> + </message> + <message> + <source>Warning</source> + <translation>Peringatan</translation> + </message> + <message> + <source>Information</source> + <translation>Informasi</translation> + </message> + <message> + <source>Up to date</source> + <translation>Terkini</translation> + </message> + <message> + <source>%1 client</source> + <translation>%1 client</translation> + </message> + <message> + <source>Connecting to peers...</source> + <translation>Menghubungkan ke peers...</translation> + </message> + <message> + <source>Catching up...</source> + <translation>Catching up...</translation> + </message> + <message> + <source>Date: %1 +</source> + <translation>Tanggal: %1 +</translation> + </message> + <message> + <source>Amount: %1 +</source> + <translation>Jumlah: %1 +</translation> + </message> + <message> + <source>Type: %1 +</source> + <translation>Tipe: %1 +</translation> + </message> + <message> + <source>Label: %1 +</source> + <translation>Label: %1 +</translation> + </message> + <message> + <source>Address: %1 +</source> + <translation>Alamat: %1 +</translation> + </message> + <message> + <source>Sent transaction</source> + <translation>Transaksi terkirim</translation> + </message> + <message> + <source>Incoming transaction</source> + <translation>Transaksi datang</translation> + </message> + <message> + <source>HD key generation is <b>enabled</b></source> + <translation>Pembuatan kunci HD <b>diaktifkan</b></translation> + </message> + <message> + <source>HD key generation is <b>disabled</b></source> + <translation>Pembuatan kunci HD <b>dinonaktifkan</b></translation> + </message> + </context> +<context> + <name>CoinControlDialog</name> + <message> + <source>Coin Selection</source> + <translation>Pemilihan koin</translation> + </message> + <message> + <source>Quantity:</source> + <translation>Jumlah:</translation> + </message> + <message> + <source>Bytes:</source> + <translation>Bytes:</translation> + </message> + <message> + <source>Amount:</source> + <translation>Jumlah:</translation> + </message> + <message> + <source>Fee:</source> + <translation>Biaya:</translation> + </message> + <message> + <source>Dust:</source> + <translation>Dust:</translation> + </message> + <message> + <source>After Fee:</source> + <translation>Setelah biaya:</translation> + </message> + <message> + <source>Change:</source> + <translation>Ganti:</translation> + </message> + <message> + <source>(un)select all</source> + <translation>(tidak)pilih semua</translation> + </message> + <message> + <source>Tree mode</source> + <translation>Mode pohon</translation> + </message> + <message> + <source>List mode</source> + <translation>Mode list</translation> + </message> + <message> + <source>Amount</source> + <translation>Jumlah</translation> + </message> + <message> + <source>Received with label</source> + <translation>Diterima dengan label</translation> + </message> + <message> + <source>Received with address</source> + <translation>Diterima dengan alamat</translation> + </message> + <message> + <source>Date</source> + <translation>Tanggal</translation> + </message> + <message> + <source>Confirmations</source> + <translation>Konfirmasi</translation> + </message> + <message> + <source>Confirmed</source> + <translation>Telah dikonfirmasi</translation> + </message> + <message> + <source>Copy address</source> + <translation>Salin alamat</translation> + </message> + <message> + <source>Copy label</source> + <translation>Salin label</translation> + </message> + <message> + <source>Copy amount</source> + <translation>Salin jumla</translation> + </message> + <message> + <source>Copy transaction ID</source> + <translation>Salin ID transaksi</translation> + </message> + <message> + <source>Lock unspent</source> + <translation>Kunci yang tidak digunakan</translation> + </message> + <message> + <source>Unlock unspent</source> + <translation>Buka kunci yang tidak digunakan</translation> + </message> + <message> + <source>Copy quantity</source> + <translation>Salin jumlah</translation> + </message> + <message> + <source>Copy fee</source> + <translation>Salin biaya</translation> + </message> + <message> + <source>Copy after fee</source> + <translation>Salin setelah biaya</translation> + </message> + <message> + <source>Copy bytes</source> + <translation>salin bytes</translation> + </message> + <message> + <source>Copy dust</source> + <translation>Salin dust</translation> + </message> + <message> + <source>Copy change</source> + <translation>Salin perubahan</translation> + </message> + <message> + <source>(%1 locked)</source> + <translation>(%1 terkunci)</translation> + </message> + <message> + <source>yes</source> + <translation>Ya</translation> + </message> + <message> + <source>no</source> + <translation>Tidak</translation> + </message> + <message> + <source>(no label)</source> + <translation>(tanpa label)</translation> + </message> + <message> + <source>(change)</source> + <translation>(ganti)</translation> + </message> +</context> +<context> + <name>EditAddressDialog</name> + <message> + <source>Edit Address</source> + <translation>Ubah Alamat</translation> + </message> + <message> + <source>&Label</source> + <translation>&Label</translation> + </message> + <message> + <source>New sending address</source> + <translation>Alamat pengirim baru</translation> + </message> + <message> + <source>Edit receiving address</source> + <translation>Ubah alamat penerima</translation> + </message> + <message> + <source>Edit sending address</source> + <translation>Ubah alamat pengieim</translation> + </message> + <message> + <source>Could not unlock wallet.</source> + <translation>Tidak bisa membuka wallet</translation> + </message> + <message> + <source>New key generation failed.</source> + <translation>Pembuatan kunci baru gagal.</translation> + </message> +</context> +<context> + <name>FreespaceChecker</name> + <message> + <source>name</source> + <translation>nama</translation> + </message> + </context> +<context> + <name>HelpMessageDialog</name> + <message> + <source>version</source> + <translation>versi</translation> + </message> + <message> + <source>(%1-bit)</source> + <translation>(%1-bit)</translation> + </message> + <message> + <source>About %1</source> + <translation>Tentang %1</translation> + </message> + </context> +<context> + <name>Intro</name> + <message> + <source>Bitcoin</source> + <translation>Bitcoin</translation> + </message> + <message> + <source>Error</source> + <translation>Error</translation> + </message> + </context> +<context> + <name>ModalOverlay</name> + </context> +<context> + <name>OpenURIDialog</name> + </context> +<context> + <name>OptionsDialog</name> + <message> + <source>Error</source> + <translation>Error</translation> + </message> + </context> +<context> + <name>OverviewPage</name> + </context> +<context> + <name>PaymentServer</name> + </context> +<context> + <name>PeerTableModel</name> + </context> +<context> + <name>QObject</name> + <message> + <source>Amount</source> + <translation>Jumlah</translation> + </message> + </context> +<context> + <name>QObject::QObject</name> + </context> +<context> + <name>QRImageWidget</name> + </context> +<context> + <name>RPCConsole</name> + </context> +<context> + <name>ReceiveCoinsDialog</name> + <message> + <source>Copy label</source> + <translation>Salin label</translation> + </message> + <message> + <source>Copy amount</source> + <translation>Salin jumla</translation> + </message> +</context> +<context> + <name>ReceiveRequestDialog</name> + <message> + <source>Address</source> + <translation>Alamat</translation> + </message> + <message> + <source>Amount</source> + <translation>Jumlah</translation> + </message> + <message> + <source>Label</source> + <translation>Label</translation> + </message> + <message> + <source>Wallet</source> + <translation>Wallet</translation> + </message> + </context> +<context> + <name>RecentRequestsTableModel</name> + <message> + <source>Date</source> + <translation>Tanggal</translation> + </message> + <message> + <source>Label</source> + <translation>Label</translation> + </message> + <message> + <source>(no label)</source> + <translation>(tanpa label)</translation> + </message> + </context> +<context> + <name>SendCoinsDialog</name> + <message> + <source>Quantity:</source> + <translation>Jumlah:</translation> + </message> + <message> + <source>Bytes:</source> + <translation>Bytes:</translation> + </message> + <message> + <source>Amount:</source> + <translation>Jumlah:</translation> + </message> + <message> + <source>Fee:</source> + <translation>Biaya:</translation> + </message> + <message> + <source>After Fee:</source> + <translation>Setelah biaya:</translation> + </message> + <message> + <source>Change:</source> + <translation>Ganti:</translation> + </message> + <message> + <source>Dust:</source> + <translation>Dust:</translation> + </message> + <message> + <source>Copy quantity</source> + <translation>Salin jumlah</translation> + </message> + <message> + <source>Copy amount</source> + <translation>Salin jumla</translation> + </message> + <message> + <source>Copy after fee</source> + <translation>Salin setelah biaya</translation> + </message> + <message> + <source>Copy bytes</source> + <translation>salin bytes</translation> + </message> + <message> + <source>Copy dust</source> + <translation>Salin dust</translation> + </message> + <message> + <source>Copy change</source> + <translation>Salin perubahan</translation> + </message> + <message> + <source>(no label)</source> + <translation>(tanpa label)</translation> + </message> +</context> +<context> + <name>SendCoinsEntry</name> + </context> +<context> + <name>SendConfirmationDialog</name> + </context> +<context> + <name>ShutdownWindow</name> + </context> +<context> + <name>SignVerifyMessageDialog</name> + </context> +<context> + <name>SplashScreen</name> + </context> +<context> + <name>TrafficGraphWidget</name> + </context> +<context> + <name>TransactionDesc</name> + <message> + <source>Date</source> + <translation>Tanggal</translation> + </message> + <message> + <source>Amount</source> + <translation>Jumlah</translation> + </message> + </context> +<context> + <name>TransactionDescDialog</name> + </context> +<context> + <name>TransactionTableModel</name> + <message> + <source>Date</source> + <translation>Tanggal</translation> + </message> + <message> + <source>Label</source> + <translation>Label</translation> + </message> + <message> + <source>(no label)</source> + <translation>(tanpa label)</translation> + </message> + </context> +<context> + <name>TransactionView</name> + <message> + <source>Copy address</source> + <translation>Salin alamat</translation> + </message> + <message> + <source>Copy label</source> + <translation>Salin label</translation> + </message> + <message> + <source>Copy amount</source> + <translation>Salin jumla</translation> + </message> + <message> + <source>Copy transaction ID</source> + <translation>Salin ID transaksi</translation> + </message> + <message> + <source>Comma separated file (*.csv)</source> + <translation>File dipisahkan dengan Comma (*.csv)</translation> + </message> + <message> + <source>Confirmed</source> + <translation>Telah dikonfirmasi</translation> + </message> + <message> + <source>Date</source> + <translation>Tanggal</translation> + </message> + <message> + <source>Label</source> + <translation>Label</translation> + </message> + <message> + <source>Address</source> + <translation>Alamat</translation> + </message> + <message> + <source>Exporting Failed</source> + <translation>Exporting gagal</translation> + </message> + </context> +<context> + <name>UnitDisplayStatusBarControl</name> + </context> +<context> + <name>WalletFrame</name> + </context> +<context> + <name>WalletModel</name> + </context> +<context> + <name>WalletView</name> + <message> + <source>&Export</source> + <translation>&Export</translation> + </message> + <message> + <source>Export the data in the current tab to a file</source> + <translation>Ekspor data dalam tab saat ini ke file</translation> + </message> + </context> +<context> + <name>bitcoin-core</name> + <message> + <source>Information</source> + <translation>Informasi</translation> + </message> + <message> + <source>Warning</source> + <translation>Peringatan</translation> + </message> + <message> + <source>Error</source> + <translation>Error</translation> + </message> +</context> +</TS>
\ No newline at end of file diff --git a/src/qt/locale/bitcoin_id_ID.ts b/src/qt/locale/bitcoin_id_ID.ts index 3c79d54e94..a487936fd2 100644 --- a/src/qt/locale/bitcoin_id_ID.ts +++ b/src/qt/locale/bitcoin_id_ID.ts @@ -326,6 +326,14 @@ <translation>Buka &URI</translation> </message> <message> + <source>Wallet:</source> + <translation>Wallet:</translation> + </message> + <message> + <source>default wallet</source> + <translation>wallet default</translation> + </message> + <message> <source>Click to disable network activity.</source> <translation>Klik untuk menonaktifkan aktivitas jaringan.</translation> </message> @@ -346,6 +354,10 @@ <translation>Mengindex ulang blok di dalam disk...</translation> </message> <message> + <source>Proxy is <b>enabled</b>: %1</source> + <translation>Proxy di <b>aktifkan</b>: %1</translation> + </message> + <message> <source>Send coins to a Bitcoin address</source> <translation>Kirim koin ke alamat Bitcoin</translation> </message> @@ -514,6 +526,12 @@ </translation> </message> <message> + <source>Wallet: %1 +</source> + <translation>Wallet: %1 +</translation> + </message> + <message> <source>Type: %1 </source> <translation>Tipe: %1 @@ -698,7 +716,15 @@ <source>(no label)</source> <translation>(tidak ada label)</translation> </message> - </context> + <message> + <source>change from %1 (%2)</source> + <translation>kembalian dari %1 (%2)</translation> + </message> + <message> + <source>(change)</source> + <translation>(kembalian)</translation> + </message> +</context> <context> <name>EditAddressDialog</name> <message> @@ -738,6 +764,14 @@ <translation>Alamat yang dimasukkan "%1" bukanlah alamat Bitcoin yang valid.</translation> </message> <message> + <source>Address "%1" already exists as a receiving address with label "%2" and so cannot be added as a sending address.</source> + <translation>Alamat "%1" sudah ada sebagai alamat penerimaan dengan label "%2" sehingga tidak bisa ditambah sebagai alamat pengiriman.</translation> + </message> + <message> + <source>The entered address "%1" is already in the address book with label "%2".</source> + <translation>Alamat "%1" yang dimasukkan sudah ada di dalam buku alamat dengan label "%2".</translation> + </message> + <message> <source>Could not unlock wallet.</source> <translation>Tidak dapat membuka dompet.</translation> </message> @@ -870,6 +904,10 @@ <translation>Transaksi-transaksi terkini mungkin belum terlihat dan oleh karenanya, saldo dompet Anda mungkin tidak tepat. Informasi ini akan akurat ketika dompet Anda tersinkronisasi dengan jaringan Bitcoin, seperti rincian berikut.</translation> </message> <message> + <source>Attempting to spend bitcoins that are affected by not-yet-displayed transactions will not be accepted by the network.</source> + <translation>Usaha untuk menggunakan bitcoin yang dipengaruhi oleh transaksi yang belum terlihat tidak akan diterima oleh jaringan.</translation> + </message> + <message> <source>Number of blocks left</source> <translation>Jumlah blok tersisa</translation> </message> @@ -882,6 +920,14 @@ <translation>Waktu blok terakhir</translation> </message> <message> + <source>Progress</source> + <translation>Perkembangan</translation> + </message> + <message> + <source>Progress increase per hour</source> + <translation>Peningkatan perkembangan per jam</translation> + </message> + <message> <source>calculating...</source> <translation>menghitung...</translation> </message> @@ -916,7 +962,11 @@ <source>Select payment request file</source> <translation>Pilih data permintaan pembayaran</translation> </message> - </context> + <message> + <source>Select payment request file to open</source> + <translation>Pilih data permintaan pembayaran yang akan dibuka</translation> + </message> +</context> <context> <name>OptionsDialog</name> <message> @@ -952,10 +1002,22 @@ <translation>Alamat IP proxy (cth. IPv4: 127.0.0.1 / IPv6: ::1)</translation> </message> <message> + <source>Shows if the supplied default SOCKS5 proxy is used to reach peers via this network type.</source> + <translation>Perlihatkan apabila proxy SOCKS5 default digunakan untuk berhungan dengan orang lain lewat tipe jaringan ini.</translation> + </message> + <message> + <source>Use separate SOCKS&5 proxy to reach peers via Tor hidden services:</source> + <translation>Menggunakan proxy SOCKS5 tersendiri untuk berhubungan dengan orang lain melalui layanan Tor:</translation> + </message> + <message> <source>Hide the icon from the system tray.</source> <translation>Sembunyikan ikon dari system tray.</translation> </message> <message> + <source>&Hide tray icon</source> + <translation>&Sembunyikan ikon tray</translation> + </message> + <message> <source>Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Exit in the menu.</source> <translation>Minimalisasi aplikasi ketika jendela ditutup. Ketika pilihan ini dipilih, aplikasi akan menutup seluruhnya jika anda memilih Keluar di menu yang tersedia.</translation> </message> @@ -968,6 +1030,10 @@ <translation>Pilihan command-line yang aktif menimpa diatas opsi: </translation> </message> <message> + <source>Open the %1 configuration file from the working directory.</source> + <translation>Buka file konfigurasi %1 dari direktori kerja.</translation> + </message> + <message> <source>Open Configuration File</source> <translation>Buka Berkas Konfigurasi</translation> </message> @@ -984,6 +1050,18 @@ <translation>&Jaringan</translation> </message> <message> + <source>Disables some advanced features but all blocks will still be fully validated. Reverting this setting requires re-downloading the entire blockchain. Actual disk usage may be somewhat higher.</source> + <translation>Menonaktifkan beberapa fitur canggih akan tetapi semua block akan tetap divalidasi seutuhnya. Mengembalikan pengaturan ini memerlukan untuk mengunduh seluruh blockchain. Penggunaan disk mungkin akan lebih tinggi.</translation> + </message> + <message> + <source>GB</source> + <translation>GB</translation> + </message> + <message> + <source>Reverting this setting requires re-downloading the entire blockchain.</source> + <translation>Mengembalikan pengaturan ini membutuhkan pengunduhan seluruh blockchain lagi. </translation> + </message> + <message> <source>(0 = auto, <0 = leave that many cores free)</source> <translation>(0 = auto, <0 = leave that many cores free)</translation> </message> @@ -1028,6 +1106,10 @@ <translation>Hubungkan ke jaringan Bitcoin melalui SOCKS5 proxy.</translation> </message> <message> + <source>&Connect through SOCKS5 proxy (default proxy):</source> + <translation>&Hubungkan melalui proxy SOCKS5 (proxy default):</translation> + </message> + <message> <source>Proxy &IP:</source> <translation>IP Proxy:</translation> </message> @@ -1040,6 +1122,10 @@ <translation>Port proxy (cth. 9050)</translation> </message> <message> + <source>Used for reaching peers via:</source> + <translation>Digunakan untuk berhubungan dengan peers melalui:</translation> + </message> + <message> <source>IPv4</source> <translation>IPv4</translation> </message> @@ -1052,6 +1138,10 @@ <translation>Tor</translation> </message> <message> + <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services.</source> + <translation>Koneksi ke jaringan bitcoin melalui proxy SOCKS5 yang berbeda untuk layanan Tor tersembunyi.</translation> + </message> + <message> <source>&Window</source> <translation>&Jendela</translation> </message> @@ -1092,6 +1182,10 @@ <translation>Ingin menunjukkan cara pengaturan koin atau tidak.</translation> </message> <message> + <source>&Third party transaction URLs</source> + <translation>&URL transaksi pihak ketiga</translation> + </message> + <message> <source>&OK</source> <translation>&YA</translation> </message> @@ -1120,6 +1214,14 @@ <translation>Klien akan dimatikan, apakah anda hendak melanjutkan?</translation> </message> <message> + <source>Configuration options</source> + <translation>Konfigurasi pengaturan</translation> + </message> + <message> + <source>The configuration file is used to specify advanced user options which override GUI settings. Additionally, any command-line options will override this configuration file.</source> + <translation>File konfigurasi digunakan untuk menspesifikkan pilihan khusus pengguna yang akan menimpa pengaturan GUI. Sebagai tambahan, pengaturan command-line apapun akan menimpa file konfigurasi itu.</translation> + </message> + <message> <source>Error</source> <translation>Terjadi sebuah kesalahan</translation> </message> @@ -1147,6 +1249,10 @@ <translation>Informasi terlampir mungkin sudah kedaluwarsa. Dompet Anda secara otomatis mensinkronisasi dengan jaringan Bitcoin ketika sebuah hubungan terbentuk, namun proses ini belum selesai.</translation> </message> <message> + <source>Watch-only:</source> + <translation>Hanya lihat:</translation> + </message> + <message> <source>Available:</source> <translation>Tersedia:</translation> </message> @@ -1183,16 +1289,76 @@ <translation>Jumlah saldo Anda sekarang</translation> </message> <message> + <source>Your current balance in watch-only addresses</source> + <translation>Saldomu di alamat hanya lihat</translation> + </message> + <message> + <source>Spendable:</source> + <translation>Bisa digunakan:</translation> + </message> + <message> <source>Recent transactions</source> <translation>Transaksi-transaksi terkini</translation> </message> - </context> + <message> + <source>Unconfirmed transactions to watch-only addresses</source> + <translation>Transaksi yang belum terkonfirmasi ke alamat hanya lihat</translation> + </message> + <message> + <source>Mined balance in watch-only addresses that has not yet matured</source> + <translation>Saldo hasil mining di alamat hanya lihat yang belum bisa digunakan</translation> + </message> + <message> + <source>Current total balance in watch-only addresses</source> + <translation>Jumlah saldo di alamat hanya lihat</translation> + </message> +</context> <context> <name>PaymentServer</name> <message> <source>Payment request error</source> <translation>Terjadi kesalahan pada permintaan pembayaran</translation> </message> + <message> + <source>Cannot start bitcoin: click-to-pay handler</source> + <translation>Tidak bisa memulai bitcoin: handler click-to-pay</translation> + </message> + <message> + <source>URI handling</source> + <translation>Pengelolaan URI</translation> + </message> + <message> + <source>'bitcoin://' is not a valid URI. Use 'bitcoin:' instead.</source> + <translation>'bitcoin://' bukanlah alamat URI yang valid. Silakan gunakan 'bitcoin:'.</translation> + </message> + <message> + <source>Payment request fetch URL is invalid: %1</source> + <translation>URL permintaan pembayaran tidak valid: %1</translation> + </message> + <message> + <source>URI cannot be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters.</source> + <translation>URI tidak bisa dimengerti! Hal ini bisa disebabkan karena alamat Bitcoin yang tidak sah atau parameter URI yang tidak tepat.</translation> + </message> + <message> + <source>Payment request file handling</source> + <translation>Pengelolaan file permintaan pembayaran</translation> + </message> + <message> + <source>Payment request file cannot be read! This can be caused by an invalid payment request file.</source> + <translation>File permintaan pembayaran tidak bisa dibaca! Hal ini bisa disebabkan karena file permintaan pembayaran tidak valid.</translation> + </message> + <message> + <source>Payment request rejected</source> + <translation>Permintaan pembayaran ditolak</translation> + </message> + <message> + <source>Payment request network doesn't match client network.</source> + <translation>Jaringan permintaan pembayaran tidak sesuai dengan jaringan klien.</translation> + </message> + <message> + <source>Payment request expired.</source> + <translation>Permintaan pembayaran telah kadaluarsa.</translation> + </message> </context> <context> <name>PeerTableModel</name> @@ -1375,6 +1541,10 @@ <translation>1 &tahun</translation> </message> <message> + <source>default wallet</source> + <translation>wallet default</translation> + </message> + <message> <source>Yes</source> <translation>Ya</translation> </message> @@ -1631,6 +1801,10 @@ <translation>Biaya Transaksi</translation> </message> <message> + <source>Payment request expired.</source> + <translation>Permintaan pembayaran telah kadaluarsa.</translation> + </message> + <message> <source>(no label)</source> <translation>(tidak ada label)</translation> </message> diff --git a/src/qt/locale/bitcoin_is.ts b/src/qt/locale/bitcoin_is.ts new file mode 100644 index 0000000000..6a4e26ac22 --- /dev/null +++ b/src/qt/locale/bitcoin_is.ts @@ -0,0 +1,997 @@ +<TS language="is" version="2.1"> +<context> + <name>AddressBookPage</name> + <message> + <source>Right-click to edit address or label</source> + <translation>Smelltu á hægri músatakka til að breyta færslugildi eða merkingu</translation> + </message> + <message> + <source>Create a new address</source> + <translation>Búa til nýtt færslugildi</translation> + </message> + <message> + <source>&New</source> + <translation>&Nýtt</translation> + </message> + <message> + <source>Copy the currently selected address to the system clipboard</source> + <translation>Afrita valið færslugildi í klemmuspjald</translation> + </message> + <message> + <source>&Copy</source> + <translation>&Afrita</translation> + </message> + <message> + <source>C&lose</source> + <translation>&Loka</translation> + </message> + <message> + <source>Delete the currently selected address from the list</source> + <translation>Eyða völdu færslugildi úr listanum</translation> + </message> + <message> + <source>Export the data in the current tab to a file</source> + <translation>Flytja gögn í flipanum í skrá</translation> + </message> + <message> + <source>&Export</source> + <translation>&Flytja út</translation> + </message> + <message> + <source>&Delete</source> + <translation>&Eyða</translation> + </message> + <message> + <source>Choose the address to send coins to</source> + <translation>Veldu færslugildi sem greiða skal til</translation> + </message> + <message> + <source>Choose the address to receive coins with</source> + <translation>Veldu færslugildi sem á að taka við mynt</translation> + </message> + <message> + <source>C&hoose</source> + <translation>&Veldu</translation> + </message> + <message> + <source>Sending addresses</source> + <translation>Færslugildi sem senda frá sér</translation> + </message> + <message> + <source>Receiving addresses</source> + <translation>Færslugildi sem þiggja til sín</translation> + </message> + <message> + <source>These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins.</source> + <translation>Þetta eru Bitcoin færslugildin sem senda greiðslur. Skoðið ævinlega vel upphæðina og færslugildin sem þiggja greiðslur áður en mynt er send.</translation> + </message> + <message> + <source>These are your Bitcoin addresses for receiving payments. It is recommended to use a new receiving address for each transaction.</source> + <translation>Þetta eru Bitcoin færslugildin sem þiggja greiðslur. Mælt er með að nota aldrei sama færslugildið til að þiggja fleiri en eina greiðslu.</translation> + </message> + <message> + <source>&Copy Address</source> + <translation>&Afrita færslugildi</translation> + </message> + <message> + <source>Copy &Label</source> + <translation>Afrita og &Merkja</translation> + </message> + <message> + <source>&Edit</source> + <translation>&Breyta</translation> + </message> + <message> + <source>Export Address List</source> + <translation>Flytja út færslulista</translation> + </message> + <message> + <source>Comma separated file (*.csv)</source> + <translation>Gildi aðskilin með kommu (*.csv)</translation> + </message> + <message> + <source>Exporting Failed</source> + <translation>Útflutningur tókst ekki</translation> + </message> + <message> + <source>There was an error trying to save the address list to %1. Please try again.</source> + <translation>Ekki tókst að vista færslugildalistann á %1. Reyndu aftur.</translation> + </message> +</context> +<context> + <name>AddressTableModel</name> + <message> + <source>Label</source> + <translation>Merking</translation> + </message> + <message> + <source>Address</source> + <translation>Færslugildi</translation> + </message> + <message> + <source>(no label)</source> + <translation>(engin merking)</translation> + </message> +</context> +<context> + <name>AskPassphraseDialog</name> + <message> + <source>Passphrase Dialog</source> + <translation>Lykilsetning</translation> + </message> + <message> + <source>Enter passphrase</source> + <translation>Skráðu lykilsetningu</translation> + </message> + <message> + <source>New passphrase</source> + <translation>Ný lykilsetning</translation> + </message> + <message> + <source>Repeat new passphrase</source> + <translation>Endurtaktu nýja lykilsetningu</translation> + </message> + <message> + <source>Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>.</source> + <translation>Skráðu nýju lykilsetninguna í veskið. <br/>Vinsamlegast notaðu lykilsetningu með <b>tíu eða fleiri slembibókstöfum</b>, eða <b>átta eða fleiri orðum</b>.</translation> + </message> + <message> + <source>Encrypt wallet</source> + <translation>Dulkóða veski</translation> + </message> + <message> + <source>This operation needs your wallet passphrase to unlock the wallet.</source> + <translation>Þessi aðgerð þarf að fá lykilsetninguna þína til að opna veskið.</translation> + </message> + <message> + <source>Unlock wallet</source> + <translation>Opna veskið</translation> + </message> + <message> + <source>This operation needs your wallet passphrase to decrypt the wallet.</source> + <translation>Þessi aðgerð þarf lykilsetninguna þína til að dulráða veskið.</translation> + </message> + <message> + <source>Decrypt wallet</source> + <translation>Dulráða veskið</translation> + </message> + <message> + <source>Change passphrase</source> + <translation>Breyta lykilsetningu</translation> + </message> + <message> + <source>Enter the old passphrase and new passphrase to the wallet.</source> + <translation>Skráðu gömlu lykilsetninguna og þá nýju í veskið.</translation> + </message> + <message> + <source>Confirm wallet encryption</source> + <translation>Staðfesta dulkóðun veskis</translation> + </message> + <message> + <source>Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>!</source> + <translation>Viðvörun: Ef þú dulkóðar veskið og týnir lykilsetningunn þá munt þú <b>TAPA ALLRI ÞINNI BITCOIN MYNT</b>!</translation> + </message> + <message> + <source>Are you sure you wish to encrypt your wallet?</source> + <translation>Ertu viss um að þú viljir dulkóða veskið þitt?</translation> + </message> + <message> + <source>Wallet encrypted</source> + <translation>Veski dulkóðað</translation> + </message> + <message> + <source>%1 will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source> + <translation>%1 lokast núna til að dulkóðun klárist. Mundu að dulkóðun veskis kemur ekki að fullu í veg fyrir að mynt verði stolið úr tölvunni þinni með aðstoð smitforrita. </translation> + </message> + <message> + <source>IMPORTANT: Any previous backups you have made of your wallet file should be replaced with the newly generated, encrypted wallet file. For security reasons, previous backups of the unencrypted wallet file will become useless as soon as you start using the new, encrypted wallet.</source> + <translation>MIKILVÆGT: Nýja dulkóðaða veskisskráin þarf að koma í staðinn fyrir öll fyrri afrit sem þú hefur gert af upprunalegu veskisskránni. Af öryggisástæðum munu öll fyrri afrit af ódulkóðaða veskinu verða óvirk um leið og þú byrjar að nota nýja, dulkóðaða veskið.</translation> + </message> + <message> + <source>Wallet encryption failed</source> + <translation>Dulkóðun veskis mistókst</translation> + </message> + <message> + <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source> + <translation>Dulkóðun veskis mistóks vegna innri villu. Veskið þitt var ekki dulkóðað.</translation> + </message> + <message> + <source>The supplied passphrases do not match.</source> + <translation>Lykilsetningarnar eru ekki þær sömu.</translation> + </message> + <message> + <source>Wallet unlock failed</source> + <translation>Ekki tókst að opna veskið</translation> + </message> + <message> + <source>The passphrase entered for the wallet decryption was incorrect.</source> + <translation>Lykilsetningin sem notuð var til að dulráða veskið var ekki rétt.</translation> + </message> + <message> + <source>Wallet decryption failed</source> + <translation>Ekki tókst að dulráða veski</translation> + </message> + <message> + <source>Wallet passphrase was successfully changed.</source> + <translation>Það tókst að breyta lykilsetningu veskis.</translation> + </message> + <message> + <source>Warning: The Caps Lock key is on!</source> + <translation>Viðvörun: Kveikt er á HÁSTÖFUM!</translation> + </message> +</context> +<context> + <name>BanTableModel</name> + <message> + <source>IP/Netmask</source> + <translation>IP/Netgríma</translation> + </message> + <message> + <source>Banned Until</source> + <translation>Bannað til</translation> + </message> +</context> +<context> + <name>BitcoinGUI</name> + <message> + <source>Sign &message...</source> + <translation>Undirrita &skilaboð</translation> + </message> + <message> + <source>Synchronizing with network...</source> + <translation>Samstilli við netið...</translation> + </message> + <message> + <source>&Overview</source> + <translation>&Yfirlit</translation> + </message> + <message> + <source>Node</source> + <translation>Hnútur</translation> + </message> + <message> + <source>Show general overview of wallet</source> + <translation>Sýna almennt yfirlit af veski</translation> + </message> + <message> + <source>&Transactions</source> + <translation>&Færslur</translation> + </message> + <message> + <source>Browse transaction history</source> + <translation>Skoða færslusögu</translation> + </message> + <message> + <source>E&xit</source> + <translation>&Hætta</translation> + </message> + <message> + <source>Quit application</source> + <translation>Hætta í forriti</translation> + </message> + <message> + <source>&About %1</source> + <translation>&Um %1</translation> + </message> + <message> + <source>Show information about %1</source> + <translation>Sýna upplýsingar um %1</translation> + </message> + <message> + <source>About &Qt</source> + <translation>Um &Qt</translation> + </message> + <message> + <source>Show information about Qt</source> + <translation>Sýna upplýsingar um Qt</translation> + </message> + <message> + <source>&Options...</source> + <translation>&Valkostir...</translation> + </message> + <message> + <source>Modify configuration options for %1</source> + <translation>Breyta samstillingum fyrir %1</translation> + </message> + <message> + <source>&Encrypt Wallet...</source> + <translation>&Dulkóða veski...</translation> + </message> + <message> + <source>&Backup Wallet...</source> + <translation>&Öryggisafrit á veski...</translation> + </message> + <message> + <source>&Change Passphrase...</source> + <translation>&Breyta lykilsetningu</translation> + </message> + <message> + <source>&Sending addresses...</source> + <translation>&Sendi færslugildi...</translation> + </message> + <message> + <source>&Receiving addresses...</source> + <translation>&Tek við færslugildum...</translation> + </message> + <message> + <source>Open &URI...</source> + <translation>Opna &URL...</translation> + </message> + <message> + <source>Click to disable network activity.</source> + <translation>Smelltu til að loka fyrir netumferð.</translation> + </message> + <message> + <source>Network activity disabled.</source> + <translation>Slökkt á netumferð.</translation> + </message> + <message> + <source>Click to enable network activity again.</source> + <translation>Smelltu til að hefja aftur netumferð.</translation> + </message> + <message> + <source>Syncing Headers (%1%)...</source> + <translation>Samstilli hausa (%1%)...</translation> + </message> + <message> + <source>Reindexing blocks on disk...</source> + <translation>Endurraða blokkum á drifi...</translation> + </message> + <message> + <source>Send coins to a Bitcoin address</source> + <translation>Senda mynt í Bitcoin færslugildi</translation> + </message> + <message> + <source>Backup wallet to another location</source> + <translation>Öryggisafrita veski á annan stað</translation> + </message> + <message> + <source>Change the passphrase used for wallet encryption</source> + <translation>Breyta lykilsetningunni sem gildir um dulkóðun veskis</translation> + </message> + <message> + <source>&Debug window</source> + <translation>&Kembunargluggi</translation> + </message> + <message> + <source>Open debugging and diagnostic console</source> + <translation>Opna kembunar- og greiningarstjórnborð</translation> + </message> + <message> + <source>&Verify message...</source> + <translation>&Yfirfara skilaboð...</translation> + </message> + <message> + <source>Bitcoin</source> + <translation>Bitcoin</translation> + </message> + <message> + <source>Wallet</source> + <translation>Veski</translation> + </message> + <message> + <source>&Send</source> + <translation>&Senda</translation> + </message> + <message> + <source>&Receive</source> + <translation>&Taka við</translation> + </message> + <message> + <source>&Show / Hide</source> + <translation>&Sýna / Fela</translation> + </message> + <message> + <source>Show or hide the main Window</source> + <translation>Sýna eða fela megin glugga</translation> + </message> + <message> + <source>Encrypt the private keys that belong to your wallet</source> + <translation>Dulkóða einkalyklana sem tilheyra veskinu þínu</translation> + </message> + <message> + <source>Sign messages with your Bitcoin addresses to prove you own them</source> + <translation>Kvitta undir skilaboð með Bitcoin færslugildunum þínum til að sanna að þú eigir þau</translation> + </message> + <message> + <source>Verify messages to ensure they were signed with specified Bitcoin addresses</source> + <translation>Yfirfara skilaboð til að tryggja að kvittað hafi verið fyrir þau með tilteknum Bitcoin færslugildum</translation> + </message> + <message> + <source>&File</source> + <translation>&Skrá</translation> + </message> + <message> + <source>&Settings</source> + <translation>&Stillingar</translation> + </message> + <message> + <source>&Help</source> + <translation>&Hjálp</translation> + </message> + <message> + <source>Tabs toolbar</source> + <translation>Tólaborð flipa</translation> + </message> + <message> + <source>Request payments (generates QR codes and bitcoin: URIs)</source> + <translation>Óska eftir greiðslum (býr til QR kóða og bitcoin: URI)</translation> + </message> + <message> + <source>Show the list of used sending addresses and labels</source> + <translation>Sýna lista yfir færslugildi sem notuð hafa verið til sendingar og merkingar þeirra</translation> + </message> + <message> + <source>Show the list of used receiving addresses and labels</source> + <translation>Sýna færslugildi sem notuð hafa verið til að taka við mynt og merkingar þeirra</translation> + </message> + <message> + <source>Open a bitcoin: URI or payment request</source> + <translation>Opna bitcoin: URI eða greiðslubeiðni</translation> + </message> + <message> + <source>Indexing blocks on disk...</source> + <translation>Raða blokkum á drifi</translation> + </message> + <message> + <source>Processing blocks on disk...</source> + <translation>Vinn úr blokkum á drifi...</translation> + </message> + <message> + <source>%1 behind</source> + <translation>%1 á eftir</translation> + </message> + <message> + <source>Last received block was generated %1 ago.</source> + <translation>Síðasta viðtekna blokk var búin til fyrir %1 síðan.</translation> + </message> + <message> + <source>Transactions after this will not yet be visible.</source> + <translation>Færslur á eftir þessari munu ekki sjást.</translation> + </message> + <message> + <source>Error</source> + <translation>Villa</translation> + </message> + <message> + <source>Warning</source> + <translation>Viðvörun</translation> + </message> + <message> + <source>Information</source> + <translation>Upplýsingar</translation> + </message> + <message> + <source>Up to date</source> + <translation>Uppfært</translation> + </message> + <message> + <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source> + <translation>Sýna %1 hjálparskilaboðin til að fá lista yfir valkosti Bitcoin aðgerðir í skipanalínu</translation> + </message> + <message> + <source>%1 client</source> + <translation>%1 biðlarar</translation> + </message> + <message> + <source>Connecting to peers...</source> + <translation>Tengist jafningjum...</translation> + </message> + <message> + <source>Catching up...</source> + <translation>Færist nær...</translation> + </message> + <message> + <source>Date: %1 +</source> + <translation>Dagsetning: %1 +</translation> + </message> + <message> + <source>Amount: %1 +</source> + <translation>Upphæð: %1 +</translation> + </message> + <message> + <source>Type: %1 +</source> + <translation>Tegund: %1 +</translation> + </message> + <message> + <source>Label: %1 +</source> + <translation>Merki: %1 +</translation> + </message> + <message> + <source>Address: %1 +</source> + <translation>Færslugildi: %1 +</translation> + </message> + <message> + <source>Sent transaction</source> + <translation>Send færsla</translation> + </message> + <message> + <source>Incoming transaction</source> + <translation>Móttökufærsla</translation> + </message> + <message> + <source>HD key generation is <b>enabled</b></source> + <translation>HD lyklagerð er <b>virkjuð</b></translation> + </message> + <message> + <source>HD key generation is <b>disabled</b></source> + <translation>HD lyklagerð er <b>óvirk</b></translation> + </message> + <message> + <source>Wallet is <b>encrypted</b> and currently <b>unlocked</b></source> + <translation>Veskið er <b>dulkóðað</b> og núna <b>ólæst</b></translation> + </message> + <message> + <source>Wallet is <b>encrypted</b> and currently <b>locked</b></source> + <translation>Veskið er <b>dulkóðað</b> and currently <b>locked</b></translation> + </message> + <message> + <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source> + <translation>Alvarleg villa átti sér stað. Bitcoin getur ekki haldið áfram með öruggum hætti og stoppar hér.</translation> + </message> +</context> +<context> + <name>CoinControlDialog</name> + <message> + <source>Coin Selection</source> + <translation>Myntval</translation> + </message> + <message> + <source>Quantity:</source> + <translation>Magn:</translation> + </message> + <message> + <source>Bytes:</source> + <translation>Bæti:</translation> + </message> + <message> + <source>Amount:</source> + <translation>Upphæð:</translation> + </message> + <message> + <source>Fee:</source> + <translation>Gjald:</translation> + </message> + <message> + <source>Dust:</source> + <translation>Ryk:</translation> + </message> + <message> + <source>After Fee:</source> + <translation>Eftirgjald:</translation> + </message> + <message> + <source>Change:</source> + <translation>Skiptimynt:</translation> + </message> + <message> + <source>(un)select all</source> + <translation>(af)velja allt</translation> + </message> + <message> + <source>Tree mode</source> + <translation>Hrísluhamur</translation> + </message> + <message> + <source>List mode</source> + <translation>Listahamur</translation> + </message> + <message> + <source>Amount</source> + <translation>Upphæð</translation> + </message> + <message> + <source>Received with label</source> + <translation>Móttekið með merkingu</translation> + </message> + <message> + <source>Received with address</source> + <translation>Móttekið með færslugildi</translation> + </message> + <message> + <source>Copy address</source> + <translation>Afrita færslugildi</translation> + </message> + <message> + <source>Copy label</source> + <translation>Afrita merki</translation> + </message> + <message> + <source>This label turns red if any recipient receives an amount smaller than the current dust threshold.</source> + <translation>Þetta merki verður rautt ef einhver viðtakandi tekur við upphæð sem er lægri en núgildandi þröskuldur.</translation> + </message> + <message> + <source>(no label)</source> + <translation>(ekkert merki)</translation> + </message> + </context> +<context> + <name>EditAddressDialog</name> + <message> + <source>Edit Address</source> + <translation>Breyta færslugildi</translation> + </message> + <message> + <source>&Label</source> + <translation>&Merki</translation> + </message> + <message> + <source>The label associated with this address list entry</source> + <translation>Merking tengd þessu færslugildi</translation> + </message> + <message> + <source>The address associated with this address list entry. This can only be modified for sending addresses.</source> + <translation>Færslugildið sem tengt er þessari færslu. Þessu má einungis breyta þegar sent er.</translation> + </message> + <message> + <source>&Address</source> + <translation>Nýtt móttökufærslugildi</translation> + </message> + <message> + <source>New sending address</source> + <translation>Nýtt sendingarfærslugildi</translation> + </message> + <message> + <source>Edit receiving address</source> + <translation>Breyta móttökufærslugildi</translation> + </message> + <message> + <source>Edit sending address</source> + <translation>Breyta sendingarfærslugildi</translation> + </message> + <message> + <source>The entered address "%1" is not a valid Bitcoin address.</source> + <translation>Færslugildið sem slegið var inn "%1" er ekki leyfilegt Bitcoin færslugildi.</translation> + </message> + </context> +<context> + <name>FreespaceChecker</name> + </context> +<context> + <name>HelpMessageDialog</name> + </context> +<context> + <name>Intro</name> + <message> + <source>Bitcoin</source> + <translation>Bitcoin</translation> + </message> + <message> + <source>Error</source> + <translation>Villa</translation> + </message> + </context> +<context> + <name>ModalOverlay</name> + <message> + <source>Number of blocks left</source> + <translation>Fjöldi blokka sem eftir eru</translation> + </message> + <message> + <source>Last block time</source> + <translation>Tími síðustu blokkar</translation> + </message> + </context> +<context> + <name>OpenURIDialog</name> + </context> +<context> + <name>OptionsDialog</name> + <message> + <source>IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1)</source> + <translation>IP tala staðgengils (t.d. IPv4: 127.0.0.1 / IPv6: ::1)</translation> + </message> + <message> + <source>Third party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items. %s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |.</source> + <translation>URL frá þriðja aðila (t.d. blokkarskoðari) sem birtast í færsluflipanum sem samhengisatriði. %s í URL-inu skipt út fyrir færslutvíkross. Mörg URL eru aðskilin með lóðréttu striki |.</translation> + </message> + <message> + <source>Error</source> + <translation>Villa</translation> + </message> + <message> + <source>The supplied proxy address is invalid.</source> + <translation>Uppgefið færslugildi staðgengils er ógilt.</translation> + </message> +</context> +<context> + <name>OverviewPage</name> + <message> + <source>Mined balance that has not yet matured</source> + <translation>Námuunnin innistæða sem hefur enn ekki komið fram</translation> + </message> + <message> + <source>Your current balance in watch-only addresses</source> + <translation>Innistæða færslugilda sem eru einungis til skoðunar</translation> + </message> + <message> + <source>Unconfirmed transactions to watch-only addresses</source> + <translation>Óstaðfestar færslur til færslugilda sem eru einungis til skoðunar</translation> + </message> + <message> + <source>Mined balance in watch-only addresses that has not yet matured</source> + <translation>Námuunnin innistæða á færslugildum sem eru einungis til skoðunar og hafa ekki komið fram</translation> + </message> + <message> + <source>Current total balance in watch-only addresses</source> + <translation>Innistæða á færslugildum sem eru einungis til skoðunar</translation> + </message> +</context> +<context> + <name>PaymentServer</name> + <message> + <source>Invalid payment address %1</source> + <translation>Ógilt færslugildi til greiðslu %1</translation> + </message> + </context> +<context> + <name>PeerTableModel</name> + </context> +<context> + <name>QObject</name> + <message> + <source>Amount</source> + <translation>Upphæð</translation> + </message> + </context> +<context> + <name>QObject::QObject</name> + </context> +<context> + <name>QRImageWidget</name> + </context> +<context> + <name>RPCConsole</name> + <message> + <source>Block chain</source> + <translation>Blokkarkeðja</translation> + </message> + <message> + <source>Current number of blocks</source> + <translation>Núverandi fjöldi blokka</translation> + </message> + <message> + <source>Starting Block</source> + <translation>Upphafsblokk</translation> + </message> + <message> + <source>Synced Blocks</source> + <translation>Samhæfðar blokkir</translation> + </message> + <message> + <source>Last block time</source> + <translation>Tími síðustu blokkar</translation> + </message> + </context> +<context> + <name>ReceiveCoinsDialog</name> + <message> + <source>&Label:</source> + <translation>&Merki:</translation> + </message> + <message> + <source>An optional label to associate with the new receiving address.</source> + <translation>Valfrjálst merki sem tengist nýju móttökufærslutölunni.</translation> + </message> + <message> + <source>Copy label</source> + <translation>Afrita merki</translation> + </message> + </context> +<context> + <name>ReceiveRequestDialog</name> + <message> + <source>Address</source> + <translation>Vistfang</translation> + </message> + <message> + <source>Amount</source> + <translation>Upphæð</translation> + </message> + <message> + <source>Label</source> + <translation>Merki</translation> + </message> + <message> + <source>Wallet</source> + <translation>Veski</translation> + </message> + <message> + <source>Resulting URI too long, try to reduce the text for label / message.</source> + <translation>URI varð of langt, reyndu að minnka texta í merki / skilaboðum.</translation> + </message> + </context> +<context> + <name>RecentRequestsTableModel</name> + <message> + <source>Label</source> + <translation>Merki</translation> + </message> + <message> + <source>(no label)</source> + <translation>(ekkert merki)</translation> + </message> + </context> +<context> + <name>SendCoinsDialog</name> + <message> + <source>Quantity:</source> + <translation>Magn:</translation> + </message> + <message> + <source>Bytes:</source> + <translation>Bæti:</translation> + </message> + <message> + <source>Amount:</source> + <translation>Upphæð:</translation> + </message> + <message> + <source>Fee:</source> + <translation>Gjald:</translation> + </message> + <message> + <source>After Fee:</source> + <translation>Eftirgjald:</translation> + </message> + <message> + <source>Change:</source> + <translation>Skiptimynt:</translation> + </message> + <message> + <source>Paying only the minimum fee is just fine as long as there is less transaction volume than space in the blocks. But be aware that this can end up in a never confirming transaction once there is more demand for bitcoin transactions than the network can process.</source> + <translation>Það er í lagi að greiða einungis lágmarksupphæðina svo framarlega sem færslurúmtakið er minna en plássið í blokkunum. En gætið þess að þegar það er meiri eftirspurn eftir bitcoin færslum en netið getur unnið úr þá gæti svo farið að færslurnar verða aldrei samþykktar.</translation> + </message> + <message> + <source>(Smart fee not initialized yet. This usually takes a few blocks...)</source> + <translation>(Smart gjald er ekki gangsett ennþá. Þetta tekur venjulega nokkrar blokkir...)</translation> + </message> + <message> + <source>Dust:</source> + <translation>Ryk:</translation> + </message> + <message> + <source>(no label)</source> + <translation>(ekkert merki)</translation> + </message> +</context> +<context> + <name>SendCoinsEntry</name> + <message> + <source>&Label:</source> + <translation>&Merki:</translation> + </message> + </context> +<context> + <name>SendConfirmationDialog</name> + </context> +<context> + <name>ShutdownWindow</name> + </context> +<context> + <name>SignVerifyMessageDialog</name> + </context> +<context> + <name>SplashScreen</name> + </context> +<context> + <name>TrafficGraphWidget</name> + </context> +<context> + <name>TransactionDesc</name> + <message> + <source>Generated coins must mature %1 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, its state will change to "not accepted" and it won't be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.</source> + <translation>Fullgerð mynt verður að nýta %1 blokkir. Þegar þú bjóst til þessa blokk, þá var jafnóðum tilkynnt á netinu að hún eigi að bætast við blokkakeðjuna. Ef hún kemst ekki í keðjuna þá mun staða hennar breytast í "ósamþykkt" og ekki verður hægt að nota hana. Þetta gerist annað slagið ef annar hnútpunktur klárar blokk nokkrum sekúndum á undan þinni.</translation> + </message> + <message> + <source>Amount</source> + <translation>Upphæð</translation> + </message> + </context> +<context> + <name>TransactionDescDialog</name> + </context> +<context> + <name>TransactionTableModel</name> + <message> + <source>Label</source> + <translation>Merki</translation> + </message> + <message> + <source>Mined</source> + <translation>Námuunnið</translation> + </message> + <message> + <source>(no label)</source> + <translation>(ekkert merki)</translation> + </message> + </context> +<context> + <name>TransactionView</name> + <message> + <source>Mined</source> + <translation>Námuunnið</translation> + </message> + <message> + <source>Copy address</source> + <translation>Afrita færslugildi</translation> + </message> + <message> + <source>Copy label</source> + <translation>Afrita merki</translation> + </message> + <message> + <source>Comma separated file (*.csv)</source> + <translation>Gildi aðskilin með kommu (*.csv)</translation> + </message> + <message> + <source>Label</source> + <translation>Merki</translation> + </message> + <message> + <source>Address</source> + <translation>Vistfang</translation> + </message> + <message> + <source>Exporting Failed</source> + <translation>Útflutningur tókst ekki</translation> + </message> + </context> +<context> + <name>UnitDisplayStatusBarControl</name> + </context> +<context> + <name>WalletFrame</name> + </context> +<context> + <name>WalletModel</name> + </context> +<context> + <name>WalletView</name> + <message> + <source>&Export</source> + <translation>&Flytja út</translation> + </message> + <message> + <source>Export the data in the current tab to a file</source> + <translation>Flytja gögn í flipanum í skrá</translation> + </message> + </context> +<context> + <name>bitcoin-core</name> + <message> + <source>Error reading %s! All keys read correctly, but transaction data or address book entries might be missing or incorrect.</source> + <translation>Villa við lestur %s! Allir lyklar fóru inn á réttan hátt, en færslugögn eða færslugildi gætu verið röng eða horfin.</translation> + </message> + <message> + <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source> + <translation>Viðvörun: Netið er ekki í fullu samræmi! Einhver námuvinnsla virðist í ólagi.</translation> + </message> + <message> + <source>Information</source> + <translation>Upplýsingar</translation> + </message> + <message> + <source>Warning</source> + <translation>Viðvörun</translation> + </message> + <message> + <source>Warning: Unknown block versions being mined! It's possible unknown rules are in effect</source> + <translation>Viðvörun: Óþekkt blokkarútgáfa í námavinnslu! Það er mögulegt að óþekktum reglum sé fylgt</translation> + </message> + <message> + <source>Error</source> + <translation>Villa</translation> + </message> +</context> +</TS>
\ No newline at end of file diff --git a/src/qt/locale/bitcoin_it.ts b/src/qt/locale/bitcoin_it.ts index 5b24fcdf46..7513e3e30e 100644 --- a/src/qt/locale/bitcoin_it.ts +++ b/src/qt/locale/bitcoin_it.ts @@ -3169,6 +3169,10 @@ Nota: poiché la commissione è calcolata su base per byte, una commissione di " <translation>Errore lettura %s! Tutte le chiavi sono state lette correttamente, ma i dati delle transazioni o della rubrica potrebbero essere mancanti o non corretti.</translation> </message> <message> + <source>Group outputs by address, selecting all or none, instead of selecting on a per-output basis. Privacy is improved as an address is only used once (unless someone sends to it after spending from it), but may result in slightly higher fees as suboptimal coin selection may result due to the added limitation (default: %u)</source> + <translation>Raggruppa gli output per indirizzo, selezionando tutti o nessuno, invece di selezionarli in base all'output. La privacy è migliorata in quanto un indirizzo viene usato una sola volta (a meno che qualcuno vi invii denaro dopo che avevate già speso da quell'indirizzo), ma può comportare commissioni leggermente più alte visto che le limitazioni aggiunte possono condurre a una selezione subottimale degli input da spendere (default: %u)</translation> + </message> + <message> <source>Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly.</source> <translation>Per favore controllate che la data del computer e l'ora siano corrette! Se il vostro orologio è sbagliato %s non funzionerà correttamente.</translation> </message> @@ -3305,6 +3309,10 @@ Nota: poiché la commissione è calcolata su base per byte, una commissione di " <translation>Importo non valido per -fallbackfee=<amount>: '%s'</translation> </message> <message> + <source>Specified blocks directory "%s" does not exist.</source> + <translation>La cartella specificata "%s" non esiste.</translation> + </message> + <message> <source>Upgrading txindex database</source> <translation>Aggiornamento del database txindex</translation> </message> diff --git a/src/qt/locale/bitcoin_it_IT.ts b/src/qt/locale/bitcoin_it_IT.ts index eccf015bf5..d97d888f23 100644 --- a/src/qt/locale/bitcoin_it_IT.ts +++ b/src/qt/locale/bitcoin_it_IT.ts @@ -232,7 +232,7 @@ </message> <message> <source>Banned Until</source> - <translation>bannato fino </translation> + <translation>Bannato fino </translation> </message> </context> <context> @@ -760,7 +760,7 @@ </message> <message> <source>The wallet will also be stored in this directory.</source> - <translation>Il portafoglio sara' </translation> + <translation>Il wallet verra' inoltre memorizzato su questa cartella.</translation> </message> <message> <source>Error</source> @@ -770,6 +770,14 @@ <context> <name>ModalOverlay</name> <message> + <source>Recent transactions may not yet be visible, and therefore your wallet's balance might be incorrect. This information will be correct once your wallet has finished synchronizing with the bitcoin network, as detailed below.</source> + <translation>Le transazioni recenti potrebbero non essere ancora visibili, e quindi il saldo del wallet potrebbe essere incorretto. Questa informazione verra' corretta non appena il tuo wallet ha finito di sincronizzarsi con la rete bitcoin, come specificato di seguito.</translation> + </message> + <message> + <source>Attempting to spend bitcoins that are affected by not-yet-displayed transactions will not be accepted by the network.</source> + <translation>Tentare di spendere bitcoin che sono affetti da transazioni non ancora mostrate, non verra' accettato dal network.</translation> + </message> + <message> <source>Number of blocks left</source> <translation>Numero di blocchi rimanente</translation> </message> diff --git a/src/qt/locale/bitcoin_ja.ts b/src/qt/locale/bitcoin_ja.ts index 7650694e15..2ee78dbb29 100644 --- a/src/qt/locale/bitcoin_ja.ts +++ b/src/qt/locale/bitcoin_ja.ts @@ -3,11 +3,11 @@ <name>AddressBookPage</name> <message> <source>Right-click to edit address or label</source> - <translation>右クリックでアドレスまたはラベルを編集します</translation> + <translation>右クリックでアドレスまたはラベルを編集</translation> </message> <message> <source>Create a new address</source> - <translation>新規アドレスの作成</translation> + <translation>新しいアドレスを作成</translation> </message> <message> <source>&New</source> @@ -15,7 +15,7 @@ </message> <message> <source>Copy the currently selected address to the system clipboard</source> - <translation>現在選択されているアドレスをシステムのクリップボードにコピーする</translation> + <translation>現在選択されているアドレスをシステムのクリップボードにコピー</translation> </message> <message> <source>&Copy</source> @@ -27,15 +27,15 @@ </message> <message> <source>Delete the currently selected address from the list</source> - <translation>選択されたアドレスを一覧から削除する</translation> + <translation>選択されたアドレスを一覧から削除</translation> </message> <message> <source>Enter address or label to search</source> - <translation>検索するアドレスまたはラベルを入力</translation> + <translation>検索したいアドレスまたはラベルを入力</translation> </message> <message> <source>Export the data in the current tab to a file</source> - <translation>ファイルに現在のタブのデータをエクスポート</translation> + <translation>このタブのデータをファイルにエクスポート</translation> </message> <message> <source>&Export</source> @@ -47,11 +47,11 @@ </message> <message> <source>Choose the address to send coins to</source> - <translation>送信先のアドレスを選択</translation> + <translation>コインを送りたいアドレスを選択</translation> </message> <message> <source>Choose the address to receive coins with</source> - <translation>支払いを受け取るアドレスを指定する</translation> + <translation>コインを受け取りたいアドレスを選択</translation> </message> <message> <source>C&hoose</source> @@ -59,19 +59,19 @@ </message> <message> <source>Sending addresses</source> - <translation>送金用</translation> + <translation>送金先アドレス</translation> </message> <message> <source>Receiving addresses</source> - <translation>受け取りアドレス</translation> + <translation>受取用アドレス</translation> </message> <message> <source>These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins.</source> - <translation>これらは支払いを送信するためのあなたの Bitcoin アドレスです。コインを送信する前に、常に額と受信アドレスを確認してください。</translation> + <translation>これらは、あなたが知っている支払い送り先の Bitcoin アドレスです。コインを送る前に、必ず金額と送金先アドレスを確認してください。</translation> </message> <message> <source>These are your Bitcoin addresses for receiving payments. It is recommended to use a new receiving address for each transaction.</source> - <translation>これらは支払いを受け取るためのビットコインアドレスです。トランザクションごとに新しい受け取り用アドレスを作成することが推奨されます。</translation> + <translation>これらは支払いを受け取るための、あなたの Bitcoin アドレスです。トランザクションごとに新しい受け取り用アドレスを作成することが推奨されます。</translation> </message> <message> <source>&Copy Address</source> @@ -149,7 +149,7 @@ </message> <message> <source>This operation needs your wallet passphrase to unlock the wallet.</source> - <translation>この操作はウォレットをアンロックするためにパスフレーズが必要です。</translation> + <translation>この操作を続行するには、ウォレットをアンロックするためのパスフレーズが必要です。</translation> </message> <message> <source>Unlock wallet</source> @@ -157,7 +157,7 @@ </message> <message> <source>This operation needs your wallet passphrase to decrypt the wallet.</source> - <translation>この操作はウォレットの暗号化解除のためにパスフレーズが必要です。</translation> + <translation>この操作を続行するには、ウォレットの暗号化を解除するためのパスフレーズが必要です。</translation> </message> <message> <source>Decrypt wallet</source> @@ -177,7 +177,7 @@ </message> <message> <source>Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>!</source> - <translation>警告: もしもあなたのウォレットを暗号化してパスフレーズを失ってしまったなら、<b>あなたの Bitcoin はすべて失われます</b>!</translation> + <translation>警告: もしもあなたのウォレットを暗号化してパスフレーズを忘れてしまったら、<b>あなたの Bitcoin はすべて失われます</b>!</translation> </message> <message> <source>Are you sure you wish to encrypt your wallet?</source> @@ -189,11 +189,11 @@ </message> <message> <source>%1 will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source> - <translation>暗号化処理を完了させるため %1 をいますぐ終了します。ウォレットの暗号化では、コンピュータに感染したマルウェアなどによるビットコインの盗難から完全に守ることはできないことにご注意ください。</translation> + <translation>暗号化処理を完了させるため %1 をいますぐ終了します。ウォレットを暗号化しても、コンピュータに感染したマルウェアなどによる Bitcoin の盗難を完全に防ぐことはできないことにご注意ください。</translation> </message> <message> <source>IMPORTANT: Any previous backups you have made of your wallet file should be replaced with the newly generated, encrypted wallet file. For security reasons, previous backups of the unencrypted wallet file will become useless as soon as you start using the new, encrypted wallet.</source> - <translation>重要: 過去のウォレット ファイルのバックアップは、暗号化された新しいウォレット ファイルに取り替える必要があります。セキュリティ上の理由により、暗号化された新しいウォレットを使い始めると、暗号化されていないウォレット ファイルのバックアップはすぐに使えなくなります。</translation> + <translation>重要: 今までに作成されたウォレット ファイルのバックアップは、暗号化された新しいウォレット ファイルに置き換える必要があります。セキュリティ上の理由により、暗号化された新しいウォレットを使い始めると、暗号化されていないウォレット ファイルのバックアップはすぐに使えなくなります。</translation> </message> <message> <source>Wallet encryption failed</source> @@ -225,7 +225,7 @@ </message> <message> <source>Warning: The Caps Lock key is on!</source> - <translation>警告: Caps Lock キーがオンになっています!</translation> + <translation>警告: Caps Lock キーがオンになっています!</translation> </message> </context> <context> @@ -247,7 +247,7 @@ </message> <message> <source>Synchronizing with network...</source> - <translation>ネットワークに同期中……</translation> + <translation>ネットワークと同期しています……</translation> </message> <message> <source>&Overview</source> @@ -347,11 +347,11 @@ </message> <message> <source>Syncing Headers (%1%)...</source> - <translation>未知。ヘッダを同期しています (%1%)...</translation> + <translation>ヘッダーを同期しています (%1%)...</translation> </message> <message> <source>Reindexing blocks on disk...</source> - <translation>ディスク上のブロックのインデックスを再作成中...</translation> + <translation>ディスク上のブロックのインデックスを再作成しています...</translation> </message> <message> <source>Proxy is <b>enabled</b>: %1</source> @@ -395,7 +395,7 @@ </message> <message> <source>&Receive</source> - <translation>入金 (&R)</translation> + <translation>受取 (&R)</translation> </message> <message> <source>&Show / Hide</source> @@ -411,11 +411,11 @@ </message> <message> <source>Sign messages with your Bitcoin addresses to prove you own them</source> - <translation>あなたが所有していることを証明するために、あなたの Bitcoin アドレスでメッセージに署名してください</translation> + <translation>Bitcoin アドレスをあなたが所有していることを証明するために、そのアドレスでメッセージに署名してください</translation> </message> <message> <source>Verify messages to ensure they were signed with specified Bitcoin addresses</source> - <translation>指定された Bitcoin アドレスで署名されたことを確認するためにメッセージを検証します</translation> + <translation>指定された Bitcoin アドレスで署名されたことを確認するために、メッセージを検証してください</translation> </message> <message> <source>&File</source> @@ -435,15 +435,15 @@ </message> <message> <source>Request payments (generates QR codes and bitcoin: URIs)</source> - <translation>支払いを要求する (QRコードとbitcoin:ではじまるURIを生成する)</translation> + <translation>支払いをリクエストする (QRコードとbitcoin:ではじまるURIを生成する)</translation> </message> <message> <source>Show the list of used sending addresses and labels</source> - <translation>使用済みの送金用アドレスとラベルの一覧を表示する</translation> + <translation>使用したことのある送金用アドレスとラベルの一覧を表示する</translation> </message> <message> <source>Show the list of used receiving addresses and labels</source> - <translation>支払いを受け取るアドレスとラベルのリストを表示する</translation> + <translation>使用したことのある受け取り用アドレスとラベルの一覧を表示する</translation> </message> <message> <source>Open a bitcoin: URI or payment request</source> @@ -455,7 +455,7 @@ </message> <message numerus="yes"> <source>%n active connection(s) to Bitcoin network</source> - <translation><numerusform>%n の Bitcoin ネットワークへのアクティブな接続</numerusform></translation> + <translation><numerusform>Bitcoin ネットワークへのアクティブな接続は %n 個</numerusform></translation> </message> <message> <source>Indexing blocks on disk...</source> @@ -479,7 +479,7 @@ </message> <message> <source>Transactions after this will not yet be visible.</source> - <translation>この後の取引はまだ表示されません。</translation> + <translation>この後の取引はまだ表示されていません。</translation> </message> <message> <source>Error</source> @@ -575,7 +575,7 @@ </message> <message> <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source> - <translation>致命的なエラーが発生しました。Bitcoin は安全に継続することができず終了するでしょう。</translation> + <translation>致命的なエラーが発生しました。Bitcoin を安全に動作し続けることができないため終了します。</translation> </message> </context> <context> @@ -710,7 +710,7 @@ </message> <message> <source>This label turns red if any recipient receives an amount smaller than the current dust threshold.</source> - <translation>少なくともひとつの受取額が現在のダスト閾値を下回る場合にはこのラベルは赤くなります。</translation> + <translation>少なくともひとつの受取額が現在のダスト閾値を下回る場合に、このラベルは赤くなります。</translation> </message> <message> <source>Can vary +/- %1 satoshi(s) per input.</source> @@ -753,15 +753,15 @@ </message> <message> <source>New sending address</source> - <translation>新しい送信アドレス</translation> + <translation>新しい送金用アドレス</translation> </message> <message> <source>Edit receiving address</source> - <translation>入金アドレスを編集</translation> + <translation>受け取り用アドレスを編集</translation> </message> <message> <source>Edit sending address</source> - <translation>送信アドレスを編集</translation> + <translation>送金用アドレスを編集</translation> </message> <message> <source>The entered address "%1" is not a valid Bitcoin address.</source> @@ -769,11 +769,11 @@ </message> <message> <source>Address "%1" already exists as a receiving address with label "%2" and so cannot be added as a sending address.</source> - <translation>アドレス "%1" は既に受取用アドレスにラベル "%2" として存在するので、送金用アドレスとしては追加できません。</translation> + <translation>アドレス "%1" は、既に受け取り用アドレスにラベル "%2" として存在するので、送金用アドレスとしては追加できません。</translation> </message> <message> <source>The entered address "%1" is already in the address book with label "%2".</source> - <translation>入力されたアドレス"%1"はすでにアドレス帳のラベル"%2"に存在します。</translation> + <translation>入力されたアドレス"%1"は、既にアドレス帳にラベル "%2" として存在します。</translation> </message> <message> <source>Could not unlock wallet.</source> @@ -796,7 +796,7 @@ </message> <message> <source>Directory already exists. Add %1 if you intend to create a new directory here.</source> - <translation>ディレクトリがもうあります。 新しいのディレクトリを作るつもりなら%1を書いてください。</translation> + <translation>ディレクトリが既に存在します。 新しいディレクトリを作成したい場合は %1 を追加してください。</translation> </message> <message> <source>Path already exists, and is not a directory.</source> @@ -846,19 +846,19 @@ </message> <message> <source>This initial synchronisation is very demanding, and may expose hardware problems with your computer that had previously gone unnoticed. Each time you run %1, it will continue downloading where it left off.</source> - <translation>この初期同期には多大なリソースを消費し、あなたのコンピュータにこれまで見つからなかったハードウェア上の問題を露呈させるかもしれません。%1 を実行する度に、中断された時点からダウンロードを継続します。</translation> + <translation>この初期同期には多大なリソースを消費し、あなたのコンピュータでこれまで見つからなかったハードウェア上の問題が発生する場合があります。%1 を実行する度に、中断された時点からダウンロードを再開します。</translation> </message> <message> <source>If you have chosen to limit block chain storage (pruning), the historical data must still be downloaded and processed, but will be deleted afterward to keep your disk usage low.</source> - <translation>ブロックチェーンの保存容量に制限を設けることを選択した場合 (剪定) にも、過去のデータのダウンロードおよび処理が必要になります。しかしこれらのデータはディスク使用量を低く抑えるためにその後削除されるでしょう</translation> + <translation>ブロックチェーンの保存容量に制限を設けることを選択した場合 (剪定) にも、過去のデータのダウンロードおよび処理が必要になります。しかし、これらのデータはディスク使用量を低く抑えるために、後で削除されます。</translation> </message> <message> <source>Use the default data directory</source> - <translation>初期値のデータ ディレクトリを使用</translation> + <translation>既定のデータ ディレクトリを使用</translation> </message> <message> <source>Use a custom data directory:</source> - <translation>任意のデータ ディレクトリを使用:</translation> + <translation>カスタムのデータ ディレクトリを使用:</translation> </message> <message> <source>Bitcoin</source> @@ -905,11 +905,11 @@ </message> <message> <source>Recent transactions may not yet be visible, and therefore your wallet's balance might be incorrect. This information will be correct once your wallet has finished synchronizing with the bitcoin network, as detailed below.</source> - <translation>確認できない最近のトランザクションがあるかもしれません。これによりウォレットの残高は不正確なものである可能性があります。この情報はウォレットが一度ビットコインネットワークへの同期が完了すると正確なものとなります。詳細は下記を参照してください。</translation> + <translation>最近のトランザクションがまだ表示されていない可能性があります。そのため、ウォレットの残高が正しく表示されていないかもしれません。この情報は、ウォレットが Bitcoin ネットワークへの同期が完了すると正確なものとなります。詳細は下記を参照してください。</translation> </message> <message> <source>Attempting to spend bitcoins that are affected by not-yet-displayed transactions will not be accepted by the network.</source> - <translation>まだ表示されていないトランザクションが影響するビットコインを使用しようとすると、ネットワークから認証がなされないでしょう。</translation> + <translation>まだ表示されていないトランザクションが影響する Bitcoin を使用しようとすると、ネットワークから認証を受けられません。</translation> </message> <message> <source>Number of blocks left</source> @@ -3200,6 +3200,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>%s の読み込みエラー! すべてのキーは正しく読み取れますが、取引データやアドレス帳のエントリが失われたか、正しくない可能性があります。</translation> </message> <message> + <source>Group outputs by address, selecting all or none, instead of selecting on a per-output basis. Privacy is improved as an address is only used once (unless someone sends to it after spending from it), but may result in slightly higher fees as suboptimal coin selection may result due to the added limitation (default: %u)</source> + <translation>出力ごとではなく、アドレス単位に出力をまとめて選択します。(後からまたそのアドレスに支払われない限り)アドレスが一度しか使用されないためプライバシーが向上します。ただし追加の制限により最適ではないコイン選択が発生した場合に、わずかに高い手数料となる可能性があります。(初期値: %u)</translation> + </message> + <message> <source>Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly.</source> <translation>あなたのPCの日付と時刻が正しいことを確認して下さい! もしあなたの時計が正しくなければ %s が正確に動作しません。</translation> </message> @@ -3341,6 +3345,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>不正な額 -fallbackfee=<amount>: '%s'</translation> </message> <message> + <source>Specified blocks directory "%s" does not exist.</source> + <translation>指定のブロックディレクトリ"%s"は存在しません。</translation> + </message> + <message> <source>Upgrading txindex database</source> <translation>txindex データベースを更新しています</translation> </message> @@ -3481,12 +3489,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>取引の署名に失敗しました</translation> </message> <message> - <source>Specified blocks directory "%s" does not exist. -</source> - <translation>指定のブロックディレクトリ"%s"が存在しません。 -</translation> - </message> - <message> <source>The transaction amount is too small to pay the fee</source> <translation>トランザクションの金額が小さすぎて手数料を支払えません</translation> </message> diff --git a/src/qt/locale/bitcoin_ka.ts b/src/qt/locale/bitcoin_ka.ts index 3fd95eb6f5..57053ac62d 100644 --- a/src/qt/locale/bitcoin_ka.ts +++ b/src/qt/locale/bitcoin_ka.ts @@ -200,6 +200,14 @@ <translation>საფულის დაშიფვრა წარუმატებით დამთვრდა</translation> </message> <message> + <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source> + <translation>საფულის დაშიფრვა ვერ მოხდა შიდა შეცდომის გამო. თქვენი საფულე არ არის დაშიფრული.</translation> + </message> + <message> + <source>The supplied passphrases do not match.</source> + <translation>მოწოდებული ფრაზა-პაროლები არ ემთხვევა ერთმანეთს.</translation> + </message> + <message> <source>Wallet unlock failed</source> <translation>საფულის გახსნა წარუმატებლად შესრულდა</translation> </message> diff --git a/src/qt/locale/bitcoin_ko.ts b/src/qt/locale/bitcoin_ko.ts new file mode 100644 index 0000000000..aa05383a83 --- /dev/null +++ b/src/qt/locale/bitcoin_ko.ts @@ -0,0 +1,471 @@ +<TS language="ko" version="2.1"> +<context> + <name>AddressBookPage</name> + <message> + <source>Right-click to edit address or label</source> + <translation>마우스 오른쪽 클릭을 해서 라벨이나 주소를 편집할 수 있습니다</translation> + </message> + <message> + <source>Create a new address</source> + <translation>새로운 주소 발급받기</translation> + </message> + <message> + <source>&New</source> + <translation>&발급받기</translation> + </message> + <message> + <source>Copy the currently selected address to the system clipboard</source> + <translation>선택된 주소 클립보드에 붙여넣기</translation> + </message> + <message> + <source>&Copy</source> + <translation>&복사</translation> + </message> + <message> + <source>C&lose</source> + <translation>&닫기</translation> + </message> + <message> + <source>Delete the currently selected address from the list</source> + <translation>선택한 주소 리스트에서 삭제</translation> + </message> + <message> + <source>Enter address or label to search</source> + <translation>검색할 주소나 라벨을 입력하세요</translation> + </message> + <message> + <source>Export the data in the current tab to a file</source> + <translation>현재 탭의 데이터를 파일로 내보냅니다</translation> + </message> + <message> + <source>&Export</source> + <translation>&내보내기</translation> + </message> + <message> + <source>&Delete</source> + <translation>&삭제하기</translation> + </message> + <message> + <source>Choose the address to send coins to</source> + <translation>코인을 보낼 주소를 선택하세요</translation> + </message> + <message> + <source>Choose the address to receive coins with</source> + <translation>코인을 받을 주소를 선택하세요</translation> + </message> + <message> + <source>C&hoose</source> + <translation>&선택하기</translation> + </message> + <message> + <source>Sending addresses</source> + <translation>보낼 주소</translation> + </message> + <message> + <source>Receiving addresses</source> + <translation>받을 주소</translation> + </message> + <message> + <source>These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins.</source> + <translation>이것은 비트코인 전송을 위한 주소입니다. 코인을 보내기 전에 항상 받는 주소와 수량을 확인하세요</translation> + </message> + <message> + <source>These are your Bitcoin addresses for receiving payments. It is recommended to use a new receiving address for each transaction.</source> + <translation>이것은 비트코인 수신을 위한 주소입니다. 코인을 받을 때 마다 항상 다른 주소를 사용 하시는 것을 권장합니다.</translation> + </message> + <message> + <source>&Copy Address</source> + <translation>&주소 복사</translation> + </message> + <message> + <source>Copy &Label</source> + <translation>&라벨 복사</translation> + </message> + <message> + <source>&Edit</source> + <translation>&편집</translation> + </message> + <message> + <source>Export Address List</source> + <translation>주소 목록 내보내기</translation> + </message> + <message> + <source>Exporting Failed</source> + <translation>내보내기 실패</translation> + </message> + <message> + <source>There was an error trying to save the address list to %1. Please try again.</source> + <translation>주소 목록을 %1 로 저장하는 작업이 실패했습니다. 다시 시도해 주세요.</translation> + </message> +</context> +<context> + <name>AddressTableModel</name> + </context> +<context> + <name>AskPassphraseDialog</name> + <message> + <source>Enter passphrase</source> + <translation>암호문 입력</translation> + </message> + <message> + <source>New passphrase</source> + <translation>새 암호문</translation> + </message> + <message> + <source>Repeat new passphrase</source> + <translation>새 암호문 다시 입력</translation> + </message> + <message> + <source>Show password</source> + <translation>비밀번호 보이기</translation> + </message> + <message> + <source>Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>.</source> + <translation>새 암호문을 지갑에 입력합니다. <br/>이러한 형식의 암호문을 사용해 주십시요.<b>10개 이상의 임의 문자</b> 또는 <b>8개 이상의 단어</b>.</translation> + </message> + <message> + <source>Encrypt wallet</source> + <translation>지갑 암호화</translation> + </message> + <message> + <source>This operation needs your wallet passphrase to unlock the wallet.</source> + <translation>이 작업을 수행하려면 지갑을 잠금 해제 할 암호문이 필요합니다.</translation> + </message> + <message> + <source>Unlock wallet</source> + <translation>지갑 잠금 해제</translation> + </message> + <message> + <source>This operation needs your wallet passphrase to decrypt the wallet.</source> + <translation>이 작업을 수행하려면 지갑을 복호화할 암호문이 필요합니다.</translation> + </message> + <message> + <source>Decrypt wallet</source> + <translation>지갑 복호화</translation> + </message> + <message> + <source>Change passphrase</source> + <translation>암호문 변경</translation> + </message> + <message> + <source>Enter the old passphrase and new passphrase to the wallet.</source> + <translation>예전 암호문과 변경할 암호문을 입력하십시요.</translation> + </message> + <message> + <source>Confirm wallet encryption</source> + <translation>지갑 암호화 확인</translation> + </message> + <message> + <source>Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>!</source> + <translation>경고: 지갑이 암호화된 상태로 당신의 암호문을 잃어버리셨다면, 당신은 <b>모든 비트코인을 잃게됩니다</b>!</translation> + </message> + <message> + <source>Are you sure you wish to encrypt your wallet?</source> + <translation>진짜로 지갑을 암호화 할까요?</translation> + </message> + <message> + <source>Wallet encrypted</source> + <translation>지갑 암호화</translation> + </message> + <message> + <source>%1 will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source> + <translation>%1 이(가) 암호화 작업을 위해 종료됩니다. 이 암호화 작업이 바이러스로부터 비트코인을 완전히 지키지 못한다는 점을 기억하십시요.</translation> + </message> + <message> + <source>IMPORTANT: Any previous backups you have made of your wallet file should be replaced with the newly generated, encrypted wallet file. For security reasons, previous backups of the unencrypted wallet file will become useless as soon as you start using the new, encrypted wallet.</source> + <translation>중요: 예전에 만들었던 모든 백업 파일은 새로 만들어진 암호화된 지갑 파일으로 교체됩니다. 보안을 위해서 예전에 만들었던 암호화 되지 않은 백업 파일은 당신이 새로 암호화된 지갑을 사용하고 사용할 수 없게 됩니다. </translation> + </message> + <message> + <source>Wallet encryption failed</source> + <translation>지갑 암호화 실패</translation> + </message> + <message> + <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source> + <translation>내부 오류로 인해 지갑 암호화가 실패했습니다. 지갑이 암호화 되지 않았습니다.</translation> + </message> + <message> + <source>The supplied passphrases do not match.</source> + <translation>입력한 암호문이 일치하지 않습니다.</translation> + </message> + <message> + <source>Wallet unlock failed</source> + <translation>지갑 잠금 해제 실패</translation> + </message> + <message> + <source>The passphrase entered for the wallet decryption was incorrect.</source> + <translation>지갑 복호화를 위한 암호문이 일치하지 않습니다.</translation> + </message> + <message> + <source>Wallet decryption failed</source> + <translation>지갑 복호화 실패</translation> + </message> + <message> + <source>Wallet passphrase was successfully changed.</source> + <translation>지갑 암호문이 성공적으로 변경되었습니다.</translation> + </message> + <message> + <source>Warning: The Caps Lock key is on!</source> + <translation>주의: Caps Lock이 켜져있습니다!</translation> + </message> +</context> +<context> + <name>BanTableModel</name> + <message> + <source>IP/Netmask</source> + <translation>IP/Netmask</translation> + </message> + <message> + <source>Banned Until</source> + <translation>특정 시점까지 차단</translation> + </message> +</context> +<context> + <name>BitcoinGUI</name> + <message> + <source>Sign &message...</source> + <translation>&메시지에 서명하기...</translation> + </message> + <message> + <source>Synchronizing with network...</source> + <translation>네트워크와 동기화중...</translation> + </message> + <message> + <source>&Overview</source> + <translation>&개요</translation> + </message> + <message> + <source>Node</source> + <translation>노드</translation> + </message> + <message> + <source>Show general overview of wallet</source> + <translation>지갑의 일반적인 개요 표시</translation> + </message> + <message> + <source>&Transactions</source> + <translation>&거래</translation> + </message> + <message> + <source>Browse transaction history</source> + <translation>거래 기록 보기</translation> + </message> + <message> + <source>E&xit</source> + <translation>&나가기</translation> + </message> + <message> + <source>Quit application</source> + <translation>애플리케이션 종료</translation> + </message> + <message> + <source>&About %1</source> + <translation>&%1에 대해</translation> + </message> + <message> + <source>Show information about %1</source> + <translation>%1에 대한 정보 표시</translation> + </message> + <message> + <source>About &Qt</source> + <translation>&Qt에 대해</translation> + </message> + <message> + <source>Show information about Qt</source> + <translation>Qt에 대한 정보 표시</translation> + </message> + <message> + <source>&Options...</source> + <translation>&설정...</translation> + </message> + <message> + <source>Modify configuration options for %1</source> + <translation>%1에 대한 구성 수정</translation> + </message> + <message> + <source>&Encrypt Wallet...</source> + <translation>&지갑 암호화...</translation> + </message> + <message> + <source>&Backup Wallet...</source> + <translation>&지갑 백업...</translation> + </message> + <message> + <source>&Change Passphrase...</source> + <translation>&암호문 변경...</translation> + </message> + <message> + <source>&Sending addresses...</source> + <translation>&보낼 주소...</translation> + </message> + <message> + <source>&Receiving addresses...</source> + <translation>&받을 주소...</translation> + </message> + <message> + <source>Open &URI...</source> + <translation>&URL 열기</translation> + </message> + <message> + <source>Wallet:</source> + <translation>지갑:</translation> + </message> + <message> + <source>default wallet</source> + <translation>기본 지갑</translation> + </message> + <message> + <source>Click to disable network activity.</source> + <translation>클릭해서 네트워크 활동 중지</translation> + </message> + <message> + <source>Network activity disabled.</source> + <translation>네트워크 활동 중지</translation> + </message> + <message> + <source>Click to enable network activity again.</source> + <translation>클릭해서 네트워크 활동 활성화</translation> + </message> + <message> + <source>Syncing Headers (%1%)...</source> + <translation>헤더 동기화 (%1%)...</translation> + </message> + <message> + <source>Reindexing blocks on disk...</source> + <translation>디스크에서 블럭 불러오는 중</translation> + </message> + <message> + <source>Send coins to a Bitcoin address</source> + <translation>비트코인 주소로 코인 보내기</translation> + </message> + <message> + <source>Backup wallet to another location</source> + <translation>이 지갑을 다른 곳으로 백업</translation> + </message> + <message> + <source>Change the passphrase used for wallet encryption</source> + <translation>지갑 암호화에 사용될 암호문 바꾸기</translation> + </message> + </context> +<context> + <name>CoinControlDialog</name> + </context> +<context> + <name>EditAddressDialog</name> + </context> +<context> + <name>FreespaceChecker</name> + </context> +<context> + <name>HelpMessageDialog</name> + </context> +<context> + <name>Intro</name> + </context> +<context> + <name>ModalOverlay</name> + </context> +<context> + <name>OpenURIDialog</name> + </context> +<context> + <name>OptionsDialog</name> + </context> +<context> + <name>OverviewPage</name> + </context> +<context> + <name>PaymentServer</name> + </context> +<context> + <name>PeerTableModel</name> + </context> +<context> + <name>QObject</name> + </context> +<context> + <name>QObject::QObject</name> + </context> +<context> + <name>QRImageWidget</name> + </context> +<context> + <name>RPCConsole</name> + <message> + <source>default wallet</source> + <translation>기본 지갑</translation> + </message> + </context> +<context> + <name>ReceiveCoinsDialog</name> + </context> +<context> + <name>ReceiveRequestDialog</name> + </context> +<context> + <name>RecentRequestsTableModel</name> + </context> +<context> + <name>SendCoinsDialog</name> + </context> +<context> + <name>SendCoinsEntry</name> + </context> +<context> + <name>SendConfirmationDialog</name> + </context> +<context> + <name>ShutdownWindow</name> + </context> +<context> + <name>SignVerifyMessageDialog</name> + </context> +<context> + <name>SplashScreen</name> + </context> +<context> + <name>TrafficGraphWidget</name> + </context> +<context> + <name>TransactionDesc</name> + </context> +<context> + <name>TransactionDescDialog</name> + </context> +<context> + <name>TransactionTableModel</name> + </context> +<context> + <name>TransactionView</name> + <message> + <source>Exporting Failed</source> + <translation>내보내기 실패</translation> + </message> + </context> +<context> + <name>UnitDisplayStatusBarControl</name> + </context> +<context> + <name>WalletFrame</name> + </context> +<context> + <name>WalletModel</name> + </context> +<context> + <name>WalletView</name> + <message> + <source>&Export</source> + <translation>&내보내기</translation> + </message> + <message> + <source>Export the data in the current tab to a file</source> + <translation>현재 탭의 데이터를 파일로 내보냅니다</translation> + </message> + </context> +<context> + <name>bitcoin-core</name> + <message> + <source>Transaction amounts must not be negative</source> + <translation>송금액은 마이너스가 될 수 없습니다</translation> + </message> + </context> +</TS>
\ No newline at end of file diff --git a/src/qt/locale/bitcoin_ko_KR.ts b/src/qt/locale/bitcoin_ko_KR.ts index a7a0767464..76ac713e05 100644 --- a/src/qt/locale/bitcoin_ko_KR.ts +++ b/src/qt/locale/bitcoin_ko_KR.ts @@ -3108,7 +3108,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>Could not commit transaction</source> - <translation>트랜잭션을 커밋 할 수 없습니다.</translation> + <translation>거래를 커밋 할 수 없습니다.</translation> </message> </context> <context> @@ -3337,6 +3337,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>유효하지 않은 금액 -fallbackfee=<amount>: '%s'</translation> </message> <message> + <source>Specified blocks directory "%s" does not exist.</source> + <translation>디렉토리 "%s"에 지정한 블록들이 존재하지 않습니다.</translation> + </message> + <message> <source>Upgrading txindex database</source> <translation>txindex 데이터베이스 업테이트중</translation> </message> @@ -3489,11 +3493,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>애러: 지정한 지갑 폴더 "%s"은 디렉토리가 아닙니다.</translation> </message> <message> - <source>Specified blocks directory "%s" does not exist. -</source> - <translation>지정한 블록 폴더 "%s"는 존재하지 않습니다.</translation> - </message> - <message> <source>The transaction amount is too small to pay the fee</source> <translation>거래액이 수수료를 지불하기엔 너무 작습니다</translation> </message> diff --git a/src/qt/locale/bitcoin_lt.ts b/src/qt/locale/bitcoin_lt.ts index b4207524c9..26d89de8e9 100644 --- a/src/qt/locale/bitcoin_lt.ts +++ b/src/qt/locale/bitcoin_lt.ts @@ -3,7 +3,7 @@ <name>AddressBookPage</name> <message> <source>Right-click to edit address or label</source> - <translation>Spustelėkite dešinįjį klavišą norint keisti adresą arba etiketę</translation> + <translation>Spustelėkite dešinįjį klaviša norint keisti adresą arba etiketę</translation> </message> <message> <source>Create a new address</source> @@ -49,14 +49,74 @@ <source>Choose the address to send coins to</source> <translation>Pasirinkite adresą, kuriam siūsite monetas</translation> </message> - </context> + <message> + <source>Choose the address to receive coins with</source> + <translation>Pasirinkite adresą su kuriuo gauti monetas</translation> + </message> + <message> + <source>C&hoose</source> + <translation>P&asirinkti</translation> + </message> + <message> + <source>Sending addresses</source> + <translation>Išsiuntimo adresai</translation> + </message> + <message> + <source>Receiving addresses</source> + <translation>Gavimo adresai</translation> + </message> + <message> + <source>These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins.</source> + <translation>Tai yra jūsų Bitcoin adresai išeinantiems mokėjimams. Visada pasitikrinkite sumą ir gavėjo adresą prieš siunčiant lėšas. </translation> + </message> + <message> + <source>These are your Bitcoin addresses for receiving payments. It is recommended to use a new receiving address for each transaction.</source> + <translation>Tai yra Jūsų Bitcoin adresai įeinantiems mokėjimams. Kiekvienam mokėjimui rekomenduojama naudoti naują adresą. </translation> + </message> + <message> + <source>&Copy Address</source> + <translation>&Kopijuoti adresą</translation> + </message> + <message> + <source>Copy &Label</source> + <translation>Kopijuoti &Žymę</translation> + </message> + <message> + <source>&Edit</source> + <translation>&Keisti</translation> + </message> + <message> + <source>Export Address List</source> + <translation>Eksportuoti adresų sąrašą</translation> + </message> + <message> + <source>Comma separated file (*.csv)</source> + <translation>Kableliais atskirtų duomenų failas (*.csv)</translation> + </message> + <message> + <source>Exporting Failed</source> + <translation>Eksportavimas nepavyko</translation> + </message> + <message> + <source>There was an error trying to save the address list to %1. Please try again.</source> + <translation>Bandant išsaugoti adresų sąrašą - įvyko klaida keliant į %1. Prašome bandyti dar kartą.</translation> + </message> +</context> <context> <name>AddressTableModel</name> <message> + <source>Label</source> + <translation>Žymė</translation> + </message> + <message> <source>Address</source> <translation>Adresas</translation> </message> - </context> + <message> + <source>(no label)</source> + <translation>(nėra žymės)</translation> + </message> +</context> <context> <name>AskPassphraseDialog</name> <message> @@ -75,7 +135,95 @@ <source>Repeat new passphrase</source> <translation>Pakartokite naują slaptafrazę</translation> </message> - </context> + <message> + <source>Show password</source> + <translation>Rodyti slaptažodį</translation> + </message> + <message> + <source>Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>.</source> + <translation>Įveskite naują piniginės slaptafrazę.<br/>Prašome naudoti slaptafrazę iš <b> 10 ar daugiau atsitiktinių simbolių</b> arba <b>aštuonių ar daugiau žodžių</b>.</translation> + </message> + <message> + <source>Encrypt wallet</source> + <translation>Užšifruoti piniginę</translation> + </message> + <message> + <source>This operation needs your wallet passphrase to unlock the wallet.</source> + <translation>Ši operacija reikalauja jūsų piniginės slaptafrazės jai atrakinti.</translation> + </message> + <message> + <source>Unlock wallet</source> + <translation>Atrakinti piniginę</translation> + </message> + <message> + <source>This operation needs your wallet passphrase to decrypt the wallet.</source> + <translation>Ši operacija reikalauja jūsų piniginės slaptafrazės jai iššifruoti.</translation> + </message> + <message> + <source>Decrypt wallet</source> + <translation>Iššifruoti piniginę</translation> + </message> + <message> + <source>Change passphrase</source> + <translation>Pakeisti slaptafrazę</translation> + </message> + <message> + <source>Enter the old passphrase and new passphrase to the wallet.</source> + <translation>Įveskite seną ir naują piniginės slaptafrazes.</translation> + </message> + <message> + <source>Confirm wallet encryption</source> + <translation>Patvirtinkite piniginės užšifravimą</translation> + </message> + <message> + <source>Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>!</source> + <translation>Dėmesio: jei užšifruosite savo piniginę ir pamesite slaptafrazę, jūs<b>PRARASITE VISUS SAVO BITCOINUS</b>! </translation> + </message> + <message> + <source>Are you sure you wish to encrypt your wallet?</source> + <translation>Ar tikrai norite šifruoti savo piniginę?</translation> + </message> + <message> + <source>Wallet encrypted</source> + <translation>Piniginė užšifruota</translation> + </message> + <message> + <source>IMPORTANT: Any previous backups you have made of your wallet file should be replaced with the newly generated, encrypted wallet file. For security reasons, previous backups of the unencrypted wallet file will become useless as soon as you start using the new, encrypted wallet.</source> + <translation>SVARBU: Betkokios ankstesnės jūsų piniginės atsarginės kopijos turėtų būti pakeistos naujai sugeneruotu, užšifruotu piniginės failu. Dėl saugumo sumetimų, anstesnės neužšifruotos piniginės kopijos failas taps nenaudingu nuo momento, kai nauja ir užšifruota piniginė bus pradėta naudoti. </translation> + </message> + <message> + <source>Wallet encryption failed</source> + <translation>Nepavyko užšifruoti piniginę</translation> + </message> + <message> + <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source> + <translation>Dėl vidinės klaidos nepavyko užšifruoti piniginę.Piniginė neužšifruota.</translation> + </message> + <message> + <source>The supplied passphrases do not match.</source> + <translation>Įvestos slaptafrazės nesutampa.</translation> + </message> + <message> + <source>Wallet unlock failed</source> + <translation>Nepavyko atrakinti piniginę</translation> + </message> + <message> + <source>The passphrase entered for the wallet decryption was incorrect.</source> + <translation>Neteisingai įvestas slaptažodis piniginės iššifravimui.</translation> + </message> + <message> + <source>Wallet decryption failed</source> + <translation>Nepavyko iššifruoti piniginės</translation> + </message> + <message> + <source>Wallet passphrase was successfully changed.</source> + <translation>Piniginės slaptažodis sėkmingai pakeistas.</translation> + </message> + <message> + <source>Warning: The Caps Lock key is on!</source> + <translation>Įspėjimas: įjungtas Caps Lock klavišas!</translation> + </message> +</context> <context> <name>BanTableModel</name> <message> @@ -142,6 +290,10 @@ <translation>&Parinktys...</translation> </message> <message> + <source>Modify configuration options for %1</source> + <translation>Keisti %1 konfigūracijos galimybes</translation> + </message> + <message> <source>&Encrypt Wallet...</source> <translation>&Užšifruoti piniginę...</translation> </message> @@ -166,6 +318,30 @@ <translation>Atidaryti &URI...</translation> </message> <message> + <source>Wallet:</source> + <translation>Piniginė</translation> + </message> + <message> + <source>default wallet</source> + <translation>numatyta piniginė</translation> + </message> + <message> + <source>Click to disable network activity.</source> + <translation>Spauskite norėdami išjungti tinklo veiklą.</translation> + </message> + <message> + <source>Network activity disabled.</source> + <translation>Tinklo veikla išjungta.</translation> + </message> + <message> + <source>Click to enable network activity again.</source> + <translation>Spauskite norėdami įjungti tinklo veiklą.</translation> + </message> + <message> + <source>Syncing Headers (%1%)...</source> + <translation>Sinchronizuojamos Antraštės (%1%)...</translation> + </message> + <message> <source>Reindexing blocks on disk...</source> <translation>Blokai iš naujo indeksuojami...</translation> </message> @@ -222,6 +398,14 @@ <translation>Užšifruoti privačius raktus, kurie priklauso jūsų piniginei</translation> </message> <message> + <source>Sign messages with your Bitcoin addresses to prove you own them</source> + <translation>Pasirašydami žinutes su savo Bitcoin adresais įrodysite jog esate jų savininkas </translation> + </message> + <message> + <source>Verify messages to ensure they were signed with specified Bitcoin addresses</source> + <translation>Patikrinkite žinutę, jog įsitikintumėte, kad ją pasirašė nurodytas Bitcoin adresas</translation> + </message> + <message> <source>&File</source> <translation>&Failas</translation> </message> @@ -242,6 +426,18 @@ <translation>Komandinės eilutės parametrai</translation> </message> <message> + <source>Processing blocks on disk...</source> + <translation>Blokai apdirbami diske...</translation> + </message> + <message> + <source>Last received block was generated %1 ago.</source> + <translation>Paskutinis gautas blokas buvo sukurtas prieš %1.</translation> + </message> + <message> + <source>Transactions after this will not yet be visible.</source> + <translation>Sekančios operacijos dar nebus matomos. </translation> + </message> + <message> <source>Error</source> <translation>Klaida</translation> </message> @@ -258,6 +454,10 @@ <translation>Atnaujinta</translation> </message> <message> + <source>%1 client</source> + <translation>%1 klientas</translation> + </message> + <message> <source>Catching up...</source> <translation>Vejamasi...</translation> </message> @@ -268,6 +468,36 @@ </translation> </message> <message> + <source>Amount: %1 +</source> + <translation>Suma: %1 +</translation> + </message> + <message> + <source>Wallet: %1 +</source> + <translation>Piniginė: %1 +</translation> + </message> + <message> + <source>Type: %1 +</source> + <translation>Spausti: %1 +</translation> + </message> + <message> + <source>Label: %1 +</source> + <translation>Antraštė: %1 +</translation> + </message> + <message> + <source>Address: %1 +</source> + <translation>Adresas: %1 +</translation> + </message> + <message> <source>Sent transaction</source> <translation>Sandoris nusiųstas</translation> </message> @@ -342,6 +572,50 @@ <source>Confirmed</source> <translation>Patvirtintas</translation> </message> + <message> + <source>Copy address</source> + <translation>Kopijuoti adresą</translation> + </message> + <message> + <source>Copy label</source> + <translation>Kopijuoti žymę</translation> + </message> + <message> + <source>Copy amount</source> + <translation>Kopijuoti sumą</translation> + </message> + <message> + <source>Copy transaction ID</source> + <translation>Sandorio ID</translation> + </message> + <message> + <source>Copy fee</source> + <translation>Kopijuoti mokestį</translation> + </message> + <message> + <source>Copy after fee</source> + <translation>Kopijuoti po mokesčio</translation> + </message> + <message> + <source>Copy bytes</source> + <translation>Kopijuoti baitus</translation> + </message> + <message> + <source>Copy change</source> + <translation>Kopijuoti keisti</translation> + </message> + <message> + <source>yes</source> + <translation>taip</translation> + </message> + <message> + <source>no</source> + <translation>ne</translation> + </message> + <message> + <source>(no label)</source> + <translation>(nėra žymės)</translation> + </message> </context> <context> <name>EditAddressDialog</name> @@ -387,6 +661,10 @@ <translation>Bitcoin</translation> </message> <message> + <source>The wallet will also be stored in this directory.</source> + <translation>Piniginė taip pat bus saugojama šiame direktyve.</translation> + </message> + <message> <source>Error</source> <translation>Klaida</translation> </message> @@ -701,6 +979,10 @@ <translation>Išvalyti konsolę</translation> </message> <message> + <source>default wallet</source> + <translation>numatyta piniginė</translation> + </message> + <message> <source>never</source> <translation>Niekada</translation> </message> @@ -731,7 +1013,15 @@ <source>Clear</source> <translation>Išvalyti</translation> </message> - </context> + <message> + <source>Copy label</source> + <translation>Kopijuoti žymę</translation> + </message> + <message> + <source>Copy amount</source> + <translation>Kopijuoti sumą</translation> + </message> +</context> <context> <name>ReceiveRequestDialog</name> <message> @@ -747,12 +1037,24 @@ <translation>Adresas</translation> </message> <message> + <source>Label</source> + <translation>Žymė</translation> + </message> + <message> <source>Wallet</source> <translation>Piniginė</translation> </message> </context> <context> <name>RecentRequestsTableModel</name> + <message> + <source>Label</source> + <translation>Žymė</translation> + </message> + <message> + <source>(no label)</source> + <translation>(nėra žymės)</translation> + </message> </context> <context> <name>SendCoinsDialog</name> @@ -817,10 +1119,34 @@ <translation>&Siųsti</translation> </message> <message> + <source>Copy amount</source> + <translation>Kopijuoti sumą</translation> + </message> + <message> + <source>Copy fee</source> + <translation>Kopijuoti mokestį</translation> + </message> + <message> + <source>Copy after fee</source> + <translation>Kopijuoti po mokesčio</translation> + </message> + <message> + <source>Copy bytes</source> + <translation>Kopijuoti baitus</translation> + </message> + <message> + <source>Copy change</source> + <translation>Kopijuoti keisti</translation> + </message> + <message> <source>Transaction fee</source> <translation>Sandorio mokestis</translation> </message> - </context> + <message> + <source>(no label)</source> + <translation>(nėra žymės)</translation> + </message> +</context> <context> <name>SendCoinsEntry</name> <message> @@ -935,13 +1261,49 @@ </context> <context> <name>TransactionTableModel</name> + <message> + <source>Label</source> + <translation>Žymė</translation> + </message> + <message> + <source>(no label)</source> + <translation>(nėra žymės)</translation> + </message> </context> <context> <name>TransactionView</name> <message> + <source>Copy address</source> + <translation>Kopijuoti adresą</translation> + </message> + <message> + <source>Copy label</source> + <translation>Kopijuoti žymę</translation> + </message> + <message> + <source>Copy amount</source> + <translation>Kopijuoti sumą</translation> + </message> + <message> + <source>Copy transaction ID</source> + <translation>Sandorio ID</translation> + </message> + <message> + <source>Comma separated file (*.csv)</source> + <translation>Kableliais atskirtų duomenų failas (*.csv)</translation> + </message> + <message> + <source>Label</source> + <translation>Žymė</translation> + </message> + <message> <source>Address</source> <translation>Adresas</translation> </message> + <message> + <source>Exporting Failed</source> + <translation>Eksportavimas nepavyko</translation> + </message> </context> <context> <name>UnitDisplayStatusBarControl</name> diff --git a/src/qt/locale/bitcoin_ml.ts b/src/qt/locale/bitcoin_ml.ts new file mode 100644 index 0000000000..fdd3bd74bd --- /dev/null +++ b/src/qt/locale/bitcoin_ml.ts @@ -0,0 +1,336 @@ +<TS language="ml" version="2.1"> +<context> + <name>AddressBookPage</name> + <message> + <source>Right-click to edit address or label</source> + <translation>വിലാസം അല്ലെങ്കിൽ ലേബൽ എഡിറ്റുചെയ്യാൻ വലത് ക്ലിക്കുചെയ്യുക</translation> + </message> + <message> + <source>Create a new address</source> + <translation>ഒരു പുതിയ വിലാസം സൃഷ്ടിക്കുക</translation> + </message> + <message> + <source>&New</source> + <translation>&പുതിയത്</translation> + </message> + <message> + <source>Copy the currently selected address to the system clipboard</source> + <translation>നിലവിൽ തിരഞ്ഞെടുത്ത വിലാസം സിസ്റ്റം ക്ലിപ്പ്ബോർഡിലേക്ക് പകർത്തുക</translation> + </message> + <message> + <source>&Copy</source> + <translation>& പകർത്തുക +</translation> + </message> + <message> + <source>C&lose</source> + <translation>അ&ടയ്ക്കുക</translation> + </message> + <message> + <source>Delete the currently selected address from the list</source> + <translation>പട്ടികയിൽ നിന്ന് നിലവിൽ തിരഞ്ഞെടുത്ത വിലാസം ഇല്ലാതാക്കുക</translation> + </message> + <message> + <source>Export the data in the current tab to a file</source> + <translation>നിലവിലെ ടാബിൽ ഒരു ഫയലിൽ ഡാറ്റ എക്സ്പോർട്ട് ചെയ്യുക</translation> + </message> + <message> + <source>&Export</source> + <translation>& കയറ്റുമതി ചെയ്യുക</translation> + </message> + <message> + <source>&Delete</source> + <translation>&ഇല്ലാതാക്കുക</translation> + </message> + <message> + <source>Choose the address to send coins to</source> + <translation>നാണയങ്ങൾ അയയ്ക്കാനുള്ള വിലാസം തിരഞ്ഞെടുക്കുക</translation> + </message> + <message> + <source>Choose the address to receive coins with</source> + <translation>നാണയങ്ങൾ സ്വീകരിക്കാൻ വിലാസം തിരഞ്ഞെടുക്കുക</translation> + </message> + <message> + <source>C&hoose</source> + <translation>തി&രഞ്ഞെടുക്കുക</translation> + </message> + <message> + <source>Sending addresses</source> + <translation>വിലാസങ്ങൾ അയയ്ക്കുന്നു</translation> + </message> + <message> + <source>Receiving addresses</source> + <translation>സ്വീകരിക്കുന്ന വിലാസങ്ങൾ</translation> + </message> + <message> + <source>These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins.</source> + <translation>പേയ്മെന്റുകൾ അയയ്ക്കുന്നതിനുള്ള നിങ്ങളുടെ ബിറ്റ്കോയിൻ വിലാസങ്ങളാണ് ഇവ. നാണയങ്ങൾ അയയ്ക്കുന്നതിനുമുമ്പ് എല്ലായ്പ്പോഴും തുകയും സ്വീകരിക്കുന്ന വിലാസവും പരിശോധിക്കുക.</translation> + </message> + <message> + <source>These are your Bitcoin addresses for receiving payments. It is recommended to use a new receiving address for each transaction.</source> + <translation>പേയ്മെന്റ് സ്വീകരിക്കുന്നതിന് നിങ്ങളുടെ ബിറ്റ്കോയിൻ വിലാസങ്ങളാണ് ഇവ. ഓരോ ഇടപാടിനും പുതിയ സ്വീകരിക്കുന്ന വിലാസം ഉപയോഗിക്കുന്നതാണ് ഉചിതം.</translation> + </message> + <message> + <source>&Copy Address</source> + <translation>&വിലാസം പകർത്തുക</translation> + </message> + <message> + <source>Copy &Label</source> + <translation>പകർത്തുക &ലേബൽ</translation> + </message> + <message> + <source>&Edit</source> + <translation>&ചിട്ടപ്പെടുത്തുക</translation> + </message> + <message> + <source>Export Address List</source> + <translation>കയറ്റുമതി വിലാസ ലിസ്റ്റ്</translation> + </message> + <message> + <source>Comma separated file (*.csv)</source> + <translation>കോമയാൽ വേർതിരിച്ച ഫയൽ (* .csv)</translation> + </message> + <message> + <source>Exporting Failed</source> + <translation>കയറ്റുമതി പരാജയപ്പെട്ടു</translation> + </message> + </context> +<context> + <name>AddressTableModel</name> + <message> + <source>Label</source> + <translation>ലേബൽ</translation> + </message> + <message> + <source>Address</source> + <translation>വിലാസം</translation> + </message> + <message> + <source>(no label)</source> + <translation>(ലേബൽ ഇല്ല)</translation> + </message> +</context> +<context> + <name>AskPassphraseDialog</name> + <message> + <source>Passphrase Dialog</source> + <translation>രഹസ്യപദപ്രയോഗ സംഭാഷണം</translation> + </message> + <message> + <source>Enter passphrase</source> + <translation>രഹസ്യപദപ്രയോഗം നൽകുക</translation> + </message> + <message> + <source>New passphrase</source> + <translation>പുതിയ രഹസ്യപദപ്രയോഗം</translation> + </message> + <message> + <source>Repeat new passphrase</source> + <translation>പുതിയ രഹസ്യപദപ്രയോഗം ആവർത്തിക്കുക</translation> + </message> + <message> + <source>Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>.</source> + <translation>വാലറ്റിൽ പുതിയ രഹസ്യപദപ്രയോഗം നൽകുക. <br/> <b> പത്തോ അതിലധികമോ റാൻഡം പ്രതീകങ്ങൾ </ b> അല്ലെങ്കിൽ <b> എട്ട് അല്ലെങ്കിൽ അതിൽ കൂടുതൽ വാക്കുകൾ </ b> ഒരു രഹസ്യപദപ്രയോഗം ഉപയോഗിക്കുക.</translation> + </message> + <message> + <source>Encrypt wallet</source> + <translation>വാലറ്റ് എൻക്രിപ്റ്റ് ചെയ്യുക</translation> + </message> + <message> + <source>This operation needs your wallet passphrase to unlock the wallet.</source> + <translation>നിങ്ങളുടെ വാലറ്റ് അൺലോക്കുചെയ്യാൻ ഈ പ്രവർത്തനത്തിന് നിങ്ങളുടെ വാലറ്റ് രഹസ്യപദപ്രയോഗം ആവശ്യമാണ്.</translation> + </message> + <message> + <source>Unlock wallet</source> + <translation>വാലറ്റ് അൺലോക്ക് ചെയ്യുക</translation> + </message> + <message> + <source>This operation needs your wallet passphrase to decrypt the wallet.</source> + <translation>ഈ പ്രവർത്തനത്തിന് വാലറ്റ് ഡീക്രിപ്റ്റ് ചെയ്യുന്നതിന് നിങ്ങളുടെ വാലറ്റ് പാസ്ഫ്രെയ്സ് ആവശ്യമാണ്.</translation> + </message> + <message> + <source>Decrypt wallet</source> + <translation>വാലറ്റ് ഡീക്രിപ്റ്റ് ചെയ്യുക</translation> + </message> + <message> + <source>Change passphrase</source> + <translation>പാസ്ഫ്രെയ്സ് മാറ്റുക</translation> + </message> + <message> + <source>Enter the old passphrase and new passphrase to the wallet.</source> + <translation>പഴയ രഹസ്യപദപ്രയോഗം പുതിയ രഹസ്യപദപ്രയോഗം വാലറ്റിൽ നൽകുക.</translation> + </message> + <message> + <source>Confirm wallet encryption</source> + <translation>വാലറ്റ് എൻക്രിപ്ഷൻ സ്ഥിരീകരിക്കുക</translation> + </message> + <message> + <source>Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>!</source> + <translation>മുന്നറിയിപ്പ്: നിങ്ങളുടെ വാലറ്റ് എൻക്രിപ്റ്റ് ചെയ്ത് പാസ്ഫ്രെയ്സ് നഷ്ടപ്പെടുകയാണെങ്കിൽ, നിങ്ങളുടെ എല്ലാ ബിറ്റ്കൊയിനുകളും നഷ്ടപ്പെടും!</translation> + </message> + </context> +<context> + <name>BanTableModel</name> + </context> +<context> + <name>BitcoinGUI</name> + </context> +<context> + <name>CoinControlDialog</name> + <message> + <source>(no label)</source> + <translation>(ലേബൽ ഇല്ല)</translation> + </message> + </context> +<context> + <name>EditAddressDialog</name> + </context> +<context> + <name>FreespaceChecker</name> + </context> +<context> + <name>HelpMessageDialog</name> + </context> +<context> + <name>Intro</name> + </context> +<context> + <name>ModalOverlay</name> + </context> +<context> + <name>OpenURIDialog</name> + </context> +<context> + <name>OptionsDialog</name> + </context> +<context> + <name>OverviewPage</name> + </context> +<context> + <name>PaymentServer</name> + </context> +<context> + <name>PeerTableModel</name> + </context> +<context> + <name>QObject</name> + </context> +<context> + <name>QObject::QObject</name> + </context> +<context> + <name>QRImageWidget</name> + </context> +<context> + <name>RPCConsole</name> + </context> +<context> + <name>ReceiveCoinsDialog</name> + </context> +<context> + <name>ReceiveRequestDialog</name> + <message> + <source>Address</source> + <translation>വിലാസം</translation> + </message> + <message> + <source>Label</source> + <translation>ലേബൽ</translation> + </message> + </context> +<context> + <name>RecentRequestsTableModel</name> + <message> + <source>Label</source> + <translation>ലേബൽ</translation> + </message> + <message> + <source>(no label)</source> + <translation>(ലേബൽ ഇല്ല)</translation> + </message> + </context> +<context> + <name>SendCoinsDialog</name> + <message> + <source>(no label)</source> + <translation>(ലേബൽ ഇല്ല)</translation> + </message> +</context> +<context> + <name>SendCoinsEntry</name> + </context> +<context> + <name>SendConfirmationDialog</name> + </context> +<context> + <name>ShutdownWindow</name> + </context> +<context> + <name>SignVerifyMessageDialog</name> + </context> +<context> + <name>SplashScreen</name> + </context> +<context> + <name>TrafficGraphWidget</name> + </context> +<context> + <name>TransactionDesc</name> + </context> +<context> + <name>TransactionDescDialog</name> + </context> +<context> + <name>TransactionTableModel</name> + <message> + <source>Label</source> + <translation>ലേബൽ</translation> + </message> + <message> + <source>(no label)</source> + <translation>(ലേബൽ ഇല്ല)</translation> + </message> + </context> +<context> + <name>TransactionView</name> + <message> + <source>Comma separated file (*.csv)</source> + <translation>കോമയാൽ വേർതിരിച്ച ഫയൽ (* .csv)</translation> + </message> + <message> + <source>Label</source> + <translation>ലേബൽ</translation> + </message> + <message> + <source>Address</source> + <translation>വിലാസം</translation> + </message> + <message> + <source>Exporting Failed</source> + <translation>കയറ്റുമതി പരാജയപ്പെട്ടു</translation> + </message> + </context> +<context> + <name>UnitDisplayStatusBarControl</name> + </context> +<context> + <name>WalletFrame</name> + </context> +<context> + <name>WalletModel</name> + </context> +<context> + <name>WalletView</name> + <message> + <source>&Export</source> + <translation>& കയറ്റുമതി ചെയ്യുക</translation> + </message> + <message> + <source>Export the data in the current tab to a file</source> + <translation>നിലവിലെ ടാബിൽ ഒരു ഫയലിൽ ഡാറ്റ എക്സ്പോർട്ട് ചെയ്യുക</translation> + </message> + </context> +<context> + <name>bitcoin-core</name> + </context> +</TS>
\ No newline at end of file diff --git a/src/qt/locale/bitcoin_nl.ts b/src/qt/locale/bitcoin_nl.ts index b495eeaf51..152d89f878 100644 --- a/src/qt/locale/bitcoin_nl.ts +++ b/src/qt/locale/bitcoin_nl.ts @@ -3200,6 +3200,10 @@ Notitie: Omdat de vergoeding per byte wordt gerekend, zal een vergoeding van "10 <translation>Waarschuwing: Fout bij het lezen van %s! Alle sleutels zijn in goede orde uitgelezen, maar transactiedata of adresboeklemma's zouden kunnen ontbreken of fouten bevatten.</translation> </message> <message> + <source>Group outputs by address, selecting all or none, instead of selecting on a per-output basis. Privacy is improved as an address is only used once (unless someone sends to it after spending from it), but may result in slightly higher fees as suboptimal coin selection may result due to the added limitation (default: %u)</source> + <translation>Groepeer outputs per adres, alles of niets selecterend, in plaats van per output. Privacy wordt verbeterd omdat een adres slechts één keer wordt gebruikt (tenzij iemand ernaar stuurt na ermee te betalen), maar kan resulteren in iets hogere fees, als gevolg van suboptimale coin selectie ten gevolge van de toegevoegde beperking (standaard: %u)</translation> + </message> + <message> <source>Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly.</source> <translation>Waarschuwing: Controleer dat de datum en tijd van uw computer correct zijn ingesteld! Bij een onjuist ingestelde klok zal %s niet goed werken.</translation> </message> @@ -3340,6 +3344,10 @@ Notitie: Omdat de vergoeding per byte wordt gerekend, zal een vergoeding van "10 <translation>Ongeldig bedrag voor -fallbackfee=<bedrag>: '%s'</translation> </message> <message> + <source>Specified blocks directory "%s" does not exist.</source> + <translation>Opgegeven blocks map "%s" bestaat niet.</translation> + </message> + <message> <source>Upgrading txindex database</source> <translation>Upgraden txindex database</translation> </message> @@ -3492,12 +3500,6 @@ Notitie: Omdat de vergoeding per byte wordt gerekend, zal een vergoeding van "10 <translation>Opgegeven -walletdir "%s" is geen map</translation> </message> <message> - <source>Specified blocks directory "%s" does not exist. -</source> - <translation>Opgegeven blocks map "%s" bestaat niet. -</translation> - </message> - <message> <source>The transaction amount is too small to pay the fee</source> <translation>Het transactiebedrag is te klein om transactiekosten in rekening te brengen</translation> </message> diff --git a/src/qt/locale/bitcoin_pl.ts b/src/qt/locale/bitcoin_pl.ts index 0026841975..03474f4df5 100644 --- a/src/qt/locale/bitcoin_pl.ts +++ b/src/qt/locale/bitcoin_pl.ts @@ -3342,6 +3342,11 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw <translation>Nieprawidłowa kwota dla -fallbackfee=<amount>: '%s'</translation> </message> <message> + <source>Specified blocks directory "%s" does not exist.</source> + <translation>Podany folder bloków "%s" nie istnieje. +</translation> + </message> + <message> <source>Upgrading txindex database</source> <translation>Aktualizowanie bazy txindex</translation> </message> @@ -3494,12 +3499,6 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw <translation>Podany -walletdir "%s" nie jest katalogiem</translation> </message> <message> - <source>Specified blocks directory "%s" does not exist. -</source> - <translation>Podany folder bloków "%s" nie istnieje. -</translation> - </message> - <message> <source>The transaction amount is too small to pay the fee</source> <translation>Zbyt niska kwota transakcji by zapłacić opłatę</translation> </message> diff --git a/src/qt/locale/bitcoin_pt_BR.ts b/src/qt/locale/bitcoin_pt_BR.ts index 3877fee25d..9fa0f88ac3 100644 --- a/src/qt/locale/bitcoin_pt_BR.ts +++ b/src/qt/locale/bitcoin_pt_BR.ts @@ -3,7 +3,7 @@ <name>AddressBookPage</name> <message> <source>Right-click to edit address or label</source> - <translation>Clique com o botão direito para editar o endereço ou rótulo</translation> + <translation>Clique com o botão direito para editar o endereço ou rótulo </translation> </message> <message> <source>Create a new address</source> @@ -3336,6 +3336,11 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kB" por <translation>Quantidade inválida para -fallbackfee=<amount>: '%s'</translation> </message> <message> + <source>Specified blocks directory "%s" does not exist.</source> + <translation> +Diretório de blocos especificados "%s" não existe.</translation> + </message> + <message> <source>Upgrading txindex database</source> <translation>Atualizando banco de dados txindex</translation> </message> @@ -3488,12 +3493,6 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kB" por <translation>O -walletdir "%s" especificado não é um diretório</translation> </message> <message> - <source>Specified blocks directory "%s" does not exist. -</source> - <translation>O diretório de blocos especificado "%s" não existe. -</translation> - </message> - <message> <source>The transaction amount is too small to pay the fee</source> <translation>A quantidade da transação é pequena demais para pagar a taxa</translation> </message> diff --git a/src/qt/locale/bitcoin_pt_PT.ts b/src/qt/locale/bitcoin_pt_PT.ts index 48068409be..d203c490e9 100644 --- a/src/qt/locale/bitcoin_pt_PT.ts +++ b/src/qt/locale/bitcoin_pt_PT.ts @@ -71,7 +71,7 @@ </message> <message> <source>These are your Bitcoin addresses for receiving payments. It is recommended to use a new receiving address for each transaction.</source> - <translation>Estes são os seus endereços Bitcoin para receber pagamentos. É recomendado que utilize um endereço novo para cada transacção.</translation> + <translation>Estes são os seus endereços Bitcoin para receber pagamentos. É recomendado que utilize um endereço novo para cada transação.</translation> </message> <message> <source>&Copy Address</source> @@ -189,7 +189,7 @@ </message> <message> <source>%1 will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source> - <translation>%1 irá agora ser fechado para terminar o processo de encriptação. Recorde que a encriptação da sua carteira não protegerá totalmente os seus bitcoins de serem roubados por programas maliciosos que infectem o seu computador.</translation> + <translation>%1 irá agora ser fechado para terminar o processo de encriptação. Recorde que a encriptação da sua carteira não protegerá totalmente os seus bitcoins de serem roubados por programas maliciosos que infetem o seu computador.</translation> </message> <message> <source>IMPORTANT: Any previous backups you have made of your wallet file should be replaced with the newly generated, encrypted wallet file. For security reasons, previous backups of the unencrypted wallet file will become useless as soon as you start using the new, encrypted wallet.</source> @@ -780,7 +780,7 @@ <name>FreespaceChecker</name> <message> <source>A new data directory will be created.</source> - <translation>Será criada uma nova diretoria de dados.</translation> + <translation>Será criada uma nova pasta de dados.</translation> </message> <message> <source>name</source> @@ -792,11 +792,11 @@ </message> <message> <source>Path already exists, and is not a directory.</source> - <translation>O caminho já existe, e este não é uma pasta.</translation> + <translation>O caminho já existe, e não é uma pasta.</translation> </message> <message> <source>Cannot create data directory here.</source> - <translation>Não é possível criar aqui uma diretoria de dados.</translation> + <translation>Não é possível criar aqui uma pasta de dados.</translation> </message> </context> <context> @@ -854,11 +854,11 @@ </message> <message> <source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source> - <translation>No mínimo %1 GB de dados irão ser armazenados neste diretório. </translation> + <translation>No mínimo %1 GB de dados irão ser armazenados nesta pasta. </translation> </message> <message> <source>Approximately %1 GB of data will be stored in this directory.</source> - <translation>Aproximadamente %1 GB de dados irão ser guardados nesta directoria. </translation> + <translation>Aproximadamente %1 GB de dados irão ser guardados nesta pasta. </translation> </message> <message> <source>%1 will download and store a copy of the Bitcoin block chain.</source> @@ -866,7 +866,7 @@ </message> <message> <source>The wallet will also be stored in this directory.</source> - <translation>A carteira também será guardada nesta directoria.</translation> + <translation>A carteira também será guardada nesta pasta.</translation> </message> <message> <source>Error: Specified data directory "%1" cannot be created.</source> @@ -1024,7 +1024,7 @@ </message> <message> <source>Open the %1 configuration file from the working directory.</source> - <translation>Abrir o ficheiro de configuração %1 da directoria aberta.</translation> + <translation>Abrir o ficheiro de configuração %1 da pasta aberta.</translation> </message> <message> <source>Open Configuration File</source> @@ -1100,11 +1100,11 @@ </message> <message> <source>&Port:</source> - <translation>&Porto:</translation> + <translation>&Porta:</translation> </message> <message> <source>Port of the proxy (e.g. 9050)</source> - <translation>Porto do proxy (p.ex. 9050)</translation> + <translation>Porta do proxy (por ex. 9050)</translation> </message> <message> <source>Used for reaching peers via:</source> @@ -1235,7 +1235,7 @@ </message> <message> <source>Watch-only:</source> - <translation>Modo-verificação:</translation> + <translation>Apenas vigiar:</translation> </message> <message> <source>Available:</source> @@ -1263,7 +1263,7 @@ </message> <message> <source>Balances</source> - <translation>Balanços</translation> + <translation>Saldos</translation> </message> <message> <source>Total:</source> @@ -1271,11 +1271,11 @@ </message> <message> <source>Your current total balance</source> - <translation>O seu saldo total actual</translation> + <translation>O seu saldo total atual</translation> </message> <message> <source>Your current balance in watch-only addresses</source> - <translation>O seu balanço atual em endereços de apenas observação</translation> + <translation>O seu balanço atual em endereços de apenas vigiar</translation> </message> <message> <source>Spendable:</source> @@ -1287,15 +1287,15 @@ </message> <message> <source>Unconfirmed transactions to watch-only addresses</source> - <translation>Transações não confirmadas para endereços modo-verificação</translation> + <translation>Transações não confirmadas para endereços de apenas vigiar</translation> </message> <message> <source>Mined balance in watch-only addresses that has not yet matured</source> - <translation>Saldo minado ainda não disponivél de endereços modo-verificação</translation> + <translation>Saldo minado ainda não disponível de endereços de apenas vigiar</translation> </message> <message> <source>Current total balance in watch-only addresses</source> - <translation>Saldo disponivél em enderços modo-verificação</translation> + <translation>Saldo disponível em endereços de apenas vigiar</translation> </message> </context> <context> @@ -1326,7 +1326,7 @@ </message> <message> <source>URI cannot be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters.</source> - <translation>URI não foi lido correctamente! Isto pode ser causado por um endereço Bitcoin inválido ou por parâmetros URI malformados.</translation> + <translation>URI não foi lido corretamente! Isto pode ser causado por um endereço Bitcoin inválido ou por parâmetros URI malformados.</translation> </message> <message> <source>Payment request file handling</source> @@ -1428,7 +1428,7 @@ </message> <message> <source>Enter a Bitcoin address (e.g. %1)</source> - <translation>Entre um endereço Bitcoin (ex. %1)</translation> + <translation>Introduza um endereço Bitcoin (ex. %1)</translation> </message> <message> <source>%1 d</source> @@ -1519,7 +1519,7 @@ </message> <message> <source>Error: Specified data directory "%1" does not exist.</source> - <translation>Erro: Pasta de dados especificada "%1" não existe.</translation> + <translation>Erro: a pasta de dados especificada "%1" não existe.</translation> </message> <message> <source>Error: Cannot parse configuration file: %1.</source> @@ -1601,7 +1601,7 @@ </message> <message> <source>Current number of blocks</source> - <translation>Número actual de blocos</translation> + <translation>Número atual de blocos</translation> </message> <message> <source>Memory Pool</source> @@ -1609,7 +1609,7 @@ </message> <message> <source>Current number of transactions</source> - <translation>Número actual de transacções</translation> + <translation>Número atual de transações</translation> </message> <message> <source>Memory usage</source> @@ -1653,7 +1653,7 @@ </message> <message> <source>Direction</source> - <translation>Direcção</translation> + <translation>Direção</translation> </message> <message> <source>Version</source> @@ -1677,7 +1677,7 @@ </message> <message> <source>Open the %1 debug log file from the current data directory. This can take a few seconds for large log files.</source> - <translation>Abrir o ficheiro de registo de depuração %1 da pasta de dados actual. Isto pode demorar alguns segundos para ficheiros de registo maiores.</translation> + <translation>Abrir o ficheiro de registo de depuração %1 da pasta de dados atual. Isto pode demorar alguns segundos para ficheiros de registo maiores.</translation> </message> <message> <source>Decrease font size</source> @@ -1701,11 +1701,11 @@ </message> <message> <source>Last Send</source> - <translation>Ultimo Envio</translation> + <translation>Último Envio</translation> </message> <message> <source>Last Receive</source> - <translation>Ultimo Recebimento</translation> + <translation>Último Recebimento</translation> </message> <message> <source>Ping Time</source> @@ -1809,7 +1809,7 @@ </message> <message> <source>WARNING: Scammers have been active, telling users to type commands here, stealing their wallet contents. Do not use this console without fully understanding the ramifications of a command.</source> - <translation>AVISO: Burlões têm estado activos, dizendo a utilizadores para digitar comandos aqui, roubando assim os conteúdos das suas carteiras. Não utilize esta consola sem perceber perfeitamente as ramificações de um comando.</translation> + <translation>AVISO: alguns burlões têm estado ativos, dizendo a utilizadores para digitarem comandos aqui, roubando assim os conteúdos das suas carteiras. Não utilize esta consola sem perceber perfeitamente as ramificações de um comando.</translation> </message> <message> <source>Network activity disabled</source> @@ -1896,7 +1896,7 @@ </message> <message> <source>Native segwit addresses (aka Bech32 or BIP-173) reduce your transaction fees later on and offer better protection against typos, but old wallets don't support them. When unchecked, an address compatible with older wallets will be created instead.</source> - <translation>Endereços nativos SegWit (também conhecidos como Bech32 ou BIP-173) reduzem as taxas da sua transação mais tarde e oferecem melhor protecção contra erros, mas carteiras antigas não os suportam. Quando não selecionado, um endereço compatível com carteiras antigas irá ser criado em vez.</translation> + <translation>Endereços nativos SegWit (também conhecidos como Bech32 ou BIP-173) reduzem as taxas da sua transação mais tarde e oferecem melhor proteção contra erros, mas carteiras antigas não os suportam. Quando não selecionado, um endereço compatível com carteiras antigas irá ser criado em vez.</translation> </message> <message> <source>Generate native segwit (Bech32) address</source> @@ -1912,7 +1912,7 @@ </message> <message> <source>Show the selected request (does the same as double clicking an entry)</source> - <translation>Mostrar o pedido seleccionado (faz o mesmo que clicar 2 vezes numa entrada)</translation> + <translation>Mostrar o pedido selecionado (faz o mesmo que clicar 2 vezes numa entrada)</translation> </message> <message> <source>Show</source> @@ -1920,7 +1920,7 @@ </message> <message> <source>Remove the selected entries from the list</source> - <translation>Remover as entradas seleccionadas da lista</translation> + <translation>Remover as entradas selecionadas da lista</translation> </message> <message> <source>Remove</source> @@ -2113,7 +2113,7 @@ </message> <message> <source>Paying only the minimum fee is just fine as long as there is less transaction volume than space in the blocks. But be aware that this can end up in a never confirming transaction once there is more demand for bitcoin transactions than the network can process.</source> - <translation>Pode pagar somente a taxa minima desde que haja um volume de transações inferior ao espaço nos blocos. No entanto tenha em atenção que esta opção poderá acabar em uma transação nunca confirmada assim que os pedidos de transações excedam a capacidade de processamento da rede.</translation> + <translation>Pode pagar somente a taxa mínima desde que haja um volume de transações inferior ao espaço nos blocos. No entanto tenha em atenção que esta opção poderá acabar em uma transação nunca confirmada assim que os pedidos de transações excedam a capacidade de processamento da rede.</translation> </message> <message> <source>(read the tooltip)</source> @@ -2125,7 +2125,7 @@ </message> <message> <source>Custom:</source> - <translation>Uso:</translation> + <translation>Personalizado:</translation> </message> <message> <source>(Smart fee not initialized yet. This usually takes a few blocks...)</source> @@ -2442,7 +2442,7 @@ </message> <message> <source>Copy the current signature to the system clipboard</source> - <translation>Copiar a assinatura actual para a área de transferência</translation> + <translation>Copiar a assinatura atual para a área de transferência</translation> </message> <message> <source>Sign the message to prove you own this Bitcoin address</source> @@ -2466,7 +2466,7 @@ </message> <message> <source>Enter the receiver's address, message (ensure you copy line breaks, spaces, tabs, etc. exactly) and signature below to verify the message. Be careful not to read more into the signature than what is in the signed message itself, to avoid being tricked by a man-in-the-middle attack. Note that this only proves the signing party receives with the address, it cannot prove sendership of any transaction!</source> - <translation>Introduza o endereço de assinatura, mensagem (assegure-se que copia quebras de linha, espaços, tabulações, etc. exactamente) e assinatura abaixo para verificar a mensagem. Tenha atenção para não ler mais na assinatura do que o que estiver na mensagem assinada, para evitar ser enganado por um atacante que se encontre entre si e quem assinou a mensagem.</translation> + <translation>Introduza o endereço de assinatura, mensagem (assegure-se que copia quebras de linha, espaços, tabulações, etc. exatamente) e assinatura abaixo para verificar a mensagem. Tenha atenção para não ler mais na assinatura do que o que estiver na mensagem assinada, para evitar ser enganado por um atacante que se encontre entre si e quem assinou a mensagem.</translation> </message> <message> <source>The Bitcoin address the message was signed with</source> @@ -2615,7 +2615,7 @@ </message> <message> <source>watch-only</source> - <translation>vigiar apenas</translation> + <translation>apenas vigiar</translation> </message> <message> <source>label</source> @@ -2793,7 +2793,7 @@ </message> <message> <source>watch-only</source> - <translation>vigiar apenas</translation> + <translation>apenas vigiar</translation> </message> <message> <source>(n/a)</source> @@ -2817,7 +2817,7 @@ </message> <message> <source>Whether or not a watch-only address is involved in this transaction.</source> - <translation>Se um endereço de monitoração está ou não envolvido nesta transação.</translation> + <translation>Se um endereço de apenas vigiar está ou não envolvido nesta transação.</translation> </message> <message> <source>User-defined intent/purpose of the transaction.</source> @@ -2940,7 +2940,7 @@ </message> <message> <source>Watch-only</source> - <translation>Vigiar apenas</translation> + <translation>Apenas vigiar</translation> </message> <message> <source>Date</source> @@ -3118,6 +3118,10 @@ <translation>Os programadores de %s</translation> </message> <message> + <source>Cannot obtain a lock on data directory %s. %s is probably already running.</source> + <translation>Não foi possível obter o bloqueio de escrita no da pasta de dados %s. %s provavelmente já está a ser executado.</translation> + </message> + <message> <source>Cannot provide specific connections and have addrman find outgoing connections at the same.</source> <translation>Não é possível fornecer conexões específicas e ter o addrman a procurar conexões de saída ao mesmo tempo.</translation> </message> @@ -3131,7 +3135,7 @@ </message> <message> <source>The block database contains a block which appears to be from the future. This may be due to your computer's date and time being set incorrectly. Only rebuild the block database if you are sure that your computer's date and time are correct</source> - <translation>A base de dados de blocos contém um bloco que aparenta ser do futuro. Isto pode ser causado por uma data incorrecta definida no seu computador. Reconstrua apenas a base de dados de blocos caso tenha a certeza de que a data e hora do seu computador estão correctos.</translation> + <translation>A base de dados de blocos contém um bloco que aparenta ser do futuro. Isto pode ser causado por uma data incorreta definida no seu computador. Reconstrua apenas a base de dados de blocos caso tenha a certeza de que a data e hora do seu computador estão corretos.</translation> </message> <message> <source>This is the transaction fee you may discard if change is smaller than dust at this level</source> @@ -3167,7 +3171,7 @@ </message> <message> <source>Corrupted block database detected</source> - <translation>Cadeia de blocos corrompida detectada</translation> + <translation>Detetada cadeia de blocos corrompida</translation> </message> <message> <source>Do you want to rebuild the block database now?</source> @@ -3234,6 +3238,11 @@ <translation>Valor inválido para -fallbackfee=<amount>: '%s'</translation> </message> <message> + <source>Specified blocks directory "%s" does not exist.</source> + <translation> +A pasta de blocos especificados "%s" não existe.</translation> + </message> + <message> <source>Loading P2P addresses...</source> <translation>A carregar endereços de P2P...</translation> </message> @@ -3307,7 +3316,7 @@ </message> <message> <source>The transaction amount is too small to send after the fee has been deducted</source> - <translation>O montante da transacção é demasiado baixo após a dedução da taxa</translation> + <translation>O montante da transação é demasiado baixo após a dedução da taxa</translation> </message> <message> <source>You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain</source> @@ -3346,8 +3355,12 @@ <translation>Falhou assinatura da transação</translation> </message> <message> + <source>Specified -walletdir "%s" is not a directory</source> + <translation>O -walletdir "%s" especificado não é uma pasta</translation> + </message> + <message> <source>The transaction amount is too small to pay the fee</source> - <translation>O montante da transacção é demasiado baixo para pagar a taxa</translation> + <translation>O montante da transação é demasiado baixo para pagar a taxa</translation> </message> <message> <source>This is experimental software.</source> @@ -3359,7 +3372,7 @@ </message> <message> <source>Transaction too large for fee policy</source> - <translation>Transacção demasiado grande para a política de taxas</translation> + <translation>Transação demasiado grande para a política de taxas</translation> </message> <message> <source>Transaction too large</source> @@ -3378,6 +3391,10 @@ <translation>A verificar a(s) carteira(s)...</translation> </message> <message> + <source>Wallet %s resides outside wallet directory %s</source> + <translation>A carteira %s reside fora da pasta da carteira %s</translation> + </message> + <message> <source>Warning</source> <translation>Aviso</translation> </message> @@ -3391,7 +3408,7 @@ </message> <message> <source>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source> - <translation>-maxtxfee está definido com um valor muito alto! Taxas desta magnitude podem ser pagas numa única transacção.</translation> + <translation>-maxtxfee está definido com um valor muito alto! Taxas desta magnitude podem ser pagas numa única transação.</translation> </message> <message> <source>This is the transaction fee you may pay when fee estimates are not available.</source> @@ -3454,6 +3471,10 @@ <translation>Fundos insuficientes</translation> </message> <message> + <source>Cannot write to data directory '%s'; check permissions.</source> + <translation>Não foi possível escrever na pasta de dados '%s': verifique as permissões.</translation> + </message> + <message> <source>Loading block index...</source> <translation>A carregar o índice de blocos...</translation> </message> diff --git a/src/qt/locale/bitcoin_ro.ts b/src/qt/locale/bitcoin_ro.ts index b5a478c611..bef83e831a 100644 --- a/src/qt/locale/bitcoin_ro.ts +++ b/src/qt/locale/bitcoin_ro.ts @@ -501,6 +501,10 @@ <translation>Schimbă:</translation> </message> <message> + <source>(un)select all</source> + <translation>(de)selectează tot</translation> + </message> + <message> <source>Tree mode</source> <translation>Mod arbore</translation> </message> diff --git a/src/qt/locale/bitcoin_ro_RO.ts b/src/qt/locale/bitcoin_ro_RO.ts index 3ca1878067..e5b17cfbad 100644 --- a/src/qt/locale/bitcoin_ro_RO.ts +++ b/src/qt/locale/bitcoin_ro_RO.ts @@ -23,7 +23,7 @@ </message> <message> <source>C&lose</source> - <translation>Închide</translation> + <translation>Î&nchide</translation> </message> <message> <source>Delete the currently selected address from the list</source> @@ -326,6 +326,14 @@ <translation>Deschide &URI...</translation> </message> <message> + <source>Wallet:</source> + <translation>Portofel:</translation> + </message> + <message> + <source>default wallet</source> + <translation>portofel implicit</translation> + </message> + <message> <source>Click to disable network activity.</source> <translation>Click pentru a opri activitatea retelei.</translation> </message> @@ -346,6 +354,10 @@ <translation>Se reindexează blocurile pe disc...</translation> </message> <message> + <source>Proxy is <b>enabled</b>: %1</source> + <translation>Proxy este<b>activat</b>:%1</translation> + </message> + <message> <source>Send coins to a Bitcoin address</source> <translation>Trimite monede către o adresă Bitcoin</translation> </message> @@ -514,6 +526,12 @@ </translation> </message> <message> + <source>Wallet: %1 +</source> + <translation>Portofel: %1 +</translation> + </message> + <message> <source>Type: %1 </source> <translation>Tip: %1 @@ -746,6 +764,14 @@ <translation>Adresa introdusă "%1" nu este o adresă Bitcoin validă.</translation> </message> <message> + <source>Address "%1" already exists as a receiving address with label "%2" and so cannot be added as a sending address.</source> + <translation>Adresa "%1" exista deja ca si adresa de primire cu eticheta "%2" si deci nu poate fi folosita ca si adresa de trimitere.</translation> + </message> + <message> + <source>The entered address "%1" is already in the address book with label "%2".</source> + <translation>Adresa introdusa "%1" este deja in lista de adrese cu eticheta "%2"</translation> + </message> + <message> <source>Could not unlock wallet.</source> <translation>Portofelul nu a putut fi deblocat.</translation> </message> @@ -1024,6 +1050,22 @@ <translation>Reţea</translation> </message> <message> + <source>Disables some advanced features but all blocks will still be fully validated. Reverting this setting requires re-downloading the entire blockchain. Actual disk usage may be somewhat higher.</source> + <translation>Dezactiveaza unele caracteristici avansate insa toate blocurile vor fi validate pe deplin. Inversarea acestei setari necesita re-descarcarea intregului blockchain. Utilizarea reala a discului poate fi ceva mai mare.</translation> + </message> + <message> + <source>Prune &block storage to</source> + <translation>Reductie &block storage la </translation> + </message> + <message> + <source>GB</source> + <translation>GB</translation> + </message> + <message> + <source>Reverting this setting requires re-downloading the entire blockchain.</source> + <translation> Inversarea acestei setari necesita re-descarcarea intregului blockchain.</translation> + </message> + <message> <source>(0 = auto, <0 = leave that many cores free)</source> <translation>(0 = automat, <0 = lasă atîtea nuclee libere)</translation> </message> @@ -1290,6 +1332,10 @@ <translation>Gestionare URI</translation> </message> <message> + <source>'bitcoin://' is not a valid URI. Use 'bitcoin:' instead.</source> + <translation>'bitcoin://' nu este un URI valid. Folositi 'bitcoin:' in loc.</translation> + </message> + <message> <source>Payment request fetch URL is invalid: %1</source> <translation>URL-ul cererii de plată preluat nu este valid: %1</translation> </message> @@ -1487,10 +1533,18 @@ <context> <name>QObject::QObject</name> <message> + <source>Error parsing command line arguments: %1.</source> + <translation>Eroare la analiza argumentelor linie de comanda: %1</translation> + </message> + <message> <source>Error: Specified data directory "%1" does not exist.</source> <translation>Eroare: Directorul de date specificat "%1" nu există.</translation> </message> <message> + <source>Error: Cannot parse configuration file: %1.</source> + <translation>Eroare: Nu se poate analiza fişierul de configuraţie: %1.</translation> + </message> + <message> <source>Error: %1</source> <translation>Eroare: %1</translation> </message> @@ -1581,6 +1635,14 @@ <translation>Memorie folosită</translation> </message> <message> + <source>Wallet: </source> + <translation>Portofel:</translation> + </message> + <message> + <source>(none)</source> + <translation>(nimic)</translation> + </message> + <message> <source>&Reset</source> <translation>&Resetare</translation> </message> @@ -1749,6 +1811,10 @@ <translation>&Unban</translation> </message> <message> + <source>default wallet</source> + <translation>portofel implicit</translation> + </message> + <message> <source>Welcome to the %1 RPC console.</source> <translation>Bun venit la consola %1 RPC.</translation> </message> @@ -1773,6 +1839,14 @@ <translation>Activitatea retelei a fost oprita.</translation> </message> <message> + <source>Executing command without any wallet</source> + <translation>Executarea comenzii fara nici un portofel.</translation> + </message> + <message> + <source>Executing command using "%1" wallet</source> + <translation>Executarea comenzii folosind portofelul "%1"</translation> + </message> + <message> <source>(node id: %1)</source> <translation>(node id: %1)</translation> </message> @@ -2057,6 +2131,14 @@ <translation>inchide setarile de taxare</translation> </message> <message> + <source>Specify a custom fee per kB (1,000 bytes) of the transaction's virtual size. + +Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis per kB" for a transaction size of 500 bytes (half of 1 kB) would ultimately yield a fee of only 50 satoshis.</source> + <translation>Specificati o taxa anume pe kB (1000 byte) din marimea virtuala a tranzactiei. + +Nota: Cum taxa este calculata per byte, o taxa de "100 satoshi per kB" pentru o tranzactie de 500 byte (jumatate de kB) va produce o taxa de doar 50 satoshi.</translation> + </message> + <message> <source>per kilobyte</source> <translation>per kilooctet</translation> </message> @@ -2177,6 +2259,14 @@ <translation>Puteti creste taxa mai tarziu (semnaleaza Replace-By-Fee, BIP-125).</translation> </message> <message> + <source>from wallet %1</source> + <translation>de la portofelul %1</translation> + </message> + <message> + <source>Please, review your transaction.</source> + <translation>Va rugam sa revizuiti tranzactia.</translation> + </message> + <message> <source>Transaction fee</source> <translation>Taxă tranzacţie</translation> </message> @@ -2185,6 +2275,10 @@ <translation>Nu se semnalizeaza Replace-By-Fee, BIP-125</translation> </message> <message> + <source>Total Amount</source> + <translation>Suma totală</translation> + </message> + <message> <source>Confirm send coins</source> <translation>Confirmă trimiterea monedelor</translation> </message> @@ -2638,6 +2732,10 @@ <translation>Dimensiune totala tranzacţie</translation> </message> <message> + <source>Transaction virtual size</source> + <translation>Dimensiune virtuala a tranzactiei</translation> + </message> + <message> <source>Output index</source> <translation>Index debit</translation> </message> @@ -3038,7 +3136,11 @@ <source>The wallet data was successfully saved to %1.</source> <translation>Datele portofelului s-au salvat cu succes la %1.</translation> </message> - </context> + <message> + <source>Cancel</source> + <translation>Anulare</translation> + </message> +</context> <context> <name>bitcoin-core</name> <message> @@ -3090,6 +3192,10 @@ <translation>Eroare la citirea %s! Toate cheile sînt citite corect, dar datele tranzactiei sau anumite intrări din agenda sînt incorecte sau lipsesc.</translation> </message> <message> + <source>Group outputs by address, selecting all or none, instead of selecting on a per-output basis. Privacy is improved as an address is only used once (unless someone sends to it after spending from it), but may result in slightly higher fees as suboptimal coin selection may result due to the added limitation (default: %u)</source> + <translation>Gruparea a iesirilor pe adrese, selectand totul sau nimic, in loc de selectarea bazata per-iesire. Intimitatea este imbunatatita deoarece o adresa este folosita doar o singura data (cu exceptia cuiva care trimite catre aceiasi adresa dup ce cheltuie din ea), dar se pot genera taxe mai mari deoarece poate rezulta o selectare suboptimala a monedelor datorata limitarii impuse (implicit: %u)</translation> + </message> + <message> <source>Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly.</source> <translation>Vă rugăm verificaţi dacă data/timpul calculatorului dvs. sînt corecte! Dacă ceasul calcultorului este gresit, %s nu va funcţiona corect.</translation> </message> @@ -3174,6 +3280,10 @@ <translation>Eroare la încărcarea %s</translation> </message> <message> + <source>Error loading %s: Private keys can only be disabled during creation</source> + <translation>Eroare la incarcarea %s: Cheile private pot fi dezactivate doar in momentul crearii</translation> + </message> + <message> <source>Error loading %s: Wallet corrupted</source> <translation>Eroare la încărcarea %s: Portofel corupt</translation> </message> @@ -3226,6 +3336,14 @@ <translation>Suma nevalidă pentru -fallbackfee=<amount>: '%s'</translation> </message> <message> + <source>Specified blocks directory "%s" does not exist.</source> + <translation>Directorul de blocuri "%s" specificat nu exista.</translation> + </message> + <message> + <source>Upgrading txindex database</source> + <translation>Actualizarea bazei de date txindex</translation> + </message> + <message> <source>Loading P2P addresses...</source> <translation>Încărcare adrese P2P...</translation> </message> @@ -3266,6 +3384,10 @@ <translation>Nu se poate efectua legatura la %s pe acest computer. %s probabil ruleaza deja.</translation> </message> <message> + <source>Unable to generate keys</source> + <translation>Nu s-au putut genera cheile</translation> + </message> + <message> <source>Unsupported argument -benchmark ignored, use -debug=bench.</source> <translation>Argumentul nesuportat -benchmark este ignorat, folositi debug=bench.</translation> </message> @@ -3494,6 +3616,22 @@ <translation>Fonduri insuficiente</translation> </message> <message> + <source>Can't generate a change-address key. Private keys are disabled for this wallet.</source> + <translation>Nu se poate genera o adresa pentru rest. Cheile private sunt dezactivate pentru acest portofel.</translation> + </message> + <message> + <source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source> + <translation>Estimarea taxei a esuat. Taxa implicita este dezactivata. Asteptati cateva blocuri, sau activati -fallbackfee.</translation> + </message> + <message> + <source>Warning: Private keys detected in wallet {%s} with disabled private keys</source> + <translation>Atentie: S-au detectat chei private in portofelul {%s} cu cheile private dezactivate</translation> + </message> + <message> + <source>Cannot write to data directory '%s'; check permissions.</source> + <translation>Nu se poate scrie in directorul de date '%s"; verificati permisiunile.</translation> + </message> + <message> <source>Loading block index...</source> <translation>Încărcare index bloc...</translation> </message> @@ -3518,4 +3656,4 @@ <translation>Eroare</translation> </message> </context> -</TS>
\ No newline at end of file +</TS> diff --git a/src/qt/locale/bitcoin_ru.ts b/src/qt/locale/bitcoin_ru.ts index 0cbee61fc5..9c81fe9cdb 100644 --- a/src/qt/locale/bitcoin_ru.ts +++ b/src/qt/locale/bitcoin_ru.ts @@ -337,6 +337,10 @@ </context> <context> <name>ReceiveCoinsDialog</name> + <message> + <source>Clear</source> + <translation>Очистить</translation> + </message> </context> <context> <name>ReceiveRequestDialog</name> diff --git a/src/qt/locale/bitcoin_ru_RU.ts b/src/qt/locale/bitcoin_ru_RU.ts index ea30f39969..430f2e4191 100644 --- a/src/qt/locale/bitcoin_ru_RU.ts +++ b/src/qt/locale/bitcoin_ru_RU.ts @@ -15,7 +15,7 @@ </message> <message> <source>Copy the currently selected address to the system clipboard</source> - <translation>Скопировать текущий выбранный адрес в буфер обмена системы</translation> + <translation>Скопировать выбранный адрес в буфер обмена</translation> </message> <message> <source>&Copy</source> @@ -55,7 +55,7 @@ </message> <message> <source>C&hoose</source> - <translation>В&ыбрать</translation> + <translation>Выбрать</translation> </message> <message> <source>Sending addresses</source> @@ -67,11 +67,11 @@ </message> <message> <source>These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins.</source> - <translation>Это ваши биткойн адреса для отправки платежа. Всегда проверяйте сумму и адрес получателя перед отправкой платежа.</translation> + <translation>Это ваши Bitcoin адреса для отправки платежа. Всегда проверяйте сумму и адрес получателя перед отправкой платежа.</translation> </message> <message> <source>These are your Bitcoin addresses for receiving payments. It is recommended to use a new receiving address for each transaction.</source> - <translation>Это ваши биткойн адреса для получения платежей. Настоятельно рекомендуем использовать новые адреса для получения каждой транзакции.</translation> + <translation>Это ваши Bitcoin адреса для получения платежей. Настоятельно рекомендуем использовать новые адреса для получения каждой транзакции.</translation> </message> <message> <source>&Copy Address</source> @@ -137,19 +137,19 @@ </message> <message> <source>Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>.</source> - <translation>Введите новый пароль для кошелька.<br/> Пожалуйста используйте пароль из <b> десяти или более произвольных символов</b>, или <b>восемь или боле слов</b></translation> + <translation>Введите новый пароль для кошелька.<br/> Пожалуйста используйте пароль из <b> десяти или более произвольных символов</b>, или <b>восемь или более слов</b></translation> </message> <message> <source>Encrypt wallet</source> - <translation>Зашифровать бумажник</translation> + <translation>Зашифровать кошелек</translation> </message> <message> <source>This operation needs your wallet passphrase to unlock the wallet.</source> - <translation>Эта операция требует вашего пароля для разблокировки бумажника</translation> + <translation>Эта операция требует вашего пароля для разблокировки кошелька</translation> </message> <message> <source>Unlock wallet</source> - <translation>Разблокировать бумажник</translation> + <translation>Разблокировать кошелек</translation> </message> <message> <source>This operation needs your wallet passphrase to decrypt the wallet.</source> @@ -157,7 +157,7 @@ </message> <message> <source>Decrypt wallet</source> - <translation>Расшифровать бумажник</translation> + <translation>Расшифровать кошелек</translation> </message> <message> <source>Change passphrase</source> @@ -165,11 +165,11 @@ </message> <message> <source>Enter the old passphrase and new passphrase to the wallet.</source> - <translation>Введите старый и новый пароль для кошелька.</translation> + <translation>Введите старый и новый пароль к кошельку.</translation> </message> <message> <source>Confirm wallet encryption</source> - <translation>Подтвердите шифрование бумажника</translation> + <translation>Подтвердите шифрование кошелька</translation> </message> <message> <source>Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>!</source> @@ -181,7 +181,7 @@ </message> <message> <source>Wallet encrypted</source> - <translation>Бумажник зашифрован</translation> + <translation>Кошелек зашифрован</translation> </message> <message> <source>%1 will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source> @@ -200,6 +200,10 @@ <translation>Шифрование кошелька завершилось неудачно из-за внутренней ошибки. Ваш кошелек не был зашифрован.</translation> </message> <message> + <source>The supplied passphrases do not match.</source> + <translation>Пароли не совпадают.</translation> + </message> + <message> <source>Wallet unlock failed</source> <translation>Ошибка разблокировки кошелька</translation> </message> @@ -251,7 +255,7 @@ </message> <message> <source>Show general overview of wallet</source> - <translation>Отобразить общий обзор кошелька</translation> + <translation>Отобразить главное окно кошелька</translation> </message> <message> <source>&Transactions</source> @@ -299,7 +303,7 @@ </message> <message> <source>&Backup Wallet...</source> - <translation>&Создать резервную копию бумажника</translation> + <translation>&Создать резервную копию кошелька</translation> </message> <message> <source>&Change Passphrase...</source> @@ -346,6 +350,10 @@ <translation>Реиндексация блоков на диске...</translation> </message> <message> + <source>Proxy is <b>enabled</b>: %1</source> + <translation>Прокси <b>включен</b>: %1</translation> + </message> + <message> <source>Send coins to a Bitcoin address</source> <translation>Послать средства на биткойн адрес</translation> </message> @@ -422,6 +430,10 @@ <translation>Панель вкладок</translation> </message> <message> + <source>Request payments (generates QR codes and bitcoin: URIs)</source> + <translation>Запросить платеж</translation> + </message> + <message> <source>Show the list of used sending addresses and labels</source> <translation>Показать список использованных адресов и меток получателей</translation> </message> @@ -437,6 +449,10 @@ <source>&Command-line options</source> <translation>Опции командной строки</translation> </message> + <message numerus="yes"> + <source>%n active connection(s) to Bitcoin network</source> + <translation><numerusform>%n активное подключение к сети Bitcoin</numerusform><numerusform>%n активных подключения к сети Bitcoin</numerusform><numerusform>%n активных подключений к сети Bitcoin</numerusform><numerusform>%n активных подключений к сети Bitcoin</numerusform></translation> + </message> <message> <source>Indexing blocks on disk...</source> <translation>Выполняется индексирование блоков на диске...</translation> @@ -445,6 +461,10 @@ <source>Processing blocks on disk...</source> <translation>Выполняется обработка блоков на диске...</translation> </message> + <message numerus="yes"> + <source>Processed %n block(s) of transaction history.</source> + <translation><numerusform>Обработан %n блок истории транзакций.</numerusform><numerusform>Обработано %n блока истории транзакций.</numerusform><numerusform>Обработано %n блоков истории транзакций.</numerusform><numerusform>Обработано %n блоков истории транзакций.</numerusform></translation> + </message> <message> <source>%1 behind</source> <translation>Выполнено %1</translation> @@ -573,6 +593,10 @@ <translation>Сдача:</translation> </message> <message> + <source>(un)select all</source> + <translation>Выбрать все</translation> + </message> + <message> <source>Tree mode</source> <translation>Режим дерева</translation> </message> @@ -696,10 +720,18 @@ <translation>Изменить адрес отправки</translation> </message> <message> + <source>The entered address "%1" is already in the address book with label "%2".</source> + <translation>Введённый адрес "%1" уже существует в адресной книге с меткой "%2".</translation> + </message> + <message> <source>Could not unlock wallet.</source> <translation>Невозможно разблокировать кошелек.</translation> </message> - </context> + <message> + <source>New key generation failed.</source> + <translation>Произошла ошибка при генерации нового ключа.</translation> + </message> +</context> <context> <name>FreespaceChecker</name> <message> @@ -711,6 +743,14 @@ <translation>имя</translation> </message> <message> + <source>Directory already exists. Add %1 if you intend to create a new directory here.</source> + <translation>Каталог уже существует. Добавьте %1, если хотите создать новую директорию здесь.</translation> + </message> + <message> + <source>Path already exists, and is not a directory.</source> + <translation>Данный путь уже существует и это не каталог.</translation> + </message> + <message> <source>Cannot create data directory here.</source> <translation>Невозможно создать директорию данных здесь.</translation> </message> @@ -741,6 +781,14 @@ <translation>Добро пожаловать в %1.</translation> </message> <message> + <source>As this is the first time the program is launched, you can choose where %1 will store its data.</source> + <translation>Поскольку программа запущена впервые, вы должны указать где %1 будет хранить данные.</translation> + </message> + <message> + <source>If you have chosen to limit block chain storage (pruning), the historical data must still be downloaded and processed, but will be deleted afterward to keep your disk usage low.</source> + <translation>Если вы указали сокращать объём хранимого блокчейна (pruning), все исторические данные все равно должны быть скачаны и обработаны, но впоследствии они будут удалены для экономии места на диске.</translation> + </message> + <message> <source>Use the default data directory</source> <translation>Использовать стандартную директорию данных</translation> </message> @@ -866,6 +914,10 @@ <translation>IP-адрес прокси-сервера (к примеру, IPv4: 127.0.0.1 / IPv6: ::1)</translation> </message> <message> + <source>Use separate SOCKS&5 proxy to reach peers via Tor hidden services:</source> + <translation>Использовать отдельные SOCKS&5 прокси для подключения к пирам через Tor hidden services:</translation> + </message> + <message> <source>Hide the icon from the system tray.</source> <translation>Убрать значок с области уведомлений.</translation> </message> @@ -890,10 +942,18 @@ <translation>&Сеть</translation> </message> <message> + <source>Prune &block storage to</source> + <translation>Сокращать объём хранимого блокчейна до</translation> + </message> + <message> <source>GB</source> <translation>ГБ</translation> </message> <message> + <source>Reverting this setting requires re-downloading the entire blockchain.</source> + <translation>Отмена этой настройки требует повторного скачивания всего блокчейна.</translation> + </message> + <message> <source>W&allet</source> <translation>К&ошелёк</translation> </message> @@ -902,6 +962,10 @@ <translation>Эксперт</translation> </message> <message> + <source>Enable coin &control features</source> + <translation>Включить возможность &управления монетами</translation> + </message> + <message> <source>&Spend unconfirmed change</source> <translation>&Тратить неподтвержденную сдачу</translation> </message> @@ -938,6 +1002,10 @@ <translation>Порт прокси: (напр. 9050)</translation> </message> <message> + <source>Used for reaching peers via:</source> + <translation>Используется для подключения к пирам по:</translation> + </message> + <message> <source>IPv4</source> <translation>IPv4</translation> </message> @@ -950,6 +1018,10 @@ <translation>Tor</translation> </message> <message> + <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services.</source> + <translation>Соединяться к Биткоин-сети через отдельные SOCKS5 прокси через Tor hidden services:</translation> + </message> + <message> <source>&Window</source> <translation>&Окно</translation> </message> @@ -958,6 +1030,10 @@ <translation>Отобразить только значок в области уведомлений после сворачивания окна.</translation> </message> <message> + <source>M&inimize on close</source> + <translation>З&акрыть при сворачивании</translation> + </message> + <message> <source>User Interface &language:</source> <translation>Язык пользовательского интерфейса:</translation> </message> @@ -1021,6 +1097,14 @@ <translation>Форма</translation> </message> <message> + <source>Watch-only:</source> + <translation>Только просмотр:</translation> + </message> + <message> + <source>Available:</source> + <translation>Доступно:</translation> + </message> + <message> <source>Your current spendable balance</source> <translation>Ваш доступный баланс</translation> </message> @@ -1064,6 +1148,10 @@ <translation>Ошибка запроса платежа</translation> </message> <message> + <source>'bitcoin://' is not a valid URI. Use 'bitcoin:' instead.</source> + <translation>'bitcoin://' не верный URI. Используйте 'bitcoin:' вместо этого.</translation> + </message> + <message> <source>Invalid payment address %1</source> <translation>Неверный адрес %1</translation> </message> @@ -1235,6 +1323,10 @@ <translation>Количество соединений</translation> </message> <message> + <source>Block chain</source> + <translation>Блокчейн</translation> + </message> + <message> <source>Current number of blocks</source> <translation>Текущее количество блоков</translation> </message> @@ -1275,6 +1367,10 @@ <translation>Заблокированные пиры</translation> </message> <message> + <source>Select a peer to view detailed information.</source> + <translation>Выберите пира для просмотра детальной информации.</translation> + </message> + <message> <source>Version</source> <translation>Версия</translation> </message> @@ -1406,6 +1502,14 @@ <translation>Отчистить</translation> </message> <message> + <source>Native segwit addresses (aka Bech32 or BIP-173) reduce your transaction fees later on and offer better protection against typos, but old wallets don't support them. When unchecked, an address compatible with older wallets will be created instead.</source> + <translation>"Родные" segwit адреса (Bech32 или BIP-173) в дальнейшем уменьшат комиссии ваших транзакций и предоставят улучшенную защиту от опечаток, однако старые кошельки не поддерживают эти адреса. Если не выбрано, будет создан совместимый со старыми кошелёк.</translation> + </message> + <message> + <source>Generate native segwit (Bech32) address</source> + <translation>Создать "родной" segwit (Bech32) адрес </translation> + </message> + <message> <source>Requested payments history</source> <translation>История платежных запросов</translation> </message> @@ -1639,6 +1743,10 @@ <translation>Баланс:</translation> </message> <message> + <source>Confirm the send action</source> + <translation>Подтвердить отправку</translation> + </message> + <message> <source>Copy quantity</source> <translation>Копировать количество</translation> </message> @@ -1707,6 +1815,14 @@ <translation>Истекло время ожидания запроса платежа</translation> </message> <message> + <source>Warning: Invalid Bitcoin address</source> + <translation>Предупреждение: Неверный Bitcoin адрес</translation> + </message> + <message> + <source>Warning: Unknown change address</source> + <translation>Предупреждение: Неизвестный адрес сдачи</translation> + </message> + <message> <source>(no label)</source> <translation>(нет метки)</translation> </message> @@ -2240,6 +2356,10 @@ <translation>Предупреждение</translation> </message> <message> + <source>Starting network threads...</source> + <translation>Запуск сетевых потоков...</translation> + </message> + <message> <source>This is the minimum transaction fee you pay on every transaction.</source> <translation>Это минимальная комиссия, которую вы платите для любой транзакции</translation> </message> diff --git a/src/qt/locale/bitcoin_sk.ts b/src/qt/locale/bitcoin_sk.ts index 86c5c8abda..89ed850da3 100644 --- a/src/qt/locale/bitcoin_sk.ts +++ b/src/qt/locale/bitcoin_sk.ts @@ -768,6 +768,14 @@ <translation>Vložená adresa "%1" nieje platnou adresou Bitcoin.</translation> </message> <message> + <source>Address "%1" already exists as a receiving address with label "%2" and so cannot be added as a sending address.</source> + <translation>Adresa "%1" už existuje ako prijímacia adresa s označením "%2" .Nemôže tak byť pridaná ako odosielacia adresa.</translation> + </message> + <message> + <source>The entered address "%1" is already in the address book with label "%2".</source> + <translation>Zadaná adresa "%1" sa už nachádza v zozname adries s označením "%2".</translation> + </message> + <message> <source>Could not unlock wallet.</source> <translation>Nepodarilo sa odomknúť peňaženku.</translation> </message> @@ -1046,10 +1054,22 @@ <translation>&Sieť</translation> </message> <message> + <source>Disables some advanced features but all blocks will still be fully validated. Reverting this setting requires re-downloading the entire blockchain. Actual disk usage may be somewhat higher.</source> + <translation>Zakáže niektoré pokročilé funkcie, ale všetky bloky budú stále plne overené. Obnovenie tohto nastavenia vyžaduje opätovné prevzatie celého blockchainu. Skutočné využitie disku môže byť o niečo vyššie.</translation> + </message> + <message> + <source>Prune &block storage to</source> + <translation>Redukovať priestor pre &bloky na</translation> + </message> + <message> <source>GB</source> <translation>GB</translation> </message> <message> + <source>Reverting this setting requires re-downloading the entire blockchain.</source> + <translation>Obnovenie tohto nastavenia vyžaduje opätovné prevzatie celého blockchainu.</translation> + </message> + <message> <source>(0 = auto, <0 = leave that many cores free)</source> <translation>(0 = auto, <0 = nechať toľko jadier voľných)</translation> </message> @@ -1517,10 +1537,18 @@ <context> <name>QObject::QObject</name> <message> + <source>Error parsing command line arguments: %1.</source> + <translation>Chyba pri spracovaní argumentov príkazového riadku: %1.</translation> + </message> + <message> <source>Error: Specified data directory "%1" does not exist.</source> <translation>Chyba: Zadaný adresár pre dáta „%1“ neexistuje.</translation> </message> <message> + <source>Error: Cannot parse configuration file: %1.</source> + <translation>Chyba: Konfiguračný súbor sa nedá spracovať: %1.</translation> + </message> + <message> <source>Error: %1</source> <translation>Chyba: %1</translation> </message> @@ -1816,6 +1844,14 @@ <translation>Sieťová aktivita zakázaná</translation> </message> <message> + <source>Executing command without any wallet</source> + <translation>Príkaz sa vykonáva bez peňaženky</translation> + </message> + <message> + <source>Executing command using "%1" wallet</source> + <translation>Príkaz sa vykonáva s použitím peňaženky "%1"</translation> + </message> + <message> <source>(node id: %1)</source> <translation>(ID uzlu: %1)</translation> </message> @@ -2100,6 +2136,14 @@ <translation>zbaliť nastavenia poplatkov</translation> </message> <message> + <source>Specify a custom fee per kB (1,000 bytes) of the transaction's virtual size. + +Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis per kB" for a transaction size of 500 bytes (half of 1 kB) would ultimately yield a fee of only 50 satoshis.</source> + <translation>Špecifikujte vlastný poplatok za kB (1000 bajtov) virtuálnej veľkosti transakcie. + +Poznámka: Keďže poplatok je počítaný za bajt, poplatok o hodnote "100 satoshi za kB" a veľkosti transakcie 500 bajtov (polovica z 1 kB) by stál len 50 satoshi.</translation> + </message> + <message> <source>per kilobyte</source> <translation>za kilobajt</translation> </message> @@ -2224,6 +2268,10 @@ <translation>z peňaženky %1</translation> </message> <message> + <source>Please, review your transaction.</source> + <translation>Prosím, skontrolujte Vašu transakciu.</translation> + </message> + <message> <source>Transaction fee</source> <translation>Transakčný poplatok</translation> </message> @@ -2689,6 +2737,10 @@ <translation>Celková veľkosť transakcie</translation> </message> <message> + <source>Transaction virtual size</source> + <translation>Virtuálna veľkosť transakcie</translation> + </message> + <message> <source>Output index</source> <translation>Index výstupu</translation> </message> @@ -3149,6 +3201,10 @@ <translation>Nastala chyba pri čítaní súboru %s! Všetkz kľúče sa prečítali správne, ale dáta o transakcíách alebo záznamy v adresári môžu chýbať alebo byť nesprávne.</translation> </message> <message> + <source>Group outputs by address, selecting all or none, instead of selecting on a per-output basis. Privacy is improved as an address is only used once (unless someone sends to it after spending from it), but may result in slightly higher fees as suboptimal coin selection may result due to the added limitation (default: %u)</source> + <translation>Zoskupenie výstupov podľa adresy, pri vybratí všetkých alebo žiadnych, namiesto vybratia na báze za výstup. Zlepší sa súkromie, keďže adresa je použitá len raz (pokiaľ nikto na túto adresu už nič nepošle po minutí), ale môže vyústiť v trochu väčšie poplatky keďže ne-optimalizovaný výber mincí môže vyústiť v pridané obmedzenia (predvolené: %u)</translation> + </message> + <message> <source>Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly.</source> <translation>Prosím skontrolujte systémový čas a dátum. Keď je váš čas nesprávny, %s nebude fungovať správne.</translation> </message> @@ -3233,6 +3289,10 @@ <translation>Chyba načítania %s</translation> </message> <message> + <source>Error loading %s: Private keys can only be disabled during creation</source> + <translation>Chyba pri načítaní %s: Súkromné kľúče môžu byť zakázané len počas vytvárania</translation> + </message> + <message> <source>Error loading %s: Wallet corrupted</source> <translation>Chyba načítania %s: Peňaženka je poškodená</translation> </message> @@ -3285,6 +3345,10 @@ <translation>Neplatná suma pre -fallbackfee=<amount>: '%s'</translation> </message> <message> + <source>Specified blocks directory "%s" does not exist.</source> + <translation>Zadaný adresár blokov "%s" neexistuje.</translation> + </message> + <message> <source>Upgrading txindex database</source> <translation>Inovuje sa txindex databáza</translation> </message> @@ -3437,12 +3501,6 @@ <translation>Uvedený -walletdir "%s" nie je priečinok</translation> </message> <message> - <source>Specified blocks directory "%s" does not exist. -</source> - <translation>Uvedený priečinok s dátami "%s" neexistuje. -</translation> - </message> - <message> <source>The transaction amount is too small to pay the fee</source> <translation>Suma transakcie je príliš malá na zaplatenie poplatku</translation> </message> @@ -3575,6 +3633,22 @@ <translation>Nedostatok prostriedkov</translation> </message> <message> + <source>Can't generate a change-address key. Private keys are disabled for this wallet.</source> + <translation>Nie je možné vygenerovať kľúč na zmenu adresy. Súkromné kľúče sú pre túto peňaženku zakázané.</translation> + </message> + <message> + <source>Cannot upgrade a non HD split wallet without upgrading to support pre split keypool. Please use -upgradewallet=169900 or -upgradewallet with no version specified.</source> + <translation>Nie je možné vylepšiť peňaženku bez HD bez aktualizácie, ktorá podporuje delenie keypoolu. Použite prosím -upgradewallet=169900 alebo -upgradewallet bez špecifikovania verzie.</translation> + </message> + <message> + <source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source> + <translation>Odhad poplatku sa nepodaril. Fallbackfee je zakázaný. Počkajte niekoľko blokov alebo povoľte -fallbackfee.</translation> + </message> + <message> + <source>Warning: Private keys detected in wallet {%s} with disabled private keys</source> + <translation>Upozornenie: Boli zistené súkromné kľúče v peňaženke {%s} so zakázanými súkromnými kľúčmi.</translation> + </message> + <message> <source>Loading block index...</source> <translation>Načítavanie zoznamu blokov...</translation> </message> diff --git a/src/qt/locale/bitcoin_sl_SI.ts b/src/qt/locale/bitcoin_sl_SI.ts index 91080a774a..08b00984c0 100644 --- a/src/qt/locale/bitcoin_sl_SI.ts +++ b/src/qt/locale/bitcoin_sl_SI.ts @@ -1874,6 +1874,10 @@ <translation>Brišem vse transakcije iz denarnice ...</translation> </message> <message> + <source>Transaction must have at least one recipient</source> + <translation>Transakcija mora imeti vsaj enega prejemnika.</translation> + </message> + <message> <source>Unknown network specified in -onlynet: '%s'</source> <translation>Neznano omrežje določeno v -onlynet: '%s'.</translation> </message> diff --git a/src/qt/locale/bitcoin_sn.ts b/src/qt/locale/bitcoin_sn.ts new file mode 100644 index 0000000000..895962cb45 --- /dev/null +++ b/src/qt/locale/bitcoin_sn.ts @@ -0,0 +1,367 @@ +<TS language="sn" version="2.1"> +<context> + <name>AddressBookPage</name> + <message> + <source>Create a new address</source> + <translation>Gadzira Kero Itsva</translation> + </message> + <message> + <source>&New</source> + <translation>Itsva</translation> + </message> + <message> + <source>&Copy</source> + <translation>&Kopera</translation> + </message> + <message> + <source>C&lose</source> + <translation>Vhara</translation> + </message> + <message> + <source>&Delete</source> + <translation>Dzima</translation> + </message> + <message> + <source>Sending addresses</source> + <translation>Makero ekutumira</translation> + </message> + <message> + <source>Receiving addresses</source> + <translation>Makero ekutambira</translation> + </message> + <message> + <source>&Copy Address</source> + <translation>Kopera Kero</translation> + </message> + <message> + <source>&Edit</source> + <translation>&Gadzirisa</translation> + </message> + </context> +<context> + <name>AddressTableModel</name> + <message> + <source>Label</source> + <translation>Zita</translation> + </message> + <message> + <source>Address</source> + <translation>Kero</translation> + </message> + <message> + <source>(no label)</source> + <translation>(hapana zita)</translation> + </message> +</context> +<context> + <name>AskPassphraseDialog</name> + </context> +<context> + <name>BanTableModel</name> + <message> + <source>Banned Until</source> + <translation>Wakavharirwa Kusvika</translation> + </message> +</context> +<context> + <name>BitcoinGUI</name> + <message> + <source>E&xit</source> + <translation>Buda</translation> + </message> + <message> + <source>Quit application</source> + <translation>Vhara Application</translation> + </message> + <message> + <source>&About %1</source> + <translation>&Kuma %1</translation> + </message> + <message> + <source>Show information about %1</source> + <translation>Taridza ruzivo rwekuma %1</translation> + </message> + <message> + <source>Show information about Qt</source> + <translation>Taridza ruzivo rwe Qt</translation> + </message> + <message> + <source>&Sending addresses...</source> + <translation>&Makero ekutumira nawo</translation> + </message> + <message> + <source>&Receiving addresses...</source> + <translation>&Makero ekutambira nawo</translation> + </message> + <message> + <source>Open &URI...</source> + <translation>Vhura &URI</translation> + </message> + <message> + <source>Bitcoin</source> + <translation>Bitcoin</translation> + </message> + <message> + <source>Wallet</source> + <translation>Chikwama</translation> + </message> + <message> + <source>&Send</source> + <translation>&Tumira</translation> + </message> + <message> + <source>&Receive</source> + <translation>&Tambira</translation> + </message> + <message> + <source>&Show / Hide</source> + <translation>&Taridza/Usataridza</translation> + </message> + <message> + <source>&File</source> + <translation>&Faira</translation> + </message> + <message> + <source>&Help</source> + <translation>&Rubatsiro</translation> + </message> + <message> + <source>%1 behind</source> + <translation>%1 kumashure</translation> + </message> + <message> + <source>Warning</source> + <translation>Hokoyo</translation> + </message> + <message> + <source>Information</source> + <translation>Ruzivo</translation> + </message> + </context> +<context> + <name>CoinControlDialog</name> + <message> + <source>Amount</source> + <translation>Marii </translation> + </message> + <message> + <source>Date</source> + <translation>Zuva</translation> + </message> + <message> + <source>(no label)</source> + <translation>(hapana zita)</translation> + </message> + </context> +<context> + <name>EditAddressDialog</name> + </context> +<context> + <name>FreespaceChecker</name> + </context> +<context> + <name>HelpMessageDialog</name> + </context> +<context> + <name>Intro</name> + <message> + <source>Bitcoin</source> + <translation>Bitcoin</translation> + </message> + </context> +<context> + <name>ModalOverlay</name> + </context> +<context> + <name>OpenURIDialog</name> + </context> +<context> + <name>OptionsDialog</name> + </context> +<context> + <name>OverviewPage</name> + </context> +<context> + <name>PaymentServer</name> + </context> +<context> + <name>PeerTableModel</name> + </context> +<context> + <name>QObject</name> + <message> + <source>Amount</source> + <translation>Marii </translation> + </message> + <message> + <source>Enter a Bitcoin address (e.g. %1)</source> + <translation>Nyora kero ye Bitcoin (sekuti %1)</translation> + </message> + <message> + <source>%1 d</source> + <translation>%1 d</translation> + </message> + <message> + <source>%1 h</source> + <translation>%1 h</translation> + </message> + <message> + <source>%1 m</source> + <translation>%1 m</translation> + </message> + <message> + <source>%1 s</source> + <translation>%1 s</translation> + </message> + <message> + <source>None</source> + <translation>Hapana</translation> + </message> + <message> + <source>N/A</source> + <translation>Hapana </translation> + </message> + </context> +<context> + <name>QObject::QObject</name> + </context> +<context> + <name>QRImageWidget</name> + </context> +<context> + <name>RPCConsole</name> + <message> + <source>N/A</source> + <translation>Hapana </translation> + </message> + </context> +<context> + <name>ReceiveCoinsDialog</name> + </context> +<context> + <name>ReceiveRequestDialog</name> + <message> + <source>Address</source> + <translation>Kero</translation> + </message> + <message> + <source>Amount</source> + <translation>Marii </translation> + </message> + <message> + <source>Label</source> + <translation>Zita</translation> + </message> + <message> + <source>Wallet</source> + <translation>Chikwama</translation> + </message> + </context> +<context> + <name>RecentRequestsTableModel</name> + <message> + <source>Date</source> + <translation>Zuva</translation> + </message> + <message> + <source>Label</source> + <translation>Zita</translation> + </message> + <message> + <source>(no label)</source> + <translation>(hapana zita)</translation> + </message> + </context> +<context> + <name>SendCoinsDialog</name> + <message> + <source>(no label)</source> + <translation>(hapana zita)</translation> + </message> +</context> +<context> + <name>SendCoinsEntry</name> + </context> +<context> + <name>SendConfirmationDialog</name> + </context> +<context> + <name>ShutdownWindow</name> + </context> +<context> + <name>SignVerifyMessageDialog</name> + </context> +<context> + <name>SplashScreen</name> + </context> +<context> + <name>TrafficGraphWidget</name> + </context> +<context> + <name>TransactionDesc</name> + <message> + <source>Date</source> + <translation>Zuva</translation> + </message> + <message> + <source>Amount</source> + <translation>Marii </translation> + </message> + </context> +<context> + <name>TransactionDescDialog</name> + </context> +<context> + <name>TransactionTableModel</name> + <message> + <source>Date</source> + <translation>Zuva</translation> + </message> + <message> + <source>Label</source> + <translation>Zita</translation> + </message> + <message> + <source>(no label)</source> + <translation>(hapana zita)</translation> + </message> + </context> +<context> + <name>TransactionView</name> + <message> + <source>Date</source> + <translation>Zuva</translation> + </message> + <message> + <source>Label</source> + <translation>Zita</translation> + </message> + <message> + <source>Address</source> + <translation>Kero</translation> + </message> + </context> +<context> + <name>UnitDisplayStatusBarControl</name> + </context> +<context> + <name>WalletFrame</name> + </context> +<context> + <name>WalletModel</name> + </context> +<context> + <name>WalletView</name> + </context> +<context> + <name>bitcoin-core</name> + <message> + <source>Information</source> + <translation>Ruzivo</translation> + </message> + <message> + <source>Warning</source> + <translation>Hokoyo</translation> + </message> + </context> +</TS>
\ No newline at end of file diff --git a/src/qt/locale/bitcoin_sv.ts b/src/qt/locale/bitcoin_sv.ts index d0fcef9297..405cde3c99 100644 --- a/src/qt/locale/bitcoin_sv.ts +++ b/src/qt/locale/bitcoin_sv.ts @@ -327,6 +327,14 @@ Var vänlig och försök igen.</translation> <translation>Öppna &URI...</translation> </message> <message> + <source>Wallet:</source> + <translation>Plånbok:</translation> + </message> + <message> + <source>default wallet</source> + <translation>Standardplånbok</translation> + </message> + <message> <source>Click to disable network activity.</source> <translation>Klicka för att inaktivera nätverksaktivitet.</translation> </message> @@ -347,6 +355,10 @@ Var vänlig och försök igen.</translation> <translation>Återindexerar block på disken...</translation> </message> <message> + <source>Proxy is <b>enabled</b>: %1</source> + <translation>Proxy är <b> aktiverad </b>: %1</translation> + </message> + <message> <source>Send coins to a Bitcoin address</source> <translation>Skicka bitcoin till en Bitcoin-adress</translation> </message> @@ -515,6 +527,12 @@ Var vänlig och försök igen.</translation> </translation> </message> <message> + <source>Wallet: %1 +</source> + <translation>Plånbok: %1 +</translation> + </message> + <message> <source>Type: %1 </source> <translation>Typ: %1 @@ -751,6 +769,14 @@ Var vänlig och försök igen.</translation> <translation>Den angivna adressen "%1" är inte en giltig Bitcoin-adress.</translation> </message> <message> + <source>Address "%1" already exists as a receiving address with label "%2" and so cannot be added as a sending address.</source> + <translation>Adress "%1" finns redan som en mottagande adress med etikett "%2" och kan därför anges som utgående adress.</translation> + </message> + <message> + <source>The entered address "%1" is already in the address book with label "%2".</source> + <translation>Den angivna adressen "%1" finns redan i adressboken med etikett "%2".</translation> + </message> + <message> <source>Could not unlock wallet.</source> <translation>Kunde inte låsa upp plånboken.</translation> </message> @@ -824,6 +850,10 @@ Var vänlig och försök igen.</translation> <translation>Denna första synkronisering är väldigt krävande, och kan påvisa hårdvaruproblem med din dator som tidigare inte visats sig. Varje gång du kör %1, kommer nerladdningen att fortsätta där den avslutades.</translation> </message> <message> + <source>If you have chosen to limit block chain storage (pruning), the historical data must still be downloaded and processed, but will be deleted afterward to keep your disk usage low.</source> + <translation>Om du valt att begränsa storleken på blockkedjan (pruning), måste historisk data fortfarande bli nedladdad och processerad, men kommer bli borttagen för att minimera hårddiskutrymme.</translation> + </message> + <message> <source>Use the default data directory</source> <translation>Använd den förvalda datakatalogen</translation> </message> @@ -1025,6 +1055,22 @@ Var vänlig och försök igen.</translation> <translation>&Nätverk</translation> </message> <message> + <source>Disables some advanced features but all blocks will still be fully validated. Reverting this setting requires re-downloading the entire blockchain. Actual disk usage may be somewhat higher.</source> + <translation>Stänger av en del avancerade funktioner, men samtliga block kommer fortfarande verifieras. Vid avstängning av denna inställning kommer den fullständiga blockkedjan behövas laddas ned igen. Det använda hårddiskutrymmet kan öka något.</translation> + </message> + <message> + <source>Prune &block storage to</source> + <translation>Trim- & block-utrymme till</translation> + </message> + <message> + <source>GB</source> + <translation>GB</translation> + </message> + <message> + <source>Reverting this setting requires re-downloading the entire blockchain.</source> + <translation>Vid avstängning av denna inställning kommer den fullständiga blockkedjan behövas laddas ned igen.</translation> + </message> + <message> <source>(0 = auto, <0 = leave that many cores free)</source> <translation>(0 = auto, <0 = lämna så många kärnor lediga)</translation> </message> @@ -1291,6 +1337,10 @@ Var vänlig och försök igen.</translation> <translation>URI-hantering</translation> </message> <message> + <source>'bitcoin://' is not a valid URI. Use 'bitcoin:' instead.</source> + <translation>'bitcoin://' är inte en accepterad URI. Använd 'bitcoin:' istället.</translation> + </message> + <message> <source>Payment request fetch URL is invalid: %1</source> <translation>Hämtningsadressen för betalningsbegäran är ogiltig: %1</translation> </message> @@ -1488,10 +1538,18 @@ Var vänlig och försök igen.</translation> <context> <name>QObject::QObject</name> <message> + <source>Error parsing command line arguments: %1.</source> + <translation>Kunde inte tolka argumentet: %1.</translation> + </message> + <message> <source>Error: Specified data directory "%1" does not exist.</source> <translation>Fel: Angiven datakatalog "%1" finns inte.</translation> </message> <message> + <source>Error: Cannot parse configuration file: %1.</source> + <translation>Fel: Kan inte tolka konfigurationsfil: %1.</translation> + </message> + <message> <source>Error: %1</source> <translation>Fel: %1</translation> </message> @@ -1582,6 +1640,14 @@ Var vänlig och försök igen.</translation> <translation>Minnesåtgång</translation> </message> <message> + <source>Wallet: </source> + <translation>Plånbok:</translation> + </message> + <message> + <source>(none)</source> + <translation>(ingen)</translation> + </message> + <message> <source>&Reset</source> <translation>&Återställ</translation> </message> @@ -1750,6 +1816,10 @@ Var vänlig och försök igen.</translation> <translation>&Ta bort blockering</translation> </message> <message> + <source>default wallet</source> + <translation>Standardplånbok</translation> + </message> + <message> <source>Welcome to the %1 RPC console.</source> <translation>Välkommen till %1 RPC-konsolen.</translation> </message> @@ -1774,6 +1844,14 @@ Var vänlig och försök igen.</translation> <translation>Nätverksaktivitet inaktiverad</translation> </message> <message> + <source>Executing command without any wallet</source> + <translation>Utför instruktion utan plånbok</translation> + </message> + <message> + <source>Executing command using "%1" wallet</source> + <translation>Utför instruktion med plånbok "%1"</translation> + </message> + <message> <source>(node id: %1)</source> <translation>(nod-id: %1)</translation> </message> @@ -1845,6 +1923,14 @@ Var vänlig och försök igen.</translation> <translation>Rensa</translation> </message> <message> + <source>Native segwit addresses (aka Bech32 or BIP-173) reduce your transaction fees later on and offer better protection against typos, but old wallets don't support them. When unchecked, an address compatible with older wallets will be created instead.</source> + <translation>Bech32-addresser (BIP-173) är billigare att spendera från och har bättre skytt mot skrivfel mot konstnaden att äldre plånböcker inte förstår dem. När inte valet är gjort kommer en address som är kompatibel med äldre plånböcker att skapas istället.</translation> + </message> + <message> + <source>Generate native segwit (Bech32) address</source> + <translation>Skapa Bech32-adress</translation> + </message> + <message> <source>Requested payments history</source> <translation>Historik för begärda betalningar</translation> </message> @@ -2050,6 +2136,14 @@ Var vänlig och försök igen.</translation> <translation>Fäll ihop avgiftsinställningarna</translation> </message> <message> + <source>Specify a custom fee per kB (1,000 bytes) of the transaction's virtual size. + +Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis per kB" for a transaction size of 500 bytes (half of 1 kB) would ultimately yield a fee of only 50 satoshis.</source> + <translation>Ange en egen avgift per kB (1 000 bytes) av transaktionens virtuella storlek. + +Notera: Då avgiften beräknas per byte kommer en avgift på 50 satoshi tas ut för en transaktion på 500 bytes (en halv kB) om man valt "100 satoshi per kB" som egen avgift.</translation> + </message> + <message> <source>per kilobyte</source> <translation>per kilobyte</translation> </message> @@ -2170,6 +2264,14 @@ Var vänlig och försök igen.</translation> <translation>Du kan välja att höja avgiften senare (med ersättande avgift, BIP-125).</translation> </message> <message> + <source>from wallet %1</source> + <translation>från plånbok: %1</translation> + </message> + <message> + <source>Please, review your transaction.</source> + <translation>Var vänlig se över din transaktion.</translation> + </message> + <message> <source>Transaction fee</source> <translation>Transaktionsavgift</translation> </message> @@ -2178,6 +2280,10 @@ Var vänlig och försök igen.</translation> <translation>Använder inte ersättande avgift, BIP-125.</translation> </message> <message> + <source>Total Amount</source> + <translation>Totalt</translation> + </message> + <message> <source>Confirm send coins</source> <translation>Bekräfta att mynt ska skickas</translation> </message> @@ -2631,6 +2737,10 @@ Var vänlig och försök igen.</translation> <translation>Transaktionens totala storlek</translation> </message> <message> + <source>Transaction virtual size</source> + <translation>Transaktionens virtuella storlek</translation> + </message> + <message> <source>Output index</source> <translation>Utmatningsindex</translation> </message> @@ -2965,6 +3075,10 @@ Var vänlig och försök igen.</translation> <translation>Skicka Bitcoins</translation> </message> <message> + <source>Fee bump error</source> + <translation>Avgiftsökningsfel</translation> + </message> + <message> <source>Increasing transaction fee failed</source> <translation>Ökning av avgiften lyckades inte</translation> </message> @@ -3031,7 +3145,11 @@ Var vänlig och försök igen.</translation> <source>The wallet data was successfully saved to %1.</source> <translation>Plånbokens data sparades till %1.</translation> </message> - </context> + <message> + <source>Cancel</source> + <translation>Avbryt</translation> + </message> +</context> <context> <name>bitcoin-core</name> <message> @@ -3075,10 +3193,18 @@ Var vänlig och försök igen.</translation> <translation>Kan inte låsa data-mappen %s. %s körs förmodligen redan.</translation> </message> <message> + <source>Cannot provide specific connections and have addrman find outgoing connections at the same.</source> + <translation>Kan inte låta addrman hitta utgående uppkopplingar samtidigt som specifika uppkopplingar skapas</translation> + </message> + <message> <source>Error reading %s! All keys read correctly, but transaction data or address book entries might be missing or incorrect.</source> <translation>Fel vid läsning av %s! Alla nycklar lästes korrekt, men transaktionsdata eller poster i adressboken kanske saknas eller är felaktiga.</translation> </message> <message> + <source>Group outputs by address, selecting all or none, instead of selecting on a per-output basis. Privacy is improved as an address is only used once (unless someone sends to it after spending from it), but may result in slightly higher fees as suboptimal coin selection may result due to the added limitation (default: %u)</source> + <translation>Gruppera utgående transaktioner med adress, där samtliga eller inga används, istället för att välja vid varje utgående transaktion. Detta ökar din integritet genom att en adress enbart används en gång (om inte någon skickar till den efteråt), men kan öka dina utgifter då valet av ingående transaktioner görs suboptimalt (standardvärde: %u)</translation> + </message> + <message> <source>Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly.</source> <translation>Vänligen kolla så att din dators datum och tid är korrekt! Om din klocka går fel kommer %s inte att fungera korrekt.</translation> </message> @@ -3095,6 +3221,10 @@ Var vänlig och försök igen.</translation> <translation>Detta är ett förhandstestbygge - använd på egen risk - använd inte för brytning eller handelsapplikationer</translation> </message> <message> + <source>This is the transaction fee you may discard if change is smaller than dust at this level</source> + <translation>Detta är transaktionsavgiften som slängs borta om det är mindre än damm på denna nivå</translation> + </message> + <message> <source>Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate.</source> <translation>Kunde inte spela om block. Du kommer att behöva bygga om databasen med -reindex-chainstate.</translation> </message> @@ -3143,6 +3273,10 @@ Var vänlig och försök igen.</translation> <translation>Vill du bygga om blockdatabasen nu?</translation> </message> <message> + <source>Error creating %s: You can't create non-HD wallets with this version.</source> + <translation>Fel vid skapande av %s: Det är inte möjligt att skapa icke-HD plånböcker med denna version.</translation> + </message> + <message> <source>Error initializing block database</source> <translation>Fel vid initiering av blockdatabasen</translation> </message> @@ -3155,6 +3289,10 @@ Var vänlig och försök igen.</translation> <translation>Fel vid inläsning av %s</translation> </message> <message> + <source>Error loading %s: Private keys can only be disabled during creation</source> + <translation>Fel vid laddning av %s: Privata nycklar kan enbart bli avstängda vid skapelsen</translation> + </message> + <message> <source>Error loading %s: Wallet corrupted</source> <translation>Fel vid inläsning av %s: Plånboken är korrupt</translation> </message> @@ -3207,6 +3345,14 @@ Var vänlig och försök igen.</translation> <translation>Ogiltigt belopp för -fallbackfee=<amount>: '%s'</translation> </message> <message> + <source>Specified blocks directory "%s" does not exist.</source> + <translation>Den specificerade mappen för block "%s" existerar inte.</translation> + </message> + <message> + <source>Upgrading txindex database</source> + <translation>Uppgraderar databas för txindex</translation> + </message> + <message> <source>Loading P2P addresses...</source> <translation>Läser in P2P-adresser...</translation> </message> @@ -3247,6 +3393,10 @@ Var vänlig och försök igen.</translation> <translation>Det går inte att binda till %s på den här datorn. %s är förmodligen redan igång.</translation> </message> <message> + <source>Unable to generate keys</source> + <translation>Lyckas inte generera nycklar</translation> + </message> + <message> <source>Unsupported argument -benchmark ignored, use -debug=bench.</source> <translation>Argumentet -benchmark stöds inte och ignoreras, använd -debug=bench.</translation> </message> @@ -3383,6 +3533,10 @@ Var vänlig och försök igen.</translation> <translation>Verifierar plånbok(er)...</translation> </message> <message> + <source>Wallet %s resides outside wallet directory %s</source> + <translation>Plånbok %s är lokaliserad utanför plånboksmappen %s</translation> + </message> + <message> <source>Warning</source> <translation>Varning</translation> </message> @@ -3439,6 +3593,10 @@ Var vänlig och försök igen.</translation> <translation>Fel vid inläsningen av plånbok %s. Dublett -wallet filnamn angavs.</translation> </message> <message> + <source>Keypool ran out, please call keypoolrefill first</source> + <translation>Nyckelpoolen har tagit slut, var vänlig anropa keypoolrefill först.</translation> + </message> + <message> <source>Starting network threads...</source> <translation>Startar nätverkstrådar...</translation> </message> @@ -3475,6 +3633,26 @@ Var vänlig och försök igen.</translation> <translation>Otillräckligt med bitcoins</translation> </message> <message> + <source>Can't generate a change-address key. Private keys are disabled for this wallet.</source> + <translation>Kan inte generera en nyckel för växeladress. Privata nycklar är avstängda för denna plånboken.</translation> + </message> + <message> + <source>Cannot upgrade a non HD split wallet without upgrading to support pre split keypool. Please use -upgradewallet=169900 or -upgradewallet with no version specified.</source> + <translation>Kan inte uppgradera till en icke-HD delad plånbok utan att uppgradera till att stödja nyckelpoolen innan splittring. Var vänlig använd -upgradewallet=169900 eller -upgradewallet utan version specificerad.</translation> + </message> + <message> + <source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source> + <translation>Avgiftsestimering misslyckades. Fallbackfee är avstänt. Var vänlig vänta några block, alternativt aktivera -fallbackfee.</translation> + </message> + <message> + <source>Warning: Private keys detected in wallet {%s} with disabled private keys</source> + <translation>Varning: Privata nycklar upptäckta i plånbok (%s) vilken har dessa inaktiverade</translation> + </message> + <message> + <source>Cannot write to data directory '%s'; check permissions.</source> + <translation>Kan inte skriva till mapp "%s", var vänlig se över filbehörigheter.</translation> + </message> + <message> <source>Loading block index...</source> <translation>Laddar blockindex...</translation> </message> diff --git a/src/qt/locale/bitcoin_szl.ts b/src/qt/locale/bitcoin_szl.ts new file mode 100644 index 0000000000..9559df2a7d --- /dev/null +++ b/src/qt/locale/bitcoin_szl.ts @@ -0,0 +1,2123 @@ +<TS language="szl" version="2.1"> +<context> + <name>AddressBookPage</name> + <message> + <source>Right-click to edit address or label</source> + <translation>Kliknij prawy knefel mysze, coby edytować adresã abo etyketã</translation> + </message> + <message> + <source>Create a new address</source> + <translation>Zrychtuj nowõ adresã</translation> + </message> + <message> + <source>&New</source> + <translation>&Nowy</translation> + </message> + <message> + <source>Copy the currently selected address to the system clipboard</source> + <translation>Skopiyruj aktualnie ôbranõ adresã do skrytki</translation> + </message> + <message> + <source>&Copy</source> + <translation>&Kopiyruj</translation> + </message> + <message> + <source>C&lose</source> + <translation>&Zawrzij</translation> + </message> + <message> + <source>Delete the currently selected address from the list</source> + <translation>Wychrōń zaznaczōnõ adresã z brify</translation> + </message> + <message> + <source>Enter address or label to search</source> + <translation>Wkludź adresã abo etyketã coby wyszukać</translation> + </message> + <message> + <source>Export the data in the current tab to a file</source> + <translation>Eksportuj dane z aktywnyj szkarty do zbioru</translation> + </message> + <message> + <source>&Export</source> + <translation>&Eksportuj</translation> + </message> + <message> + <source>&Delete</source> + <translation>&Wychrōń</translation> + </message> + <message> + <source>Choose the address to send coins to</source> + <translation>Ôbier adresã, na kerõ chcesz posłać mōnety</translation> + </message> + <message> + <source>Choose the address to receive coins with</source> + <translation>Ôbier adresã, na kerõ chcesz dostać mōnety</translation> + </message> + <message> + <source>C&hoose</source> + <translation>Ô&bier</translation> + </message> + <message> + <source>Sending addresses</source> + <translation>Adresy posyłaniŏ</translation> + </message> + <message> + <source>Receiving addresses</source> + <translation>Adresy ôdbiyraniŏ</translation> + </message> + <message> + <source>These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins.</source> + <translation>Tukej sōm adresy Bitcoin na kere posyłŏsz płaty. Dycki wybaduj wielość i adresã ôdbiyrŏcza przed posłaniym mōnet.</translation> + </message> + <message> + <source>These are your Bitcoin addresses for receiving payments. It is recommended to use a new receiving address for each transaction.</source> + <translation>Tukej sōm adresy Bitcoin do ôdbiyraniŏ płatōw. Zalycŏ sie używaniŏ nowych adres ôdbiorczych dlŏ kożdyj transakcyje.</translation> + </message> + <message> + <source>&Copy Address</source> + <translation>&Kopiyruj Adresã</translation> + </message> + <message> + <source>Copy &Label</source> + <translation>Kopiyruj &Etyketã</translation> + </message> + <message> + <source>&Edit</source> + <translation>&Edytuj</translation> + </message> + <message> + <source>Export Address List</source> + <translation>Eksportuj wykŏz adres</translation> + </message> + <message> + <source>Comma separated file (*.csv)</source> + <translation>Zbiōr *.CSV (daty rozdzielane kōmami)</translation> + </message> + <message> + <source>Exporting Failed</source> + <translation>Eksportowanie niy podarziło sie</translation> + </message> + <message> + <source>There was an error trying to save the address list to %1. Please try again.</source> + <translation>Przitrefiōł sie feler w czasie spamiyntowaniŏ brify adres do %1. Proszã sprōbować zaś.</translation> + </message> +</context> +<context> + <name>AddressTableModel</name> + <message> + <source>Label</source> + <translation>Etyketa</translation> + </message> + <message> + <source>Address</source> + <translation>Adresa</translation> + </message> + <message> + <source>(no label)</source> + <translation>(chyba etykety)</translation> + </message> +</context> +<context> + <name>AskPassphraseDialog</name> + <message> + <source>Passphrase Dialog</source> + <translation>Ôkiynko Hasła</translation> + </message> + <message> + <source>Enter passphrase</source> + <translation>Wkludź hasło</translation> + </message> + <message> + <source>New passphrase</source> + <translation>Nowe hasło</translation> + </message> + <message> + <source>Repeat new passphrase</source> + <translation>Powtōrz nowe hasło</translation> + </message> + <message> + <source>Show password</source> + <translation>Pokŏż hasło</translation> + </message> + <message> + <source>Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>.</source> + <translation>Wkludź nowe hasło do portmanyja.<br/>Proszã używać hasła słożōnego z <b>10 abo wiyncyj losowych liter</b> abo <b>8 abo wiyncyj słōw.</b>.</translation> + </message> + <message> + <source>Encrypt wallet</source> + <translation>Zaszyfruj portmanyj</translation> + </message> + <message> + <source>This operation needs your wallet passphrase to unlock the wallet.</source> + <translation>Ta ôperacyjŏ wymŏgŏ hasła do portmanyja coby ôdszperować portmanyj.</translation> + </message> + <message> + <source>Unlock wallet</source> + <translation>Ôdszperuj portmanyj.</translation> + </message> + <message> + <source>This operation needs your wallet passphrase to decrypt the wallet.</source> + <translation>Ta ôperacyjŏ wymŏgŏ hasła do portmanyja coby ôdszyfrować portmanyj.</translation> + </message> + <message> + <source>Decrypt wallet</source> + <translation>Ôdszyfruj portmanyj</translation> + </message> + <message> + <source>Change passphrase</source> + <translation>Pōmiyń hasło</translation> + </message> + <message> + <source>Enter the old passphrase and new passphrase to the wallet.</source> + <translation>Podej stare i nowe hasło do portmanyja.</translation> + </message> + <message> + <source>Confirm wallet encryption</source> + <translation>Przituplikuj szyfrowanie portmanyja</translation> + </message> + <message> + <source>Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>!</source> + <translation>Pozōr: jeźli zaszyfrujesz swōj portmanyj i stracisz hasło <b>STRACISZ WSZYJSKE SWOJE BITCOINY</b>!</translation> + </message> + <message> + <source>Are you sure you wish to encrypt your wallet?</source> + <translation>Na isto chcesz zaszyfrować swōj portmanyj?</translation> + </message> + <message> + <source>Wallet encrypted</source> + <translation>Portmanyj zaszyfrowany</translation> + </message> + <message> + <source>%1 will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source> + <translation>%1 zawrzi sie coby dokōńczyć proces szyfrowaniŏ. Pamiyntej, iże szyfrowanie portmanyja ganc niy zabezpieczŏ Twojich bitcoinów przed chabiyniym bez wirusy abo trojany mogōnce zakażać Twōj kōmputer.</translation> + </message> + <message> + <source>IMPORTANT: Any previous backups you have made of your wallet file should be replaced with the newly generated, encrypted wallet file. For security reasons, previous backups of the unencrypted wallet file will become useless as soon as you start using the new, encrypted wallet.</source> + <translation>WŎŻNE: Wszyjske wykōnane wczaśnij kopije zbioru portmanyja winny być umiyniōne na nowe, szyfrowane zbiory. Z powodōw bezpiyczyństwa, piyrwyjsze kopije niyszyfrowanych zbiorōw portmanyja stōnõ sie bezużyteczne jak ino zaczniesz używać nowego, szyfrowanego portmanyja.</translation> + </message> + <message> + <source>Wallet encryption failed</source> + <translation>Zaszyfrowanie portmanyja niy podarziło sie</translation> + </message> + <message> + <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source> + <translation>Zaszyfrowanie portmanyja niy podarziło sie bez wnyntrzny feler. Twōj portmanyj niy ôstoł zaszyfrowany.</translation> + </message> + <message> + <source>The supplied passphrases do not match.</source> + <translation>Podane hasła niy sōm take same.</translation> + </message> + <message> + <source>Wallet unlock failed</source> + <translation>Ôdszperowanie portmanyja niy podarziło sie</translation> + </message> + <message> + <source>The passphrase entered for the wallet decryption was incorrect.</source> + <translation>Wkludzōne hasło do ôdszyfrowaniŏ portmanyja je niynŏleżne.</translation> + </message> + <message> + <source>Wallet decryption failed</source> + <translation>Ôdszyfrowanie portmanyja niy podarziło sie</translation> + </message> + <message> + <source>Wallet passphrase was successfully changed.</source> + <translation>Hasło do portmanyja ôstało sprŏwnie pōmiyniōne.</translation> + </message> + <message> + <source>Warning: The Caps Lock key is on!</source> + <translation>Pozōr: Caps Lock je zapuszczōny!</translation> + </message> +</context> +<context> + <name>BanTableModel</name> + <message> + <source>IP/Netmask</source> + <translation>IP/Maska necu</translation> + </message> + <message> + <source>Banned Until</source> + <translation>Szpera do</translation> + </message> +</context> +<context> + <name>BitcoinGUI</name> + <message> + <source>Sign &message...</source> + <translation>Szkryftnij &wiadōmość</translation> + </message> + <message> + <source>Synchronizing with network...</source> + <translation>Synchrōnizacyjŏ z necym...</translation> + </message> + <message> + <source>&Overview</source> + <translation>&Podsumowanie</translation> + </message> + <message> + <source>Show general overview of wallet</source> + <translation>Pokazuje ôgōlny widok portmanyja</translation> + </message> + <message> + <source>&Transactions</source> + <translation>&Transakcyje</translation> + </message> + <message> + <source>Browse transaction history</source> + <translation>Przeglōndej historyjõ transakcyji</translation> + </message> + <message> + <source>E&xit</source> + <translation>&Zakōńcz</translation> + </message> + <message> + <source>Quit application</source> + <translation>Zawrzij aplikacyjõ</translation> + </message> + <message> + <source>&About %1</source> + <translation>&Ô %1</translation> + </message> + <message> + <source>Show information about %1</source> + <translation>Pokŏż informacyje ô %1</translation> + </message> + <message> + <source>About &Qt</source> + <translation>Ô &Qt</translation> + </message> + <message> + <source>Show information about Qt</source> + <translation>Pokŏż informacyje ô Qt</translation> + </message> + <message> + <source>&Options...</source> + <translation>Ô&pcyje...</translation> + </message> + <message> + <source>Modify configuration options for %1</source> + <translation>Zmiyń ôpcyje kōnfiguracyje dlŏ %1</translation> + </message> + <message> + <source>&Encrypt Wallet...</source> + <translation>&Zaszyfruj Portmanyj...</translation> + </message> + <message> + <source>&Backup Wallet...</source> + <translation>Zrychtuj kopijõ ibrycznõ</translation> + </message> + <message> + <source>&Change Passphrase...</source> + <translation>Pōmiyń &hasło</translation> + </message> + <message> + <source>&Sending addresses...</source> + <translation>&Adresy posyłaniŏ</translation> + </message> + <message> + <source>&Receiving addresses...</source> + <translation>Ad&resy ôdbiyraniŏ</translation> + </message> + <message> + <source>Open &URI...</source> + <translation>Ôdewrzij &URI...</translation> + </message> + <message> + <source>Wallet:</source> + <translation>Portmanyj:</translation> + </message> + <message> + <source>default wallet</source> + <translation>wychodny portmanyj</translation> + </message> + <message> + <source>Click to disable network activity.</source> + <translation>Kliknij coby zastawić aktywność necowõ.</translation> + </message> + <message> + <source>Network activity disabled.</source> + <translation>Aktywność necowŏ ôstała zastawiōnŏ.</translation> + </message> + <message> + <source>Click to enable network activity again.</source> + <translation>Kliknij, coby zaś zapuścić aktywność necowõ.</translation> + </message> + <message> + <source>Syncing Headers (%1%)...</source> + <translation>Synchrōnizowanie nŏgōwkōw (%1%)...</translation> + </message> + <message> + <source>Reindexing blocks on disk...</source> + <translation>Pōnowne indeksowanie blokōw na dysku...</translation> + </message> + <message> + <source>Proxy is <b>enabled</b>: %1</source> + <translation>Proxy je <b>zapuszczone</b>: %1</translation> + </message> + <message> + <source>Send coins to a Bitcoin address</source> + <translation>Poślij mōnety na adresã Bitcoin</translation> + </message> + <message> + <source>Backup wallet to another location</source> + <translation>Ibryczny portmanyj w inkszyj lokalizacyje</translation> + </message> + <message> + <source>Change the passphrase used for wallet encryption</source> + <translation>Pōmiyń hasło użyte do szyfrowaniŏ portmanyja</translation> + </message> + <message> + <source>&Debug window</source> + <translation>Ôkno &debugowaniŏ</translation> + </message> + <message> + <source>Open debugging and diagnostic console</source> + <translation>Ôdewrzij kōnsolã debugowaniŏ i diagnostyki</translation> + </message> + <message> + <source>&Verify message...</source> + <translation>&Weryfikuj wiadōmość...</translation> + </message> + <message> + <source>Bitcoin</source> + <translation>Bitcoin</translation> + </message> + <message> + <source>Wallet</source> + <translation>Portmanyj</translation> + </message> + <message> + <source>&Send</source> + <translation>&Poślij</translation> + </message> + <message> + <source>&Receive</source> + <translation>Ôd&bier</translation> + </message> + <message> + <source>&Show / Hide</source> + <translation>Pokŏż / &Skryj</translation> + </message> + <message> + <source>Show or hide the main Window</source> + <translation>Pokazuje abo skrywŏ bazowe ôkno</translation> + </message> + <message> + <source>Encrypt the private keys that belong to your wallet</source> + <translation>Szyfruj klucze prywatne, kere sōm we twojim portmanyju</translation> + </message> + <message> + <source>Sign messages with your Bitcoin addresses to prove you own them</source> + <translation>Podpisz wiadōmości swojōm adresōm coby dowiyść jejich posiadanie</translation> + </message> + <message> + <source>Verify messages to ensure they were signed with specified Bitcoin addresses</source> + <translation>Zweryfikuj wiadōmość, coby wejzdrzeć sie, iże ôstała podpisanŏ podanōm adresōm Bitcoin.</translation> + </message> + <message> + <source>&File</source> + <translation>&Zbiōr</translation> + </message> + <message> + <source>&Settings</source> + <translation>&Nasztalowania</translation> + </message> + <message> + <source>&Help</source> + <translation>Pō&moc</translation> + </message> + <message> + <source>Tabs toolbar</source> + <translation>Lajsta szkart</translation> + </message> + <message> + <source>Request payments (generates QR codes and bitcoin: URIs)</source> + <translation>Żōndej płatu (gyneruje kod QR jak tyż URI bitcoin:)</translation> + </message> + <message> + <source>Show the list of used sending addresses and labels</source> + <translation>Pokŏż wykŏz adres i etyket użytych do posyłaniŏ</translation> + </message> + <message> + <source>Show the list of used receiving addresses and labels</source> + <translation>Pokŏż wykŏz adres i etyket użytych do ôdbiyraniŏ</translation> + </message> + <message> + <source>Open a bitcoin: URI or payment request</source> + <translation>Ôdewrzij URI bitcoin: abo żōndanie płatu</translation> + </message> + <message> + <source>&Command-line options</source> + <translation>Ôp&cyje piski kōmynd</translation> + </message> + <message numerus="yes"> + <source>%n active connection(s) to Bitcoin network</source> + <translation><numerusform>%n aktywne połōnczynie do necu Bitcoin</numerusform><numerusform>%n aktywnych połōnczyń do necu Bitcoin</numerusform><numerusform>%n aktywnych skuplowań do necu Bitcoin</numerusform></translation> + </message> + <message> + <source>Indexing blocks on disk...</source> + <translation>Indeksowanie blokōw na dysku...</translation> + </message> + <message> + <source>Processing blocks on disk...</source> + <translation>Przetwŏrzanie blokōw na dysku...</translation> + </message> + <message numerus="yes"> + <source>Processed %n block(s) of transaction history.</source> + <translation><numerusform>Przetworzōno %n blok historyji transakcyji.</numerusform><numerusform>Przetworzōno %n blokōw historyji transakcyji.</numerusform><numerusform>Przetworzōno %n blokōw historyji transakcyji.</numerusform></translation> + </message> + <message> + <source>%1 behind</source> + <translation>%1 za</translation> + </message> + <message> + <source>Last received block was generated %1 ago.</source> + <translation>Ôstatni dostany blok ôstoł wygynerowany %1 tymu.</translation> + </message> + <message> + <source>Transactions after this will not yet be visible.</source> + <translation>Transakcyje po tym mōmyncie niy bydōm jeszcze widzialne.</translation> + </message> + <message> + <source>Error</source> + <translation>Feler</translation> + </message> + <message> + <source>Warning</source> + <translation>Pozōr</translation> + </message> + <message> + <source>Information</source> + <translation>Informacyjŏ</translation> + </message> + <message> + <source>Up to date</source> + <translation>Terŏźny</translation> + </message> + <message> + <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source> + <translation>Pokŏż pōmoc %1 coby zobŏczyć wykŏz wszyjskich ôpcyji piski nakŏzań.</translation> + </message> + <message> + <source>%1 client</source> + <translation>%1 klijynt</translation> + </message> + <message> + <source>Catching up...</source> + <translation>Trwŏ synchrōnizacyjŏ...</translation> + </message> + <message> + <source>Date: %1 +</source> + <translation>Datōm: %1 +</translation> + </message> + <message> + <source>Amount: %1 +</source> + <translation>Kwota: %1 +</translation> + </message> + <message> + <source>Wallet: %1 +</source> + <translation>Portmanyj: %1 +</translation> + </message> + <message> + <source>Type: %1 +</source> + <translation>Zorta: %1 +</translation> + </message> + <message> + <source>Label: %1 +</source> + <translation>Etyketa: %1 +</translation> + </message> + <message> + <source>Address: %1 +</source> + <translation>Adresa: %1 +</translation> + </message> + <message> + <source>Sent transaction</source> + <translation>Transakcyjŏ wysłanŏ</translation> + </message> + <message> + <source>Incoming transaction</source> + <translation>Transakcyjŏ przichodzōncŏ</translation> + </message> + <message> + <source>HD key generation is <b>enabled</b></source> + <translation>Gynerowanie kluczy HD je <b>zapuszczone</b></translation> + </message> + <message> + <source>HD key generation is <b>disabled</b></source> + <translation>Gynerowanie kluczy HD je <b>zastawiōne</b></translation> + </message> + <message> + <source>Wallet is <b>encrypted</b> and currently <b>unlocked</b></source> + <translation>Portmanyj je <b>zaszyfrowany</b> i terŏźnie <b>ôdszperowany</b></translation> + </message> + <message> + <source>Wallet is <b>encrypted</b> and currently <b>locked</b></source> + <translation>Portmanyj je <b>zaszyfrowany</b> i terŏźnie <b>zaszperowany</b></translation> + </message> + <message> + <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source> + <translation>Przitrefiōł sie krytyczny feler. Bitcoin niy poradzi kōntynuować bezpiycznie i ôstanie zawrzity.</translation> + </message> +</context> +<context> + <name>CoinControlDialog</name> + <message> + <source>Coin Selection</source> + <translation>Ôbiōr mōnet</translation> + </message> + <message> + <source>Quantity:</source> + <translation>Wielość:</translation> + </message> + <message> + <source>Bytes:</source> + <translation>Bajtōw:</translation> + </message> + <message> + <source>Amount:</source> + <translation>Kwota:</translation> + </message> + <message> + <source>Fee:</source> + <translation>Ôpłŏcka:</translation> + </message> + <message> + <source>Dust:</source> + <translation>Sztaub:</translation> + </message> + <message> + <source>After Fee:</source> + <translation>Po ôpłŏcce:</translation> + </message> + <message> + <source>Change:</source> + <translation>Wydŏwka:</translation> + </message> + <message> + <source>(un)select all</source> + <translation>Zaznacz/Ôdznacz wszyjsko</translation> + </message> + <message> + <source>Tree mode</source> + <translation>Tryb strōma</translation> + </message> + <message> + <source>List mode</source> + <translation>Tryb wykŏzu</translation> + </message> + <message> + <source>Amount</source> + <translation>Kwota</translation> + </message> + <message> + <source>Received with label</source> + <translation>Ôdebrane z etyketōm</translation> + </message> + <message> + <source>Received with address</source> + <translation>Ôdebrane z adresōm</translation> + </message> + <message> + <source>Date</source> + <translation>Datōm</translation> + </message> + <message> + <source>Confirmations</source> + <translation>Przituplowania</translation> + </message> + <message> + <source>Confirmed</source> + <translation>Przituplowany</translation> + </message> + <message> + <source>Copy address</source> + <translation>Kopiyruj adresã</translation> + </message> + <message> + <source>Copy label</source> + <translation>Kopiyruj etyketã</translation> + </message> + <message> + <source>Copy amount</source> + <translation>Kopiyruj kwotã</translation> + </message> + <message> + <source>Copy transaction ID</source> + <translation>Kopiyruj ID transakcyje</translation> + </message> + <message> + <source>Lock unspent</source> + <translation>Zaszperuj niywydane</translation> + </message> + <message> + <source>Unlock unspent</source> + <translation>Ôdszperuj niywydane</translation> + </message> + <message> + <source>Copy quantity</source> + <translation>Kopiyruj wielość</translation> + </message> + <message> + <source>Copy fee</source> + <translation>Kopiyruj ôpłŏckã</translation> + </message> + <message> + <source>Copy after fee</source> + <translation>Kopiyruj wielość po ôpłŏcce</translation> + </message> + <message> + <source>Copy bytes</source> + <translation>Kopiyruj wielość bajtōw</translation> + </message> + <message> + <source>Copy dust</source> + <translation>Kopiyruj sztaub</translation> + </message> + <message> + <source>Copy change</source> + <translation>Kopiyruj wydŏwkã</translation> + </message> + <message> + <source>(%1 locked)</source> + <translation>(%1 zaszperowane)</translation> + </message> + <message> + <source>yes</source> + <translation>ja</translation> + </message> + <message> + <source>no</source> + <translation>niy</translation> + </message> + <message> + <source>This label turns red if any recipient receives an amount smaller than the current dust threshold.</source> + <translation>Ta etyketa stŏwŏ sie czyrwōnŏ jeźli keryś z ôdbiyrŏczy dostŏwŏ kwotã myńszõ aniżeli terŏźny prōg sztaubu.</translation> + </message> + <message> + <source>Can vary +/- %1 satoshi(s) per input.</source> + <translation>Chwiyrŏ sie +/- %1 satoshi na wchōd.</translation> + </message> + <message> + <source>(no label)</source> + <translation>(chyba etykety)</translation> + </message> + <message> + <source>change from %1 (%2)</source> + <translation>wydŏwka z %1 (%2)</translation> + </message> + <message> + <source>(change)</source> + <translation>(wydŏwka)</translation> + </message> +</context> +<context> + <name>EditAddressDialog</name> + <message> + <source>Edit Address</source> + <translation>Edytuj adresã</translation> + </message> + <message> + <source>&Label</source> + <translation>&Etyketa</translation> + </message> + <message> + <source>The label associated with this address list entry</source> + <translation>Etyketa ôbwiōnzanŏ z tym wpisym na wykŏzie adres</translation> + </message> + <message> + <source>The address associated with this address list entry. This can only be modified for sending addresses.</source> + <translation>Ta adresa je ôbwiōnzanŏ z wpisym na wykŏzie adres. Może być zmodyfikowany jyno dlŏ adres posyłajōncych.</translation> + </message> + <message> + <source>&Address</source> + <translation>&Adresa</translation> + </message> + <message> + <source>New sending address</source> + <translation>Nowŏ adresa posyłaniŏ</translation> + </message> + <message> + <source>Edit receiving address</source> + <translation>Edytuj adresã ôdbiōru</translation> + </message> + <message> + <source>Edit sending address</source> + <translation>Edytuj adresã posyłaniŏ</translation> + </message> + <message> + <source>The entered address "%1" is not a valid Bitcoin address.</source> + <translation>Wkludzōnŏ adresa "%1" niyma nŏleżnōm adresōm Bitcoin.</translation> + </message> + <message> + <source>Address "%1" already exists as a receiving address with label "%2" and so cannot be added as a sending address.</source> + <translation>Adresa "%1" już je za adresã ôdbiorczõ z etyketōm "%2" i bez to niy idzie jeji przidać za adresã nadŏwcy.</translation> + </message> + <message> + <source>The entered address "%1" is already in the address book with label "%2".</source> + <translation>Wkludzōnŏ adresa "%1" już je w ksiōnżce adres z ôpisym "%2".</translation> + </message> + <message> + <source>Could not unlock wallet.</source> + <translation>Niy idzie było ôdszperować portmanyja.</translation> + </message> + <message> + <source>New key generation failed.</source> + <translation>Gynerowanie nowego klucza niy podarziło sie.</translation> + </message> +</context> +<context> + <name>FreespaceChecker</name> + <message> + <source>A new data directory will be created.</source> + <translation>Bydzie zrychtowany nowy folder danych.</translation> + </message> + <message> + <source>name</source> + <translation>miano</translation> + </message> + <message> + <source>Directory already exists. Add %1 if you intend to create a new directory here.</source> + <translation>Katalog już je. Przidej %1 jeźli mŏsz zastrojynie zrychtować tukej nowy katalog.</translation> + </message> + <message> + <source>Cannot create data directory here.</source> + <translation>Niy idzie było tukej zrychtować folderu datōw.</translation> + </message> +</context> +<context> + <name>HelpMessageDialog</name> + <message> + <source>version</source> + <translation>wersyjŏ</translation> + </message> + <message> + <source>(%1-bit)</source> + <translation>(%1-bit)</translation> + </message> + <message> + <source>About %1</source> + <translation>Ô %1</translation> + </message> + <message> + <source>Command-line options</source> + <translation>Ôpcyje piski kōmynd</translation> + </message> +</context> +<context> + <name>Intro</name> + <message> + <source>Welcome</source> + <translation>Witej</translation> + </message> + <message> + <source>Welcome to %1.</source> + <translation>Witej w %1.</translation> + </message> + <message> + <source>As this is the first time the program is launched, you can choose where %1 will store its data.</source> + <translation>Pōniywŏż je to piyrsze sztartniyńcie programu, możesz ôbrać kaj %1 bydzie spamiyntować swoje daty.</translation> + </message> + <message> + <source>When you click OK, %1 will begin to download and process the full %4 block chain (%2GB) starting with the earliest transactions in %3 when %4 initially launched.</source> + <translation>Kej naciśniesz OK, %1 zacznie pobiyrać i przetwŏrzać cołkõ %4 keta blokōw (%2GB) przi zaczynaniu ôd piyrszych transakcyji w %3 kej %4 ôstoł sztartniynty.</translation> + </message> + <message> + <source>This initial synchronisation is very demanding, and may expose hardware problems with your computer that had previously gone unnoticed. Each time you run %1, it will continue downloading where it left off.</source> + <translation>Wstympnŏ synchrōnizacyjŏ je barzo wymŏgajōncŏ i może wyzdradzić wczaśnij niyzaôbserwowane niyprzileżytości sprzyntowe. Za kożdym sztartniyńciym %1 pobiyranie bydzie kōntynuowane ôd placu w kerym ôstało zastawiōne.</translation> + </message> + <message> + <source>If you have chosen to limit block chain storage (pruning), the historical data must still be downloaded and processed, but will be deleted afterward to keep your disk usage low.</source> + <translation>Jeźli ôbrołś ôpcyjõ ukrōcyniŏ spamiyntowaniŏ kety blokōw (przicinanie) daty historyczne cołki czas bydōm musiały być pobrane i przetworzōne, jednak po tym ôstanõ wychrōniōne coby ôgraniczyć użycie dysku.</translation> + </message> + <message> + <source>Use the default data directory</source> + <translation>Użyj wychodnego folderu datōw</translation> + </message> + <message> + <source>Use a custom data directory:</source> + <translation>Użyj ôbranego folderu datōw</translation> + </message> + <message> + <source>Bitcoin</source> + <translation>Bitcoin</translation> + </message> + <message> + <source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source> + <translation>Co nojmynij %1 GB datōw ôstanie spamiyntane w tym katalogu, daty te bydōm z czasym corŏz srogsze.</translation> + </message> + <message> + <source>Approximately %1 GB of data will be stored in this directory.</source> + <translation>Kole %1 GB datōw ôstanie spamiyntane w tym katalogu.</translation> + </message> + <message> + <source>%1 will download and store a copy of the Bitcoin block chain.</source> + <translation>%1 sebiere i spamiyntŏ kopijõ kety blokōw Bitcoin.</translation> + </message> + <message> + <source>The wallet will also be stored in this directory.</source> + <translation>Portmanyj tyż ôstanie spamiyntany w tym katalogu.</translation> + </message> + <message> + <source>Error: Specified data directory "%1" cannot be created.</source> + <translation>Feler: podany folder datōw "%1" niy mōg ôstać zrychtowany.</translation> + </message> + <message> + <source>Error</source> + <translation>Feler</translation> + </message> + <message numerus="yes"> + <source>%n GB of free space available</source> + <translation><numerusform>%n GB swobodnego placu dostympne</numerusform><numerusform>%n GB swobodnego placu dostympne</numerusform><numerusform>%n GB swobodnego placu dostympne</numerusform></translation> + </message> + <message numerus="yes"> + <source>(of %n GB needed)</source> + <translation><numerusform>(z %n GB przidajnego)</numerusform><numerusform>(z %n GB przidajnych)</numerusform><numerusform>(z %n GB przidajnych)</numerusform></translation> + </message> +</context> +<context> + <name>ModalOverlay</name> + <message> + <source>Form</source> + <translation>Formular</translation> + </message> + <message> + <source>Recent transactions may not yet be visible, and therefore your wallet's balance might be incorrect. This information will be correct once your wallet has finished synchronizing with the bitcoin network, as detailed below.</source> + <translation>Świyże transakcyje mogōm niy być jeszcze widzialne, a tedyć saldo portmanyja może być niynŏleżne. Te detale bydōm nŏleżne, kej portmanyj zakōńczy synchrōnizacyjõ z necym bitcoin, zgodnie z miyniōnym ôpisym.</translation> + </message> + <message> + <source>Attempting to spend bitcoins that are affected by not-yet-displayed transactions will not be accepted by the network.</source> + <translation>Prōba wydaniŏ bitcoinōw kere niy sōm jeszcze wyświytlōne za transakcyjŏ ôstanie ôdciepniyntŏ bez nec.</translation> + </message> + <message> + <source>Number of blocks left</source> + <translation>Ôstało blokōw</translation> + </message> + <message> + <source>Unknown...</source> + <translation>Niyznōme...</translation> + </message> + <message> + <source>Last block time</source> + <translation>Czŏs ôstatnigo bloku</translation> + </message> + <message> + <source>Progress</source> + <translation>Postymp</translation> + </message> + <message> + <source>Progress increase per hour</source> + <translation>Przirost postympu na godzinã</translation> + </message> + <message> + <source>calculating...</source> + <translation>ôbliczanie...</translation> + </message> + <message> + <source>Estimated time left until synced</source> + <translation>Przewidowany czŏs abszlusu synchrōnizacyje</translation> + </message> + <message> + <source>Hide</source> + <translation>Skryj</translation> + </message> + <message> + <source>Unknown. Syncing Headers (%1)...</source> + <translation>Niyznōme. Synchrōnizowanie nŏgōwkōw (%1)...</translation> + </message> +</context> +<context> + <name>OpenURIDialog</name> + <message> + <source>Open URI</source> + <translation>Ôdewrzij URI</translation> + </message> + <message> + <source>Open payment request from URI or file</source> + <translation>Ôdewrzij żōndanie płatu z URI abo zbioru</translation> + </message> + <message> + <source>URI:</source> + <translation>URI:</translation> + </message> + <message> + <source>Select payment request file</source> + <translation>Ôtwōrz żōndanie płatu ze zbioru</translation> + </message> + <message> + <source>Select payment request file to open</source> + <translation>Ôbier zbiōr żōndaniŏ płatu do ôdewrzyniŏ</translation> + </message> +</context> +<context> + <name>OptionsDialog</name> + <message> + <source>Options</source> + <translation>Ôpcyje</translation> + </message> + <message> + <source>&Main</source> + <translation>&Bazowe</translation> + </message> + <message> + <source>Automatically start %1 after logging in to the system.</source> + <translation>Autōmatycznie sztartnij %1 po wlogowaniu do systymu.</translation> + </message> + <message> + <source>&Start %1 on system login</source> + <translation>&Sztartuj %1 w czasie logowaniŏ do systymu</translation> + </message> + <message> + <source>Size of &database cache</source> + <translation>Srogość bufōra bazy datōw</translation> + </message> + <message> + <source>MB</source> + <translation>MB</translation> + </message> + <message> + <source>Number of script &verification threads</source> + <translation>Wielość wōntkōw &weryfikacyje skryptu</translation> + </message> + <message> + <source>IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1)</source> + <translation>Adresa IP proxy (bp. IPv4: 127.0.0.1 / IPv6: ::1)</translation> + </message> + <message> + <source>Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Exit in the menu.</source> + <translation>Minimalizuje zamiast zakōńczyć fungowanie aplikacyje przi zawiyraniu ôkna. Kej ta ôpcyjŏ je zapuszczonŏ, aplikacyjŏ zakōńczy fungowanie po ôbraniu Zawrzij w myni.</translation> + </message> + <message> + <source>Active command-line options that override above options:</source> + <translation>Aktywne ôpcyje piski kōmynd, kere nadpisujōm powyższe ôpcyje:</translation> + </message> + <message> + <source>Open the %1 configuration file from the working directory.</source> + <translation>Ôdewrzij %1 zbiōr kōnfiguracyje z czynnego katalogu.</translation> + </message> + <message> + <source>Open Configuration File</source> + <translation>Ôdewrzij zbiōr kōnfiguracyje</translation> + </message> + <message> + <source>Reset all client options to default.</source> + <translation>Prziwrōć wszyjske wychodne ustawiyniŏ klijynta.</translation> + </message> + <message> + <source>&Reset Options</source> + <translation>&Resetuj Ôpcyje</translation> + </message> + <message> + <source>&Network</source> + <translation>&Nec</translation> + </message> + <message> + <source>Disables some advanced features but all blocks will still be fully validated. Reverting this setting requires re-downloading the entire blockchain. Actual disk usage may be somewhat higher.</source> + <translation>Zastawiŏ niykere moderne funkcyje, ale wszyjske bloki durch bydōm w połni wybadowane. Cŏfniyńcie tego nasztalowaniŏ fołdruje pōnownego sebraniŏ cołkij kety blokōw. Istne spotrzebowanie dysku może być cosikej wyższe.</translation> + </message> + <message> + <source>Prune &block storage to</source> + <translation>Przitnij skłŏd &blokōw do</translation> + </message> + <message> + <source>GB</source> + <translation>GB</translation> + </message> + <message> + <source>Reverting this setting requires re-downloading the entire blockchain.</source> + <translation>Cŏfniyńcie tego ustawiyniŏ wymŏgŏ pōnownego sebraniŏ cołkij kety blokōw.</translation> + </message> + <message> + <source>(0 = auto, <0 = leave that many cores free)</source> + <translation>(0 = autōmatycznie, <0 = ôstŏw tela swobodnych drzyni)</translation> + </message> + <message> + <source>W&allet</source> + <translation>Portm&anyj</translation> + </message> + <message> + <source>Expert</source> + <translation>Ekspert</translation> + </message> + <message> + <source>Enable coin &control features</source> + <translation>Zapuść funkcyje kōntroli mōnet</translation> + </message> + <message> + <source>If you disable the spending of unconfirmed change, the change from a transaction cannot be used until that transaction has at least one confirmation. This also affects how your balance is computed.</source> + <translation>Jeźli zastawisz możebność wydaniŏ niyprzituplikowanyj wydanej wydŏwki, wydŏwka z transakcyje niy bydzie mogła ôstać użytŏ, podwiela ta transakcyjŏ niy bydzie miała nojmynij jednego przituplowaniŏ. To tyż mŏ wpływ na porachowanie Twojigo salda.</translation> + </message> + <message> + <source>&Spend unconfirmed change</source> + <translation>&Wydej niyprzituplowanõ wydŏwkã</translation> + </message> + <message> + <source>Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled.</source> + <translation>Autōmatycznie ôdewrzij port klijynta Bitcoin na routerze. Ta ôpcyjŏ funguje ino jeźli twōj router podpiyrŏ UPnP i je ôno zapuszczone.</translation> + </message> + <message> + <source>Map port using &UPnP</source> + <translation>Mapuj port przi używaniu &UPnP</translation> + </message> + <message> + <source>Accept connections from outside.</source> + <translation>Akceptuj skuplowania ôd zewnōntrz.</translation> + </message> + <message> + <source>Allow incomin&g connections</source> + <translation>Zwōl na skuplowania przichodzōnce</translation> + </message> + <message> + <source>Connect to the Bitcoin network through a SOCKS5 proxy.</source> + <translation>Skupluj sie z necym Bitcoin bez SOCKS5 proxy.</translation> + </message> + <message> + <source>&Connect through SOCKS5 proxy (default proxy):</source> + <translation>&Skupluj bez proxy SOCKS5 (wychodne proxy):</translation> + </message> + <message> + <source>Proxy &IP:</source> + <translation>Proxy &IP:</translation> + </message> + <message> + <source>&Port:</source> + <translation>&Port:</translation> + </message> + <message> + <source>Port of the proxy (e.g. 9050)</source> + <translation>Port ôd proxy (bp. 9050)</translation> + </message> + <message> + <source>IPv4</source> + <translation>IPv4</translation> + </message> + <message> + <source>IPv6</source> + <translation>IPv6</translation> + </message> + <message> + <source>Tor</source> + <translation>Tor</translation> + </message> + <message> + <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services.</source> + <translation>Skupluj sie z necym Bitcoin ze pōmocōm ôsobnego proxy SOCKS5 dlŏ necu TOR</translation> + </message> + <message> + <source>&Window</source> + <translation>Ô&kno</translation> + </message> + <message> + <source>User Interface &language:</source> + <translation>Gŏdka &używŏcza:</translation> + </message> + <message> + <source>The user interface language can be set here. This setting will take effect after restarting %1.</source> + <translation>Idzie sam nasztalować gŏdka interfejsu używŏcza. Nasztalowanie prziniesie skutki po resztarcie %1.</translation> + </message> + <message> + <source>&OK</source> + <translation>&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Pociep</translation> + </message> + <message> + <source>default</source> + <translation>wychodny</translation> + </message> + <message> + <source>none</source> + <translation>żŏdyn</translation> + </message> + <message> + <source>Configuration options</source> + <translation>Ôpcyje kōnfiguracyje</translation> + </message> + <message> + <source>Error</source> + <translation>Feler</translation> + </message> + </context> +<context> + <name>OverviewPage</name> + <message> + <source>Form</source> + <translation>Formular</translation> + </message> + <message> + <source>The displayed information may be out of date. Your wallet automatically synchronizes with the Bitcoin network after a connection is established, but this process has not completed yet.</source> + <translation>Wyświytlanŏ informacyjŏ może być niyterŏźnŏ. Twōj portmanyj synchrōnizuje sie autōmatycznie z necym bitcoin zarŏz po tym, jak zrychtowane je skuplowanie, ale proces tyn niy ôstoł jeszcze skōńczōny.</translation> + </message> + <message> + <source>Available:</source> + <translation>Dostympne:</translation> + </message> + <message> + <source>Pending:</source> + <translation>Czekajōnce:</translation> + </message> + <message> + <source>Balances</source> + <translation>Salda</translation> + </message> + <message> + <source>Total:</source> + <translation>Cuzamyn:</translation> + </message> + <message> + <source>Your current total balance</source> + <translation>Twoje terŏźne saldo</translation> + </message> + </context> +<context> + <name>PaymentServer</name> + <message> + <source>URI handling</source> + <translation>Bedynōng URI</translation> + </message> + <message> + <source>'bitcoin://' is not a valid URI. Use 'bitcoin:' instead.</source> + <translation>'bitcoin://' to niyma nŏleżne URI. Użyj 'bitcoin:'.</translation> + </message> + <message> + <source>Payment request network doesn't match client network.</source> + <translation>Nec żōndaniŏ płatu niy ôdpadŏ necu klijynta.</translation> + </message> + <message> + <source>Unverified payment requests to custom payment scripts are unsupported.</source> + <translation>Niyzweryfikowane żōndaniŏ płatu do włŏsnych skryptōw płatu sōm niypodpiyrane.</translation> + </message> + <message> + <source>Network request error</source> + <translation>Feler żōndaniŏ necu</translation> + </message> + <message> + <source>Payment acknowledged</source> + <translation>Płat przituplowany</translation> + </message> +</context> +<context> + <name>PeerTableModel</name> + <message> + <source>User Agent</source> + <translation>Agynt Używŏcza</translation> + </message> + <message> + <source>Ping</source> + <translation>Ping</translation> + </message> + <message> + <source>Received</source> + <translation>Ôdebrane</translation> + </message> +</context> +<context> + <name>QObject</name> + <message> + <source>Amount</source> + <translation>Kwota</translation> + </message> + <message> + <source>Enter a Bitcoin address (e.g. %1)</source> + <translation>Wkludź adresã Bitcoin (bp. %1)</translation> + </message> + <message> + <source>%1 d</source> + <translation>%1 d</translation> + </message> + <message> + <source>%1 h</source> + <translation>%1 h</translation> + </message> + <message> + <source>%1 m</source> + <translation>%1 m</translation> + </message> + <message> + <source>%1 s</source> + <translation>%1 s</translation> + </message> + <message> + <source>N/A</source> + <translation>N/A</translation> + </message> + <message> + <source>%1 ms</source> + <translation>%1 ms</translation> + </message> + <message> + <source>%1 B</source> + <translation>%1 B</translation> + </message> + <message> + <source>%1 KB</source> + <translation>%1 KB</translation> + </message> + <message> + <source>%1 MB</source> + <translation>%1 MB</translation> + </message> + <message> + <source>%1 GB</source> + <translation>%1 GB</translation> + </message> + <message> + <source>unknown</source> + <translation>niyznōme</translation> + </message> +</context> +<context> + <name>QObject::QObject</name> + <message> + <source>Error: %1</source> + <translation>Feler: %1</translation> + </message> +</context> +<context> + <name>QRImageWidget</name> + <message> + <source>&Save Image...</source> + <translation>&Spamiyntej Ôbrŏzek</translation> + </message> + <message> + <source>&Copy Image</source> + <translation>&Kopiyruj Ôbrŏzek</translation> + </message> + <message> + <source>Save QR Code</source> + <translation>Spamiyntej kod QR</translation> + </message> + <message> + <source>PNG Image (*.png)</source> + <translation>Ôbrŏzek PNG (*.png)</translation> + </message> +</context> +<context> + <name>RPCConsole</name> + <message> + <source>N/A</source> + <translation>N/A</translation> + </message> + <message> + <source>Client version</source> + <translation>Wersyjŏ klijynta</translation> + </message> + <message> + <source>Debug window</source> + <translation>Ôkno debugowaniŏ</translation> + </message> + <message> + <source>Using BerkeleyDB version</source> + <translation>Używanie wersyje BerkeleyDB</translation> + </message> + <message> + <source>Datadir</source> + <translation>Katalog datōw</translation> + </message> + <message> + <source>Startup time</source> + <translation>Czŏs sztartniyńciŏ</translation> + </message> + <message> + <source>Network</source> + <translation>Nec</translation> + </message> + <message> + <source>Name</source> + <translation>Miano</translation> + </message> + <message> + <source>Number of connections</source> + <translation>Wielość skuplowań</translation> + </message> + <message> + <source>Block chain</source> + <translation>Keta blokōw</translation> + </message> + <message> + <source>Current number of blocks</source> + <translation>Terŏźniŏ wielość blokōw</translation> + </message> + <message> + <source>Current number of transactions</source> + <translation>Terŏźniŏ wielość transakcyji</translation> + </message> + <message> + <source>Wallet: </source> + <translation>Portmanyj: </translation> + </message> + <message> + <source>Received</source> + <translation>Ôdebrane</translation> + </message> + <message> + <source>Direction</source> + <translation>Richtōng</translation> + </message> + <message> + <source>Version</source> + <translation>Wersyjŏ</translation> + </message> + <message> + <source>User Agent</source> + <translation>Agynt Używŏcza</translation> + </message> + <message> + <source>Services</source> + <translation>Usugi</translation> + </message> + <message> + <source>Connection Time</source> + <translation>Czŏs Skuplowaniŏ</translation> + </message> + <message> + <source>Last block time</source> + <translation>Czas ôstatnigo bloku</translation> + </message> + <message> + <source>&Open</source> + <translation>Ô&dewrzij</translation> + </message> + <message> + <source>&Network Traffic</source> + <translation>&Ruch necowy</translation> + </message> + <message> + <source>In:</source> + <translation>Wchōd:</translation> + </message> + <message> + <source>Out:</source> + <translation>Wychōd:</translation> + </message> + <message> + <source>1 &day</source> + <translation>1 &dziyń</translation> + </message> + <message> + <source>&Disconnect</source> + <translation>Ô&dkupluj</translation> + </message> + <message> + <source>default wallet</source> + <translation>wychodny portmanyj</translation> + </message> + <message> + <source>Welcome to the %1 RPC console.</source> + <translation>Witej w %1 kōnsoli RPC.</translation> + </message> + <message> + <source>WARNING: Scammers have been active, telling users to type commands here, stealing their wallet contents. Do not use this console without fully understanding the ramifications of a command.</source> + <translation>POZŌR: Machlyrze namŏwiajōm do wpisowaniŏ tukej roztōmajtych nakŏzań coby porwać portmanyj. Niy używej tyj kōnsole bez połnego zrozumiyniŏ wpisowanych nakŏzań.</translation> + </message> + <message> + <source>Network activity disabled</source> + <translation>Aktywność necowŏ zastawiōnŏ</translation> + </message> + <message> + <source>never</source> + <translation>nikej</translation> + </message> + <message> + <source>Inbound</source> + <translation>Wchodowy</translation> + </message> + <message> + <source>Outbound</source> + <translation>Wychodowy</translation> + </message> + <message> + <source>Yes</source> + <translation>Ja</translation> + </message> + <message> + <source>No</source> + <translation>Niy</translation> + </message> + </context> +<context> + <name>ReceiveCoinsDialog</name> + <message> + <source>&Label:</source> + <translation>&Etyketa:</translation> + </message> + <message> + <source>An optional message to attach to the payment request, which will be displayed when the request is opened. Note: The message will not be sent with the payment over the Bitcoin network.</source> + <translation>Ôpcyjōnalnŏ wiadōmość do prziwstōniŏ do żōndaniŏ płatu, kerŏ bydzie wyświytlanŏ, kej żōndanie ôstanie ôdewrzōne. Napōmniynie: wiadōmość ta niy ôstanie wysłanŏ z płatym w nec Bitcoin.</translation> + </message> + <message> + <source>Clear</source> + <translation>Wypucuj</translation> + </message> + <message> + <source>Native segwit addresses (aka Bech32 or BIP-173) reduce your transaction fees later on and offer better protection against typos, but old wallets don't support them. When unchecked, an address compatible with older wallets will be created instead.</source> + <translation>Natywne adresy segwit (aka Bech32 abo BIP-173) zmyńszajōm niyskorzij twoje ôpłŏcki za transakcyje i dadzōm lepsze zabezpieczynie przed chybami, ale stare portmanyje jejich niy podpiyrajōm. Jeźli ôdznaczōne, zrychtowanŏ ôstanie adresa kōmpatybilnŏ ze starszymi portmanyjami.</translation> + </message> + <message> + <source>Show</source> + <translation>Pokŏż</translation> + </message> + <message> + <source>Remove</source> + <translation>Wychrōń</translation> + </message> + <message> + <source>Copy URI</source> + <translation>Kopiyruj URI</translation> + </message> + <message> + <source>Copy label</source> + <translation>Kopiyruj etyketã</translation> + </message> + <message> + <source>Copy message</source> + <translation>Kopiyruj wiadōmość</translation> + </message> + <message> + <source>Copy amount</source> + <translation>Kopiyruj kwotã</translation> + </message> +</context> +<context> + <name>ReceiveRequestDialog</name> + <message> + <source>QR Code</source> + <translation>Kod QR</translation> + </message> + <message> + <source>Copy &URI</source> + <translation>Kopiyruj &URI</translation> + </message> + <message> + <source>Copy &Address</source> + <translation>Kopiyruj &Adresã</translation> + </message> + <message> + <source>&Save Image...</source> + <translation>&Spamiyntej Ôbrozek</translation> + </message> + <message> + <source>Payment information</source> + <translation>Informacyje ô płacie</translation> + </message> + <message> + <source>URI</source> + <translation>URI</translation> + </message> + <message> + <source>Address</source> + <translation>Adresa</translation> + </message> + <message> + <source>Amount</source> + <translation>Kwota</translation> + </message> + <message> + <source>Label</source> + <translation>Etyketa</translation> + </message> + <message> + <source>Message</source> + <translation>Wiadōmość</translation> + </message> + <message> + <source>Wallet</source> + <translation>Portmanyj</translation> + </message> + </context> +<context> + <name>RecentRequestsTableModel</name> + <message> + <source>Date</source> + <translation>Datōm</translation> + </message> + <message> + <source>Label</source> + <translation>Etyketa</translation> + </message> + <message> + <source>Message</source> + <translation>Wiadōmość</translation> + </message> + <message> + <source>(no label)</source> + <translation>(chyba etykety)</translation> + </message> + </context> +<context> + <name>SendCoinsDialog</name> + <message> + <source>Send Coins</source> + <translation>Poślij mōnety</translation> + </message> + <message> + <source>Quantity:</source> + <translation>Wielość:</translation> + </message> + <message> + <source>Bytes:</source> + <translation>Bajtōw:</translation> + </message> + <message> + <source>Amount:</source> + <translation>Kwota:</translation> + </message> + <message> + <source>Fee:</source> + <translation>Ôpłŏcka:</translation> + </message> + <message> + <source>After Fee:</source> + <translation>Po ôpłŏcce:</translation> + </message> + <message> + <source>Change:</source> + <translation>Wydŏwka:</translation> + </message> + <message> + <source>Choose...</source> + <translation>Ôbier...</translation> + </message> + <message> + <source>Warning: Fee estimation is currently not possible.</source> + <translation>Pozōr: Ôszacowanie ôpłŏcki za transakcyje je aktualnie niymożebne.</translation> + </message> + <message> + <source>per kilobyte</source> + <translation>na kilobajt</translation> + </message> + <message> + <source>Hide</source> + <translation>Skryj</translation> + </message> + <message> + <source>Recommended:</source> + <translation>Doradzane:</translation> + </message> + <message> + <source>Custom:</source> + <translation>Włŏsne:</translation> + </message> + <message> + <source>Dust:</source> + <translation>Sztaub:</translation> + </message> + <message> + <source>Balance:</source> + <translation>Saldo:</translation> + </message> + <message> + <source>Copy quantity</source> + <translation>Kopiyruj wielość</translation> + </message> + <message> + <source>Copy amount</source> + <translation>Kopiyruj kwotã</translation> + </message> + <message> + <source>Copy fee</source> + <translation>Kopiyruj ôpłŏckã</translation> + </message> + <message> + <source>Copy after fee</source> + <translation>Kopiyruj wielość po ôpłŏcce</translation> + </message> + <message> + <source>Copy bytes</source> + <translation>Kopiyruj wielość bajtōw</translation> + </message> + <message> + <source>Copy dust</source> + <translation>Kopiyruj sztaub</translation> + </message> + <message> + <source>Copy change</source> + <translation>Kopiyruj wydŏwkã</translation> + </message> + <message> + <source>%1 (%2 blocks)</source> + <translation>%1 (%2 blokōw)</translation> + </message> + <message> + <source>or</source> + <translation>abo</translation> + </message> + <message> + <source>Transaction creation failed!</source> + <translation>Utworzynie transakcyje niy podarziło sie!</translation> + </message> + <message> + <source>Warning: Invalid Bitcoin address</source> + <translation>Pozōr: niynŏleżnŏ adresa Bitcoin</translation> + </message> + <message> + <source>Warning: Unknown change address</source> + <translation>Pozōr: Niyznōmŏ adresa wydŏwki</translation> + </message> + <message> + <source>(no label)</source> + <translation>(chyba etykety)</translation> + </message> +</context> +<context> + <name>SendCoinsEntry</name> + <message> + <source>&Label:</source> + <translation>&Etyketa:</translation> + </message> + <message> + <source>This is a normal payment.</source> + <translation>To je normalny płat.</translation> + </message> + <message> + <source>Alt+A</source> + <translation>Alt+A</translation> + </message> + <message> + <source>Alt+P</source> + <translation>Alt+P</translation> + </message> + <message> + <source>Use available balance</source> + <translation>Użyj dostympnego salda</translation> + </message> + <message> + <source>Message:</source> + <translation>Wiadōmość:</translation> + </message> + <message> + <source>A message that was attached to the bitcoin: URI which will be stored with the transaction for your reference. Note: This message will not be sent over the Bitcoin network.</source> + <translation>Wiadōmość, kerŏ ôstała prziwstōnŏ do URI bitcoin:, kerŏ bydzie przechowowanŏ z transakcyjōm w cylach informacyjnych. Napōmniynie: Ta wiadōmość niy bydzie rozszyrzowanŏ w necu Bitcoin.</translation> + </message> + </context> +<context> + <name>SendConfirmationDialog</name> + <message> + <source>Yes</source> + <translation>Ja</translation> + </message> +</context> +<context> + <name>ShutdownWindow</name> + </context> +<context> + <name>SignVerifyMessageDialog</name> + <message> + <source>Signatures - Sign / Verify a Message</source> + <translation>Szkryfki - Podpisz / Zweryfikuj Wiadōmość</translation> + </message> + <message> + <source>&Sign Message</source> + <translation>&Szkryftnij Wiadōmość</translation> + </message> + <message> + <source>Alt+A</source> + <translation>Alt+A</translation> + </message> + <message> + <source>Alt+P</source> + <translation>Alt+P</translation> + </message> + <message> + <source>Sign &Message</source> + <translation>Szkryftnij &Wiadōmość</translation> + </message> + <message> + <source>&Verify Message</source> + <translation>&Weryfikuj Wiadōmość</translation> + </message> + <message> + <source>Message signing failed.</source> + <translation>Szkryftniyńcie wiadōmości niy podarziło sie.</translation> + </message> + <message> + <source>Message signed.</source> + <translation>Wiadōmość szkryftniyntŏ.</translation> + </message> + <message> + <source>Message verification failed.</source> + <translation>Weryfikacyjŏ wiadōmości niy podarziła sie.</translation> + </message> + </context> +<context> + <name>SplashScreen</name> + <message> + <source>[testnet]</source> + <translation>[testnet]</translation> + </message> +</context> +<context> + <name>TrafficGraphWidget</name> + <message> + <source>KB/s</source> + <translation>KB/s</translation> + </message> +</context> +<context> + <name>TransactionDesc</name> + <message> + <source>Status</source> + <translation>Sztatus</translation> + </message> + <message> + <source>Date</source> + <translation>Datōm</translation> + </message> + <message> + <source>Source</source> + <translation>Źrōdło</translation> + </message> + <message> + <source>From</source> + <translation>Z</translation> + </message> + <message> + <source>unknown</source> + <translation>niyznōme</translation> + </message> + <message> + <source>To</source> + <translation>Do</translation> + </message> + <message> + <source>label</source> + <translation>etyketa</translation> + </message> + <message> + <source>Message</source> + <translation>Wiadōmość</translation> + </message> + <message> + <source>Comment</source> + <translation>Kōmyntŏrz</translation> + </message> + <message> + <source>Transaction</source> + <translation>Transakcyjŏ</translation> + </message> + <message> + <source>Amount</source> + <translation>Kwota</translation> + </message> + </context> +<context> + <name>TransactionDescDialog</name> + </context> +<context> + <name>TransactionTableModel</name> + <message> + <source>Date</source> + <translation>Datōm</translation> + </message> + <message> + <source>Type</source> + <translation>Zorta</translation> + </message> + <message> + <source>Label</source> + <translation>Etyketa</translation> + </message> + <message> + <source>Received with</source> + <translation>Ôdebrane z</translation> + </message> + <message> + <source>Received from</source> + <translation>Ôdebrane ôd</translation> + </message> + <message> + <source>Payment to yourself</source> + <translation>Płat do siebie</translation> + </message> + <message> + <source>(no label)</source> + <translation>(chyba etykety)</translation> + </message> + </context> +<context> + <name>TransactionView</name> + <message> + <source>All</source> + <translation>Wszyjske</translation> + </message> + <message> + <source>Today</source> + <translation>Dzisiej</translation> + </message> + <message> + <source>Received with</source> + <translation>Ôdebrane z</translation> + </message> + <message> + <source>Other</source> + <translation>Inksze</translation> + </message> + <message> + <source>Enter address, transaction id, or label to search</source> + <translation>Wkludź adresa, idyntyfikatōr transakcyje abo etyketã coby wyszukać</translation> + </message> + <message> + <source>Copy address</source> + <translation>Kopiyruj adresã</translation> + </message> + <message> + <source>Copy label</source> + <translation>Kopiyruj etyketã</translation> + </message> + <message> + <source>Copy amount</source> + <translation>Kopiyruj kwotã</translation> + </message> + <message> + <source>Copy transaction ID</source> + <translation>Kopiyruj ID transakcyje</translation> + </message> + <message> + <source>Edit label</source> + <translation>Edytuj etyketa</translation> + </message> + <message> + <source>Comma separated file (*.csv)</source> + <translation>Zbiōr *.CSV (dane rozdzielane kōmami)</translation> + </message> + <message> + <source>Confirmed</source> + <translation>Przituplowany</translation> + </message> + <message> + <source>Date</source> + <translation>Datōm</translation> + </message> + <message> + <source>Type</source> + <translation>Zorta</translation> + </message> + <message> + <source>Label</source> + <translation>Etyketa</translation> + </message> + <message> + <source>Address</source> + <translation>Adresa</translation> + </message> + <message> + <source>ID</source> + <translation>ID</translation> + </message> + <message> + <source>Exporting Failed</source> + <translation>Eksportowanie niy podarziło sie</translation> + </message> + <message> + <source>to</source> + <translation>do</translation> + </message> +</context> +<context> + <name>UnitDisplayStatusBarControl</name> + </context> +<context> + <name>WalletFrame</name> + </context> +<context> + <name>WalletModel</name> + <message> + <source>Send Coins</source> + <translation>Poślij mōnety</translation> + </message> + <message> + <source>New fee:</source> + <translation>Nowŏ ôpłŏcka:</translation> + </message> + </context> +<context> + <name>WalletView</name> + <message> + <source>Export the data in the current tab to a file</source> + <translation>Eksportuj dane z aktywnyj szkarty do zbioru</translation> + </message> + <message> + <source>Backup Failed</source> + <translation>Backup niy podarził sie</translation> + </message> + <message> + <source>Cancel</source> + <translation>Pociep</translation> + </message> +</context> +<context> + <name>bitcoin-core</name> + <message> + <source>Bitcoin Core</source> + <translation>Bitcoin Core</translation> + </message> + <message> + <source>The %s developers</source> + <translation>Twōrcy %s</translation> + </message> + <message> + <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source> + <translation>Pozōr: Nec niy wydŏwŏ sie w połni zgodliwy! Niykerzi grubiŏrze wydajōm sie doświadczać niyprzileżytości.</translation> + </message> + <message> + <source>Copyright (C) %i-%i</source> + <translation>Copyright (C) %i-%i</translation> + </message> + <message> + <source>Error loading %s</source> + <translation>Feler wgrŏwaniŏ %s</translation> + </message> + <message> + <source>Error loading %s: Private keys can only be disabled during creation</source> + <translation>Feler wgrŏwaniŏ %s: Klucze prywatne mogōm być zastawiōne ino w czasie tworzyniŏ</translation> + </message> + <message> + <source>Error loading %s: Wallet corrupted</source> + <translation>Feler wgrŏwaniŏ %s: Portmanyj poprzniōny</translation> + </message> + <message> + <source>Error loading %s: Wallet requires newer version of %s</source> + <translation>Feler wgrŏwaniŏ %s: Portmanyj wymŏgŏ nowszyj wersyje %s</translation> + </message> + <message> + <source>Error loading block database</source> + <translation>Feler wgrŏwaniŏ bazy blokōw</translation> + </message> + <message> + <source>Error: Disk space is low!</source> + <translation>Feler: Za mało wolnego placu na dysku!</translation> + </message> + <message> + <source>Loading P2P addresses...</source> + <translation>Wgrŏwanie adres P2P...</translation> + </message> + <message> + <source>Loading banlist...</source> + <translation>Wgrŏwanie wykŏzu zaszperowanych...</translation> + </message> + <message> + <source>Unsupported argument -benchmark ignored, use -debug=bench.</source> + <translation>Niypodpiyrany argumynt -benchmark zignorowany, użyj -debug=bench.</translation> + </message> + <message> + <source>Unsupported argument -debugnet ignored, use -debug=net.</source> + <translation>Niypodpiyrany argumynt -debugnet zignorowany, użyj -debug=net.</translation> + </message> + <message> + <source>Unsupported argument -tor found, use -onion.</source> + <translation>Znŏdniynto było niypodpiyrany argumynt -tor, użyj -onion.</translation> + </message> + <message> + <source>Unsupported logging category %s=%s.</source> + <translation>Niypodpiyranŏ kategoryjŏ registrowaniŏ %s=%s.</translation> + </message> + <message> + <source>Verifying blocks...</source> + <translation>Weryfikacyjŏ blokōw...</translation> + </message> + <message> + <source>Error loading %s: You can't disable HD on an already existing HD wallet</source> + <translation>Feler w czasie wgrŏwaniŏ %s: Niy idzie zastawić HD w już bydōncym portmanyju HD</translation> + </message> + <message> + <source>Information</source> + <translation>Informacyjŏ</translation> + </message> + <message> + <source>Signing transaction failed</source> + <translation>Szkryftniyńcie transakcyji niy podarziło sie</translation> + </message> + <message> + <source>This is experimental software.</source> + <translation>To je eksperymyntalny softwer.</translation> + </message> + <message> + <source>Transaction too large</source> + <translation>Transakcyjŏ za srogŏ</translation> + </message> + <message> + <source>Verifying wallet(s)...</source> + <translation>Weryfikacyjŏ portmanyja(ōw)...</translation> + </message> + <message> + <source>Warning</source> + <translation>Pozōr</translation> + </message> + <message> + <source>Warning: unknown new rules activated (versionbit %i)</source> + <translation>Pozōr: aktywowano było niyznōme nowe prawidła (versionbit %i)</translation> + </message> + <message> + <source>Error loading %s: You can't enable HD on an already existing non-HD wallet</source> + <translation>Feler w czasie wgrŏwaniŏ %s: Niy idzie zapuścić HD w już bydōncym portmanyju niy-HD</translation> + </message> + <message> + <source>Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments.</source> + <translation>Imyntnŏ dugość kety wersyje (%i) przekrŏczŏ maksymalnõ dopuszczalnõ dugość (%i). Zmyńsz wielość abo miara parametra uacomment.</translation> + </message> + <message> + <source>Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported.</source> + <translation>Znŏdniynto było niypodpiyrany argumynt -socks. Ôbiyranie wersyje SOCKS je już niymożebne, podpiyrane sōm ino proxy SOCKS5.</translation> + </message> + <message> + <source>Unsupported argument -whitelistalwaysrelay ignored, use -whitelistrelay and/or -whitelistforcerelay.</source> + <translation>Niypodpiyrany argumynt -whitelistalwaysrelay zignorowany, użyj -whitelistrelay i/abo -whitelistforcerelay.</translation> + </message> + <message> + <source>Warning: Unknown block versions being mined! It's possible unknown rules are in effect</source> + <translation>Pozōr: wydobywane sōm niyznōme wersyje blokōw! Możliwe, iże ôbowiōnzujōm niyznōme prawidła.</translation> + </message> + <message> + <source>Warning: Wallet file corrupt, data salvaged! Original %s saved as %s in %s; if your balance or transactions are incorrect you should restore from a backup.</source> + <translation>Pozōr: Ôdtworzōno było dane z poprzniōnego zbioru portmanyja! Ôryginalny %s ôstoł zapisany za %s w %s; jeźli twoje saldo abo transakcyje sōm niynŏleżne winiyn żeś prziwrōcić kopijõ ibrycznõ.</translation> + </message> + <message> + <source>Error loading wallet %s. Duplicate -wallet filename specified.</source> + <translation>Feler w czasie wgrŏwaniŏ portmanyja %s. Podanŏ tuplowane miano zbioru w -wallet.</translation> + </message> + <message> + <source>Starting network threads...</source> + <translation>Sztartowanie wōntkōw necowych...</translation> + </message> + <message> + <source>Unknown network specified in -onlynet: '%s'</source> + <translation>Niyznōmy nec ôkryślōny w -onlynet: '%s'</translation> + </message> + <message> + <source>Warning: Private keys detected in wallet {%s} with disabled private keys</source> + <translation>Pozōr: Wykryto było klucze prywatne w portmanyju {%s} kery mŏ zastawiōne klucze prywatne</translation> + </message> + <message> + <source>Loading block index...</source> + <translation>Wgrŏwanie indeksu blokōw...</translation> + </message> + <message> + <source>Loading wallet...</source> + <translation>Wgrŏwanie portmanyja...</translation> + </message> + <message> + <source>Rescanning...</source> + <translation>Pōnowne skanowanie</translation> + </message> + <message> + <source>Done loading</source> + <translation>Wgrŏwanie zakōńczōne</translation> + </message> + <message> + <source>Error</source> + <translation>Feler</translation> + </message> +</context> +</TS>
\ No newline at end of file diff --git a/src/qt/locale/bitcoin_tr.ts b/src/qt/locale/bitcoin_tr.ts index b092ee060e..db30aa04c2 100644 --- a/src/qt/locale/bitcoin_tr.ts +++ b/src/qt/locale/bitcoin_tr.ts @@ -326,6 +326,14 @@ <translation>&URI Aç...</translation> </message> <message> + <source>Wallet:</source> + <translation>Cüzdan:</translation> + </message> + <message> + <source>default wallet</source> + <translation>varsayılan cüzdan</translation> + </message> + <message> <source>Click to disable network activity.</source> <translation>Ağ etkinliğini devre dışı bırakmak için tıklayın.</translation> </message> @@ -346,6 +354,10 @@ <translation>Diskteki bloklar yeniden indeksleniyor...</translation> </message> <message> + <source>Proxy is <b>enabled</b>: %1</source> + <translation>Tünelleme <b>etkin</b>: %1</translation> + </message> + <message> <source>Send coins to a Bitcoin address</source> <translation>Bir bitcoin adresine bitcoin gönder</translation> </message> @@ -514,6 +526,12 @@ </translation> </message> <message> + <source>Wallet: %1 +</source> + <translation>Cüzdan: %1 +</translation> + </message> + <message> <source>Type: %1 </source> <translation>Tür: %1 @@ -750,6 +768,10 @@ <translation>Girilen "%1" adresi geçerli bir Bitcoin adresi değildir.</translation> </message> <message> + <source>Address "%1" already exists as a receiving address with label "%2" and so cannot be added as a sending address.</source> + <translation>Adres "%1" adres "%2" etiketiyle alım adresiniz olarak mevcut ve bu sebepten gönderen adres olarak eklenemiyor.</translation> + </message> + <message> <source>Could not unlock wallet.</source> <translation>Cüzdan kilidi açılamadı.</translation> </message> @@ -1479,6 +1501,10 @@ <translation>Hata: Belirtilen "%1" veri klasörü yoktur.</translation> </message> <message> + <source>Error: Cannot parse configuration file: %1.</source> + <translation>Hata: %1 yapılandırma dosyası ayrıştırılamadı. </translation> + </message> + <message> <source>Error: %1</source> <translation>Hata: %1</translation> </message> @@ -1569,6 +1595,14 @@ <translation>Bellek kullanımı</translation> </message> <message> + <source>Wallet: </source> + <translation>Cüzdan:</translation> + </message> + <message> + <source>(none)</source> + <translation>(boş)</translation> + </message> + <message> <source>&Reset</source> <translation>&Sıfırla</translation> </message> @@ -1737,6 +1771,10 @@ <translation>&Yasaklamayı Kaldır</translation> </message> <message> + <source>default wallet</source> + <translation>varsayılan cüzdan</translation> + </message> + <message> <source>Welcome to the %1 RPC console.</source> <translation>%1 RPC konsoluna hoş geldiniz.</translation> </message> @@ -1761,6 +1799,14 @@ <translation>Ağ etkinliği devre dışı bırakıldı</translation> </message> <message> + <source>Executing command without any wallet</source> + <translation>Komut bir cüzdan olmadan çalıştırılıyor</translation> + </message> + <message> + <source>Executing command using "%1" wallet</source> + <translation>Komut "%1" cüzdanı kullanılarak çalıştırılıyor</translation> + </message> + <message> <source>(node id: %1)</source> <translation>(düğüm kimliği: %1)</translation> </message> @@ -1832,6 +1878,10 @@ <translation>Temizle</translation> </message> <message> + <source>Generate native segwit (Bech32) address</source> + <translation>Yerli segwit (Bech32) adresi oluştur</translation> + </message> + <message> <source>Requested payments history</source> <translation>Talep edilen ödemelerin tarihçesi</translation> </message> @@ -2141,10 +2191,22 @@ <translation>veya</translation> </message> <message> + <source>from wallet %1</source> + <translation>cüzdan %1'den</translation> + </message> + <message> + <source>Please, review your transaction.</source> + <translation>Lütfen, işleminizi gözden geçirin.</translation> + </message> + <message> <source>Transaction fee</source> <translation>İşlem ücreti</translation> </message> <message> + <source>Total Amount</source> + <translation>Toplam Tutar</translation> + </message> + <message> <source>Confirm send coins</source> <translation>Bitcoin gönderimini onaylayın</translation> </message> @@ -2990,7 +3052,11 @@ <source>The wallet data was successfully saved to %1.</source> <translation>Cüzdan verileri %1 konumuna başarıyla kaydedildi.</translation> </message> - </context> + <message> + <source>Cancel</source> + <translation>İptal</translation> + </message> +</context> <context> <name>bitcoin-core</name> <message> @@ -3162,6 +3228,10 @@ <translation> -fallbackfee=<tutar> için geçersiz tutar: '%s'</translation> </message> <message> + <source>Upgrading txindex database</source> + <translation>txindex veritabanı yükseltiliyor</translation> + </message> + <message> <source>Loading P2P addresses...</source> <translation>P2P adresleri yükleniyor...</translation> </message> @@ -3202,6 +3272,10 @@ <translation>Bu bilgisayarda %s unsuruna bağlanılamadı. %s muhtemelen hâlihazırda çalışmaktadır.</translation> </message> <message> + <source>Unable to generate keys</source> + <translation>Anahtar üretilemiyor</translation> + </message> + <message> <source>Unsupported argument -benchmark ignored, use -debug=bench.</source> <translation>Desteklenmeyen -benchmark argümanı görmezden gelindi, -debug=bench kullanınız.</translation> </message> @@ -3338,6 +3412,10 @@ <translation>Cüzdan(lar) kontrol ediliyor...</translation> </message> <message> + <source>Wallet %s resides outside wallet directory %s</source> + <translation>Cüzdan %s, %s cüzdan klasörünün dışında bulunuyor</translation> + </message> + <message> <source>Warning</source> <translation>Uyarı</translation> </message> @@ -3434,6 +3512,14 @@ <translation>Yetersiz bakiye</translation> </message> <message> + <source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source> + <translation>İşlem ücreti hesaplama başarısız. Fallbackfee özelliği devre dışı. Lütfen bir kaç blok için bekleyiniz yada -fallbackfee özelliğini aktif ediniz.</translation> + </message> + <message> + <source>Cannot write to data directory '%s'; check permissions.</source> + <translation>Veriler klasöre yazılamıyor '%s'; yetkilendirmeyi kontrol edin.</translation> + </message> + <message> <source>Loading block index...</source> <translation>Blok indeksi yükleniyor...</translation> </message> diff --git a/src/qt/locale/bitcoin_tr_TR.ts b/src/qt/locale/bitcoin_tr_TR.ts index cf119c65c2..bf2dae99dc 100644 --- a/src/qt/locale/bitcoin_tr_TR.ts +++ b/src/qt/locale/bitcoin_tr_TR.ts @@ -30,6 +30,10 @@ <translation>Seçili adresi listeden sil</translation> </message> <message> + <source>Enter address or label to search</source> + <translation>Aramak için adres veya etiket girin</translation> + </message> + <message> <source>Export the data in the current tab to a file</source> <translation>Seçili sekmedeki veriyi dosya olarak dışa aktar</translation> </message> @@ -132,6 +136,10 @@ <translation>Yeni parolayı tekrarla</translation> </message> <message> + <source>Show password</source> + <translation>Şifreyi göster</translation> + </message> + <message> <source>Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>.</source> <translation>Yeni parolayı cüzdana girin.<br/>Lütfen <b>on yada daha fazla karakter</b> veya <b>sekiz yada daha fazla kelime</b>içeren bir parola kullanın. </translation> </message> @@ -192,6 +200,10 @@ <translation>Cüzdan şifreleme başarısız oldu</translation> </message> <message> + <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source> + <translation>Cüzdan şifreleme dahili bir hata nedeniyle başarısız oldu. Cüzdanınız şifrelenemedi.</translation> + </message> + <message> <source>The supplied passphrases do not match.</source> <translation>Girilen parolalar eşleşmiyor.</translation> </message> diff --git a/src/qt/locale/bitcoin_uk.ts b/src/qt/locale/bitcoin_uk.ts index 6698aa4235..1865a84834 100644 --- a/src/qt/locale/bitcoin_uk.ts +++ b/src/qt/locale/bitcoin_uk.ts @@ -3478,12 +3478,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>Вказаний шлях -walletdir "%s" не є каталогом</translation> </message> <message> - <source>Specified blocks directory "%s" does not exist. -</source> - <translation>Вказаний шлях до блоків "%s" не існує -</translation> - </message> - <message> <source>The transaction amount is too small to pay the fee</source> <translation>Неможливо сплатити комісію із-за малої суми транзакції</translation> </message> diff --git a/src/qt/locale/bitcoin_ur_PK.ts b/src/qt/locale/bitcoin_ur_PK.ts index eadd059f7d..03502be8a8 100644 --- a/src/qt/locale/bitcoin_ur_PK.ts +++ b/src/qt/locale/bitcoin_ur_PK.ts @@ -53,10 +53,46 @@ <source>C&hoose</source> <translation>چننا</translation> </message> + <message> + <source>Sending addresses</source> + <translation>پتے ارسال کیے جارہے ہیں</translation> + </message> + <message> + <source>Receiving addresses</source> + <translation>پتے موصول ہورہے ہیں</translation> + </message> + <message> + <source>&Copy Address</source> + <translation>&پتا نقل کریں</translation> + </message> + <message> + <source>Copy &Label</source> + <translation>&لیبل نقل کریں</translation> + </message> + <message> + <source>&Edit</source> + <translation>&تدوین</translation> + </message> + <message> + <source>Export Address List</source> + <translation>پتا فہرست ایکسپورٹ کریں</translation> + </message> + <message> + <source>Comma separated file (*.csv)</source> + <translation>کاما سے جدا فائلیں (*.csv)</translation> + </message> + <message> + <source>Exporting Failed</source> + <translation>ایکسپورٹ ناکام ہوا</translation> + </message> </context> <context> <name>AddressTableModel</name> <message> + <source>Label</source> + <translation>لیبل</translation> + </message> + <message> <source>Address</source> <translation> پتہ</translation> </message> @@ -176,9 +212,17 @@ <source>Address</source> <translation> پتہ</translation> </message> + <message> + <source>Label</source> + <translation>لیبل</translation> + </message> </context> <context> <name>RecentRequestsTableModel</name> + <message> + <source>Label</source> + <translation>لیبل</translation> + </message> </context> <context> <name>SendCoinsDialog</name> @@ -221,13 +265,29 @@ </context> <context> <name>TransactionTableModel</name> + <message> + <source>Label</source> + <translation>لیبل</translation> + </message> </context> <context> <name>TransactionView</name> <message> + <source>Comma separated file (*.csv)</source> + <translation>کاما سے جدا فائلیں (*.csv)</translation> + </message> + <message> + <source>Label</source> + <translation>لیبل</translation> + </message> + <message> <source>Address</source> <translation> پتہ</translation> </message> + <message> + <source>Exporting Failed</source> + <translation>ایکسپورٹ ناکام ہوا</translation> + </message> </context> <context> <name>UnitDisplayStatusBarControl</name> diff --git a/src/qt/locale/bitcoin_vi.ts b/src/qt/locale/bitcoin_vi.ts index 563d047ff7..768ad38912 100644 --- a/src/qt/locale/bitcoin_vi.ts +++ b/src/qt/locale/bitcoin_vi.ts @@ -3,15 +3,15 @@ <name>AddressBookPage</name> <message> <source>Right-click to edit address or label</source> - <translation>Phải chuột để edit address hoặc label</translation> + <translation>Phải chuột để sửa địa chỉ hoặc nhãn</translation> </message> <message> <source>Create a new address</source> - <translation>Create một address mới</translation> + <translation>Tạo một địa chỉ mới</translation> </message> <message> <source>&New</source> - <translation>&Tạo mới</translation> + <translation>&Mới</translation> </message> <message> <source>Copy the currently selected address to the system clipboard</source> @@ -318,6 +318,10 @@ <translation>Mở &URI...</translation> </message> <message> + <source>Wallet:</source> + <translation>Ví tiền</translation> + </message> + <message> <source>Click to disable network activity.</source> <translation>Click để vô hiệu hoạt động mạng.</translation> </message> diff --git a/src/qt/locale/bitcoin_zh_CN.ts b/src/qt/locale/bitcoin_zh_CN.ts index 6678641ad3..ed9f6c2d7d 100644 --- a/src/qt/locale/bitcoin_zh_CN.ts +++ b/src/qt/locale/bitcoin_zh_CN.ts @@ -47,15 +47,15 @@ </message> <message> <source>Choose the address to send coins to</source> - <translation>选择要付钱过去的地址</translation> + <translation>选择要发币给哪些地址</translation> </message> <message> <source>Choose the address to receive coins with</source> - <translation>选择要收钱进来的地址</translation> + <translation>选择要用哪些地址收币</translation> </message> <message> <source>C&hoose</source> - <translation>选择</translation> + <translation>选择(&C)</translation> </message> <message> <source>Sending addresses</source> @@ -67,23 +67,23 @@ </message> <message> <source>These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins.</source> - <translation>这些是你要付款过去的比特币地址。在付钱之前,务必要检查金额和收款地址是否正确。</translation> + <translation>您可以给这些比特币地址付款。在付款之前,务必要检查金额和收款地址是否正确。</translation> </message> <message> <source>These are your Bitcoin addresses for receiving payments. It is recommended to use a new receiving address for each transaction.</source> - <translation>这些是你用来收款的比特币地址。建议在每次交易时,都使用一个新的收款地址。</translation> + <translation>您可以用这些比特币地址收款。建议在每次交易时,都使用一个新的收款地址。</translation> </message> <message> <source>&Copy Address</source> - <translation>复制地址</translation> + <translation>复制地址(&C)</translation> </message> <message> <source>Copy &Label</source> - <translation>复制标签</translation> + <translation>复制标签(&L)</translation> </message> <message> <source>&Edit</source> - <translation>编辑</translation> + <translation>编辑(&E)</translation> </message> <message> <source>Export Address List</source> @@ -189,7 +189,7 @@ </message> <message> <source>%1 will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source> - <translation>%1 现在要关闭,以完成加密过程。请注意,加密钱包不能完全防止入侵你的电脑的恶意程序偷取钱币。</translation> + <translation>%1 现在要关闭,以完成加密过程。请注意,加密钱包不能完全防止入侵您电脑的恶意程序偷取您的比特币。</translation> </message> <message> <source>IMPORTANT: Any previous backups you have made of your wallet file should be replaced with the newly generated, encrypted wallet file. For security reasons, previous backups of the unencrypted wallet file will become useless as soon as you start using the new, encrypted wallet.</source> @@ -315,17 +315,25 @@ </message> <message> <source>&Sending addresses...</source> - <translation>正在发送地址(&S)...</translation> + <translation>付款地址(&S)...</translation> </message> <message> <source>&Receiving addresses...</source> - <translation>正在接收地址(&R)...</translation> + <translation>收款地址(&R)...</translation> </message> <message> <source>Open &URI...</source> <translation>打开 &URI...</translation> </message> <message> + <source>Wallet:</source> + <translation>钱包:</translation> + </message> + <message> + <source>default wallet</source> + <translation>默认钱包</translation> + </message> + <message> <source>Click to disable network activity.</source> <translation>点击禁用网络活动。</translation> </message> @@ -343,7 +351,11 @@ </message> <message> <source>Reindexing blocks on disk...</source> - <translation>正在为数据块重建索引...</translation> + <translation>正在为区块数据重建索引...</translation> + </message> + <message> + <source>Proxy is <b>enabled</b>: %1</source> + <translation>代理已被<b>启用</b>:%1</translation> </message> <message> <source>Send coins to a Bitcoin address</source> @@ -441,13 +453,21 @@ <source>&Command-line options</source> <translation>命令行选项(&C)</translation> </message> + <message numerus="yes"> + <source>%n active connection(s) to Bitcoin network</source> + <translation><numerusform>%n 个有效连接至比特币网络</numerusform></translation> + </message> <message> <source>Indexing blocks on disk...</source> - <translation>正在为数据块建立索引...</translation> + <translation>正在为区块数据建立索引...</translation> </message> <message> <source>Processing blocks on disk...</source> - <translation>正在处理数据块...</translation> + <translation>正在处理区块数据...</translation> + </message> + <message numerus="yes"> + <source>Processed %n block(s) of transaction history.</source> + <translation><numerusform>已处理 %n 个区块的交易历史</numerusform></translation> </message> <message> <source>%1 behind</source> @@ -506,6 +526,11 @@ </translation> </message> <message> + <source>Wallet: %1 +</source> + <translation>钱包:%1</translation> + </message> + <message> <source>Type: %1 </source> <translation>类型: %1 @@ -556,7 +581,7 @@ <name>CoinControlDialog</name> <message> <source>Coin Selection</source> - <translation>选择钱币</translation> + <translation>币源选择(Coin Selection)</translation> </message> <message> <source>Quantity:</source> @@ -576,7 +601,7 @@ </message> <message> <source>Dust:</source> - <translation>小额:</translation> + <translation>粉尘:</translation> </message> <message> <source>After Fee:</source> @@ -584,11 +609,11 @@ </message> <message> <source>Change:</source> - <translation>变更 : </translation> + <translation>找零 : </translation> </message> <message> <source>(un)select all</source> - <translation>(不)全选</translation> + <translation>全(不)选</translation> </message> <message> <source>Tree mode</source> @@ -664,7 +689,7 @@ </message> <message> <source>Copy dust</source> - <translation>复制零散金额</translation> + <translation>复制粉尘金额</translation> </message> <message> <source>Copy change</source> @@ -684,7 +709,7 @@ </message> <message> <source>This label turns red if any recipient receives an amount smaller than the current dust threshold.</source> - <translation>当任何一个收款金额小于目前的零散金额上限时,文字会变红色。</translation> + <translation>当任何一个收款金额小于目前的粉尘金额上限时,文字会变红色。</translation> </message> <message> <source>Can vary +/- %1 satoshi(s) per input.</source> @@ -742,12 +767,20 @@ <translation>输入的地址 %1 并不是有效的比特币地址。</translation> </message> <message> + <source>Address "%1" already exists as a receiving address with label "%2" and so cannot be added as a sending address.</source> + <translation>地址“%1”已经存在,它是一个接受地址,标签为“%2”,所以它不能被添加为一个发送地址。</translation> + </message> + <message> + <source>The entered address "%1" is already in the address book with label "%2".</source> + <translation>输入地址“%1”已经存在于地址簿中,标签为“%2”。</translation> + </message> + <message> <source>Could not unlock wallet.</source> <translation>无法将钱包解锁。</translation> </message> <message> <source>New key generation failed.</source> - <translation>产生新的密钥失败了。</translation> + <translation>生成新密钥失败。</translation> </message> </context> <context> @@ -785,7 +818,7 @@ </message> <message> <source>About %1</source> - <translation>關於 %1</translation> + <translation>关于 %1</translation> </message> <message> <source>Command-line options</source> @@ -850,7 +883,15 @@ <source>Error</source> <translation>错误</translation> </message> - </context> + <message numerus="yes"> + <source>%n GB of free space available</source> + <translation><numerusform>%n GB 可用空闲空间</numerusform></translation> + </message> + <message numerus="yes"> + <source>(of %n GB needed)</source> + <translation><numerusform>(%n GB 需要)</numerusform></translation> + </message> +</context> <context> <name>ModalOverlay</name> <message> @@ -875,7 +916,7 @@ </message> <message> <source>Last block time</source> - <translation>上一数据块时间</translation> + <translation>上一区块时间</translation> </message> <message> <source>Progress</source> @@ -977,11 +1018,11 @@ </message> <message> <source>Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Exit in the menu.</source> - <translation>窗口被关闭时最小化而不是退出应用程序。当此选项启用时,应用程序只会在菜单中选择退出时退出。</translation> + <translation>窗口被关闭时最小化而不是退出应用程序。当此选项启用时,应用程序只会在菜单中选择“退出”时退出。</translation> </message> <message> <source>Third party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items. %s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |.</source> - <translation>出现在交易的选项卡的上下文菜单项的第三方网址 (例如:区块链接查询) 。 %s的URL被替换为交易哈希。多个的URL需要竖线 | 分隔。</translation> + <translation>出现在交易的选项卡的上下文菜单项的第三方网址 (例如:区块浏览器) 。 %s的URL被替换为交易哈希。多个的URL需要竖线 | 分隔。</translation> </message> <message> <source>Active command-line options that override above options:</source> @@ -1008,6 +1049,22 @@ <translation>网络(&N)</translation> </message> <message> + <source>Disables some advanced features but all blocks will still be fully validated. Reverting this setting requires re-downloading the entire blockchain. Actual disk usage may be somewhat higher.</source> + <translation>禁用一些高级特性,但是仍然会对所有区块数据进行完整验证。必须重新下载整个区块链数据才能撤销此设置。实际的磁盘空间占用可能会略高。</translation> + </message> + <message> + <source>Prune &block storage to</source> + <translation>将区块存储修剪至(&B)</translation> + </message> + <message> + <source>GB</source> + <translation>GB</translation> + </message> + <message> + <source>Reverting this setting requires re-downloading the entire blockchain.</source> + <translation>警告:还原此设置需要重新下载整个区块链。</translation> + </message> + <message> <source>(0 = auto, <0 = leave that many cores free)</source> <translation>(0 = 自动, <0 = 保持指定数量的CPU核心空闲)</translation> </message> @@ -1025,11 +1082,11 @@ </message> <message> <source>If you disable the spending of unconfirmed change, the change from a transaction cannot be used until that transaction has at least one confirmation. This also affects how your balance is computed.</source> - <translation>如果禁用未确认的零钱,则零钱至少需要1个确认才能使用。同时账户余额计算会受到影响。</translation> + <translation>如果您禁止动用尚未确认的找零资金,则一笔交易的找零资金至少需要有1个确认后才能动用。这同时也会影响账户余额的计算。</translation> </message> <message> <source>&Spend unconfirmed change</source> - <translation>使用未经确认的零钱(&S)</translation> + <translation>动用尚未确认的找零资金(&S)</translation> </message> <message> <source>Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled.</source> @@ -1101,7 +1158,7 @@ </message> <message> <source>M&inimize on close</source> - <translation>单击关闭按钮最小化(&I)</translation> + <translation>单击关闭按钮时最小化(&I)</translation> </message> <message> <source>&Display</source> @@ -1275,6 +1332,10 @@ <translation>URI 处理</translation> </message> <message> + <source>'bitcoin://' is not a valid URI. Use 'bitcoin:' instead.</source> + <translation>‘bitcoin://’不是合法的URI。请使用'bitcoin:'作为替代。</translation> + </message> + <message> <source>Payment request fetch URL is invalid: %1</source> <translation>取得付款请求的 URL 无效: %1</translation> </message> @@ -1412,10 +1473,34 @@ <source>%1 ms</source> <translation>%1 毫秒</translation> </message> + <message numerus="yes"> + <source>%n second(s)</source> + <translation><numerusform>%n 秒</numerusform></translation> + </message> + <message numerus="yes"> + <source>%n minute(s)</source> + <translation><numerusform>%n 分</numerusform></translation> + </message> + <message numerus="yes"> + <source>%n hour(s)</source> + <translation><numerusform>%n 时</numerusform></translation> + </message> + <message numerus="yes"> + <source>%n day(s)</source> + <translation><numerusform>%n 天</numerusform></translation> + </message> + <message numerus="yes"> + <source>%n week(s)</source> + <translation><numerusform>%n 周</numerusform></translation> + </message> <message> <source>%1 and %2</source> <translation>%1 和 %2</translation> </message> + <message numerus="yes"> + <source>%n year(s)</source> + <translation><numerusform>%n 年</numerusform></translation> + </message> <message> <source>%1 B</source> <translation>%1 字节</translation> @@ -1444,10 +1529,18 @@ <context> <name>QObject::QObject</name> <message> + <source>Error parsing command line arguments: %1.</source> + <translation>解析命令行参数错误:%1</translation> + </message> + <message> <source>Error: Specified data directory "%1" does not exist.</source> <translation>错误:指定的数据目录“%1”不存在。</translation> </message> <message> + <source>Error: Cannot parse configuration file: %1.</source> + <translation>错误:无法解析配置文件:%1</translation> + </message> + <message> <source>Error: %1</source> <translation>错误:%1</translation> </message> @@ -1519,15 +1612,15 @@ </message> <message> <source>Block chain</source> - <translation>数据链</translation> + <translation>区块链</translation> </message> <message> <source>Current number of blocks</source> - <translation>当前数据块数量</translation> + <translation>当前区块数量</translation> </message> <message> <source>Memory Pool</source> - <translation>资金池</translation> + <translation>内存池</translation> </message> <message> <source>Current number of transactions</source> @@ -1538,6 +1631,14 @@ <translation>内存使用</translation> </message> <message> + <source>Wallet: </source> + <translation>钱包:</translation> + </message> + <message> + <source>(none)</source> + <translation>(无)</translation> + </message> + <message> <source>&Reset</source> <translation>&重启</translation> </message> @@ -1575,7 +1676,7 @@ </message> <message> <source>Starting Block</source> - <translation>正在启动数据块</translation> + <translation>起步区块</translation> </message> <message> <source>Synced Headers</source> @@ -1583,7 +1684,7 @@ </message> <message> <source>Synced Blocks</source> - <translation>同步区块链</translation> + <translation>已同步区块</translation> </message> <message> <source>User Agent</source> @@ -1639,7 +1740,7 @@ </message> <message> <source>Last block time</source> - <translation>上一数据块时间</translation> + <translation>上一区块时间</translation> </message> <message> <source>&Open</source> @@ -1702,6 +1803,10 @@ <translation>重新允许</translation> </message> <message> + <source>default wallet</source> + <translation>默认钱包</translation> + </message> + <message> <source>Welcome to the %1 RPC console.</source> <translation>欢迎使用 %1 的 RPC 控制台。</translation> </message> @@ -1726,6 +1831,14 @@ <translation>网络活动已禁用</translation> </message> <message> + <source>Executing command without any wallet</source> + <translation>不使用任何钱包执行命令</translation> + </message> + <message> + <source>Executing command using "%1" wallet</source> + <translation>使用“%1”钱包执行命令</translation> + </message> + <message> <source>(node id: %1)</source> <translation>(节点ID: %1)</translation> </message> @@ -1797,8 +1910,12 @@ <translation>清除</translation> </message> <message> + <source>Native segwit addresses (aka Bech32 or BIP-173) reduce your transaction fees later on and offer better protection against typos, but old wallets don't support them. When unchecked, an address compatible with older wallets will be created instead.</source> + <translation>原生隔离见证地址(又称为Bech32或者BIP-173)可减少您日后的交易费用,并且可以更好的防范打字错误,但旧版本的钱包不能识别这种地址。如果取消勾选,则会生成一个与旧版本钱包兼容的地址。</translation> + </message> + <message> <source>Generate native segwit (Bech32) address</source> - <translation>生成本地分离见证 (Bech32)地址</translation> + <translation>生成原生隔离见证 (Bech32)地址</translation> </message> <message> <source>Requested payments history</source> @@ -1975,15 +2092,15 @@ </message> <message> <source>Change:</source> - <translation>变更 : </translation> + <translation>找零 : </translation> </message> <message> <source>If this is activated, but the change address is empty or invalid, change will be sent to a newly generated address.</source> - <translation>如果激活该选项,但是零钱地址用光或者非法,将会新生成零钱地址,转入零钱。</translation> + <translation>如果该选项已被激活,但是找零地址却被用光了,或者是非法的,找零资金将会被转入新生成的地址。</translation> </message> <message> <source>Custom change address</source> - <translation>自定义零钱地址</translation> + <translation>自定义找零地址</translation> </message> <message> <source>Transaction Fee:</source> @@ -2006,6 +2123,14 @@ <translation>收起 费用设置 </translation> </message> <message> + <source>Specify a custom fee per kB (1,000 bytes) of the transaction's virtual size. + +Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis per kB" for a transaction size of 500 bytes (half of 1 kB) would ultimately yield a fee of only 50 satoshis.</source> + <translation>按照交易的虚拟大小自定义每kB ( 1,000 字节 )要交多少手续费。 + +注意:手续费是按照字节数计算的,对于一笔大小为500字节(1kB的一半)的交易来说,"每kB付100聪手续费"就意味着手续费一共只付了50聪。</translation> + </message> + <message> <source>per kilobyte</source> <translation>每kb</translation> </message> @@ -2031,7 +2156,7 @@ </message> <message> <source>(Smart fee not initialized yet. This usually takes a few blocks...)</source> - <translation>(智能交易费用 尚未初始化。 需要再下载一些数据块...)</translation> + <translation>(智能交易费用 尚未初始化。 需要再下载一些区块数据...)</translation> </message> <message> <source>Send to multiple recipients at once</source> @@ -2126,6 +2251,14 @@ <translation>你可以之后再提高手续费(有BIP-125手续费追加的标记)</translation> </message> <message> + <source>from wallet %1</source> + <translation>从钱包%1</translation> + </message> + <message> + <source>Please, review your transaction.</source> + <translation>请检查您的交易。</translation> + </message> + <message> <source>Transaction fee</source> <translation>交易费用</translation> </message> @@ -2134,6 +2267,10 @@ <translation>没有BIP-125手续费追加的标记。</translation> </message> <message> + <source>Total Amount</source> + <translation>总额</translation> + </message> + <message> <source>Confirm send coins</source> <translation>确认发送</translation> </message> @@ -2177,13 +2314,17 @@ <source>Pay only the required fee of %1</source> <translation>只支付必要费用 %1</translation> </message> + <message numerus="yes"> + <source>Estimated to begin confirmation within %n block(s).</source> + <translation><numerusform>预计 %n 个区块后开始被确认。</numerusform></translation> + </message> <message> <source>Warning: Invalid Bitcoin address</source> <translation>警告: 比特币地址无效</translation> </message> <message> <source>Warning: Unknown change address</source> - <translation>警告:未知的更改地址</translation> + <translation>警告:未知的找零地址</translation> </message> <message> <source>Confirm custom change address</source> @@ -2458,6 +2599,10 @@ </context> <context> <name>TransactionDesc</name> + <message numerus="yes"> + <source>Open for %n more block(s)</source> + <translation><numerusform>在进一步同步完%n个区块前状态待定</numerusform></translation> + </message> <message> <source>Open until %1</source> <translation>至 %1 个数据块时开启</translation> @@ -2534,6 +2679,10 @@ <source>Credit</source> <translation>收入</translation> </message> + <message numerus="yes"> + <source>matures in %n more block(s)</source> + <translation><numerusform>还差 %n 个区块成熟</numerusform></translation> + </message> <message> <source>not accepted</source> <translation>未被接受</translation> @@ -2575,6 +2724,10 @@ <translation>交易总大小</translation> </message> <message> + <source>Transaction virtual size</source> + <translation>交易虚拟大小</translation> + </message> + <message> <source>Output index</source> <translation>输出索引</translation> </message> @@ -2584,7 +2737,7 @@ </message> <message> <source>Generated coins must mature %1 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, its state will change to "not accepted" and it won't be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.</source> - <translation>生成的比特币在可以使用前必须有 %1 个成熟的区块。当您生成了此区块后,它将被广播到网络中以加入区块链。如果它未成功进入区块链,其状态将变更为“不接受”并且不可使用。这可能偶尔会发生,如果另一个节点比你早几秒钟成功生成一个区块。</translation> + <translation>新挖出的比特币在可以使用前必须经过 %1 个区块确认的成熟过程。当您挖出此区块后,它将被广播到网络中以加入区块链。如果它未成功进入区块链,其状态将变更为“不接受”并且不可使用。这可能偶尔会发生,在另一个节点比你早几秒钟成功挖出一个区块时就会这样。</translation> </message> <message> <source>Debug information</source> @@ -2636,6 +2789,10 @@ <source>Label</source> <translation>标签</translation> </message> + <message numerus="yes"> + <source>Open for %n more block(s)</source> + <translation><numerusform>在进一步同步完%n个区块前状态待定</numerusform></translation> + </message> <message> <source>Open until %1</source> <translation>至 %1 个数据块时开启</translation> @@ -2975,7 +3132,11 @@ <source>The wallet data was successfully saved to %1.</source> <translation>钱包数据成功保存至 %1。</translation> </message> - </context> + <message> + <source>Cancel</source> + <translation>取消</translation> + </message> +</context> <context> <name>bitcoin-core</name> <message> @@ -2992,7 +3153,7 @@ </message> <message> <source>Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.</source> - <translation>无法在开启修剪的状态下重扫描,请使用 -reindex重新下载完整的区块链。</translation> + <translation>无法在开启修剪的状态下进行重扫描,请使用 -reindex重新下载完整的区块链。</translation> </message> <message> <source>Error: A fatal internal error occurred, see debug.log for details</source> @@ -3044,7 +3205,7 @@ </message> <message> <source>This is the transaction fee you may discard if change is smaller than dust at this level</source> - <translation>如果对你的交易量来说,消耗的手续费微乎其微,那么这笔手续费你或许可以忽略它。</translation> + <translation>如果找零金额低于粉尘水平,你或许可以忽略这笔手续费。</translation> </message> <message> <source>Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate.</source> @@ -3080,7 +3241,7 @@ </message> <message> <source>Change index out of range</source> - <translation>修改索引超过范围</translation> + <translation>找零超过索引范围</translation> </message> <message> <source>Copyright (C) %i-%i</source> @@ -3088,11 +3249,11 @@ </message> <message> <source>Corrupted block database detected</source> - <translation>检测发现数据块数据库损坏。请使用 -reindex参数重启客户端。</translation> + <translation>检测到区块数据库损坏</translation> </message> <message> <source>Do you want to rebuild the block database now?</source> - <translation>你想现在就重建块数据库吗?</translation> + <translation>你想现在就重建区块数据库吗?</translation> </message> <message> <source>Error creating %s: You can't create non-HD wallets with this version.</source> @@ -3100,7 +3261,7 @@ </message> <message> <source>Error initializing block database</source> - <translation>初始化数据块数据库出错</translation> + <translation>初始化区块数据库出错</translation> </message> <message> <source>Error initializing wallet database environment %s!</source> @@ -3120,11 +3281,11 @@ </message> <message> <source>Error loading block database</source> - <translation>导入数据块数据库出错</translation> + <translation>导入区块数据库出错</translation> </message> <message> <source>Error opening block database</source> - <translation>导入数据块数据库出错</translation> + <translation>导入区块数据库出错</translation> </message> <message> <source>Error: Disk space is low!</source> @@ -3159,6 +3320,14 @@ <translation>-fallbackfee 的无效数额=<amount>: '%s'</translation> </message> <message> + <source>Specified blocks directory "%s" does not exist.</source> + <translation>指定的区块目录"%s"不存在。</translation> + </message> + <message> + <source>Upgrading txindex database</source> + <translation>正在升级交易索引数据库</translation> + </message> + <message> <source>Loading P2P addresses...</source> <translation>正在加载P2P地址...</translation> </message> @@ -3184,7 +3353,7 @@ </message> <message> <source>Rewinding blocks...</source> - <translation>回退区块</translation> + <translation>回退区块...</translation> </message> <message> <source>The source code is available from %s.</source> @@ -3192,13 +3361,17 @@ </message> <message> <source>Transaction fee and change calculation failed</source> - <translation>计算交易手续费和找零失败了</translation> + <translation>计算交易手续费和找零失败</translation> </message> <message> <source>Unable to bind to %s on this computer. %s is probably already running.</source> <translation>无法在本机绑定 %s 端口。%s 可能已经在运行。</translation> </message> <message> + <source>Unable to generate keys</source> + <translation>无法生成密钥</translation> + </message> + <message> <source>Unsupported argument -benchmark ignored, use -debug=bench.</source> <translation>忽略不支持的选项 -benchmark,使用 -debug=bench</translation> </message> @@ -3420,7 +3593,7 @@ </message> <message> <source>Transaction has too long of a mempool chain</source> - <translation>交易造成内存池中的交易链太长</translation> + <translation>此交易在内存池中的交易链太长</translation> </message> <message> <source>Transaction must have at least one recipient</source> @@ -3435,6 +3608,14 @@ <translation>金额不足</translation> </message> <message> + <source>Can't generate a change-address key. Private keys are disabled for this wallet.</source> + <translation>无法生成一个找零地址密钥。对于此钱包,私钥已被禁用。</translation> + </message> + <message> + <source>Cannot write to data directory '%s'; check permissions.</source> + <translation>不能写入到数据目录'%s';请检查文件权限。</translation> + </message> + <message> <source>Loading block index...</source> <translation>正在加载区块索引...</translation> </message> diff --git a/src/qt/locale/bitcoin_zh_TW.ts b/src/qt/locale/bitcoin_zh_TW.ts index 896dd58246..635151bcc9 100644 --- a/src/qt/locale/bitcoin_zh_TW.ts +++ b/src/qt/locale/bitcoin_zh_TW.ts @@ -3336,6 +3336,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>設定 -fallbackfee=<金額> 的金額無效: '%s'</translation> </message> <message> + <source>Specified blocks directory "%s" does not exist.</source> + <translation>指定的區塊目錄 "%s" 不存在。</translation> + </message> + <message> <source>Upgrading txindex database</source> <translation>正在升級 txindex 資料庫</translation> </message> @@ -3488,12 +3492,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>以 -walletdir 指定的路徑 "%s" 不是個目錄</translation> </message> <message> - <source>Specified blocks directory "%s" does not exist. -</source> - <translation>指定的區塊目錄 "%s" 不存在。 -</translation> - </message> - <message> <source>The transaction amount is too small to pay the fee</source> <translation>交易金額太少而付不起手續費</translation> </message> diff --git a/src/qt/modaloverlay.cpp b/src/qt/modaloverlay.cpp index c5bedf007a..8ecc33da84 100644 --- a/src/qt/modaloverlay.cpp +++ b/src/qt/modaloverlay.cpp @@ -71,6 +71,7 @@ void ModalOverlay::setKnownBestHeight(int count, const QDateTime& blockDate) if (count > bestHeaderHeight) { bestHeaderHeight = count; bestHeaderDate = blockDate; + UpdateHeaderSyncLabel(); } } @@ -136,11 +137,16 @@ void ModalOverlay::tipUpdate(int count, const QDateTime& blockDate, double nVeri if (estimateNumHeadersLeft < HEADER_HEIGHT_DELTA_SYNC && hasBestHeader) { ui->numberOfBlocksLeft->setText(QString::number(bestHeaderHeight - count)); } else { - ui->numberOfBlocksLeft->setText(tr("Unknown. Syncing Headers (%1)...").arg(bestHeaderHeight)); + UpdateHeaderSyncLabel(); ui->expectedTimeLeft->setText(tr("Unknown...")); } } +void ModalOverlay::UpdateHeaderSyncLabel() { + int est_headers_left = bestHeaderDate.secsTo(QDateTime::currentDateTime()) / Params().GetConsensus().nPowTargetSpacing; + ui->numberOfBlocksLeft->setText(tr("Unknown. Syncing Headers (%1, %2%)...").arg(bestHeaderHeight).arg(QString::number(100.0 / (bestHeaderHeight + est_headers_left) * bestHeaderHeight, 'f', 1))); +} + void ModalOverlay::toggleVisibility() { showHide(layerIsVisible, true); diff --git a/src/qt/modaloverlay.h b/src/qt/modaloverlay.h index 66a6ad1e02..cf8b53f2b3 100644 --- a/src/qt/modaloverlay.h +++ b/src/qt/modaloverlay.h @@ -45,6 +45,7 @@ private: QVector<QPair<qint64, double> > blockProcessTime; bool layerIsVisible; bool userClosed; + void UpdateHeaderSyncLabel(); }; #endif // BITCOIN_QT_MODALOVERLAY_H diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp index b1ec90ad36..43dccec4ea 100644 --- a/src/qt/paymentserver.cpp +++ b/src/qt/paymentserver.cpp @@ -292,9 +292,9 @@ void PaymentServer::handleURIOrFile(const QString& s) else if (s.startsWith(BITCOIN_IPC_PREFIX, Qt::CaseInsensitive)) // bitcoin: URI { QUrlQuery uri((QUrl(s))); +#ifdef ENABLE_BIP70 if (uri.hasQueryItem("r")) // payment request URI { -#ifdef ENABLE_BIP70 Q_EMIT message(tr("URI handling"), tr("You are using a BIP70 URL which will be unsupported in the future."), CClientUIInterface::ICON_WARNING); @@ -315,19 +315,23 @@ void PaymentServer::handleURIOrFile(const QString& s) tr("Payment request fetch URL is invalid: %1").arg(fetchUrl.toString()), CClientUIInterface::ICON_WARNING); } -#else - Q_EMIT message(tr("URI handling"), - tr("Cannot process payment request because BIP70 support was not compiled in."), - CClientUIInterface::ICON_WARNING); -#endif return; } - else // normal URI + else +#endif + // normal URI { SendCoinsRecipient recipient; if (GUIUtil::parseBitcoinURI(s, &recipient)) { if (!IsValidDestinationString(recipient.address.toStdString())) { +#ifndef ENABLE_BIP70 + if (uri.hasQueryItem("r")) { // payment request + Q_EMIT message(tr("URI handling"), + tr("Cannot process payment request because BIP70 support was not compiled in."), + CClientUIInterface::ICON_WARNING); + } +#endif Q_EMIT message(tr("URI handling"), tr("Invalid payment address %1").arg(recipient.address), CClientUIInterface::MSG_ERROR); } @@ -343,9 +347,9 @@ void PaymentServer::handleURIOrFile(const QString& s) } } -#ifdef ENABLE_BIP70 if (QFile::exists(s)) // payment request file { +#ifdef ENABLE_BIP70 PaymentRequestPlus request; SendCoinsRecipient recipient; if (!readPaymentRequestFromFile(s, request)) @@ -358,8 +362,12 @@ void PaymentServer::handleURIOrFile(const QString& s) Q_EMIT receivedPaymentRequest(recipient); return; - } +#else + Q_EMIT message(tr("Payment request file handling"), + tr("Cannot process payment request because BIP70 support was not compiled in."), + CClientUIInterface::ICON_WARNING); #endif + } } void PaymentServer::handleURIConnection() diff --git a/src/qt/test/addressbooktests.cpp b/src/qt/test/addressbooktests.cpp index 3e414df1f0..7f5e92ea9f 100644 --- a/src/qt/test/addressbooktests.cpp +++ b/src/qt/test/addressbooktests.cpp @@ -95,6 +95,7 @@ void TestAddAddressesToSendBook() } auto check_addbook_size = [&wallet](int expected_size) { + LOCK(wallet->cs_wallet); QCOMPARE(static_cast<int>(wallet->mapAddressBook.size()), expected_size); }; diff --git a/src/qt/test/apptests.cpp b/src/qt/test/apptests.cpp index 2c477a2e98..da25d83175 100644 --- a/src/qt/test/apptests.cpp +++ b/src/qt/test/apptests.cpp @@ -27,9 +27,7 @@ #include <QTest> #include <QTextEdit> #include <QtGlobal> -#if QT_VERSION >= 0x050000 #include <QtTest/QtTestWidgets> -#endif #include <QtTest/QtTestGui> #include <new> #include <string> diff --git a/src/qt/test/rpcnestedtests.cpp b/src/qt/test/rpcnestedtests.cpp index 173c814f1e..f8a9c25303 100644 --- a/src/qt/test/rpcnestedtests.cpp +++ b/src/qt/test/rpcnestedtests.cpp @@ -120,7 +120,6 @@ void RPCNestedTests::rpcNestedTests() RPCConsole::RPCExecuteCommandLine(*node, result, "rpcNestedTest( abc , cba )"); QVERIFY(result == "[\"abc\",\"cba\"]"); -#if QT_VERSION >= 0x050300 // do the QVERIFY_EXCEPTION_THROWN checks only with Qt5.3 and higher (QVERIFY_EXCEPTION_THROWN was introduced in Qt5.3) QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(*node, result, "getblockchaininfo() .\n"), std::runtime_error); //invalid syntax QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(*node, result, "getblockchaininfo() getblockchaininfo()"), std::runtime_error); //invalid syntax @@ -131,5 +130,4 @@ void RPCNestedTests::rpcNestedTests() QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(*node, result, "rpcNestedTest abc,,abc"), std::runtime_error); //don't tollerate empty arguments when using , QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(*node, result, "rpcNestedTest(abc,,abc)"), std::runtime_error); //don't tollerate empty arguments when using , QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(*node, result, "rpcNestedTest(abc,,)"), std::runtime_error); //don't tollerate empty arguments when using , -#endif } diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp index ee84da0cdf..2b50a2ba81 100644 --- a/src/qt/test/wallettests.cpp +++ b/src/qt/test/wallettests.cpp @@ -149,8 +149,8 @@ void TestGUI() reserver.reserve(); CWallet::ScanResult result = wallet->ScanForWalletTransactions(locked_chain->getBlockHash(0), {} /* stop_block */, reserver, true /* fUpdate */); QCOMPARE(result.status, CWallet::ScanResult::SUCCESS); - QCOMPARE(result.stop_block, chainActive.Tip()->GetBlockHash()); - QVERIFY(result.failed_block.IsNull()); + QCOMPARE(result.last_scanned_block, chainActive.Tip()->GetBlockHash()); + QVERIFY(result.last_failed_block.IsNull()); } wallet->SetBroadcastTransactions(true); diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp index eb6437eb31..762ec434a1 100644 --- a/src/qt/transactionview.cpp +++ b/src/qt/transactionview.cpp @@ -229,8 +229,8 @@ void TransactionView::setModel(WalletModel *_model) transactionView->setAlternatingRowColors(true); transactionView->setSelectionBehavior(QAbstractItemView::SelectRows); transactionView->setSelectionMode(QAbstractItemView::ExtendedSelection); + transactionView->horizontalHeader()->setSortIndicator(TransactionTableModel::Date, Qt::DescendingOrder); transactionView->setSortingEnabled(true); - transactionView->sortByColumn(TransactionTableModel::Date, Qt::DescendingOrder); transactionView->verticalHeader()->hide(); transactionView->setColumnWidth(TransactionTableModel::Status, STATUS_COLUMN_WIDTH); diff --git a/src/qt/walletcontroller.cpp b/src/qt/walletcontroller.cpp index df2b7a3f9b..fab86a7912 100644 --- a/src/qt/walletcontroller.cpp +++ b/src/qt/walletcontroller.cpp @@ -9,6 +9,7 @@ #include <algorithm> +#include <QMessageBox> #include <QMutexLocker> #include <QThread> @@ -25,11 +26,17 @@ WalletController::WalletController(interfaces::Node& node, const PlatformStyle* for (std::unique_ptr<interfaces::Wallet>& wallet : m_node.getWallets()) { getOrCreateWallet(std::move(wallet)); } + + m_activity_thread.start(); } // Not using the default destructor because not all member types definitions are // available in the header, just forward declared. -WalletController::~WalletController() {} +WalletController::~WalletController() +{ + m_activity_thread.quit(); + m_activity_thread.wait(); +} std::vector<WalletModel*> WalletController::getWallets() const { @@ -37,6 +44,40 @@ std::vector<WalletModel*> WalletController::getWallets() const return m_wallets; } +std::vector<std::string> WalletController::getWalletsAvailableToOpen() const +{ + QMutexLocker locker(&m_mutex); + std::vector<std::string> wallets = m_node.listWalletDir(); + for (WalletModel* wallet_model : m_wallets) { + auto it = std::remove(wallets.begin(), wallets.end(), wallet_model->wallet().getWalletName()); + if (it != wallets.end()) wallets.erase(it); + } + return wallets; +} + +OpenWalletActivity* WalletController::openWallet(const std::string& name, QWidget* parent) +{ + OpenWalletActivity* activity = new OpenWalletActivity(this, name); + activity->moveToThread(&m_activity_thread); + return activity; +} + +void WalletController::closeWallet(WalletModel* wallet_model, QWidget* parent) +{ + QMessageBox box(parent); + box.setWindowTitle(tr("Close wallet")); + box.setText(tr("Are you sure you wish to close wallet <i>%1</i>?").arg(wallet_model->getDisplayName())); + box.setInformativeText(tr("Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.")); + box.setStandardButtons(QMessageBox::Yes|QMessageBox::Cancel); + box.setDefaultButton(QMessageBox::Yes); + if (box.exec() != QMessageBox::Yes) return; + + // First remove wallet from node. + wallet_model->wallet().remove(); + // Now release the model. + removeAndDeleteWallet(wallet_model); +} + WalletModel* WalletController::getOrCreateWallet(std::unique_ptr<interfaces::Wallet> wallet) { QMutexLocker locker(&m_mutex); @@ -93,3 +134,24 @@ void WalletController::removeAndDeleteWallet(WalletModel* wallet_model) // CWallet shared pointer. delete wallet_model; } + + +OpenWalletActivity::OpenWalletActivity(WalletController* wallet_controller, const std::string& name) + : m_wallet_controller(wallet_controller) + , m_name(name) +{} + +void OpenWalletActivity::open() +{ + std::string error, warning; + std::unique_ptr<interfaces::Wallet> wallet = m_wallet_controller->m_node.loadWallet(m_name, error, warning); + if (!warning.empty()) { + Q_EMIT message(QMessageBox::Warning, QString::fromStdString(warning)); + } + if (wallet) { + Q_EMIT opened(m_wallet_controller->getOrCreateWallet(std::move(wallet))); + } else { + Q_EMIT message(QMessageBox::Critical, QString::fromStdString(error)); + } + Q_EMIT finished(); +} diff --git a/src/qt/walletcontroller.h b/src/qt/walletcontroller.h index 22b71b07ff..19b3a82253 100644 --- a/src/qt/walletcontroller.h +++ b/src/qt/walletcontroller.h @@ -12,7 +12,9 @@ #include <memory> #include <vector> +#include <QMessageBox> #include <QMutex> +#include <QThread> class OptionsModel; class PlatformStyle; @@ -22,6 +24,8 @@ class Handler; class Node; } // namespace interfaces +class OpenWalletActivity; + /** * Controller between interfaces::Node, WalletModel instances and the GUI. */ @@ -37,6 +41,10 @@ public: ~WalletController(); std::vector<WalletModel*> getWallets() const; + std::vector<std::string> getWalletsAvailableToOpen() const; + + OpenWalletActivity* openWallet(const std::string& name, QWidget* parent = nullptr); + void closeWallet(WalletModel* wallet_model, QWidget* parent = nullptr); private Q_SLOTS: void addWallet(WalletModel* wallet_model); @@ -48,12 +56,35 @@ Q_SIGNALS: void coinsSent(WalletModel* wallet_model, SendCoinsRecipient recipient, QByteArray transaction); private: + QThread m_activity_thread; interfaces::Node& m_node; const PlatformStyle* const m_platform_style; OptionsModel* const m_options_model; mutable QMutex m_mutex; std::vector<WalletModel*> m_wallets; std::unique_ptr<interfaces::Handler> m_handler_load_wallet; + + friend class OpenWalletActivity; +}; + +class OpenWalletActivity : public QObject +{ + Q_OBJECT + +public: + OpenWalletActivity(WalletController* wallet_controller, const std::string& name); + +public Q_SLOTS: + void open(); + +Q_SIGNALS: + void message(QMessageBox::Icon icon, const QString text); + void finished(); + void opened(WalletModel* wallet_model); + +private: + WalletController* const m_wallet_controller; + std::string const m_name; }; #endif // BITCOIN_QT_WALLETCONTROLLER_H diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 2a9144bec9..f4f3be8f43 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -580,12 +580,7 @@ bool WalletModel::privateKeysDisabled() const bool WalletModel::canGetAddresses() const { - // The wallet can provide a fresh address if: - // * hdEnabled(): an HD seed is present; or - // * it is a legacy wallet, because: - // * !hdEnabled(): an HD seed is not present; and - // * !IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS): private keys have not been disabled (which results in hdEnabled() == true) - return m_wallet->hdEnabled() || (!m_wallet->hdEnabled() && !m_wallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)); + return m_wallet->canGetAddresses(); } QString WalletModel::getWalletName() const diff --git a/src/random.cpp b/src/random.cpp index 3b7f7910b0..1aa78a9034 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -78,25 +78,119 @@ static inline int64_t GetPerformanceCounter() noexcept } #if defined(__x86_64__) || defined(__amd64__) || defined(__i386__) -static bool rdrand_supported = false; +static bool g_rdrand_supported = false; +static bool g_rdseed_supported = false; static constexpr uint32_t CPUID_F1_ECX_RDRAND = 0x40000000; +static constexpr uint32_t CPUID_F7_EBX_RDSEED = 0x00040000; +#ifdef bit_RDRND +static_assert(CPUID_F1_ECX_RDRAND == bit_RDRND, "Unexpected value for bit_RDRND"); +#endif +#ifdef bit_RDSEED +static_assert(CPUID_F7_EBX_RDSEED == bit_RDSEED, "Unexpected value for bit_RDSEED"); +#endif +static void inline GetCPUID(uint32_t leaf, uint32_t subleaf, uint32_t& a, uint32_t& b, uint32_t& c, uint32_t& d) +{ + // We can't use __get_cpuid as it doesn't support subleafs. +#ifdef __GNUC__ + __cpuid_count(leaf, subleaf, a, b, c, d); +#else + __asm__ ("cpuid" : "=a"(a), "=b"(b), "=c"(c), "=d"(d) : "0"(leaf), "2"(subleaf)); +#endif +} + static void InitHardwareRand() { uint32_t eax, ebx, ecx, edx; - if (__get_cpuid(1, &eax, &ebx, &ecx, &edx) && (ecx & CPUID_F1_ECX_RDRAND)) { - rdrand_supported = true; + GetCPUID(1, 0, eax, ebx, ecx, edx); + if (ecx & CPUID_F1_ECX_RDRAND) { + g_rdrand_supported = true; + } + GetCPUID(7, 0, eax, ebx, ecx, edx); + if (ebx & CPUID_F7_EBX_RDSEED) { + g_rdseed_supported = true; } } static void ReportHardwareRand() { - if (rdrand_supported) { - // This must be done in a separate function, as HWRandInit() may be indirectly called - // from global constructors, before logging is initialized. + // This must be done in a separate function, as HWRandInit() may be indirectly called + // from global constructors, before logging is initialized. + if (g_rdseed_supported) { + LogPrintf("Using RdSeed as additional entropy source\n"); + } + if (g_rdrand_supported) { LogPrintf("Using RdRand as an additional entropy source\n"); } } +/** Read 64 bits of entropy using rdrand. + * + * Must only be called when RdRand is supported. + */ +static uint64_t GetRdRand() noexcept +{ + // RdRand may very rarely fail. Invoke it up to 10 times in a loop to reduce this risk. +#ifdef __i386__ + uint8_t ok; + uint32_t r1, r2; + for (int i = 0; i < 10; ++i) { + __asm__ volatile (".byte 0x0f, 0xc7, 0xf0; setc %1" : "=a"(r1), "=q"(ok) :: "cc"); // rdrand %eax + if (ok) break; + } + for (int i = 0; i < 10; ++i) { + __asm__ volatile (".byte 0x0f, 0xc7, 0xf0; setc %1" : "=a"(r2), "=q"(ok) :: "cc"); // rdrand %eax + if (ok) break; + } + return (((uint64_t)r2) << 32) | r1; +#elif defined(__x86_64__) || defined(__amd64__) + uint8_t ok; + uint64_t r1; + for (int i = 0; i < 10; ++i) { + __asm__ volatile (".byte 0x48, 0x0f, 0xc7, 0xf0; setc %1" : "=a"(r1), "=q"(ok) :: "cc"); // rdrand %rax + if (ok) break; + } + return r1; +#else +#error "RdRand is only supported on x86 and x86_64" +#endif +} + +/** Read 64 bits of entropy using rdseed. + * + * Must only be called when RdSeed is supported. + */ +static uint64_t GetRdSeed() noexcept +{ + // RdSeed may fail when the HW RNG is overloaded. Loop indefinitely until enough entropy is gathered, + // but pause after every failure. +#ifdef __i386__ + uint8_t ok; + uint32_t r1, r2; + do { + __asm__ volatile (".byte 0x0f, 0xc7, 0xf8; setc %1" : "=a"(r1), "=q"(ok) :: "cc"); // rdseed %eax + if (ok) break; + __asm__ volatile ("pause"); + } while(true); + do { + __asm__ volatile (".byte 0x0f, 0xc7, 0xf8; setc %1" : "=a"(r2), "=q"(ok) :: "cc"); // rdseed %eax + if (ok) break; + __asm__ volatile ("pause"); + } while(true); + return (((uint64_t)r2) << 32) | r1; +#elif defined(__x86_64__) || defined(__amd64__) + uint8_t ok; + uint64_t r1; + do { + __asm__ volatile (".byte 0x48, 0x0f, 0xc7, 0xf8; setc %1" : "=a"(r1), "=q"(ok) :: "cc"); // rdseed %rax + if (ok) break; + __asm__ volatile ("pause"); + } while(true); + return r1; +#else +#error "RdSeed is only supported on x86 and x86_64" +#endif +} + #else /* Access to other hardware random number generators could be added here later, * assuming it is sufficiently fast (in the order of a few hundred CPU cycles). @@ -107,40 +201,40 @@ static void InitHardwareRand() {} static void ReportHardwareRand() {} #endif -static bool GetHardwareRand(unsigned char* ent32) noexcept { +/** Add 64 bits of entropy gathered from hardware to hasher. Do nothing if not supported. */ +static void SeedHardwareFast(CSHA512& hasher) noexcept { #if defined(__x86_64__) || defined(__amd64__) || defined(__i386__) - if (rdrand_supported) { - uint8_t ok; - // Not all assemblers support the rdrand instruction, write it in hex. -#ifdef __i386__ - for (int iter = 0; iter < 4; ++iter) { - uint32_t r1, r2; - __asm__ volatile (".byte 0x0f, 0xc7, 0xf0;" // rdrand %eax - ".byte 0x0f, 0xc7, 0xf2;" // rdrand %edx - "setc %2" : - "=a"(r1), "=d"(r2), "=q"(ok) :: "cc"); - if (!ok) return false; - WriteLE32(ent32 + 8 * iter, r1); - WriteLE32(ent32 + 8 * iter + 4, r2); - } -#else - uint64_t r1, r2, r3, r4; - __asm__ volatile (".byte 0x48, 0x0f, 0xc7, 0xf0, " // rdrand %rax - "0x48, 0x0f, 0xc7, 0xf3, " // rdrand %rbx - "0x48, 0x0f, 0xc7, 0xf1, " // rdrand %rcx - "0x48, 0x0f, 0xc7, 0xf2; " // rdrand %rdx - "setc %4" : - "=a"(r1), "=b"(r2), "=c"(r3), "=d"(r4), "=q"(ok) :: "cc"); - if (!ok) return false; - WriteLE64(ent32, r1); - WriteLE64(ent32 + 8, r2); - WriteLE64(ent32 + 16, r3); - WriteLE64(ent32 + 24, r4); + if (g_rdrand_supported) { + uint64_t out = GetRdRand(); + hasher.Write((const unsigned char*)&out, sizeof(out)); + return; + } #endif - return true; +} + +/** Add 256 bits of entropy gathered from hardware to hasher. Do nothing if not supported. */ +static void SeedHardwareSlow(CSHA512& hasher) noexcept { +#if defined(__x86_64__) || defined(__amd64__) || defined(__i386__) + // When we want 256 bits of entropy, prefer RdSeed over RdRand, as it's + // guaranteed to produce independent randomness on every call. + if (g_rdseed_supported) { + for (int i = 0; i < 4; ++i) { + uint64_t out = GetRdSeed(); + hasher.Write((const unsigned char*)&out, sizeof(out)); + } + return; + } + // When falling back to RdRand, XOR the result of 1024 results. + // This guarantees a reseeding occurs between each. + if (g_rdrand_supported) { + for (int i = 0; i < 4; ++i) { + uint64_t out = 0; + for (int j = 0; j < 1024; ++j) out ^= GetRdRand(); + hasher.Write((const unsigned char*)&out, sizeof(out)); + } + return; } #endif - return false; } static void RandAddSeedPerfmon(CSHA512& hasher) @@ -407,8 +501,7 @@ static void SeedFast(CSHA512& hasher) noexcept hasher.Write((const unsigned char*)&ptr, sizeof(ptr)); // Hardware randomness is very fast when available; use it always. - bool have_hw_rand = GetHardwareRand(buffer); - if (have_hw_rand) hasher.Write(buffer, sizeof(buffer)); + SeedHardwareFast(hasher); // High-precision timestamp SeedTimestamp(hasher); @@ -460,6 +553,9 @@ static void SeedStartup(CSHA512& hasher) noexcept RAND_screen(); #endif + // Gather 256 bits of hardware randomness, if available + SeedHardwareSlow(hasher); + // Everything that the 'slow' seeder includes. SeedSlow(hasher); @@ -514,9 +610,11 @@ void GetRandBytes(unsigned char* buf, int num) noexcept { ProcRand(buf, num, RNG void GetStrongRandBytes(unsigned char* buf, int num) noexcept { ProcRand(buf, num, RNGLevel::SLOW); } void RandAddSeedSleep() { ProcRand(nullptr, 0, RNGLevel::SLEEP); } +bool g_mock_deterministic_tests{false}; + uint64_t GetRand(uint64_t nMax) noexcept { - return FastRandomContext().randrange(nMax); + return FastRandomContext(g_mock_deterministic_tests).randrange(nMax); } int GetRandInt(int nMax) noexcept diff --git a/src/random.h b/src/random.h index 4c73f3822a..1c035f87ba 100644 --- a/src/random.h +++ b/src/random.h @@ -24,7 +24,7 @@ * perform 'fast' seeding, consisting of mixing in: * - A stack pointer (indirectly committing to calling thread and call stack) * - A high-precision timestamp (rdtsc when available, c++ high_resolution_clock otherwise) - * - Hardware RNG (rdrand) when available. + * - 64 bits from the hardware RNG (rdrand) when available. * These entropy sources are very fast, and only designed to protect against situations * where a VM state restore/copy results in multiple systems with the same randomness. * FastRandomContext on the other hand does not protect against this once created, but @@ -48,6 +48,7 @@ * * On first use of the RNG (regardless of what function is called first), all entropy * sources used in the 'slow' seeder are included, but also: + * - 256 bits from the hardware RNG (rdseed or rdrand) when available. * - (On Windows) Performance monitoring data from the OS. * - (On Windows) Through OpenSSL, the screen contents. * diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index fa0b62ec48..7e8e5e07d0 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2009-2018 The Bitcoin Core developers +// Copyright (c) 2009-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -215,7 +215,7 @@ static UniValue waitfornewblock(const JSONRPCRequest& request) "\nWaits for a specific new block and returns useful info about it.\n" "\nReturns the current block on timeout or exit.\n", { - {"timeout", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "0", "Time in milliseconds to wait for a response. 0 indicates no timeout."}, + {"timeout", RPCArg::Type::NUM, /* default */ "0", "Time in milliseconds to wait for a response. 0 indicates no timeout."}, }, RPCResult{ "{ (json object)\n" @@ -256,8 +256,8 @@ static UniValue waitforblock(const JSONRPCRequest& request) "\nWaits for a specific new block and returns useful info about it.\n" "\nReturns the current block on timeout or exit.\n", { - {"blockhash", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "Block hash to wait for."}, - {"timeout", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "0", "Time in milliseconds to wait for a response. 0 indicates no timeout."}, + {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "Block hash to wait for."}, + {"timeout", RPCArg::Type::NUM, /* default */ "0", "Time in milliseconds to wait for a response. 0 indicates no timeout."}, }, RPCResult{ "{ (json object)\n" @@ -302,8 +302,8 @@ static UniValue waitforblockheight(const JSONRPCRequest& request) "of the current tip.\n" "\nReturns the current block on timeout or exit.\n", { - {"height", RPCArg::Type::NUM, /* opt */ false, /* default_val */ "", "Block height to wait for."}, - {"timeout", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "0", "Time in milliseconds to wait for a response. 0 indicates no timeout."}, + {"height", RPCArg::Type::NUM, RPCArg::Optional::NO, "Block height to wait for."}, + {"timeout", RPCArg::Type::NUM, /* default */ "0", "Time in milliseconds to wait for a response. 0 indicates no timeout."}, }, RPCResult{ "{ (json object)\n" @@ -501,7 +501,7 @@ static UniValue getrawmempool(const JSONRPCRequest& request) "\nReturns all transaction ids in memory pool as a json array of string transaction ids.\n" "\nHint: use getmempoolentry to fetch a specific transaction from the mempool.\n", { - {"verbose", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "True for a json object, false for array of transaction ids"}, + {"verbose", RPCArg::Type::BOOL, /* default */ "false", "True for a json object, false for array of transaction ids"}, }, RPCResult{"for verbose = false", "[ (json array of string)\n" @@ -535,8 +535,8 @@ static UniValue getmempoolancestors(const JSONRPCRequest& request) RPCHelpMan{"getmempoolancestors", "\nIf txid is in the mempool, returns all in-mempool ancestors.\n", { - {"txid", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "The transaction id (must be in mempool)"}, - {"verbose", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "True for a json object, false for array of transaction ids"}, + {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id (must be in mempool)"}, + {"verbose", RPCArg::Type::BOOL, /* default */ "false", "True for a json object, false for array of transaction ids"}, }, { RPCResult{"for verbose = false", @@ -605,8 +605,8 @@ static UniValue getmempooldescendants(const JSONRPCRequest& request) RPCHelpMan{"getmempooldescendants", "\nIf txid is in the mempool, returns all in-mempool descendants.\n", { - {"txid", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "The transaction id (must be in mempool)"}, - {"verbose", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "True for a json object, false for array of transaction ids"}, + {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id (must be in mempool)"}, + {"verbose", RPCArg::Type::BOOL, /* default */ "false", "True for a json object, false for array of transaction ids"}, }, { RPCResult{"for verbose = false", @@ -675,7 +675,7 @@ static UniValue getmempoolentry(const JSONRPCRequest& request) RPCHelpMan{"getmempoolentry", "\nReturns mempool data for given transaction\n", { - {"txid", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "The transaction id (must be in mempool)"}, + {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id (must be in mempool)"}, }, RPCResult{ "{ (json object)\n" @@ -711,7 +711,7 @@ static UniValue getblockhash(const JSONRPCRequest& request) RPCHelpMan{"getblockhash", "\nReturns hash of block in best-block-chain at height provided.\n", { - {"height", RPCArg::Type::NUM, /* opt */ false, /* default_val */ "", "The height index"}, + {"height", RPCArg::Type::NUM, RPCArg::Optional::NO, "The height index"}, }, RPCResult{ "\"hash\" (string) The block hash\n" @@ -740,8 +740,8 @@ static UniValue getblockheader(const JSONRPCRequest& request) "\nIf verbose is false, returns a string that is serialized, hex-encoded data for blockheader 'hash'.\n" "If verbose is true, returns an Object with information about blockheader <hash>.\n", { - {"blockhash", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "The block hash"}, - {"verbose", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "true", "true for a json object, false for the hex-encoded data"}, + {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The block hash"}, + {"verbose", RPCArg::Type::BOOL, /* default */ "true", "true for a json object, false for the hex-encoded data"}, }, { RPCResult{"for verbose = true", @@ -830,8 +830,8 @@ static UniValue getblock(const JSONRPCRequest& request) "If verbosity is 1, returns an Object with information about block <hash>.\n" "If verbosity is 2, returns an Object with information about block <hash> and information about each transaction. \n", { - {"blockhash", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "The block hash"}, - {"verbosity", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "1", "0 for hex-encoded data, 1 for a json object, and 2 for json object with transaction data"}, + {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The block hash"}, + {"verbosity", RPCArg::Type::NUM, /* default */ "1", "0 for hex-encoded data, 1 for a json object, and 2 for json object with transaction data"}, }, { RPCResult{"for verbosity = 0", @@ -986,7 +986,7 @@ static UniValue pruneblockchain(const JSONRPCRequest& request) throw std::runtime_error( RPCHelpMan{"pruneblockchain", "", { - {"height", RPCArg::Type::NUM, /* opt */ false, /* default_val */ "", "The block height to prune up to. May be set to a discrete height, or a unix timestamp\n" + {"height", RPCArg::Type::NUM, RPCArg::Optional::NO, "The block height to prune up to. May be set to a discrete height, or a unix timestamp\n" " to prune blocks whose block time is at least 2 hours older than the provided timestamp."}, }, RPCResult{ @@ -1085,9 +1085,9 @@ UniValue gettxout(const JSONRPCRequest& request) RPCHelpMan{"gettxout", "\nReturns details about an unspent transaction output.\n", { - {"txid", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The transaction id"}, - {"n", RPCArg::Type::NUM, /* opt */ false, /* default_val */ "", "vout number"}, - {"include_mempool", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "true", "Whether to include the mempool. Note that an unspent output that is spent in the mempool won't appear."}, + {"txid", RPCArg::Type::STR, RPCArg::Optional::NO, "The transaction id"}, + {"n", RPCArg::Type::NUM, RPCArg::Optional::NO, "vout number"}, + {"include_mempool", RPCArg::Type::BOOL, /* default */ "true", "Whether to include the mempool. Note that an unspent output that is spent in the mempool won't appear."}, }, RPCResult{ "{\n" @@ -1166,8 +1166,8 @@ static UniValue verifychain(const JSONRPCRequest& request) RPCHelpMan{"verifychain", "\nVerifies blockchain database.\n", { - {"checklevel", RPCArg::Type::NUM, /* opt */ true, /* default_val */ strprintf("%d, range=0-4", nCheckLevel), "How thorough the block verification is."}, - {"nblocks", RPCArg::Type::NUM, /* opt */ true, /* default_val */ strprintf("%d, 0=all", nCheckDepth), "The number of blocks to check."}, + {"checklevel", RPCArg::Type::NUM, /* default */ strprintf("%d, range=0-4", nCheckLevel), "How thorough the block verification is."}, + {"nblocks", RPCArg::Type::NUM, /* default */ strprintf("%d, 0=all", nCheckDepth), "The number of blocks to check."}, }, RPCResult{ "true|false (boolean) Verified or not\n" @@ -1534,7 +1534,7 @@ static UniValue preciousblock(const JSONRPCRequest& request) "\nA later preciousblock call can override the effect of an earlier one.\n" "\nThe effects of preciousblock are not retained across restarts.\n", { - {"blockhash", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "the hash of the block to mark as precious"}, + {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "the hash of the block to mark as precious"}, }, RPCResults{}, RPCExamples{ @@ -1571,7 +1571,7 @@ static UniValue invalidateblock(const JSONRPCRequest& request) RPCHelpMan{"invalidateblock", "\nPermanently marks a block as invalid, as if it violated a consensus rule.\n", { - {"blockhash", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "the hash of the block to mark as invalid"}, + {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "the hash of the block to mark as invalid"}, }, RPCResults{}, RPCExamples{ @@ -1612,7 +1612,7 @@ static UniValue reconsiderblock(const JSONRPCRequest& request) "\nRemoves invalidity status of a block, its ancestors and its descendants, reconsider them for activation.\n" "This can be used to undo the effects of invalidateblock.\n", { - {"blockhash", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "the hash of the block to reconsider"}, + {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "the hash of the block to reconsider"}, }, RPCResults{}, RPCExamples{ @@ -1650,8 +1650,8 @@ static UniValue getchaintxstats(const JSONRPCRequest& request) RPCHelpMan{"getchaintxstats", "\nCompute statistics about the total number and rate of transactions in the chain.\n", { - {"nblocks", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "one month", "Size of the window in number of blocks"}, - {"blockhash", RPCArg::Type::STR_HEX, /* opt */ true, /* default_val */ "chain tip", "The hash of the block that ends the window."}, + {"nblocks", RPCArg::Type::NUM, /* default */ "one month", "Size of the window in number of blocks"}, + {"blockhash", RPCArg::Type::STR_HEX, /* default */ "chain tip", "The hash of the block that ends the window."}, }, RPCResult{ "{\n" @@ -1778,18 +1778,16 @@ static constexpr size_t PER_UTXO_OVERHEAD = sizeof(COutPoint) + sizeof(uint32_t) static UniValue getblockstats(const JSONRPCRequest& request) { - if (request.fHelp || request.params.size() < 1 || request.params.size() > 4) { - throw std::runtime_error( - RPCHelpMan{"getblockstats", + const RPCHelpMan help{"getblockstats", "\nCompute per block statistics for a given window. All amounts are in satoshis.\n" "It won't work for some heights with pruning.\n" "It won't work without -txindex for utxo_size_inc, *fee or *feerate stats.\n", { - {"hash_or_height", RPCArg::Type::NUM, /* opt */ false, /* default_val */ "", "The block hash or height of the target block", "", {"", "string or numeric"}}, - {"stats", RPCArg::Type::ARR, /* opt */ true, /* default_val */ "all values", "Values to plot (see result below)", + {"hash_or_height", RPCArg::Type::NUM, RPCArg::Optional::NO, "The block hash or height of the target block", "", {"", "string or numeric"}}, + {"stats", RPCArg::Type::ARR, /* default */ "all values", "Values to plot (see result below)", { - {"height", RPCArg::Type::STR, /* opt */ true, /* default_val */ "", "Selected statistic"}, - {"time", RPCArg::Type::STR, /* opt */ true, /* default_val */ "", "Selected statistic"}, + {"height", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Selected statistic"}, + {"time", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Selected statistic"}, }, "stats"}, }, @@ -1836,7 +1834,9 @@ static UniValue getblockstats(const JSONRPCRequest& request) HelpExampleCli("getblockstats", "1000 '[\"minfeerate\",\"avgfeerate\"]'") + HelpExampleRpc("getblockstats", "1000 '[\"minfeerate\",\"avgfeerate\"]'") }, - }.ToString()); + }; + if (request.fHelp || !help.IsValidNumArgs(request.params.size())) { + throw std::runtime_error(help.ToString()); } LOCK(cs_main); @@ -2148,18 +2148,18 @@ UniValue scantxoutset(const JSONRPCRequest& request) "In the latter case, a range needs to be specified by below if different from 1000.\n" "For more information on output descriptors, see the documentation in the doc/descriptors.md file.\n", { - {"action", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The action to execute\n" + {"action", RPCArg::Type::STR, RPCArg::Optional::NO, "The action to execute\n" " \"start\" for starting a scan\n" " \"abort\" for aborting the current scan (returns true when abort was successful)\n" " \"status\" for progress report (in %) of the current scan"}, - {"scanobjects", RPCArg::Type::ARR, /* opt */ false, /* default_val */ "", "Array of scan objects\n" + {"scanobjects", RPCArg::Type::ARR, RPCArg::Optional::NO, "Array of scan objects\n" " Every scan object is either a string descriptor or an object:", { - {"descriptor", RPCArg::Type::STR, /* opt */ true, /* default_val */ "", "An output descriptor"}, - {"", RPCArg::Type::OBJ, /* opt */ true, /* default_val */ "", "An object with output descriptor and metadata", + {"descriptor", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "An output descriptor"}, + {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "An object with output descriptor and metadata", { - {"desc", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "An output descriptor"}, - {"range", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "1000", "Up to what child index HD chains should be explored"}, + {"desc", RPCArg::Type::STR, RPCArg::Optional::NO, "An output descriptor"}, + {"range", RPCArg::Type::RANGE, /* default */ "1000", "The range of HD chain indexes to explore (either end or [begin,end])"}, }, }, }, @@ -2216,7 +2216,7 @@ UniValue scantxoutset(const JSONRPCRequest& request) // loop through the scan objects for (const UniValue& scanobject : request.params[1].get_array().getValues()) { std::string desc_str; - int range = 1000; + std::pair<int64_t, int64_t> range = {0, 1000}; if (scanobject.isStr()) { desc_str = scanobject.get_str(); } else if (scanobject.isObject()) { @@ -2225,8 +2225,8 @@ UniValue scantxoutset(const JSONRPCRequest& request) desc_str = desc_uni.get_str(); UniValue range_uni = find_value(scanobject, "range"); if (!range_uni.isNull()) { - range = range_uni.get_int(); - if (range < 0 || range > 1000000) throw JSONRPCError(RPC_INVALID_PARAMETER, "range out of range"); + range = ParseRange(range_uni); + if (range.first < 0 || (range.second >> 31) != 0 || range.second >= range.first + 1000000) throw JSONRPCError(RPC_INVALID_PARAMETER, "range out of range"); } } else { throw JSONRPCError(RPC_INVALID_PARAMETER, "Scan object needs to be either a string or an object"); @@ -2237,8 +2237,11 @@ UniValue scantxoutset(const JSONRPCRequest& request) if (!desc) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Invalid descriptor '%s'", desc_str)); } - if (!desc->IsRange()) range = 0; - for (int i = 0; i <= range; ++i) { + if (!desc->IsRange()) { + range.first = 0; + range.second = 0; + } + for (int i = range.first; i <= range.second; ++i) { std::vector<CScript> scripts; if (!desc->Expand(i, provider, scripts, provider)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Cannot derive script without private keys: '%s'", desc_str)); diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index 6f1bfb03d1..1cdc9f87a7 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -68,6 +68,8 @@ static const CRPCConvertParam vRPCConvertParams[] = { "sendmany", 4, "subtractfeefrom" }, { "sendmany", 5 , "replaceable" }, { "sendmany", 6 , "conf_target" }, + { "deriveaddresses", 1, "begin" }, + { "deriveaddresses", 2, "end" }, { "scantxoutset", 1, "scanobjects" }, { "addmultisigaddress", 0, "nrequired" }, { "addmultisigaddress", 1, "keys" }, @@ -89,8 +91,6 @@ static const CRPCConvertParam vRPCConvertParams[] = { "createrawtransaction", 2, "locktime" }, { "createrawtransaction", 3, "replaceable" }, { "decoderawtransaction", 1, "iswitness" }, - { "signrawtransaction", 1, "prevtxs" }, - { "signrawtransaction", 2, "privkeys" }, { "signrawtransactionwithkey", 1, "privkeys" }, { "signrawtransactionwithkey", 2, "prevtxs" }, { "signrawtransactionwithwallet", 1, "prevtxs" }, @@ -112,6 +112,7 @@ static const CRPCConvertParam vRPCConvertParams[] = { "createpsbt", 2, "locktime" }, { "createpsbt", 3, "replaceable" }, { "combinepsbt", 0, "txs"}, + { "joinpsbts", 0, "txs"}, { "finalizepsbt", 1, "extract"}, { "converttopsbt", 1, "permitsigdata"}, { "converttopsbt", 2, "iswitness"}, @@ -161,6 +162,7 @@ static const CRPCConvertParam vRPCConvertParams[] = { "rescanblockchain", 0, "start_height"}, { "rescanblockchain", 1, "stop_height"}, { "createwallet", 1, "disable_private_keys"}, + { "createwallet", 2, "blank"}, { "getnodeaddresses", 0, "count"}, { "stop", 0, "wait" }, }; diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 200dfa107b..6625a03bbd 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -31,16 +31,6 @@ #include <memory> #include <stdint.h> -unsigned int ParseConfirmTarget(const UniValue& value) -{ - int target = value.get_int(); - unsigned int max_target = ::feeEstimator.HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE); - if (target < 1 || (unsigned int)target > max_target) { - throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid conf_target, must be between %u - %u", 1, max_target)); - } - return (unsigned int)target; -} - /** * Return average network hashes per second based on the last 'lookup' blocks, * or from the last difficulty change if 'lookup' is nonpositive. @@ -92,8 +82,8 @@ static UniValue getnetworkhashps(const JSONRPCRequest& request) "Pass in [blocks] to override # of blocks, -1 specifies since last difficulty change.\n" "Pass in [height] to estimate the network speed at the time when a certain block was found.\n", { - {"nblocks", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "120", "The number of blocks, or -1 for blocks since last difficulty change."}, - {"height", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "-1", "To estimate at the time of the given height."}, + {"nblocks", RPCArg::Type::NUM, /* default */ "120", "The number of blocks, or -1 for blocks since last difficulty change."}, + {"height", RPCArg::Type::NUM, /* default */ "-1", "To estimate at the time of the given height."}, }, RPCResult{ "x (numeric) Hashes per second estimated\n" @@ -163,9 +153,9 @@ static UniValue generatetoaddress(const JSONRPCRequest& request) RPCHelpMan{"generatetoaddress", "\nMine blocks immediately to a specified address (before the RPC call returns)\n", { - {"nblocks", RPCArg::Type::NUM, /* opt */ false, /* default_val */ "", "How many blocks are generated immediately."}, - {"address", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The address to send the newly generated bitcoin to."}, - {"maxtries", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "1000000", "How many iterations to try."}, + {"nblocks", RPCArg::Type::NUM, RPCArg::Optional::NO, "How many blocks are generated immediately."}, + {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The address to send the newly generated bitcoin to."}, + {"maxtries", RPCArg::Type::NUM, /* default */ "1000000", "How many iterations to try."}, }, RPCResult{ "[ blockhashes ] (array) hashes of blocks generated\n" @@ -197,36 +187,36 @@ static UniValue generatetoaddress(const JSONRPCRequest& request) static UniValue getmininginfo(const JSONRPCRequest& request) { - if (request.fHelp || request.params.size() != 0) + if (request.fHelp || request.params.size() != 0) { throw std::runtime_error( RPCHelpMan{"getmininginfo", "\nReturns a json object containing mining-related information.", {}, RPCResult{ - "{\n" - " \"blocks\": nnn, (numeric) The current block\n" - " \"currentblockweight\": nnn, (numeric) The last block weight\n" - " \"currentblocktx\": nnn, (numeric) The last block transaction\n" - " \"difficulty\": xxx.xxxxx (numeric) The current difficulty\n" - " \"networkhashps\": nnn, (numeric) The network hashes per second\n" - " \"pooledtx\": n (numeric) The size of the mempool\n" - " \"chain\": \"xxxx\", (string) current network name as defined in BIP70 (main, test, regtest)\n" - " \"warnings\": \"...\" (string) any network and blockchain warnings\n" - "}\n" + "{\n" + " \"blocks\": nnn, (numeric) The current block\n" + " \"currentblockweight\": nnn, (numeric, optional) The block weight of the last assembled block (only present if a block was ever assembled)\n" + " \"currentblocktx\": nnn, (numeric, optional) The number of block transactions of the last assembled block (only present if a block was ever assembled)\n" + " \"difficulty\": xxx.xxxxx (numeric) The current difficulty\n" + " \"networkhashps\": nnn, (numeric) The network hashes per second\n" + " \"pooledtx\": n (numeric) The size of the mempool\n" + " \"chain\": \"xxxx\", (string) current network name as defined in BIP70 (main, test, regtest)\n" + " \"warnings\": \"...\" (string) any network and blockchain warnings\n" + "}\n" }, RPCExamples{ HelpExampleCli("getmininginfo", "") + HelpExampleRpc("getmininginfo", "") }, }.ToString()); - + } LOCK(cs_main); UniValue obj(UniValue::VOBJ); obj.pushKV("blocks", (int)chainActive.Height()); - obj.pushKV("currentblockweight", (uint64_t)nLastBlockWeight); - obj.pushKV("currentblocktx", (uint64_t)nLastBlockTx); + if (BlockAssembler::m_last_block_weight) obj.pushKV("currentblockweight", *BlockAssembler::m_last_block_weight); + if (BlockAssembler::m_last_block_num_txs) obj.pushKV("currentblocktx", *BlockAssembler::m_last_block_num_txs); obj.pushKV("difficulty", (double)GetDifficulty(chainActive.Tip())); obj.pushKV("networkhashps", getnetworkhashps(request)); obj.pushKV("pooledtx", (uint64_t)mempool.size()); @@ -244,10 +234,10 @@ static UniValue prioritisetransaction(const JSONRPCRequest& request) RPCHelpMan{"prioritisetransaction", "Accepts the transaction into mined blocks at a higher (or lower) priority\n", { - {"txid", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "The transaction id."}, - {"dummy", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "null", "API-Compatibility for previous API. Must be zero or null.\n" + {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id."}, + {"dummy", RPCArg::Type::NUM, RPCArg::Optional::OMITTED_NAMED_ARG, "API-Compatibility for previous API. Must be zero or null.\n" " DEPRECATED. For forward compatibility use named arguments and omit this parameter."}, - {"fee_delta", RPCArg::Type::NUM, /* opt */ false, /* default_val */ "", "The fee value (in satoshis) to add (or subtract, if negative).\n" + {"fee_delta", RPCArg::Type::NUM, RPCArg::Optional::NO, "The fee value (in satoshis) to add (or subtract, if negative).\n" " Note, that this value is not a fee rate. It is a value to modify absolute fee of the TX.\n" " The fee is not actually paid, only the algorithm for selecting transactions into a block\n" " considers the transaction as it would have paid a higher (or lower) fee."}, @@ -316,17 +306,17 @@ static UniValue getblocktemplate(const JSONRPCRequest& request) " https://github.com/bitcoin/bips/blob/master/bip-0009.mediawiki#getblocktemplate_changes\n" " https://github.com/bitcoin/bips/blob/master/bip-0145.mediawiki\n", { - {"template_request", RPCArg::Type::OBJ, /* opt */ false, /* default_val */ "", "A json object in the following spec", + {"template_request", RPCArg::Type::OBJ, RPCArg::Optional::NO, "A json object in the following spec", { - {"mode", RPCArg::Type::STR, /* opt */ true, /* default_val */ "", "This must be set to \"template\", \"proposal\" (see BIP 23), or omitted"}, - {"capabilities", RPCArg::Type::ARR, /* opt */ true, /* default_val */ "", "A list of strings", + {"mode", RPCArg::Type::STR, /* treat as named arg */ RPCArg::Optional::OMITTED_NAMED_ARG, "This must be set to \"template\", \"proposal\" (see BIP 23), or omitted"}, + {"capabilities", RPCArg::Type::ARR, /* treat as named arg */ RPCArg::Optional::OMITTED_NAMED_ARG, "A list of strings", { - {"support", RPCArg::Type::STR, /* opt */ true, /* default_val */ "", "client side supported feature, 'longpoll', 'coinbasetxn', 'coinbasevalue', 'proposal', 'serverlist', 'workid'"}, + {"support", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "client side supported feature, 'longpoll', 'coinbasetxn', 'coinbasevalue', 'proposal', 'serverlist', 'workid'"}, }, }, - {"rules", RPCArg::Type::ARR, /* opt */ false, /* default_val */ "", "A list of strings", + {"rules", RPCArg::Type::ARR, RPCArg::Optional::NO, "A list of strings", { - {"support", RPCArg::Type::STR, /* opt */ true, /* default_val */ "", "client side supported softfork deployment"}, + {"support", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "client side supported softfork deployment"}, }, }, }, @@ -716,8 +706,8 @@ static UniValue submitblock(const JSONRPCRequest& request) "\nAttempts to submit new block to network.\n" "See https://en.bitcoin.it/wiki/BIP_0022 for full specification.\n", { - {"hexdata", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "the hex-encoded block data to submit"}, - {"dummy", RPCArg::Type::STR, /* opt */ true, /* default_val */ "ignored", "dummy value, for compatibility with BIP22. This value is ignored."}, + {"hexdata", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "the hex-encoded block data to submit"}, + {"dummy", RPCArg::Type::STR, /* default */ "ignored", "dummy value, for compatibility with BIP22. This value is ignored."}, }, RPCResults{}, RPCExamples{ @@ -781,7 +771,7 @@ static UniValue submitheader(const JSONRPCRequest& request) "\nDecode the given hexdata as a header and submit it as a candidate chain tip if valid." "\nThrows when the header is invalid.\n", { - {"hexdata", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "the hex-encoded block header data"}, + {"hexdata", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "the hex-encoded block header data"}, }, RPCResult{ "None" @@ -823,8 +813,8 @@ static UniValue estimatesmartfee(const JSONRPCRequest& request) "for which the estimate is valid. Uses virtual transaction size as defined\n" "in BIP 141 (witness data is discounted).\n", { - {"conf_target", RPCArg::Type::NUM, /* opt */ false, /* default_val */ "", "Confirmation target in blocks (1 - 1008)"}, - {"estimate_mode", RPCArg::Type::STR, /* opt */ true, /* default_val */ "CONSERVATIVE", "The fee estimate mode.\n" + {"conf_target", RPCArg::Type::NUM, RPCArg::Optional::NO, "Confirmation target in blocks (1 - 1008)"}, + {"estimate_mode", RPCArg::Type::STR, /* default */ "CONSERVATIVE", "The fee estimate mode.\n" " Whether to return a more conservative estimate which also satisfies\n" " a longer history. A conservative estimate potentially returns a\n" " higher feerate and is more likely to be sufficient for the desired\n" @@ -890,8 +880,8 @@ static UniValue estimaterawfee(const JSONRPCRequest& request) "confirmation within conf_target blocks if possible. Uses virtual transaction size as\n" "defined in BIP 141 (witness data is discounted).\n", { - {"conf_target", RPCArg::Type::NUM, /* opt */ false, /* default_val */ "", "Confirmation target in blocks (1 - 1008)"}, - {"threshold", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "0.95", "The proportion of transactions in a given feerate range that must have been\n" + {"conf_target", RPCArg::Type::NUM, RPCArg::Optional::NO, "Confirmation target in blocks (1 - 1008)"}, + {"threshold", RPCArg::Type::NUM, /* default */ "0.95", "The proportion of transactions in a given feerate range that must have been\n" " confirmed within conf_target in order to consider those feerates as high enough and proceed to check\n" " lower buckets."}, }, diff --git a/src/rpc/mining.h b/src/rpc/mining.h index 8d46273159..be9a973315 100644 --- a/src/rpc/mining.h +++ b/src/rpc/mining.h @@ -12,7 +12,4 @@ /** Generate blocks (mine) */ UniValue generateBlocks(std::shared_ptr<CReserveScript> coinbaseScript, int nGenerate, uint64_t nMaxTries, bool keepScript); -/** Check bounds on a command line confirm target */ -unsigned int ParseConfirmTarget(const UniValue& value); - #endif diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index 9d17a2fc4e..765fd772fe 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -16,6 +16,7 @@ #include <rpc/blockchain.h> #include <rpc/server.h> #include <rpc/util.h> +#include <script/descriptor.h> #include <timedata.h> #include <util/system.h> #include <util/strencodings.h> @@ -39,7 +40,7 @@ static UniValue validateaddress(const JSONRPCRequest& request) "fields have moved to getaddressinfo and will only be shown here with -deprecatedrpc=validateaddress: ismine, iswatchonly,\n" "script, hex, pubkeys, sigsrequired, pubkey, addresses, embedded, iscompressed, account, timestamp, hdkeypath, kdmasterkeyid.\n", { - {"address", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The bitcoin address to validate"}, + {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The bitcoin address to validate"}, }, RPCResult{ "{\n" @@ -86,12 +87,12 @@ static UniValue createmultisig(const JSONRPCRequest& request) "\nCreates a multi-signature address with n signature of m keys required.\n" "It returns a json object with the address and redeemScript.\n", { - {"nrequired", RPCArg::Type::NUM, /* opt */ false, /* default_val */ "", "The number of required signatures out of the n keys."}, - {"keys", RPCArg::Type::ARR, /* opt */ false, /* default_val */ "", "A json array of hex-encoded public keys.", + {"nrequired", RPCArg::Type::NUM, RPCArg::Optional::NO, "The number of required signatures out of the n keys."}, + {"keys", RPCArg::Type::ARR, RPCArg::Optional::NO, "A json array of hex-encoded public keys.", { - {"key", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "The hex-encoded public key"}, + {"key", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "The hex-encoded public key"}, }}, - {"address_type", RPCArg::Type::STR, /* opt */ true, /* default_val */ "legacy", "The address type to use. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."}, + {"address_type", RPCArg::Type::STR, /* default */ "legacy", "The address type to use. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."}, }, RPCResult{ "{\n" @@ -142,6 +143,135 @@ static UniValue createmultisig(const JSONRPCRequest& request) return result; } +UniValue getdescriptorinfo(const JSONRPCRequest& request) +{ + if (request.fHelp || request.params.size() != 1) { + throw std::runtime_error( + RPCHelpMan{"getdescriptorinfo", + {"\nAnalyses a descriptor.\n"}, + { + {"descriptor", RPCArg::Type::STR, RPCArg::Optional::NO, "The descriptor."}, + }, + RPCResult{ + "{\n" + " \"descriptor\" : \"desc\", (string) The descriptor in canonical form, without private keys\n" + " \"isrange\" : true|false, (boolean) Whether the descriptor is ranged\n" + " \"issolvable\" : true|false, (boolean) Whether the descriptor is solvable\n" + " \"hasprivatekeys\" : true|false, (boolean) Whether the input descriptor contained at least one private key\n" + "}\n" + }, + RPCExamples{ + "Analyse a descriptor\n" + + HelpExampleCli("getdescriptorinfo", "\"wpkh([d34db33f/84h/0h/0h]0279be667ef9dcbbac55a06295Ce870b07029Bfcdb2dce28d959f2815b16f81798)\"") + }}.ToString() + ); + } + + RPCTypeCheck(request.params, {UniValue::VSTR}); + + FlatSigningProvider provider; + auto desc = Parse(request.params[0].get_str(), provider); + if (!desc) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Invalid descriptor")); + } + + UniValue result(UniValue::VOBJ); + result.pushKV("descriptor", desc->ToString()); + result.pushKV("isrange", desc->IsRange()); + result.pushKV("issolvable", desc->IsSolvable()); + result.pushKV("hasprivatekeys", provider.keys.size() > 0); + return result; +} + +UniValue deriveaddresses(const JSONRPCRequest& request) +{ + if (request.fHelp || request.params.empty() || request.params.size() > 2) { + throw std::runtime_error( + RPCHelpMan{"deriveaddresses", + {"\nDerives one or more addresses corresponding to an output descriptor.\n" + "Examples of output descriptors are:\n" + " pkh(<pubkey>) P2PKH outputs for the given pubkey\n" + " wpkh(<pubkey>) Native segwit P2PKH outputs for the given pubkey\n" + " sh(multi(<n>,<pubkey>,<pubkey>,...)) P2SH-multisig outputs for the given threshold and pubkeys\n" + " raw(<hex script>) Outputs whose scriptPubKey equals the specified hex scripts\n" + "\nIn the above, <pubkey> either refers to a fixed public key in hexadecimal notation, or to an xpub/xprv optionally followed by one\n" + "or more path elements separated by \"/\", where \"h\" represents a hardened child key.\n" + "For more information on output descriptors, see the documentation in the doc/descriptors.md file.\n"}, + { + {"descriptor", RPCArg::Type::STR, RPCArg::Optional::NO, "The descriptor."}, + {"range", RPCArg::Type::RANGE, RPCArg::Optional::OMITTED_NAMED_ARG, "If a ranged descriptor is used, this specifies the end or the range (in [begin,end] notation) to derive."}, + }, + RPCResult{ + "[ address ] (array) the derived addresses\n" + }, + RPCExamples{ + "First three native segwit receive addresses\n" + + HelpExampleCli("deriveaddresses", "\"wpkh([d34db33f/84h/0h/0h]xpub6DJ2dNUysrn5Vt36jH2KLBT2i1auw1tTSSomg8PhqNiUtx8QX2SvC9nrHu81fT41fvDUnhMjEzQgXnQjKEu3oaqMSzhSrHMxyyoEAmUHQbY/0/*)#trd0mf0l\" \"[0,2]\"") + }}.ToString() + ); + } + + RPCTypeCheck(request.params, {UniValue::VSTR, UniValueType()}); // Range argument is checked later + const std::string desc_str = request.params[0].get_str(); + + int64_t range_begin = 0; + int64_t range_end = 0; + + if (request.params.size() >= 2 && !request.params[1].isNull()) { + auto range = ParseRange(request.params[1]); + if (range.first < 0) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Range should be greater or equal than 0"); + } + if ((range.second >> 31) != 0) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "End of range is too high"); + } + if (range.second >= range.first + 1000000) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Range is too large"); + } + range_begin = range.first; + range_end = range.second; + } + + FlatSigningProvider provider; + auto desc = Parse(desc_str, provider, /* require_checksum = */ true); + if (!desc) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Invalid descriptor")); + } + + if (!desc->IsRange() && request.params.size() > 1) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Range should not be specified for an un-ranged descriptor"); + } + + if (desc->IsRange() && request.params.size() == 1) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Range must be specified for a ranged descriptor"); + } + + UniValue addresses(UniValue::VARR); + + for (int i = range_begin; i <= range_end; ++i) { + std::vector<CScript> scripts; + if (!desc->Expand(i, provider, scripts, provider)) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Cannot derive script without private keys")); + } + + for (const CScript &script : scripts) { + CTxDestination dest; + if (!ExtractDestination(script, dest)) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Descriptor does not have a corresponding address")); + } + + addresses.push_back(EncodeDestination(dest)); + } + } + + // This should not be possible, but an assert seems overkill: + if (addresses.empty()) { + throw JSONRPCError(RPC_MISC_ERROR, "Unexpected empty result"); + } + + return addresses; +} + static UniValue verifymessage(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 3) @@ -149,9 +279,9 @@ static UniValue verifymessage(const JSONRPCRequest& request) RPCHelpMan{"verifymessage", "\nVerify a signed message\n", { - {"address", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The bitcoin address to use for the signature."}, - {"signature", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The signature provided by the signer in base 64 encoding (see signmessage)."}, - {"message", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The message that was signed."}, + {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The bitcoin address to use for the signature."}, + {"signature", RPCArg::Type::STR, RPCArg::Optional::NO, "The signature provided by the signer in base 64 encoding (see signmessage)."}, + {"message", RPCArg::Type::STR, RPCArg::Optional::NO, "The message that was signed."}, }, RPCResult{ "true|false (boolean) If the signature is verified or not.\n" @@ -208,8 +338,8 @@ static UniValue signmessagewithprivkey(const JSONRPCRequest& request) RPCHelpMan{"signmessagewithprivkey", "\nSign a message with the private key of an address\n", { - {"privkey", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The private key to sign the message with."}, - {"message", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The message to create a signature of."}, + {"privkey", RPCArg::Type::STR, RPCArg::Optional::NO, "The private key to sign the message with."}, + {"message", RPCArg::Type::STR, RPCArg::Optional::NO, "The message to create a signature of."}, }, RPCResult{ "\"signature\" (string) The signature of the message encoded in base 64\n" @@ -250,7 +380,7 @@ static UniValue setmocktime(const JSONRPCRequest& request) RPCHelpMan{"setmocktime", "\nSet the local time to given timestamp (-regtest only)\n", { - {"timestamp", RPCArg::Type::NUM, /* opt */ false, /* default_val */ "", "Unix seconds-since-epoch timestamp\n" + {"timestamp", RPCArg::Type::NUM, RPCArg::Optional::NO, "Unix seconds-since-epoch timestamp\n" " Pass 0 to go back to using the system time."}, }, RPCResults{}, @@ -316,7 +446,7 @@ static UniValue getmemoryinfo(const JSONRPCRequest& request) RPCHelpMan{"getmemoryinfo", "Returns an object containing information about memory usage.\n", { - {"mode", RPCArg::Type::STR, /* opt */ true, /* default_val */ "\"stats\"", "determines what kind of information is returned.\n" + {"mode", RPCArg::Type::STR, /* default */ "\"stats\"", "determines what kind of information is returned.\n" " - \"stats\" returns general statistics about memory usage in the daemon.\n" " - \"mallocinfo\" returns an XML string describing low-level heap state (only available if compiled with glibc 2.10+)."}, }, @@ -366,9 +496,9 @@ static void EnableOrDisableLogCategories(UniValue cats, bool enable) { bool success; if (enable) { - success = g_logger->EnableCategory(cat); + success = LogInstance().EnableCategory(cat); } else { - success = g_logger->DisableCategory(cat); + success = LogInstance().DisableCategory(cat); } if (!success) { @@ -393,13 +523,13 @@ UniValue logging(const JSONRPCRequest& request) " - \"none\", \"0\" : even if other logging categories are specified, ignore all of them.\n" , { - {"include", RPCArg::Type::ARR, /* opt */ true, /* default_val */ "null", "A json array of categories to add debug logging", + {"include", RPCArg::Type::ARR, RPCArg::Optional::OMITTED_NAMED_ARG, "A json array of categories to add debug logging", { - {"include_category", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "the valid logging category"}, + {"include_category", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "the valid logging category"}, }}, - {"exclude", RPCArg::Type::ARR, /* opt */ true, /* default_val */ "null", "A json array of categories to remove debug logging", + {"exclude", RPCArg::Type::ARR, RPCArg::Optional::OMITTED_NAMED_ARG, "A json array of categories to remove debug logging", { - {"exclude_category", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "the valid logging category"}, + {"exclude_category", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "the valid logging category"}, }}, }, RPCResult{ @@ -415,14 +545,14 @@ UniValue logging(const JSONRPCRequest& request) }.ToString()); } - uint32_t original_log_categories = g_logger->GetCategoryMask(); + uint32_t original_log_categories = LogInstance().GetCategoryMask(); if (request.params[0].isArray()) { EnableOrDisableLogCategories(request.params[0], true); } if (request.params[1].isArray()) { EnableOrDisableLogCategories(request.params[1], false); } - uint32_t updated_log_categories = g_logger->GetCategoryMask(); + uint32_t updated_log_categories = LogInstance().GetCategoryMask(); uint32_t changed_log_categories = original_log_categories ^ updated_log_categories; // Update libevent logging if BCLog::LIBEVENT has changed. @@ -431,8 +561,8 @@ UniValue logging(const JSONRPCRequest& request) // Throw an error if the user has explicitly asked to change only the libevent // flag and it failed. if (changed_log_categories & BCLog::LIBEVENT) { - if (!UpdateHTTPServerLogging(g_logger->WillLogCategory(BCLog::LIBEVENT))) { - g_logger->DisableCategory(BCLog::LIBEVENT); + if (!UpdateHTTPServerLogging(LogInstance().WillLogCategory(BCLog::LIBEVENT))) { + LogInstance().DisableCategory(BCLog::LIBEVENT); if (changed_log_categories == BCLog::LIBEVENT) { throw JSONRPCError(RPC_INVALID_PARAMETER, "libevent logging cannot be updated when using libevent before v2.1.1."); } @@ -473,6 +603,8 @@ static const CRPCCommand commands[] = { "control", "logging", &logging, {"include", "exclude"}}, { "util", "validateaddress", &validateaddress, {"address"} }, { "util", "createmultisig", &createmultisig, {"nrequired","keys","address_type"} }, + { "util", "deriveaddresses", &deriveaddresses, {"descriptor", "begin", "end"} }, + { "util", "getdescriptorinfo", &getdescriptorinfo, {"descriptor"} }, { "util", "verifymessage", &verifymessage, {"address","signature","message"} }, { "util", "signmessagewithprivkey", &signmessagewithprivkey, {"privkey","message"} }, diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index b50038b085..c7b3478f44 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -221,8 +221,8 @@ static UniValue addnode(const JSONRPCRequest& request) "Nodes added using addnode (or -connect) are protected from DoS disconnection and are not required to be\n" "full nodes/support SegWit as other outbound peers are (though such peers will not be synced from).\n", { - {"node", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The node (see getpeerinfo for nodes)"}, - {"command", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "'add' to add a node to the list, 'remove' to remove a node from the list, 'onetry' to try a connection to the node once"}, + {"node", RPCArg::Type::STR, RPCArg::Optional::NO, "The node (see getpeerinfo for nodes)"}, + {"command", RPCArg::Type::STR, RPCArg::Optional::NO, "'add' to add a node to the list, 'remove' to remove a node from the list, 'onetry' to try a connection to the node once"}, }, RPCResults{}, RPCExamples{ @@ -266,8 +266,8 @@ static UniValue disconnectnode(const JSONRPCRequest& request) "\nStrictly one out of 'address' and 'nodeid' can be provided to identify the node.\n" "\nTo disconnect by nodeid, either set 'address' to the empty string, or call using the named 'nodeid' argument only.\n", { - {"address", RPCArg::Type::STR, /* opt */ true, /* default_val */ "fallback to nodeid", "The IP address/port of the node"}, - {"nodeid", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "fallback to address", "The node ID (see getpeerinfo for node IDs)"}, + {"address", RPCArg::Type::STR, /* default */ "fallback to nodeid", "The IP address/port of the node"}, + {"nodeid", RPCArg::Type::NUM, /* default */ "fallback to address", "The node ID (see getpeerinfo for node IDs)"}, }, RPCResults{}, RPCExamples{ @@ -311,7 +311,7 @@ static UniValue getaddednodeinfo(const JSONRPCRequest& request) "\nReturns information about the given added node, or all added nodes\n" "(note that onetry addnodes are not listed here)\n", { - {"node", RPCArg::Type::STR, /* opt */ true, /* default_val */ "all nodes", "If provided, return information about this specific node, otherwise all nodes are returned."}, + {"node", RPCArg::Type::STR, /* default */ "all nodes", "If provided, return information about this specific node, otherwise all nodes are returned."}, }, RPCResult{ "[\n" @@ -523,19 +523,13 @@ static UniValue getnetworkinfo(const JSONRPCRequest& request) static UniValue setban(const JSONRPCRequest& request) { - std::string strCommand; - if (!request.params[1].isNull()) - strCommand = request.params[1].get_str(); - if (request.fHelp || request.params.size() < 2 || - (strCommand != "add" && strCommand != "remove")) - throw std::runtime_error( - RPCHelpMan{"setban", + const RPCHelpMan help{"setban", "\nAttempts to add or remove an IP/Subnet from the banned list.\n", { - {"subnet", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The IP/Subnet (see getpeerinfo for nodes IP) with an optional netmask (default is /32 = single IP)"}, - {"command", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "'add' to add an IP/Subnet to the list, 'remove' to remove an IP/Subnet from the list"}, - {"bantime", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "0", "time in seconds how long (or until when if [absolute] is set) the IP is banned (0 or empty means using the default time of 24h which can also be overwritten by the -bantime startup argument)"}, - {"absolute", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "If set, the bantime must be an absolute timestamp in seconds since epoch (Jan 1 1970 GMT)"}, + {"subnet", RPCArg::Type::STR, RPCArg::Optional::NO, "The IP/Subnet (see getpeerinfo for nodes IP) with an optional netmask (default is /32 = single IP)"}, + {"command", RPCArg::Type::STR, RPCArg::Optional::NO, "'add' to add an IP/Subnet to the list, 'remove' to remove an IP/Subnet from the list"}, + {"bantime", RPCArg::Type::NUM, /* default */ "0", "time in seconds how long (or until when if [absolute] is set) the IP is banned (0 or empty means using the default time of 24h which can also be overwritten by the -bantime startup argument)"}, + {"absolute", RPCArg::Type::BOOL, /* default */ "false", "If set, the bantime must be an absolute timestamp in seconds since epoch (Jan 1 1970 GMT)"}, }, RPCResults{}, RPCExamples{ @@ -543,7 +537,13 @@ static UniValue setban(const JSONRPCRequest& request) + HelpExampleCli("setban", "\"192.168.0.0/24\" \"add\"") + HelpExampleRpc("setban", "\"192.168.0.6\", \"add\", 86400") }, - }.ToString()); + }; + std::string strCommand; + if (!request.params[1].isNull()) + strCommand = request.params[1].get_str(); + if (request.fHelp || !help.IsValidNumArgs(request.params.size()) || (strCommand != "add" && strCommand != "remove")) { + throw std::runtime_error(help.ToString()); + } if (!g_banman) { throw JSONRPCError(RPC_DATABASE_ERROR, "Error: Ban database not loaded"); } @@ -667,7 +667,7 @@ static UniValue setnetworkactive(const JSONRPCRequest& request) RPCHelpMan{"setnetworkactive", "\nDisable/enable all p2p network activity.\n", { - {"state", RPCArg::Type::BOOL, /* opt */ false, /* default_val */ "", "true to enable networking, false to disable"}, + {"state", RPCArg::Type::BOOL, RPCArg::Optional::NO, "true to enable networking, false to disable"}, }, RPCResults{}, RPCExamples{""}, @@ -691,7 +691,7 @@ static UniValue getnodeaddresses(const JSONRPCRequest& request) RPCHelpMan{"getnodeaddresses", "\nReturn known addresses which can potentially be used to find new nodes in the network\n", { - {"count", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "1", "How many addresses to return. Limited to the smaller of " + std::to_string(ADDRMAN_GETADDR_MAX) + " or " + std::to_string(ADDRMAN_GETADDR_MAX_PCT) + "% of all known addresses."}, + {"count", RPCArg::Type::NUM, /* default */ "1", "How many addresses to return. Limited to the smaller of " + std::to_string(ADDRMAN_GETADDR_MAX) + " or " + std::to_string(ADDRMAN_GETADDR_MAX_PCT) + "% of all known addresses."}, }, RPCResult{ "[\n" diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index ac2e0ff4ee..d19afaa8a1 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -1,11 +1,12 @@ // Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2009-2018 The Bitcoin Core developers +// Copyright (c) 2009-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include <chain.h> #include <coins.h> #include <compat/byteswap.h> +#include <consensus/tx_verify.h> #include <consensus/validation.h> #include <core_io.h> #include <index/txindex.h> @@ -13,10 +14,11 @@ #include <key_io.h> #include <keystore.h> #include <merkleblock.h> -#include <net.h> +#include <node/transaction.h> #include <policy/policy.h> #include <policy/rbf.h> #include <primitives/transaction.h> +#include <psbt.h> #include <rpc/rawtransaction.h> #include <rpc/server.h> #include <rpc/util.h> @@ -24,13 +26,14 @@ #include <script/script_error.h> #include <script/sign.h> #include <script/standard.h> -#include <txmempool.h> #include <uint256.h> +#include <util/bip32.h> #include <util/strencodings.h> #include <validation.h> #include <validationinterface.h> -#include <future> + +#include <numeric> #include <stdint.h> #include <univalue.h> @@ -64,23 +67,24 @@ static void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& static UniValue getrawtransaction(const JSONRPCRequest& request) { - if (request.fHelp || request.params.size() < 1 || request.params.size() > 3) - throw std::runtime_error( - RPCHelpMan{"getrawtransaction", + const RPCHelpMan help{ + "getrawtransaction", + "\nReturn the raw transaction data.\n" + "\nBy default this function only works for mempool transactions. When called with a blockhash\n" "argument, getrawtransaction will return the transaction if the specified block is available and\n" "the transaction is found in that block. When called without a blockhash argument, getrawtransaction\n" "will return the transaction if it is in the mempool, or if -txindex is enabled and the transaction\n" "is in a block in the blockchain.\n" - "\nReturn the raw transaction data.\n" - "\nIf verbose is 'true', returns an Object with information about 'txid'.\n" - "If verbose is 'false' or omitted, returns a string that is serialized, hex-encoded data for 'txid'.\n" - , + "\nHint: Use gettransaction for wallet transactions.\n" + + "\nIf verbose is 'true', returns an Object with information about 'txid'.\n" + "If verbose is 'false' or omitted, returns a string that is serialized, hex-encoded data for 'txid'.\n", { - {"txid", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "The transaction id"}, - {"verbose", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "If false, return a string, otherwise return a json object"}, - {"blockhash", RPCArg::Type::STR_HEX, /* opt */ true, /* default_val */ "null", "The block in which to look for the transaction"}, + {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"}, + {"verbose", RPCArg::Type::BOOL, /* default */ "false", "If false, return a string, otherwise return a json object"}, + {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED_NAMED_ARG, "The block in which to look for the transaction"}, }, { RPCResult{"if verbose is not set or set to false", @@ -141,7 +145,11 @@ static UniValue getrawtransaction(const JSONRPCRequest& request) + HelpExampleCli("getrawtransaction", "\"mytxid\" false \"myblockhash\"") + HelpExampleCli("getrawtransaction", "\"mytxid\" true \"myblockhash\"") }, - }.ToString()); + }; + + if (request.fHelp || !help.IsValidNumArgs(request.params.size())) { + throw std::runtime_error(help.ToString()); + } bool in_active_chain = true; uint256 hash = ParseHashV(request.params[0], "parameter 1"); @@ -214,12 +222,12 @@ static UniValue gettxoutproof(const JSONRPCRequest& request) "you need to maintain a transaction index, using the -txindex command line option or\n" "specify the block in which the transaction is included manually (by blockhash).\n", { - {"txids", RPCArg::Type::ARR, /* opt */ false, /* default_val */ "", "A json array of txids to filter", + {"txids", RPCArg::Type::ARR, RPCArg::Optional::NO, "A json array of txids to filter", { - {"txid", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "A transaction hash"}, + {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "A transaction hash"}, }, }, - {"blockhash", RPCArg::Type::STR_HEX, /* opt */ true, /* default_val */ "null", "If specified, looks for txid in the block with this hash"}, + {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED_NAMED_ARG, "If specified, looks for txid in the block with this hash"}, }, RPCResult{ "\"data\" (string) A string that is a serialized, hex-encoded data for the proof.\n" @@ -307,7 +315,7 @@ static UniValue verifytxoutproof(const JSONRPCRequest& request) "\nVerifies that a proof points to a transaction in a block, returning the transaction it commits to\n" "and throwing an RPC error if the block is not in our best chain\n", { - {"proof", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "The hex-encoded proof generated by gettxoutproof"}, + {"proof", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hex-encoded proof generated by gettxoutproof"}, }, RPCResult{ "[\"txid\"] (array, strings) The txid(s) which the proof commits to, or empty array if the proof can not be validated.\n" @@ -468,36 +476,36 @@ static UniValue createrawtransaction(const JSONRPCRequest& request) "Note that the transaction's inputs are not signed, and\n" "it is not stored in the wallet or transmitted to the network.\n", { - {"inputs", RPCArg::Type::ARR, /* opt */ false, /* default_val */ "", "A json array of json objects", + {"inputs", RPCArg::Type::ARR, RPCArg::Optional::NO, "A json array of json objects", { - {"", RPCArg::Type::OBJ, /* opt */ true, /* default_val */ "", "", + {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "", { - {"txid", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "The transaction id"}, - {"vout", RPCArg::Type::NUM, /* opt */ false, /* default_val */ "", "The output number"}, - {"sequence", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "depends on the value of the 'replaceable' and 'locktime' arguments", "The sequence number"}, + {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"}, + {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"}, + {"sequence", RPCArg::Type::NUM, /* default */ "depends on the value of the 'replaceable' and 'locktime' arguments", "The sequence number"}, }, }, }, }, - {"outputs", RPCArg::Type::ARR, /* opt */ false, /* default_val */ "", "a json array with outputs (key-value pairs), where none of the keys are duplicated.\n" + {"outputs", RPCArg::Type::ARR, RPCArg::Optional::NO, "a json array with outputs (key-value pairs), where none of the keys are duplicated.\n" "That is, each address can only appear once and there can only be one 'data' object.\n" "For compatibility reasons, a dictionary, which holds the key-value pairs directly, is also\n" " accepted as second parameter.", { - {"", RPCArg::Type::OBJ, /* opt */ true, /* default_val */ "", "", + {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "", { - {"address", RPCArg::Type::AMOUNT, /* opt */ false, /* default_val */ "", "A key-value pair. The key (string) is the bitcoin address, the value (float or string) is the amount in " + CURRENCY_UNIT}, + {"address", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "A key-value pair. The key (string) is the bitcoin address, the value (float or string) is the amount in " + CURRENCY_UNIT}, }, }, - {"", RPCArg::Type::OBJ, /* opt */ true, /* default_val */ "", "", + {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "", { - {"data", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "A key-value pair. The key must be \"data\", the value is hex-encoded data"}, + {"data", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "A key-value pair. The key must be \"data\", the value is hex-encoded data"}, }, }, }, }, - {"locktime", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "0", "Raw locktime. Non-0 value also locktime-activates inputs"}, - {"replaceable", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "Marks this transaction as BIP125-replaceable.\n" + {"locktime", RPCArg::Type::NUM, /* default */ "0", "Raw locktime. Non-0 value also locktime-activates inputs"}, + {"replaceable", RPCArg::Type::BOOL, /* default */ "false", "Marks this transaction as BIP125-replaceable.\n" " Allows this transaction to be replaced by a transaction with higher fees. If provided, it is an error if explicit sequence numbers are incompatible."}, }, RPCResult{ @@ -532,8 +540,8 @@ static UniValue decoderawtransaction(const JSONRPCRequest& request) RPCHelpMan{"decoderawtransaction", "\nReturn a JSON object representing the serialized, hex-encoded transaction.\n", { - {"hexstring", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "The transaction hex string"}, - {"iswitness", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "depends on heuristic tests", "Whether the transaction hex is a serialized witness transaction\n" + {"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction hex string"}, + {"iswitness", RPCArg::Type::BOOL, /* default */ "depends on heuristic tests", "Whether the transaction hex is a serialized witness transaction\n" " If iswitness is not present, heuristic tests will be used in decoding"}, }, RPCResult{ @@ -607,7 +615,7 @@ static UniValue decodescript(const JSONRPCRequest& request) RPCHelpMan{"decodescript", "\nDecode a hex-encoded script.\n", { - {"hexstring", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "the hex-encoded script"}, + {"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "the hex-encoded script"}, }, RPCResult{ "{\n" @@ -707,9 +715,9 @@ static UniValue combinerawtransaction(const JSONRPCRequest& request) "The combined transaction may be another partially signed transaction or a \n" "fully signed transaction.", { - {"txs", RPCArg::Type::ARR, /* opt */ false, /* default_val */ "", "A json array of hex strings of partially signed transactions", + {"txs", RPCArg::Type::ARR, RPCArg::Optional::NO, "A json array of hex strings of partially signed transactions", { - {"hexstring", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "A transaction hash"}, + {"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "A transaction hash"}, }, }, }, @@ -852,15 +860,25 @@ UniValue SignTransaction(interfaces::Chain& chain, CMutableTransaction& mtx, con RPCTypeCheckObj(prevOut, { {"redeemScript", UniValueType(UniValue::VSTR)}, - }); - UniValue v = find_value(prevOut, "redeemScript"); - if (!v.isNull()) { - std::vector<unsigned char> rsData(ParseHexV(v, "redeemScript")); + {"witnessScript", UniValueType(UniValue::VSTR)}, + }, true); + UniValue rs = find_value(prevOut, "redeemScript"); + if (!rs.isNull()) { + std::vector<unsigned char> rsData(ParseHexV(rs, "redeemScript")); CScript redeemScript(rsData.begin(), rsData.end()); keystore->AddCScript(redeemScript); // Automatically also add the P2WSH wrapped version of the script (to deal with P2SH-P2WSH). + // This is only for compatibility, it is encouraged to use the explicit witnessScript field instead. keystore->AddCScript(GetScriptForWitness(redeemScript)); } + UniValue ws = find_value(prevOut, "witnessScript"); + if (!ws.isNull()) { + std::vector<unsigned char> wsData(ParseHexV(ws, "witnessScript")); + CScript witnessScript(wsData.begin(), wsData.end()); + keystore->AddCScript(witnessScript); + // Automatically also add the P2WSH wrapped version of the script (to deal with P2SH-P2WSH). + keystore->AddCScript(GetScriptForWitness(witnessScript)); + } } } } @@ -932,26 +950,27 @@ static UniValue signrawtransactionwithkey(const JSONRPCRequest& request) "The third optional argument (may be null) is an array of previous transaction outputs that\n" "this transaction depends on but may not yet be in the block chain.\n", { - {"hexstring", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The transaction hex string"}, - {"privkeys", RPCArg::Type::ARR, /* opt */ false, /* default_val */ "", "A json array of base58-encoded private keys for signing", + {"hexstring", RPCArg::Type::STR, RPCArg::Optional::NO, "The transaction hex string"}, + {"privkeys", RPCArg::Type::ARR, RPCArg::Optional::NO, "A json array of base58-encoded private keys for signing", { - {"privatekey", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "private key in base58-encoding"}, + {"privatekey", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "private key in base58-encoding"}, }, }, - {"prevtxs", RPCArg::Type::ARR, /* opt */ true, /* default_val */ "null", "A json array of previous dependent transaction outputs", + {"prevtxs", RPCArg::Type::ARR, RPCArg::Optional::OMITTED_NAMED_ARG, "A json array of previous dependent transaction outputs", { - {"", RPCArg::Type::OBJ, /* opt */ true, /* default_val */ "", "", + {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "", { - {"txid", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "The transaction id"}, - {"vout", RPCArg::Type::NUM, /* opt */ false, /* default_val */ "", "The output number"}, - {"scriptPubKey", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "script key"}, - {"redeemScript", RPCArg::Type::STR_HEX, /* opt */ true, /* default_val */ "omitted", "(required for P2SH or P2WSH) redeem script"}, - {"amount", RPCArg::Type::AMOUNT, /* opt */ false, /* default_val */ "", "The amount spent"}, + {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"}, + {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"}, + {"scriptPubKey", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "script key"}, + {"redeemScript", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "(required for P2SH) redeem script"}, + {"witnessScript", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "(required for P2WSH or P2SH-P2WSH) witness script"}, + {"amount", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "The amount spent"}, }, }, }, }, - {"sighashtype", RPCArg::Type::STR, /* opt */ true, /* default_val */ "ALL", "The signature hash type. Must be one of:\n" + {"sighashtype", RPCArg::Type::STR, /* default */ "ALL", "The signature hash type. Must be one of:\n" " \"ALL\"\n" " \"NONE\"\n" " \"SINGLE\"\n" @@ -1019,8 +1038,8 @@ static UniValue sendrawtransaction(const JSONRPCRequest& request) "\nSubmits raw transaction (serialized, hex-encoded) to local node and network.\n" "\nAlso see createrawtransaction and signrawtransactionwithkey calls.\n", { - {"hexstring", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "The hex string of the raw transaction"}, - {"allowhighfees", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "Allow high fees"}, + {"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hex string of the raw transaction"}, + {"allowhighfees", RPCArg::Type::BOOL, /* default */ "false", "Allow high fees"}, }, RPCResult{ "\"hex\" (string) The transaction hash in hex\n" @@ -1037,8 +1056,6 @@ static UniValue sendrawtransaction(const JSONRPCRequest& request) }, }.ToString()); - std::promise<void> promise; - RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL}); // parse hex string from parameter @@ -1046,67 +1063,18 @@ static UniValue sendrawtransaction(const JSONRPCRequest& request) if (!DecodeHexTx(mtx, request.params[0].get_str())) throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed"); CTransactionRef tx(MakeTransactionRef(std::move(mtx))); - const uint256& hashTx = tx->GetHash(); - CAmount nMaxRawTxFee = maxTxFee; - if (!request.params[1].isNull() && request.params[1].get_bool()) - nMaxRawTxFee = 0; - - { // cs_main scope - LOCK(cs_main); - CCoinsViewCache &view = *pcoinsTip; - bool fHaveChain = false; - for (size_t o = 0; !fHaveChain && o < tx->vout.size(); o++) { - const Coin& existingCoin = view.AccessCoin(COutPoint(hashTx, o)); - fHaveChain = !existingCoin.IsSpent(); - } - bool fHaveMempool = mempool.exists(hashTx); - if (!fHaveMempool && !fHaveChain) { - // push to local node and sync with wallets - CValidationState state; - bool fMissingInputs; - if (!AcceptToMemoryPool(mempool, state, std::move(tx), &fMissingInputs, - nullptr /* plTxnReplaced */, false /* bypass_limits */, nMaxRawTxFee)) { - if (state.IsInvalid()) { - throw JSONRPCError(RPC_TRANSACTION_REJECTED, FormatStateMessage(state)); - } else { - if (fMissingInputs) { - throw JSONRPCError(RPC_TRANSACTION_ERROR, "Missing inputs"); - } - throw JSONRPCError(RPC_TRANSACTION_ERROR, FormatStateMessage(state)); - } - } else { - // If wallet is enabled, ensure that the wallet has been made aware - // of the new transaction prior to returning. This prevents a race - // where a user might call sendrawtransaction with a transaction - // to/from their wallet, immediately call some wallet RPC, and get - // a stale result because callbacks have not yet been processed. - CallFunctionInValidationInterfaceQueue([&promise] { - promise.set_value(); - }); - } - } else if (fHaveChain) { - throw JSONRPCError(RPC_TRANSACTION_ALREADY_IN_CHAIN, "transaction already in block chain"); - } else { - // Make sure we don't block forever if re-sending - // a transaction already in mempool. - promise.set_value(); + bool allowhighfees = false; + if (!request.params[1].isNull()) allowhighfees = request.params[1].get_bool(); + const CAmount highfee{allowhighfees ? 0 : ::maxTxFee}; + uint256 txid; + std::string err_string; + const TransactionError err = BroadcastTransaction(tx, txid, err_string, highfee); + if (TransactionError::OK != err) { + throw JSONRPCTransactionError(err, err_string); } - } // cs_main - - promise.get_future().wait(); - - if(!g_connman) - throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); - - CInv inv(MSG_TX, hashTx); - g_connman->ForEachNode([&inv](CNode* pnode) - { - pnode->PushInventory(inv); - }); - - return hashTx.GetHex(); + return txid.GetHex(); } static UniValue testmempoolaccept(const JSONRPCRequest& request) @@ -1118,13 +1086,13 @@ static UniValue testmempoolaccept(const JSONRPCRequest& request) "\nThis checks if the transaction violates the consensus or policy rules.\n" "\nSee sendrawtransaction call.\n", { - {"rawtxs", RPCArg::Type::ARR, /* opt */ false, /* default_val */ "", "An array of hex strings of raw transactions.\n" + {"rawtxs", RPCArg::Type::ARR, RPCArg::Optional::NO, "An array of hex strings of raw transactions.\n" " Length must be one for now.", { - {"rawtx", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", ""}, + {"rawtx", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, ""}, }, }, - {"allowhighfees", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "Allow high fees"}, + {"allowhighfees", RPCArg::Type::BOOL, /* default */ "false", "Allow high fees"}, }, RPCResult{ "[ (array) The result of the mempool acceptance test for each raw transaction in the input array.\n" @@ -1219,7 +1187,7 @@ UniValue decodepsbt(const JSONRPCRequest& request) RPCHelpMan{"decodepsbt", "\nReturn a JSON object representing the serialized, base64-encoded partially signed Bitcoin transaction.\n", { - {"psbt", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The PSBT base64 string"}, + {"psbt", RPCArg::Type::STR, RPCArg::Optional::NO, "The PSBT base64 string"}, }, RPCResult{ "{\n" @@ -1319,7 +1287,7 @@ UniValue decodepsbt(const JSONRPCRequest& request) // Unserialize the transactions PartiallySignedTransaction psbtx; std::string error; - if (!DecodePSBT(psbtx, request.params[0].get_str(), error)) { + if (!DecodeBase64PSBT(psbtx, request.params[0].get_str(), error)) { throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("TX decode failed %s", error)); } @@ -1495,9 +1463,9 @@ UniValue combinepsbt(const JSONRPCRequest& request) "\nCombine multiple partially signed Bitcoin transactions into one transaction.\n" "Implements the Combiner role.\n", { - {"txs", RPCArg::Type::ARR, /* opt */ false, /* default_val */ "", "A json array of base64 strings of partially signed transactions", + {"txs", RPCArg::Type::ARR, RPCArg::Optional::NO, "A json array of base64 strings of partially signed transactions", { - {"psbt", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "A base64 string of a PSBT"}, + {"psbt", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "A base64 string of a PSBT"}, }, }, }, @@ -1514,26 +1482,22 @@ UniValue combinepsbt(const JSONRPCRequest& request) // Unserialize the transactions std::vector<PartiallySignedTransaction> psbtxs; UniValue txs = request.params[0].get_array(); + if (txs.empty()) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Parameter 'txs' cannot be empty"); + } for (unsigned int i = 0; i < txs.size(); ++i) { PartiallySignedTransaction psbtx; std::string error; - if (!DecodePSBT(psbtx, txs[i].get_str(), error)) { + if (!DecodeBase64PSBT(psbtx, txs[i].get_str(), error)) { throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("TX decode failed %s", error)); } psbtxs.push_back(psbtx); } - PartiallySignedTransaction merged_psbt(psbtxs[0]); // Copy the first one - - // Merge - for (auto it = std::next(psbtxs.begin()); it != psbtxs.end(); ++it) { - if (*it != merged_psbt) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "PSBTs do not refer to the same transactions."); - } - merged_psbt.Merge(*it); - } - if (!merged_psbt.IsSane()) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Merged PSBT is inconsistent"); + PartiallySignedTransaction merged_psbt; + const TransactionError error = CombinePSBTs(merged_psbt, psbtxs); + if (error != TransactionError::OK) { + throw JSONRPCTransactionError(error); } UniValue result(UniValue::VOBJ); @@ -1552,8 +1516,8 @@ UniValue finalizepsbt(const JSONRPCRequest& request) "created which has the final_scriptSig and final_scriptWitness fields filled for inputs that are complete.\n" "Implements the Finalizer and Extractor roles.\n", { - {"psbt", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "A base64 string of a PSBT"}, - {"extract", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "true", "If true and the transaction is complete,\n" + {"psbt", RPCArg::Type::STR, RPCArg::Optional::NO, "A base64 string of a PSBT"}, + {"extract", RPCArg::Type::BOOL, /* default */ "true", "If true and the transaction is complete,\n" " extract and return the complete transaction in normal network serialization instead of the PSBT."}, }, RPCResult{ @@ -1574,33 +1538,27 @@ UniValue finalizepsbt(const JSONRPCRequest& request) // Unserialize the transactions PartiallySignedTransaction psbtx; std::string error; - if (!DecodePSBT(psbtx, request.params[0].get_str(), error)) { + if (!DecodeBase64PSBT(psbtx, request.params[0].get_str(), error)) { throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("TX decode failed %s", error)); } - // Finalize input signatures -- in case we have partial signatures that add up to a complete - // signature, but have not combined them yet (e.g. because the combiner that created this - // PartiallySignedTransaction did not understand them), this will combine them into a final - // script. - bool complete = true; - for (unsigned int i = 0; i < psbtx.tx->vin.size(); ++i) { - complete &= SignPSBTInput(DUMMY_SIGNING_PROVIDER, psbtx, i, SIGHASH_ALL); - } + bool extract = request.params[1].isNull() || (!request.params[1].isNull() && request.params[1].get_bool()); + + CMutableTransaction mtx; + bool complete = FinalizeAndExtractPSBT(psbtx, mtx); UniValue result(UniValue::VOBJ); CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); - bool extract = request.params[1].isNull() || (!request.params[1].isNull() && request.params[1].get_bool()); + std::string result_str; + if (complete && extract) { - CMutableTransaction mtx(*psbtx.tx); - for (unsigned int i = 0; i < mtx.vin.size(); ++i) { - mtx.vin[i].scriptSig = psbtx.inputs[i].final_script_sig; - mtx.vin[i].scriptWitness = psbtx.inputs[i].final_script_witness; - } ssTx << mtx; - result.pushKV("hex", HexStr(ssTx.str())); + result_str = HexStr(ssTx.str()); + result.pushKV("hex", result_str); } else { ssTx << psbtx; - result.pushKV("psbt", EncodeBase64(ssTx.str())); + result_str = EncodeBase64(ssTx.str()); + result.pushKV("psbt", result_str); } result.pushKV("complete", complete); @@ -1615,36 +1573,36 @@ UniValue createpsbt(const JSONRPCRequest& request) "\nCreates a transaction in the Partially Signed Transaction format.\n" "Implements the Creator role.\n", { - {"inputs", RPCArg::Type::ARR, /* opt */ false, /* default_val */ "", "A json array of json objects", + {"inputs", RPCArg::Type::ARR, RPCArg::Optional::NO, "A json array of json objects", { - {"", RPCArg::Type::OBJ, /* opt */ false, /* default_val */ "", "", + {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "", { - {"txid", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "The transaction id"}, - {"vout", RPCArg::Type::NUM, /* opt */ false, /* default_val */ "", "The output number"}, - {"sequence", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "depends on the value of the 'replaceable' and 'locktime' arguments", "The sequence number"}, + {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"}, + {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"}, + {"sequence", RPCArg::Type::NUM, /* default */ "depends on the value of the 'replaceable' and 'locktime' arguments", "The sequence number"}, }, }, }, }, - {"outputs", RPCArg::Type::ARR, /* opt */ false, /* default_val */ "", "a json array with outputs (key-value pairs), where none of the keys are duplicated.\n" + {"outputs", RPCArg::Type::ARR, RPCArg::Optional::NO, "a json array with outputs (key-value pairs), where none of the keys are duplicated.\n" "That is, each address can only appear once and there can only be one 'data' object.\n" "For compatibility reasons, a dictionary, which holds the key-value pairs directly, is also\n" " accepted as second parameter.", { - {"", RPCArg::Type::OBJ, /* opt */ true, /* default_val */ "", "", + {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "", { - {"address", RPCArg::Type::AMOUNT, /* opt */ false, /* default_val */ "", "A key-value pair. The key (string) is the bitcoin address, the value (float or string) is the amount in " + CURRENCY_UNIT}, + {"address", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "A key-value pair. The key (string) is the bitcoin address, the value (float or string) is the amount in " + CURRENCY_UNIT}, }, }, - {"", RPCArg::Type::OBJ, /* opt */ true, /* default_val */ "", "", + {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "", { - {"data", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "A key-value pair. The key must be \"data\", the value is hex-encoded data"}, + {"data", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "A key-value pair. The key must be \"data\", the value is hex-encoded data"}, }, }, }, }, - {"locktime", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "0", "Raw locktime. Non-0 value also locktime-activates inputs"}, - {"replaceable", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "Marks this transaction as BIP125 replaceable.\n" + {"locktime", RPCArg::Type::NUM, /* default */ "0", "Raw locktime. Non-0 value also locktime-activates inputs"}, + {"replaceable", RPCArg::Type::BOOL, /* default */ "false", "Marks this transaction as BIP125 replaceable.\n" " Allows this transaction to be replaced by a transaction with higher fees. If provided, it is an error if explicit sequence numbers are incompatible."}, }, RPCResult{ @@ -1691,10 +1649,10 @@ UniValue converttopsbt(const JSONRPCRequest& request) "\nConverts a network serialized transaction to a PSBT. This should be used only with createrawtransaction and fundrawtransaction\n" "createpsbt and walletcreatefundedpsbt should be used for new applications.\n", { - {"hexstring", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "The hex string of a raw transaction"}, - {"permitsigdata", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "If true, any signatures in the input will be discarded and conversion.\n" + {"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hex string of a raw transaction"}, + {"permitsigdata", RPCArg::Type::BOOL, /* default */ "false", "If true, any signatures in the input will be discarded and conversion.\n" " will continue. If false, RPC will fail if any signatures are present."}, - {"iswitness", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "depends on heuristic tests", "Whether the transaction hex is a serialized witness transaction.\n" + {"iswitness", RPCArg::Type::BOOL, /* default */ "depends on heuristic tests", "Whether the transaction hex is a serialized witness transaction.\n" " If iswitness is not present, heuristic tests will be used in decoding. If true, only witness deserializaion\n" " will be tried. If false, only non-witness deserialization will be tried. Only has an effect if\n" " permitsigdata is true."}, @@ -1750,6 +1708,338 @@ UniValue converttopsbt(const JSONRPCRequest& request) return EncodeBase64((unsigned char*)ssTx.data(), ssTx.size()); } +UniValue utxoupdatepsbt(const JSONRPCRequest& request) +{ + if (request.fHelp || request.params.size() != 1) { + throw std::runtime_error( + RPCHelpMan{"utxoupdatepsbt", + "\nUpdates a PSBT with witness UTXOs retrieved from the UTXO set or the mempool.\n", + { + {"psbt", RPCArg::Type::STR, RPCArg::Optional::NO, "A base64 string of a PSBT"} + }, + RPCResult { + " \"psbt\" (string) The base64-encoded partially signed transaction with inputs updated\n" + }, + RPCExamples { + HelpExampleCli("utxoupdatepsbt", "\"psbt\"") + }}.ToString()); + } + + RPCTypeCheck(request.params, {UniValue::VSTR}, true); + + // Unserialize the transactions + PartiallySignedTransaction psbtx; + std::string error; + if (!DecodeBase64PSBT(psbtx, request.params[0].get_str(), error)) { + throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("TX decode failed %s", error)); + } + + // Fetch previous transactions (inputs): + CCoinsView viewDummy; + CCoinsViewCache view(&viewDummy); + { + LOCK2(cs_main, mempool.cs); + CCoinsViewCache &viewChain = *pcoinsTip; + CCoinsViewMemPool viewMempool(&viewChain, mempool); + view.SetBackend(viewMempool); // temporarily switch cache backend to db+mempool view + + for (const CTxIn& txin : psbtx.tx->vin) { + view.AccessCoin(txin.prevout); // Load entries from viewChain into view; can fail. + } + + view.SetBackend(viewDummy); // switch back to avoid locking mempool for too long + } + + // Fill the inputs + for (unsigned int i = 0; i < psbtx.tx->vin.size(); ++i) { + PSBTInput& input = psbtx.inputs.at(i); + + if (input.non_witness_utxo || !input.witness_utxo.IsNull()) { + continue; + } + + const Coin& coin = view.AccessCoin(psbtx.tx->vin[i].prevout); + + std::vector<std::vector<unsigned char>> solutions_data; + txnouttype which_type = Solver(coin.out.scriptPubKey, solutions_data); + if (which_type == TX_WITNESS_V0_SCRIPTHASH || which_type == TX_WITNESS_V0_KEYHASH || which_type == TX_WITNESS_UNKNOWN) { + input.witness_utxo = coin.out; + } + } + + CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); + ssTx << psbtx; + return EncodeBase64((unsigned char*)ssTx.data(), ssTx.size()); +} + +UniValue joinpsbts(const JSONRPCRequest& request) +{ + if (request.fHelp || request.params.size() != 1) { + throw std::runtime_error( + RPCHelpMan{"joinpsbts", + "\nJoins multiple distinct PSBTs with different inputs and outputs into one PSBT with inputs and outputs from all of the PSBTs\n" + "No input in any of the PSBTs can be in more than one of the PSBTs.\n", + { + {"txs", RPCArg::Type::ARR, RPCArg::Optional::NO, "A json array of base64 strings of partially signed transactions", + { + {"psbt", RPCArg::Type::STR, RPCArg::Optional::NO, "A base64 string of a PSBT"} + }} + }, + RPCResult { + " \"psbt\" (string) The base64-encoded partially signed transaction\n" + }, + RPCExamples { + HelpExampleCli("joinpsbts", "\"psbt\"") + }}.ToString()); + } + + RPCTypeCheck(request.params, {UniValue::VARR}, true); + + // Unserialize the transactions + std::vector<PartiallySignedTransaction> psbtxs; + UniValue txs = request.params[0].get_array(); + + if (txs.size() <= 1) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "At least two PSBTs are required to join PSBTs."); + } + + int32_t best_version = 1; + uint32_t best_locktime = 0xffffffff; + for (unsigned int i = 0; i < txs.size(); ++i) { + PartiallySignedTransaction psbtx; + std::string error; + if (!DecodeBase64PSBT(psbtx, txs[i].get_str(), error)) { + throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("TX decode failed %s", error)); + } + psbtxs.push_back(psbtx); + // Choose the highest version number + if (psbtx.tx->nVersion > best_version) { + best_version = psbtx.tx->nVersion; + } + // Choose the lowest lock time + if (psbtx.tx->nLockTime < best_locktime) { + best_locktime = psbtx.tx->nLockTime; + } + } + + // Create a blank psbt where everything will be added + PartiallySignedTransaction merged_psbt; + merged_psbt.tx = CMutableTransaction(); + merged_psbt.tx->nVersion = best_version; + merged_psbt.tx->nLockTime = best_locktime; + + // Merge + for (auto& psbt : psbtxs) { + for (unsigned int i = 0; i < psbt.tx->vin.size(); ++i) { + if (!merged_psbt.AddInput(psbt.tx->vin[i], psbt.inputs[i])) { + throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Input %s:%d exists in multiple PSBTs", psbt.tx->vin[i].prevout.hash.ToString().c_str(), psbt.tx->vin[i].prevout.n)); + } + } + for (unsigned int i = 0; i < psbt.tx->vout.size(); ++i) { + merged_psbt.AddOutput(psbt.tx->vout[i], psbt.outputs[i]); + } + merged_psbt.unknown.insert(psbt.unknown.begin(), psbt.unknown.end()); + } + + CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); + ssTx << merged_psbt; + return EncodeBase64((unsigned char*)ssTx.data(), ssTx.size()); +} + +UniValue analyzepsbt(const JSONRPCRequest& request) +{ + if (request.fHelp || request.params.size() != 1) { + throw std::runtime_error( + RPCHelpMan{"analyzepsbt", + "\nAnalyzes and provides information about the current status of a PSBT and its inputs\n", + { + {"psbt", RPCArg::Type::STR, RPCArg::Optional::NO, "A base64 string of a PSBT"} + }, + RPCResult { + "{\n" + " \"inputs\" : [ (array of json objects)\n" + " {\n" + " \"has_utxo\" : true|false (boolean) Whether a UTXO is provided\n" + " \"is_final\" : true|false (boolean) Whether the input is finalized\n" + " \"missing\" : { (json object, optional) Things that are missing that are required to complete this input\n" + " \"pubkeys\" : [ (array)\n" + " \"keyid\" (string) Public key ID, hash160 of the public key, of a public key whose BIP 32 derivation path is missing\n" + " ]\n" + " \"signatures\" : [ (array)\n" + " \"keyid\" (string) Public key ID, hash160 of the public key, of a public key whose signature is missing\n" + " ]\n" + " \"redeemscript\" : \"hash\" (string) Hash160 of the redeemScript that is missing\n" + " \"witnessscript\" : \"hash\" (string) SHA256 of the witnessScript that is missing\n" + " }\n" + " \"next\" : \"role\" (string) Role of the next person that this input needs to go to\n" + " }\n" + " ,...\n" + " ]\n" + " \"estimated_vsize\" : vsize (numeric) Estimated vsize of the final signed transaction\n" + " \"estimated_feerate\" : feerate (numeric, optional) Estimated feerate of the final signed transaction. Shown only if all UTXO slots in the PSBT have been filled.\n" + " \"fee\" : fee (numeric, optional) The transaction fee paid. Shown only if all UTXO slots in the PSBT have been filled.\n" + " \"next\" : \"role\" (string) Role of the next person that this psbt needs to go to\n" + "}\n" + }, + RPCExamples { + HelpExampleCli("analyzepsbt", "\"psbt\"") + }}.ToString()); + } + + RPCTypeCheck(request.params, {UniValue::VSTR}); + + // Unserialize the transaction + PartiallySignedTransaction psbtx; + std::string error; + if (!DecodeBase64PSBT(psbtx, request.params[0].get_str(), error)) { + throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("TX decode failed %s", error)); + } + + // Go through each input and build status + UniValue result(UniValue::VOBJ); + UniValue inputs_result(UniValue::VARR); + bool calc_fee = true; + bool all_final = true; + bool only_missing_sigs = true; + bool only_missing_final = false; + CAmount in_amt = 0; + for (unsigned int i = 0; i < psbtx.tx->vin.size(); ++i) { + PSBTInput& input = psbtx.inputs[i]; + UniValue input_univ(UniValue::VOBJ); + UniValue missing(UniValue::VOBJ); + + // Check for a UTXO + CTxOut utxo; + if (psbtx.GetInputUTXO(utxo, i)) { + in_amt += utxo.nValue; + input_univ.pushKV("has_utxo", true); + } else { + input_univ.pushKV("has_utxo", false); + input_univ.pushKV("is_final", false); + input_univ.pushKV("next", "updater"); + calc_fee = false; + } + + // Check if it is final + if (!utxo.IsNull() && !PSBTInputSigned(input)) { + input_univ.pushKV("is_final", false); + all_final = false; + + // Figure out what is missing + SignatureData outdata; + bool complete = SignPSBTInput(DUMMY_SIGNING_PROVIDER, psbtx, i, 1, &outdata); + + // Things are missing + if (!complete) { + if (!outdata.missing_pubkeys.empty()) { + // Missing pubkeys + UniValue missing_pubkeys_univ(UniValue::VARR); + for (const CKeyID& pubkey : outdata.missing_pubkeys) { + missing_pubkeys_univ.push_back(HexStr(pubkey)); + } + missing.pushKV("pubkeys", missing_pubkeys_univ); + } + if (!outdata.missing_redeem_script.IsNull()) { + // Missing redeemScript + missing.pushKV("redeemscript", HexStr(outdata.missing_redeem_script)); + } + if (!outdata.missing_witness_script.IsNull()) { + // Missing witnessScript + missing.pushKV("witnessscript", HexStr(outdata.missing_witness_script)); + } + if (!outdata.missing_sigs.empty()) { + // Missing sigs + UniValue missing_sigs_univ(UniValue::VARR); + for (const CKeyID& pubkey : outdata.missing_sigs) { + missing_sigs_univ.push_back(HexStr(pubkey)); + } + missing.pushKV("signatures", missing_sigs_univ); + } + input_univ.pushKV("missing", missing); + + // If we are only missing signatures and nothing else, then next is signer + if (outdata.missing_pubkeys.empty() && outdata.missing_redeem_script.IsNull() && outdata.missing_witness_script.IsNull() && !outdata.missing_sigs.empty()) { + input_univ.pushKV("next", "signer"); + } else { + only_missing_sigs = false; + input_univ.pushKV("next", "updater"); + } + } else { + only_missing_final = true; + input_univ.pushKV("next", "finalizer"); + } + } else if (!utxo.IsNull()){ + input_univ.pushKV("is_final", true); + } + inputs_result.push_back(input_univ); + } + result.pushKV("inputs", inputs_result); + + if (all_final) { + only_missing_sigs = false; + result.pushKV("next", "extractor"); + } + if (calc_fee) { + // Get the output amount + CAmount out_amt = std::accumulate(psbtx.tx->vout.begin(), psbtx.tx->vout.end(), 0, + [](int a, const CTxOut& b) { + return a += b.nValue; + } + ); + + // Get the fee + CAmount fee = in_amt - out_amt; + + // Estimate the size + CMutableTransaction mtx(*psbtx.tx); + CCoinsView view_dummy; + CCoinsViewCache view(&view_dummy); + bool success = true; + + for (unsigned int i = 0; i < psbtx.tx->vin.size(); ++i) { + PSBTInput& input = psbtx.inputs[i]; + if (SignPSBTInput(DUMMY_SIGNING_PROVIDER, psbtx, i, 1, nullptr, true)) { + mtx.vin[i].scriptSig = input.final_script_sig; + mtx.vin[i].scriptWitness = input.final_script_witness; + + Coin newcoin; + if (!psbtx.GetInputUTXO(newcoin.out, i)) { + success = false; + break; + } + newcoin.nHeight = 1; + view.AddCoin(psbtx.tx->vin[i].prevout, std::move(newcoin), true); + } else { + success = false; + break; + } + } + + if (success) { + CTransaction ctx = CTransaction(mtx); + size_t size = GetVirtualTransactionSize(ctx, GetTransactionSigOpCost(ctx, view, STANDARD_SCRIPT_VERIFY_FLAGS)); + result.pushKV("estimated_vsize", (int)size); + // Estimate fee rate + CFeeRate feerate(fee, size); + result.pushKV("estimated_feerate", feerate.ToString()); + } + result.pushKV("fee", ValueFromAmount(fee)); + + if (only_missing_sigs) { + result.pushKV("next", "signer"); + } else if (only_missing_final) { + result.pushKV("next", "finalizer"); + } else if (all_final) { + result.pushKV("next", "extractor"); + } else { + result.pushKV("next", "updater"); + } + } else { + result.pushKV("next", "updater"); + } + return result; +} + // clang-format off static const CRPCCommand commands[] = { // category name actor (function) argNames @@ -1768,6 +2058,9 @@ static const CRPCCommand commands[] = { "rawtransactions", "finalizepsbt", &finalizepsbt, {"psbt", "extract"} }, { "rawtransactions", "createpsbt", &createpsbt, {"inputs","outputs","locktime","replaceable"} }, { "rawtransactions", "converttopsbt", &converttopsbt, {"hexstring","permitsigdata","iswitness"} }, + { "rawtransactions", "utxoupdatepsbt", &utxoupdatepsbt, {"psbt"} }, + { "rawtransactions", "joinpsbts", &joinpsbts, {"txs"} }, + { "rawtransactions", "analyzepsbt", &analyzepsbt, {"psbt"} }, { "blockchain", "gettxoutproof", &gettxoutproof, {"txids", "blockhash"} }, { "blockchain", "verifytxoutproof", &verifytxoutproof, {"proof"} }, diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index 2ed74547b9..cd90573da0 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -230,7 +230,7 @@ UniValue help(const JSONRPCRequest& jsonRequest) RPCHelpMan{"help", "\nList all commands, or get help for a specified command.\n", { - {"command", RPCArg::Type::STR, /* opt */ true, /* default_val */ "all commands", "The command to get help on"}, + {"command", RPCArg::Type::STR, /* default */ "all commands", "The command to get help on"}, }, RPCResult{ "\"text\" (string) The help text\n" diff --git a/src/rpc/util.cpp b/src/rpc/util.cpp index 4275cc09a8..40ac133186 100644 --- a/src/rpc/util.cpp +++ b/src/rpc/util.cpp @@ -1,13 +1,14 @@ -// Copyright (c) 2017-2018 The Bitcoin Core developers +// Copyright (c) 2017-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include <key_io.h> #include <keystore.h> -#include <rpc/protocol.h> +#include <policy/fees.h> #include <rpc/util.h> #include <tinyformat.h> #include <util/strencodings.h> +#include <validation.h> InitInterfaces* g_rpc_interfaces = nullptr; @@ -129,6 +130,44 @@ UniValue DescribeAddress(const CTxDestination& dest) return boost::apply_visitor(DescribeAddressVisitor(), dest); } +unsigned int ParseConfirmTarget(const UniValue& value) +{ + int target = value.get_int(); + unsigned int max_target = ::feeEstimator.HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE); + if (target < 1 || (unsigned int)target > max_target) { + throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid conf_target, must be between %u - %u", 1, max_target)); + } + return (unsigned int)target; +} + +RPCErrorCode RPCErrorFromTransactionError(TransactionError terr) +{ + switch (terr) { + case TransactionError::MEMPOOL_REJECTED: + return RPC_TRANSACTION_REJECTED; + case TransactionError::ALREADY_IN_CHAIN: + return RPC_TRANSACTION_ALREADY_IN_CHAIN; + case TransactionError::P2P_DISABLED: + return RPC_CLIENT_P2P_DISABLED; + case TransactionError::INVALID_PSBT: + case TransactionError::PSBT_MISMATCH: + return RPC_INVALID_PARAMETER; + case TransactionError::SIGHASH_MISMATCH: + return RPC_DESERIALIZATION_ERROR; + default: break; + } + return RPC_TRANSACTION_ERROR; +} + +UniValue JSONRPCTransactionError(TransactionError terr, const std::string& err_string) +{ + if (err_string.length() > 0) { + return JSONRPCError(RPCErrorFromTransactionError(terr), err_string); + } else { + return JSONRPCError(RPCErrorFromTransactionError(terr), TransactionErrorString(terr)); + } +} + struct Section { Section(const std::string& left, const std::string& right) : m_left{left}, m_right{right} {} @@ -161,6 +200,7 @@ struct Sections { case RPCArg::Type::STR: case RPCArg::Type::NUM: case RPCArg::Type::AMOUNT: + case RPCArg::Type::RANGE: case RPCArg::Type::BOOL: { if (outer_type == OuterType::NAMED_ARG) return; // Nothing more to do for non-recursive types on first recursion auto left = indent; @@ -170,12 +210,12 @@ struct Sections { left += outer_type == OuterType::OBJ ? arg.ToStringObj(/* oneline */ false) : arg.ToString(/* oneline */ false); } left += ","; - PushSection({left, arg.ToDescriptionString(/* implicitly_required */ outer_type == OuterType::ARR)}); + PushSection({left, arg.ToDescriptionString()}); break; } case RPCArg::Type::OBJ: case RPCArg::Type::OBJ_USER_KEYS: { - const auto right = outer_type == OuterType::NAMED_ARG ? "" : arg.ToDescriptionString(/* implicitly_required */ outer_type == OuterType::ARR); + const auto right = outer_type == OuterType::NAMED_ARG ? "" : arg.ToDescriptionString(); PushSection({indent + "{", right}); for (const auto& arg_inner : arg.m_inner) { Push(arg_inner, current_indent + 2, OuterType::OBJ); @@ -190,7 +230,7 @@ struct Sections { auto left = indent; left += outer_type == OuterType::OBJ ? "\"" + arg.m_name + "\": " : ""; left += "["; - const auto right = outer_type == OuterType::NAMED_ARG ? "" : arg.ToDescriptionString(/* implicitly_required */ outer_type == OuterType::ARR); + const auto right = outer_type == OuterType::NAMED_ARG ? "" : arg.ToDescriptionString(); PushSection({left, right}); for (const auto& arg_inner : arg.m_inner) { Push(arg_inner, current_indent + 2, OuterType::ARR); @@ -275,6 +315,17 @@ std::string RPCExamples::ToDescriptionString() const return m_examples.empty() ? m_examples : "\nExamples:\n" + m_examples; } +bool RPCHelpMan::IsValidNumArgs(size_t num_args) const +{ + size_t num_required_args = 0; + for (size_t n = m_args.size(); n > 0; --n) { + if (!m_args.at(n - 1).IsOptional()) { + num_required_args = n; + break; + } + } + return num_required_args <= num_args && num_args <= m_args.size(); +} std::string RPCHelpMan::ToString() const { std::string ret; @@ -283,8 +334,9 @@ std::string RPCHelpMan::ToString() const ret += m_name; bool was_optional{false}; for (const auto& arg : m_args) { + const bool optional = arg.IsOptional(); ret += " "; - if (arg.m_optional) { + if (optional) { if (!was_optional) ret += "( "; was_optional = true; } else { @@ -324,7 +376,16 @@ std::string RPCHelpMan::ToString() const return ret; } -std::string RPCArg::ToDescriptionString(const bool implicitly_required) const +bool RPCArg::IsOptional() const +{ + if (m_fallback.which() == 1) { + return true; + } else { + return RPCArg::Optional::NO != boost::get<RPCArg::Optional>(m_fallback); + } +} + +std::string RPCArg::ToDescriptionString() const { std::string ret; ret += "("; @@ -345,6 +406,10 @@ std::string RPCArg::ToDescriptionString(const bool implicitly_required) const ret += "numeric or string"; break; } + case Type::RANGE: { + ret += "numeric or array"; + break; + } case Type::BOOL: { ret += "boolean"; break; @@ -362,19 +427,24 @@ std::string RPCArg::ToDescriptionString(const bool implicitly_required) const // no default case, so the compiler can warn about missing cases } } - if (!implicitly_required) { - ret += ", "; - if (m_optional) { - ret += "optional"; - if (!m_default_value.empty()) { - ret += ", default=" + m_default_value; - } else { - // TODO enable this assert, when all optional parameters have their default value documented - //assert(false); - } - } else { - ret += "required"; - assert(m_default_value.empty()); // Default value is ignored, and must not be present + if (m_fallback.which() == 1) { + ret += ", optional, default=" + boost::get<std::string>(m_fallback); + } else { + switch (boost::get<RPCArg::Optional>(m_fallback)) { + case RPCArg::Optional::OMITTED: { + // nothing to do. Element is treated as if not present and has no default value + break; + } + case RPCArg::Optional::OMITTED_NAMED_ARG: { + ret += ", optional"; // Default value is "null" + break; + } + case RPCArg::Optional::NO: { + ret += ", required"; + break; + } + + // no default case, so the compiler can warn about missing cases } } ret += ")"; @@ -399,6 +469,8 @@ std::string RPCArg::ToStringObj(const bool oneline) const return res + "\"hex\""; case Type::NUM: return res + "n"; + case Type::RANGE: + return res + "n or [n,n]"; case Type::AMOUNT: return res + "amount"; case Type::BOOL: @@ -429,6 +501,7 @@ std::string RPCArg::ToString(const bool oneline) const return "\"" + m_name + "\""; } case Type::NUM: + case Type::RANGE: case Type::AMOUNT: case Type::BOOL: { return m_name; @@ -458,3 +531,17 @@ std::string RPCArg::ToString(const bool oneline) const } assert(false); } + +std::pair<int64_t, int64_t> ParseRange(const UniValue& value) +{ + if (value.isNum()) { + return {0, value.get_int64()}; + } + if (value.isArray() && value.size() == 2 && value[0].isNum() && value[1].isNum()) { + int64_t low = value[0].get_int64(); + int64_t high = value[1].get_int64(); + if (low > high) throw JSONRPCError(RPC_INVALID_PARAMETER, "Range specified as [begin,end] must not have begin after end"); + return {low, high}; + } + throw JSONRPCError(RPC_INVALID_PARAMETER, "Range must be specified as end or as [begin,end]"); +} diff --git a/src/rpc/util.h b/src/rpc/util.h index 4a9d4be787..f1bd2c89df 100644 --- a/src/rpc/util.h +++ b/src/rpc/util.h @@ -1,17 +1,21 @@ -// Copyright (c) 2017-2018 The Bitcoin Core developers +// Copyright (c) 2017-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_RPC_UTIL_H #define BITCOIN_RPC_UTIL_H +#include <node/transaction.h> #include <pubkey.h> +#include <rpc/protocol.h> #include <script/standard.h> #include <univalue.h> #include <string> #include <vector> +#include <boost/variant.hpp> + class CKeyStore; class CPubKey; class CScript; @@ -28,6 +32,15 @@ CScript CreateMultisigRedeemscript(const int required, const std::vector<CPubKey UniValue DescribeAddress(const CTxDestination& dest); +//! Parse a confirm target option and raise an RPC error if it is invalid. +unsigned int ParseConfirmTarget(const UniValue& value); + +RPCErrorCode RPCErrorFromTransactionError(TransactionError terr); +UniValue JSONRPCTransactionError(TransactionError terr, const std::string& err_string = ""); + +//! Parse a JSON range specified as int64, or [int64, int64] +std::pair<int64_t, int64_t> ParseRange(const UniValue& value); + struct RPCArg { enum class Type { OBJ, @@ -38,12 +51,30 @@ struct RPCArg { OBJ_USER_KEYS, //!< Special type where the user must set the keys e.g. to define multiple addresses; as opposed to e.g. an options object where the keys are predefined AMOUNT, //!< Special type representing a floating point amount (can be either NUM or STR) STR_HEX, //!< Special type that is a STR with only hex chars + RANGE, //!< Special type that is a NUM or [NUM,NUM] }; + + enum class Optional { + /** Required arg */ + NO, + /** + * Optional arg that is a named argument and has a default value of + * `null`. When possible, the default value should be specified. + */ + OMITTED_NAMED_ARG, + /** + * Optional argument with default value omitted because they are + * implicitly clear. That is, elements in an array or object may not + * exist by default. + * When possible, the default value should be specified. + */ + OMITTED, + }; + using Fallback = boost::variant<Optional, /* default value for optional args */ std::string>; const std::string m_name; //!< The name of the arg (can be empty for inner args) const Type m_type; const std::vector<RPCArg> m_inner; //!< Only used for arrays or dicts - const bool m_optional; - const std::string m_default_value; //!< Only used for optional args + const Fallback m_fallback; const std::string m_description; const std::string m_oneline_description; //!< Should be empty unless it is supposed to override the auto-generated summary line const std::vector<std::string> m_type_str; //!< Should be empty unless it is supposed to override the auto-generated type strings. Vector length is either 0 or 2, m_type_str.at(0) will override the type of the value in a key-value pair, m_type_str.at(1) will override the type in the argument description. @@ -51,15 +82,13 @@ struct RPCArg { RPCArg( const std::string& name, const Type& type, - const bool opt, - const std::string& default_val, + const Fallback& fallback, const std::string& description, const std::string& oneline_description = "", const std::vector<std::string>& type_str = {}) : m_name{name}, m_type{type}, - m_optional{opt}, - m_default_value{default_val}, + m_fallback{fallback}, m_description{description}, m_oneline_description{oneline_description}, m_type_str{type_str} @@ -70,8 +99,7 @@ struct RPCArg { RPCArg( const std::string& name, const Type& type, - const bool opt, - const std::string& default_val, + const Fallback& fallback, const std::string& description, const std::vector<RPCArg>& inner, const std::string& oneline_description = "", @@ -79,8 +107,7 @@ struct RPCArg { : m_name{name}, m_type{type}, m_inner{inner}, - m_optional{opt}, - m_default_value{default_val}, + m_fallback{fallback}, m_description{description}, m_oneline_description{oneline_description}, m_type_str{type_str} @@ -88,6 +115,8 @@ struct RPCArg { assert(type == Type::ARR || type == Type::OBJ); } + bool IsOptional() const; + /** * Return the type string of the argument. * Set oneline to allow it to be overridden by a custom oneline type string (m_oneline_description). @@ -101,9 +130,8 @@ struct RPCArg { /** * Return the description string, including the argument type and whether * the argument is required. - * implicitly_required is set for arguments in an array, which are neither optional nor required. */ - std::string ToDescriptionString(bool implicitly_required = false) const; + std::string ToDescriptionString() const; }; struct RPCResult { @@ -164,6 +192,8 @@ public: RPCHelpMan(std::string name, std::string description, std::vector<RPCArg> args, RPCResults results, RPCExamples examples); std::string ToString() const; + /** If the supplied number of args is neither too small nor too high */ + bool IsValidNumArgs(size_t num_args) const; private: const std::string m_name; diff --git a/src/scheduler.h b/src/scheduler.h index 6d7f42cf9f..436f661c59 100644 --- a/src/scheduler.h +++ b/src/scheduler.h @@ -45,13 +45,13 @@ public: // Call func at/after time t void schedule(Function f, boost::chrono::system_clock::time_point t=boost::chrono::system_clock::now()); - // Convenience method: call f once deltaSeconds from now + // Convenience method: call f once deltaMilliSeconds from now void scheduleFromNow(Function f, int64_t deltaMilliSeconds); // Another convenience method: call f approximately - // every deltaSeconds forever, starting deltaSeconds from now. + // every deltaMilliSeconds forever, starting deltaMilliSeconds from now. // To be more precise: every time f is finished, it - // is rescheduled to run deltaSeconds later. If you + // is rescheduled to run deltaMilliSeconds later. If you // need more accurate scheduling, don't use this method. void scheduleEvery(Function f, int64_t deltaMilliSeconds); diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp index a702be5b78..43448d7222 100644 --- a/src/script/descriptor.cpp +++ b/src/script/descriptor.cpp @@ -10,6 +10,7 @@ #include <script/standard.h> #include <span.h> +#include <util/bip32.h> #include <util/system.h> #include <util/strencodings.h> @@ -20,21 +21,130 @@ namespace { //////////////////////////////////////////////////////////////////////////// -// Internal representation // +// Checksum // //////////////////////////////////////////////////////////////////////////// -typedef std::vector<uint32_t> KeyPath; +// This section implements a checksum algorithm for descriptors with the +// following properties: +// * Mistakes in a descriptor string are measured in "symbol errors". The higher +// the number of symbol errors, the harder it is to detect: +// * An error substituting a character from 0123456789()[],'/*abcdefgh@:$%{} for +// another in that set always counts as 1 symbol error. +// * Note that hex encoded keys are covered by these characters. Xprvs and +// xpubs use other characters too, but already have their own checksum +// mechanism. +// * Function names like "multi()" use other characters, but mistakes in +// these would generally result in an unparseable descriptor. +// * A case error always counts as 1 symbol error. +// * Any other 1 character substitution error counts as 1 or 2 symbol errors. +// * Any 1 symbol error is always detected. +// * Any 2 or 3 symbol error in a descriptor of up to 49154 characters is always detected. +// * Any 4 symbol error in a descriptor of up to 507 characters is always detected. +// * Any 5 symbol error in a descriptor of up to 77 characters is always detected. +// * Is optimized to minimize the chance a 5 symbol error in a descriptor up to 387 characters is undetected +// * Random errors have a chance of 1 in 2**40 of being undetected. +// +// These properties are achieved by expanding every group of 3 (non checksum) characters into +// 4 GF(32) symbols, over which a cyclic code is defined. + +/* + * Interprets c as 8 groups of 5 bits which are the coefficients of a degree 8 polynomial over GF(32), + * multiplies that polynomial by x, computes its remainder modulo a generator, and adds the constant term val. + * + * This generator is G(x) = x^8 + {30}x^7 + {23}x^6 + {15}x^5 + {14}x^4 + {10}x^3 + {6}x^2 + {12}x + {9}. + * It is chosen to define an cyclic error detecting code which is selected by: + * - Starting from all BCH codes over GF(32) of degree 8 and below, which by construction guarantee detecting + * 3 errors in windows up to 19000 symbols. + * - Taking all those generators, and for degree 7 ones, extend them to degree 8 by adding all degree-1 factors. + * - Selecting just the set of generators that guarantee detecting 4 errors in a window of length 512. + * - Selecting one of those with best worst-case behavior for 5 errors in windows of length up to 512. + * + * The generator and the constants to implement it can be verified using this Sage code: + * B = GF(2) # Binary field + * BP.<b> = B[] # Polynomials over the binary field + * F_mod = b**5 + b**3 + 1 + * F.<f> = GF(32, modulus=F_mod, repr='int') # GF(32) definition + * FP.<x> = F[] # Polynomials over GF(32) + * E_mod = x**3 + x + F.fetch_int(8) + * E.<e> = F.extension(E_mod) # Extension field definition + * alpha = e**2743 # Choice of an element in extension field + * for p in divisors(E.order() - 1): # Verify alpha has order 32767. + * assert((alpha**p == 1) == (p % 32767 == 0)) + * G = lcm([(alpha**i).minpoly() for i in [1056,1057,1058]] + [x + 1]) + * print(G) # Print out the generator + * for i in [1,2,4,8,16]: # Print out {1,2,4,8,16}*(G mod x^8), packed in hex integers. + * v = 0 + * for coef in reversed((F.fetch_int(i)*(G % x**8)).coefficients(sparse=True)): + * v = v*32 + coef.integer_representation() + * print("0x%x" % v) + */ +uint64_t PolyMod(uint64_t c, int val) +{ + uint8_t c0 = c >> 35; + c = ((c & 0x7ffffffff) << 5) ^ val; + if (c0 & 1) c ^= 0xf5dee51989; + if (c0 & 2) c ^= 0xa9fdca3312; + if (c0 & 4) c ^= 0x1bab10e32d; + if (c0 & 8) c ^= 0x3706b1677a; + if (c0 & 16) c ^= 0x644d626ffd; + return c; +} -std::string FormatKeyPath(const KeyPath& path) +std::string DescriptorChecksum(const Span<const char>& span) { - std::string ret; - for (auto i : path) { - ret += strprintf("/%i", (i << 1) >> 1); - if (i >> 31) ret += '\''; + /** A character set designed such that: + * - The most common 'unprotected' descriptor characters (hex, keypaths) are in the first group of 32. + * - Case errors cause an offset that's a multiple of 32. + * - As many alphabetic characters are in the same group (while following the above restrictions). + * + * If p(x) gives the position of a character c in this character set, every group of 3 characters + * (a,b,c) is encoded as the 4 symbols (p(a) & 31, p(b) & 31, p(c) & 31, (p(a) / 32) + 3 * (p(b) / 32) + 9 * (p(c) / 32). + * This means that changes that only affect the lower 5 bits of the position, or only the higher 2 bits, will just + * affect a single symbol. + * + * As a result, within-group-of-32 errors count as 1 symbol, as do cross-group errors that don't affect + * the position within the groups. + */ + static std::string INPUT_CHARSET = + "0123456789()[],'/*abcdefgh@:$%{}" + "IJKLMNOPQRSTUVWXYZ&+-.;<=>?!^_|~" + "ijklmnopqrstuvwxyzABCDEFGH`#\"\\ "; + + /** The character set for the checksum itself (same as bech32). */ + static std::string CHECKSUM_CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"; + + uint64_t c = 1; + int cls = 0; + int clscount = 0; + for (auto ch : span) { + auto pos = INPUT_CHARSET.find(ch); + if (pos == std::string::npos) return ""; + c = PolyMod(c, pos & 31); // Emit a symbol for the position inside the group, for every character. + cls = cls * 3 + (pos >> 5); // Accumulate the group numbers + if (++clscount == 3) { + // Emit an extra symbol representing the group numbers, for every 3 characters. + c = PolyMod(c, cls); + cls = 0; + clscount = 0; + } } + if (clscount > 0) c = PolyMod(c, cls); + for (int j = 0; j < 8; ++j) c = PolyMod(c, 0); // Shift further to determine the checksum. + c ^= 1; // Prevent appending zeroes from not affecting the checksum. + + std::string ret(8, ' '); + for (int j = 0; j < 8; ++j) ret[j] = CHECKSUM_CHARSET[(c >> (5 * (7 - j))) & 31]; return ret; } +std::string AddChecksum(const std::string& str) { return str + "#" + DescriptorChecksum(MakeSpan(str)); } + +//////////////////////////////////////////////////////////////////////////// +// Internal representation // +//////////////////////////////////////////////////////////////////////////// + +typedef std::vector<uint32_t> KeyPath; + /** Interface for public key objects in descriptors. */ struct PubkeyProvider { @@ -63,7 +173,7 @@ class OriginPubkeyProvider final : public PubkeyProvider std::string OriginString() const { - return HexStr(std::begin(m_origin.fingerprint), std::end(m_origin.fingerprint)) + FormatKeyPath(m_origin.path); + return HexStr(std::begin(m_origin.fingerprint), std::end(m_origin.fingerprint)) + FormatHDKeypath(m_origin.path); } public: @@ -184,7 +294,7 @@ public: } std::string ToString() const override { - std::string ret = EncodeExtPubKey(m_extkey) + FormatKeyPath(m_path); + std::string ret = EncodeExtPubKey(m_extkey) + FormatHDKeypath(m_path); if (IsRange()) { ret += "/*"; if (m_derive == DeriveType::HARDENED) ret += '\''; @@ -195,7 +305,7 @@ public: { CExtKey key; if (!GetExtKey(arg, key)) return false; - out = EncodeExtKey(key) + FormatKeyPath(m_path); + out = EncodeExtKey(key) + FormatHDKeypath(m_path); if (IsRange()) { out += "/*"; if (m_derive == DeriveType::HARDENED) out += '\''; @@ -226,7 +336,7 @@ protected: * @param pubkeys The evaluations of the m_pubkey_args field. * @param script The evaluation of m_script_arg (or nullptr when m_script_arg is nullptr). * @param out A FlatSigningProvider to put scripts or public keys in that are necessary to the solver. - * The script and pubkeys argument to this function are automatically added. + * The script arguments to this function are automatically added, as is the origin info of the provided pubkeys. * @return A vector with scriptPubKeys for this descriptor. */ virtual std::vector<CScript> MakeScripts(const std::vector<CPubKey>& pubkeys, const CScript* script, FlatSigningProvider& out) const = 0; @@ -282,10 +392,15 @@ public: { std::string ret; ToStringHelper(nullptr, ret, false); - return ret; + return AddChecksum(ret); } - bool ToPrivateString(const SigningProvider& arg, std::string& out) const override final { return ToStringHelper(&arg, out, true); } + bool ToPrivateString(const SigningProvider& arg, std::string& out) const override final + { + bool ret = ToStringHelper(&arg, out, true); + out = AddChecksum(out); + return ret; + } bool ExpandHelper(int pos, const SigningProvider& arg, Span<const unsigned char>* cache_read, std::vector<CScript>& output_scripts, FlatSigningProvider& out, std::vector<unsigned char>* cache_write) const { @@ -322,7 +437,6 @@ public: for (auto& entry : entries) { pubkeys.push_back(entry.first); out.origins.emplace(entry.first.GetID(), std::move(entry.second)); - out.pubkeys.emplace(entry.first.GetID(), entry.first); } if (m_script_arg) { for (const auto& subscript : subscripts) { @@ -396,7 +510,12 @@ public: class PKHDescriptor final : public DescriptorImpl { protected: - std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, const CScript*, FlatSigningProvider&) const override { return Singleton(GetScriptForDestination(keys[0].GetID())); } + std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, const CScript*, FlatSigningProvider& out) const override + { + CKeyID id = keys[0].GetID(); + out.pubkeys.emplace(id, keys[0]); + return Singleton(GetScriptForDestination(id)); + } public: PKHDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Singleton(std::move(prov)), {}, "pkh") {} }; @@ -405,7 +524,12 @@ public: class WPKHDescriptor final : public DescriptorImpl { protected: - std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, const CScript*, FlatSigningProvider&) const override { return Singleton(GetScriptForDestination(WitnessV0KeyHash(keys[0].GetID()))); } + std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, const CScript*, FlatSigningProvider& out) const override + { + CKeyID id = keys[0].GetID(); + out.pubkeys.emplace(id, keys[0]); + return Singleton(GetScriptForDestination(WitnessV0KeyHash(id))); + } public: WPKHDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Singleton(std::move(prov)), {}, "wpkh") {} }; @@ -418,6 +542,7 @@ protected: { std::vector<CScript> ret; CKeyID id = keys[0].GetID(); + out.pubkeys.emplace(id, keys[0]); ret.emplace_back(GetScriptForRawPubKey(keys[0])); // P2PK ret.emplace_back(GetScriptForDestination(id)); // P2PKH if (keys[0].IsCompressed()) { @@ -750,11 +875,25 @@ std::unique_ptr<DescriptorImpl> InferScript(const CScript& script, ParseScriptCo return MakeUnique<RawDescriptor>(script); } + } // namespace -std::unique_ptr<Descriptor> Parse(const std::string& descriptor, FlatSigningProvider& out) +std::unique_ptr<Descriptor> Parse(const std::string& descriptor, FlatSigningProvider& out, bool require_checksum) { Span<const char> sp(descriptor.data(), descriptor.size()); + + // Checksum checks + auto check_split = Split(sp, '#'); + if (check_split.size() > 2) return nullptr; // Multiple '#' symbols + if (check_split.size() == 1 && require_checksum) return nullptr; // Missing checksum + if (check_split.size() == 2) { + if (check_split[1].size() != 8) return nullptr; // Unexpected length for checksum + auto checksum = DescriptorChecksum(check_split[0]); + if (checksum.empty()) return nullptr; // Invalid characters in payload + if (!std::equal(checksum.begin(), checksum.end(), check_split[1].begin())) return nullptr; // Checksum mismatch + } + sp = check_split[0]; + auto ret = ParseScript(sp, ParseScriptContext::TOP, out); if (sp.size() == 0 && ret) return std::unique_ptr<Descriptor>(std::move(ret)); return nullptr; diff --git a/src/script/descriptor.h b/src/script/descriptor.h index 44f0efca03..907a102284 100644 --- a/src/script/descriptor.h +++ b/src/script/descriptor.h @@ -62,8 +62,15 @@ struct Descriptor { virtual bool ExpandFromCache(int pos, const std::vector<unsigned char>& cache, std::vector<CScript>& output_scripts, FlatSigningProvider& out) const = 0; }; -/** Parse a descriptor string. Included private keys are put in out. Returns nullptr if parsing fails. */ -std::unique_ptr<Descriptor> Parse(const std::string& descriptor, FlatSigningProvider& out); +/** Parse a descriptor string. Included private keys are put in out. + * + * If the descriptor has a checksum, it must be valid. If require_checksum + * is set, the checksum is mandatory - otherwise it is optional. + * + * If a parse error occurs, or the checksum is missing/invalid, or anything + * else is wrong, nullptr is returned. + */ +std::unique_ptr<Descriptor> Parse(const std::string& descriptor, FlatSigningProvider& out, bool require_checksum = false); /** Find a descriptor for the specified script, using information from provider where possible. * diff --git a/src/script/sign.cpp b/src/script/sign.cpp index 792fb2997f..320956d0c4 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -83,6 +83,8 @@ static bool CreateSig(const BaseSignatureCreator& creator, SignatureData& sigdat assert(i.second); return true; } + // Could not make signature or signature not found, add keyid to missing + sigdata.missing_sigs.push_back(keyid); return false; } @@ -116,17 +118,24 @@ static bool SignStep(const SigningProvider& provider, const BaseSignatureCreator case TX_PUBKEYHASH: { CKeyID keyID = CKeyID(uint160(vSolutions[0])); CPubKey pubkey; - if (!GetPubKey(provider, sigdata, keyID, pubkey)) return false; + if (!GetPubKey(provider, sigdata, keyID, pubkey)) { + // Pubkey could not be found, add to missing + sigdata.missing_pubkeys.push_back(keyID); + return false; + } if (!CreateSig(creator, sigdata, provider, sig, pubkey, scriptPubKey, sigversion)) return false; ret.push_back(std::move(sig)); ret.push_back(ToByteVector(pubkey)); return true; } case TX_SCRIPTHASH: - if (GetCScript(provider, sigdata, uint160(vSolutions[0]), scriptRet)) { + h160 = uint160(vSolutions[0]); + if (GetCScript(provider, sigdata, h160, scriptRet)) { ret.push_back(std::vector<unsigned char>(scriptRet.begin(), scriptRet.end())); return true; } + // Could not find redeemScript, add to missing + sigdata.missing_redeem_script = h160; return false; case TX_MULTISIG: { @@ -154,6 +163,8 @@ static bool SignStep(const SigningProvider& provider, const BaseSignatureCreator ret.push_back(std::vector<unsigned char>(scriptRet.begin(), scriptRet.end())); return true; } + // Could not find witnessScript, add to missing + sigdata.missing_witness_script = uint256(vSolutions[0]); return false; default: @@ -232,67 +243,6 @@ bool ProduceSignature(const SigningProvider& provider, const BaseSignatureCreato return sigdata.complete; } -bool PSBTInputSigned(PSBTInput& input) -{ - return !input.final_script_sig.empty() || !input.final_script_witness.IsNull(); -} - -bool SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction& psbt, int index, int sighash) -{ - PSBTInput& input = psbt.inputs.at(index); - const CMutableTransaction& tx = *psbt.tx; - - if (PSBTInputSigned(input)) { - return true; - } - - // Fill SignatureData with input info - SignatureData sigdata; - input.FillSignatureData(sigdata); - - // Get UTXO - bool require_witness_sig = false; - CTxOut utxo; - - // Verify input sanity, which checks that at most one of witness or non-witness utxos is provided. - if (!input.IsSane()) { - return false; - } - - if (input.non_witness_utxo) { - // If we're taking our information from a non-witness UTXO, verify that it matches the prevout. - COutPoint prevout = tx.vin[index].prevout; - if (input.non_witness_utxo->GetHash() != prevout.hash) { - return false; - } - utxo = input.non_witness_utxo->vout[prevout.n]; - } else if (!input.witness_utxo.IsNull()) { - utxo = input.witness_utxo; - // When we're taking our information from a witness UTXO, we can't verify it is actually data from - // the output being spent. This is safe in case a witness signature is produced (which includes this - // information directly in the hash), but not for non-witness signatures. Remember that we require - // a witness signature in this situation. - require_witness_sig = true; - } else { - return false; - } - - MutableTransactionSignatureCreator creator(&tx, index, utxo.nValue, sighash); - sigdata.witness = false; - bool sig_complete = ProduceSignature(provider, creator, utxo.scriptPubKey, sigdata); - // Verify that a witness signature was produced in case one was required. - if (require_witness_sig && !sigdata.witness) return false; - input.FromSignatureData(sigdata); - - // If we have a witness signature, use the smaller witness UTXO. - if (sigdata.witness) { - input.witness_utxo = utxo; - input.non_witness_utxo = nullptr; - } - - return sig_complete; -} - class SignatureExtractorChecker final : public BaseSignatureChecker { private: @@ -509,166 +459,6 @@ bool IsSolvable(const SigningProvider& provider, const CScript& script) return false; } -PartiallySignedTransaction::PartiallySignedTransaction(const CMutableTransaction& tx) : tx(tx) -{ - inputs.resize(tx.vin.size()); - outputs.resize(tx.vout.size()); -} - -bool PartiallySignedTransaction::IsNull() const -{ - return !tx && inputs.empty() && outputs.empty() && unknown.empty(); -} - -void PartiallySignedTransaction::Merge(const PartiallySignedTransaction& psbt) -{ - for (unsigned int i = 0; i < inputs.size(); ++i) { - inputs[i].Merge(psbt.inputs[i]); - } - for (unsigned int i = 0; i < outputs.size(); ++i) { - outputs[i].Merge(psbt.outputs[i]); - } - unknown.insert(psbt.unknown.begin(), psbt.unknown.end()); -} - -bool PartiallySignedTransaction::IsSane() const -{ - for (PSBTInput input : inputs) { - if (!input.IsSane()) return false; - } - return true; -} - -bool PSBTInput::IsNull() const -{ - return !non_witness_utxo && witness_utxo.IsNull() && partial_sigs.empty() && unknown.empty() && hd_keypaths.empty() && redeem_script.empty() && witness_script.empty(); -} - -void PSBTInput::FillSignatureData(SignatureData& sigdata) const -{ - if (!final_script_sig.empty()) { - sigdata.scriptSig = final_script_sig; - sigdata.complete = true; - } - if (!final_script_witness.IsNull()) { - sigdata.scriptWitness = final_script_witness; - sigdata.complete = true; - } - if (sigdata.complete) { - return; - } - - sigdata.signatures.insert(partial_sigs.begin(), partial_sigs.end()); - if (!redeem_script.empty()) { - sigdata.redeem_script = redeem_script; - } - if (!witness_script.empty()) { - sigdata.witness_script = witness_script; - } - for (const auto& key_pair : hd_keypaths) { - sigdata.misc_pubkeys.emplace(key_pair.first.GetID(), key_pair); - } -} - -void PSBTInput::FromSignatureData(const SignatureData& sigdata) -{ - if (sigdata.complete) { - partial_sigs.clear(); - hd_keypaths.clear(); - redeem_script.clear(); - witness_script.clear(); - - if (!sigdata.scriptSig.empty()) { - final_script_sig = sigdata.scriptSig; - } - if (!sigdata.scriptWitness.IsNull()) { - final_script_witness = sigdata.scriptWitness; - } - return; - } - - partial_sigs.insert(sigdata.signatures.begin(), sigdata.signatures.end()); - if (redeem_script.empty() && !sigdata.redeem_script.empty()) { - redeem_script = sigdata.redeem_script; - } - if (witness_script.empty() && !sigdata.witness_script.empty()) { - witness_script = sigdata.witness_script; - } - for (const auto& entry : sigdata.misc_pubkeys) { - hd_keypaths.emplace(entry.second); - } -} - -void PSBTInput::Merge(const PSBTInput& input) -{ - if (!non_witness_utxo && input.non_witness_utxo) non_witness_utxo = input.non_witness_utxo; - if (witness_utxo.IsNull() && !input.witness_utxo.IsNull()) { - witness_utxo = input.witness_utxo; - non_witness_utxo = nullptr; // Clear out any non-witness utxo when we set a witness one. - } - - partial_sigs.insert(input.partial_sigs.begin(), input.partial_sigs.end()); - hd_keypaths.insert(input.hd_keypaths.begin(), input.hd_keypaths.end()); - unknown.insert(input.unknown.begin(), input.unknown.end()); - - if (redeem_script.empty() && !input.redeem_script.empty()) redeem_script = input.redeem_script; - if (witness_script.empty() && !input.witness_script.empty()) witness_script = input.witness_script; - if (final_script_sig.empty() && !input.final_script_sig.empty()) final_script_sig = input.final_script_sig; - if (final_script_witness.IsNull() && !input.final_script_witness.IsNull()) final_script_witness = input.final_script_witness; -} - -bool PSBTInput::IsSane() const -{ - // Cannot have both witness and non-witness utxos - if (!witness_utxo.IsNull() && non_witness_utxo) return false; - - // If we have a witness_script or a scriptWitness, we must also have a witness utxo - if (!witness_script.empty() && witness_utxo.IsNull()) return false; - if (!final_script_witness.IsNull() && witness_utxo.IsNull()) return false; - - return true; -} - -void PSBTOutput::FillSignatureData(SignatureData& sigdata) const -{ - if (!redeem_script.empty()) { - sigdata.redeem_script = redeem_script; - } - if (!witness_script.empty()) { - sigdata.witness_script = witness_script; - } - for (const auto& key_pair : hd_keypaths) { - sigdata.misc_pubkeys.emplace(key_pair.first.GetID(), key_pair); - } -} - -void PSBTOutput::FromSignatureData(const SignatureData& sigdata) -{ - if (redeem_script.empty() && !sigdata.redeem_script.empty()) { - redeem_script = sigdata.redeem_script; - } - if (witness_script.empty() && !sigdata.witness_script.empty()) { - witness_script = sigdata.witness_script; - } - for (const auto& entry : sigdata.misc_pubkeys) { - hd_keypaths.emplace(entry.second); - } -} - -bool PSBTOutput::IsNull() const -{ - return redeem_script.empty() && witness_script.empty() && hd_keypaths.empty() && unknown.empty(); -} - -void PSBTOutput::Merge(const PSBTOutput& output) -{ - hd_keypaths.insert(output.hd_keypaths.begin(), output.hd_keypaths.end()); - unknown.insert(output.unknown.begin(), output.unknown.end()); - - if (redeem_script.empty() && !output.redeem_script.empty()) redeem_script = output.redeem_script; - if (witness_script.empty() && !output.witness_script.empty()) witness_script = output.witness_script; -} - bool HidingSigningProvider::GetCScript(const CScriptID& scriptid, CScript& script) const { return m_provider->GetCScript(scriptid, script); diff --git a/src/script/sign.h b/src/script/sign.h index e884f4c480..491fb54c45 100644 --- a/src/script/sign.h +++ b/src/script/sign.h @@ -22,13 +22,27 @@ struct CMutableTransaction; struct KeyOriginInfo { - unsigned char fingerprint[4]; + unsigned char fingerprint[4]; //!< First 32 bits of the Hash160 of the public key at the root of the path std::vector<uint32_t> path; friend bool operator==(const KeyOriginInfo& a, const KeyOriginInfo& b) { return std::equal(std::begin(a.fingerprint), std::end(a.fingerprint), std::begin(b.fingerprint)) && a.path == b.path; } + + ADD_SERIALIZE_METHODS; + template <typename Stream, typename Operation> + inline void SerializationOp(Stream& s, Operation ser_action) + { + READWRITE(fingerprint); + READWRITE(path); + } + + void clear() + { + memset(fingerprint, 0, 4); + path.clear(); + } }; /** An interface to be implemented by keystores that support signing. */ @@ -117,38 +131,16 @@ struct SignatureData { CScriptWitness scriptWitness; ///< The scriptWitness of an input. Contains complete signatures or the traditional partial signatures format. scriptWitness is part of a transaction input per BIP 144. std::map<CKeyID, SigPair> signatures; ///< BIP 174 style partial signatures for the input. May contain all signatures necessary for producing a final scriptSig or scriptWitness. std::map<CKeyID, std::pair<CPubKey, KeyOriginInfo>> misc_pubkeys; + std::vector<CKeyID> missing_pubkeys; ///< KeyIDs of pubkeys which could not be found + std::vector<CKeyID> missing_sigs; ///< KeyIDs of pubkeys for signatures which could not be found + uint160 missing_redeem_script; ///< ScriptID of the missing redeemScript (if any) + uint256 missing_witness_script; ///< SHA256 of the missing witnessScript (if any) SignatureData() {} explicit SignatureData(const CScript& script) : scriptSig(script) {} void MergeSignatureData(SignatureData sigdata); }; -// Magic bytes -static constexpr uint8_t PSBT_MAGIC_BYTES[5] = {'p', 's', 'b', 't', 0xff}; - -// Global types -static constexpr uint8_t PSBT_GLOBAL_UNSIGNED_TX = 0x00; - -// Input types -static constexpr uint8_t PSBT_IN_NON_WITNESS_UTXO = 0x00; -static constexpr uint8_t PSBT_IN_WITNESS_UTXO = 0x01; -static constexpr uint8_t PSBT_IN_PARTIAL_SIG = 0x02; -static constexpr uint8_t PSBT_IN_SIGHASH = 0x03; -static constexpr uint8_t PSBT_IN_REDEEMSCRIPT = 0x04; -static constexpr uint8_t PSBT_IN_WITNESSSCRIPT = 0x05; -static constexpr uint8_t PSBT_IN_BIP32_DERIVATION = 0x06; -static constexpr uint8_t PSBT_IN_SCRIPTSIG = 0x07; -static constexpr uint8_t PSBT_IN_SCRIPTWITNESS = 0x08; - -// Output types -static constexpr uint8_t PSBT_OUT_REDEEMSCRIPT = 0x00; -static constexpr uint8_t PSBT_OUT_WITNESSSCRIPT = 0x01; -static constexpr uint8_t PSBT_OUT_BIP32_DERIVATION = 0x02; - -// The separator is 0x00. Reading this in means that the unserializer can interpret it -// as a 0 length key which indicates that this is the separator. The separator has no value. -static constexpr uint8_t PSBT_SEPARATOR = 0x00; - // Takes a stream and multiple arguments and serializes them as if first serialized into a vector and then into the stream // The resulting output into the stream has the total serialized length of all of the objects followed by all objects concatenated with each other. template<typename Stream, typename... X> @@ -223,514 +215,6 @@ void SerializeHDKeypaths(Stream& s, const std::map<CPubKey, KeyOriginInfo>& hd_k } } -/** A structure for PSBTs which contain per-input information */ -struct PSBTInput -{ - CTransactionRef non_witness_utxo; - CTxOut witness_utxo; - CScript redeem_script; - CScript witness_script; - CScript final_script_sig; - CScriptWitness final_script_witness; - std::map<CPubKey, KeyOriginInfo> hd_keypaths; - std::map<CKeyID, SigPair> partial_sigs; - std::map<std::vector<unsigned char>, std::vector<unsigned char>> unknown; - int sighash_type = 0; - - bool IsNull() const; - void FillSignatureData(SignatureData& sigdata) const; - void FromSignatureData(const SignatureData& sigdata); - void Merge(const PSBTInput& input); - bool IsSane() const; - PSBTInput() {} - - template <typename Stream> - inline void Serialize(Stream& s) const { - // Write the utxo - // If there is a non-witness utxo, then don't add the witness one. - if (non_witness_utxo) { - SerializeToVector(s, PSBT_IN_NON_WITNESS_UTXO); - OverrideStream<Stream> os(&s, s.GetType(), s.GetVersion() | SERIALIZE_TRANSACTION_NO_WITNESS); - SerializeToVector(os, non_witness_utxo); - } else if (!witness_utxo.IsNull()) { - SerializeToVector(s, PSBT_IN_WITNESS_UTXO); - SerializeToVector(s, witness_utxo); - } - - if (final_script_sig.empty() && final_script_witness.IsNull()) { - // Write any partial signatures - for (auto sig_pair : partial_sigs) { - SerializeToVector(s, PSBT_IN_PARTIAL_SIG, MakeSpan(sig_pair.second.first)); - s << sig_pair.second.second; - } - - // Write the sighash type - if (sighash_type > 0) { - SerializeToVector(s, PSBT_IN_SIGHASH); - SerializeToVector(s, sighash_type); - } - - // Write the redeem script - if (!redeem_script.empty()) { - SerializeToVector(s, PSBT_IN_REDEEMSCRIPT); - s << redeem_script; - } - - // Write the witness script - if (!witness_script.empty()) { - SerializeToVector(s, PSBT_IN_WITNESSSCRIPT); - s << witness_script; - } - - // Write any hd keypaths - SerializeHDKeypaths(s, hd_keypaths, PSBT_IN_BIP32_DERIVATION); - } - - // Write script sig - if (!final_script_sig.empty()) { - SerializeToVector(s, PSBT_IN_SCRIPTSIG); - s << final_script_sig; - } - // write script witness - if (!final_script_witness.IsNull()) { - SerializeToVector(s, PSBT_IN_SCRIPTWITNESS); - SerializeToVector(s, final_script_witness.stack); - } - - // Write unknown things - for (auto& entry : unknown) { - s << entry.first; - s << entry.second; - } - - s << PSBT_SEPARATOR; - } - - - template <typename Stream> - inline void Unserialize(Stream& s) { - // Read loop - bool found_sep = false; - while(!s.empty()) { - // Read - std::vector<unsigned char> key; - s >> key; - - // the key is empty if that was actually a separator byte - // This is a special case for key lengths 0 as those are not allowed (except for separator) - if (key.empty()) { - found_sep = true; - break; - } - - // First byte of key is the type - unsigned char type = key[0]; - - // Do stuff based on type - switch(type) { - case PSBT_IN_NON_WITNESS_UTXO: - { - if (non_witness_utxo) { - throw std::ios_base::failure("Duplicate Key, input non-witness utxo already provided"); - } else if (key.size() != 1) { - throw std::ios_base::failure("Non-witness utxo key is more than one byte type"); - } - // Set the stream to unserialize with witness since this is always a valid network transaction - OverrideStream<Stream> os(&s, s.GetType(), s.GetVersion() & ~SERIALIZE_TRANSACTION_NO_WITNESS); - UnserializeFromVector(os, non_witness_utxo); - break; - } - case PSBT_IN_WITNESS_UTXO: - if (!witness_utxo.IsNull()) { - throw std::ios_base::failure("Duplicate Key, input witness utxo already provided"); - } else if (key.size() != 1) { - throw std::ios_base::failure("Witness utxo key is more than one byte type"); - } - UnserializeFromVector(s, witness_utxo); - break; - case PSBT_IN_PARTIAL_SIG: - { - // Make sure that the key is the size of pubkey + 1 - if (key.size() != CPubKey::PUBLIC_KEY_SIZE + 1 && key.size() != CPubKey::COMPRESSED_PUBLIC_KEY_SIZE + 1) { - throw std::ios_base::failure("Size of key was not the expected size for the type partial signature pubkey"); - } - // Read in the pubkey from key - CPubKey pubkey(key.begin() + 1, key.end()); - if (!pubkey.IsFullyValid()) { - throw std::ios_base::failure("Invalid pubkey"); - } - if (partial_sigs.count(pubkey.GetID()) > 0) { - throw std::ios_base::failure("Duplicate Key, input partial signature for pubkey already provided"); - } - - // Read in the signature from value - std::vector<unsigned char> sig; - s >> sig; - - // Add to list - partial_sigs.emplace(pubkey.GetID(), SigPair(pubkey, std::move(sig))); - break; - } - case PSBT_IN_SIGHASH: - if (sighash_type > 0) { - throw std::ios_base::failure("Duplicate Key, input sighash type already provided"); - } else if (key.size() != 1) { - throw std::ios_base::failure("Sighash type key is more than one byte type"); - } - UnserializeFromVector(s, sighash_type); - break; - case PSBT_IN_REDEEMSCRIPT: - { - if (!redeem_script.empty()) { - throw std::ios_base::failure("Duplicate Key, input redeemScript already provided"); - } else if (key.size() != 1) { - throw std::ios_base::failure("Input redeemScript key is more than one byte type"); - } - s >> redeem_script; - break; - } - case PSBT_IN_WITNESSSCRIPT: - { - if (!witness_script.empty()) { - throw std::ios_base::failure("Duplicate Key, input witnessScript already provided"); - } else if (key.size() != 1) { - throw std::ios_base::failure("Input witnessScript key is more than one byte type"); - } - s >> witness_script; - break; - } - case PSBT_IN_BIP32_DERIVATION: - { - DeserializeHDKeypaths(s, key, hd_keypaths); - break; - } - case PSBT_IN_SCRIPTSIG: - { - if (!final_script_sig.empty()) { - throw std::ios_base::failure("Duplicate Key, input final scriptSig already provided"); - } else if (key.size() != 1) { - throw std::ios_base::failure("Final scriptSig key is more than one byte type"); - } - s >> final_script_sig; - break; - } - case PSBT_IN_SCRIPTWITNESS: - { - if (!final_script_witness.IsNull()) { - throw std::ios_base::failure("Duplicate Key, input final scriptWitness already provided"); - } else if (key.size() != 1) { - throw std::ios_base::failure("Final scriptWitness key is more than one byte type"); - } - UnserializeFromVector(s, final_script_witness.stack); - break; - } - // Unknown stuff - default: - if (unknown.count(key) > 0) { - throw std::ios_base::failure("Duplicate Key, key for unknown value already provided"); - } - // Read in the value - std::vector<unsigned char> val_bytes; - s >> val_bytes; - unknown.emplace(std::move(key), std::move(val_bytes)); - break; - } - } - - if (!found_sep) { - throw std::ios_base::failure("Separator is missing at the end of an input map"); - } - } - - template <typename Stream> - PSBTInput(deserialize_type, Stream& s) { - Unserialize(s); - } -}; - -/** A structure for PSBTs which contains per output information */ -struct PSBTOutput -{ - CScript redeem_script; - CScript witness_script; - std::map<CPubKey, KeyOriginInfo> hd_keypaths; - std::map<std::vector<unsigned char>, std::vector<unsigned char>> unknown; - - bool IsNull() const; - void FillSignatureData(SignatureData& sigdata) const; - void FromSignatureData(const SignatureData& sigdata); - void Merge(const PSBTOutput& output); - bool IsSane() const; - PSBTOutput() {} - - template <typename Stream> - inline void Serialize(Stream& s) const { - // Write the redeem script - if (!redeem_script.empty()) { - SerializeToVector(s, PSBT_OUT_REDEEMSCRIPT); - s << redeem_script; - } - - // Write the witness script - if (!witness_script.empty()) { - SerializeToVector(s, PSBT_OUT_WITNESSSCRIPT); - s << witness_script; - } - - // Write any hd keypaths - SerializeHDKeypaths(s, hd_keypaths, PSBT_OUT_BIP32_DERIVATION); - - // Write unknown things - for (auto& entry : unknown) { - s << entry.first; - s << entry.second; - } - - s << PSBT_SEPARATOR; - } - - - template <typename Stream> - inline void Unserialize(Stream& s) { - // Read loop - bool found_sep = false; - while(!s.empty()) { - // Read - std::vector<unsigned char> key; - s >> key; - - // the key is empty if that was actually a separator byte - // This is a special case for key lengths 0 as those are not allowed (except for separator) - if (key.empty()) { - found_sep = true; - break; - } - - // First byte of key is the type - unsigned char type = key[0]; - - // Do stuff based on type - switch(type) { - case PSBT_OUT_REDEEMSCRIPT: - { - if (!redeem_script.empty()) { - throw std::ios_base::failure("Duplicate Key, output redeemScript already provided"); - } else if (key.size() != 1) { - throw std::ios_base::failure("Output redeemScript key is more than one byte type"); - } - s >> redeem_script; - break; - } - case PSBT_OUT_WITNESSSCRIPT: - { - if (!witness_script.empty()) { - throw std::ios_base::failure("Duplicate Key, output witnessScript already provided"); - } else if (key.size() != 1) { - throw std::ios_base::failure("Output witnessScript key is more than one byte type"); - } - s >> witness_script; - break; - } - case PSBT_OUT_BIP32_DERIVATION: - { - DeserializeHDKeypaths(s, key, hd_keypaths); - break; - } - // Unknown stuff - default: { - if (unknown.count(key) > 0) { - throw std::ios_base::failure("Duplicate Key, key for unknown value already provided"); - } - // Read in the value - std::vector<unsigned char> val_bytes; - s >> val_bytes; - unknown.emplace(std::move(key), std::move(val_bytes)); - break; - } - } - } - - if (!found_sep) { - throw std::ios_base::failure("Separator is missing at the end of an output map"); - } - } - - template <typename Stream> - PSBTOutput(deserialize_type, Stream& s) { - Unserialize(s); - } -}; - -/** A version of CTransaction with the PSBT format*/ -struct PartiallySignedTransaction -{ - boost::optional<CMutableTransaction> tx; - std::vector<PSBTInput> inputs; - std::vector<PSBTOutput> outputs; - std::map<std::vector<unsigned char>, std::vector<unsigned char>> unknown; - - bool IsNull() const; - void Merge(const PartiallySignedTransaction& psbt); - bool IsSane() const; - PartiallySignedTransaction() {} - PartiallySignedTransaction(const PartiallySignedTransaction& psbt_in) : tx(psbt_in.tx), inputs(psbt_in.inputs), outputs(psbt_in.outputs), unknown(psbt_in.unknown) {} - explicit PartiallySignedTransaction(const CMutableTransaction& tx); - - // Only checks if they refer to the same transaction - friend bool operator==(const PartiallySignedTransaction& a, const PartiallySignedTransaction &b) - { - return a.tx->GetHash() == b.tx->GetHash(); - } - friend bool operator!=(const PartiallySignedTransaction& a, const PartiallySignedTransaction &b) - { - return !(a == b); - } - - template <typename Stream> - inline void Serialize(Stream& s) const { - - // magic bytes - s << PSBT_MAGIC_BYTES; - - // unsigned tx flag - SerializeToVector(s, PSBT_GLOBAL_UNSIGNED_TX); - - // Write serialized tx to a stream - OverrideStream<Stream> os(&s, s.GetType(), s.GetVersion() | SERIALIZE_TRANSACTION_NO_WITNESS); - SerializeToVector(os, *tx); - - // Write the unknown things - for (auto& entry : unknown) { - s << entry.first; - s << entry.second; - } - - // Separator - s << PSBT_SEPARATOR; - - // Write inputs - for (const PSBTInput& input : inputs) { - s << input; - } - // Write outputs - for (const PSBTOutput& output : outputs) { - s << output; - } - } - - - template <typename Stream> - inline void Unserialize(Stream& s) { - // Read the magic bytes - uint8_t magic[5]; - s >> magic; - if (!std::equal(magic, magic + 5, PSBT_MAGIC_BYTES)) { - throw std::ios_base::failure("Invalid PSBT magic bytes"); - } - - // Read global data - bool found_sep = false; - while(!s.empty()) { - // Read - std::vector<unsigned char> key; - s >> key; - - // the key is empty if that was actually a separator byte - // This is a special case for key lengths 0 as those are not allowed (except for separator) - if (key.empty()) { - found_sep = true; - break; - } - - // First byte of key is the type - unsigned char type = key[0]; - - // Do stuff based on type - switch(type) { - case PSBT_GLOBAL_UNSIGNED_TX: - { - if (tx) { - throw std::ios_base::failure("Duplicate Key, unsigned tx already provided"); - } else if (key.size() != 1) { - throw std::ios_base::failure("Global unsigned tx key is more than one byte type"); - } - CMutableTransaction mtx; - // Set the stream to serialize with non-witness since this should always be non-witness - OverrideStream<Stream> os(&s, s.GetType(), s.GetVersion() | SERIALIZE_TRANSACTION_NO_WITNESS); - UnserializeFromVector(os, mtx); - tx = std::move(mtx); - // Make sure that all scriptSigs and scriptWitnesses are empty - for (const CTxIn& txin : tx->vin) { - if (!txin.scriptSig.empty() || !txin.scriptWitness.IsNull()) { - throw std::ios_base::failure("Unsigned tx does not have empty scriptSigs and scriptWitnesses."); - } - } - break; - } - // Unknown stuff - default: { - if (unknown.count(key) > 0) { - throw std::ios_base::failure("Duplicate Key, key for unknown value already provided"); - } - // Read in the value - std::vector<unsigned char> val_bytes; - s >> val_bytes; - unknown.emplace(std::move(key), std::move(val_bytes)); - } - } - } - - if (!found_sep) { - throw std::ios_base::failure("Separator is missing at the end of the global map"); - } - - // Make sure that we got an unsigned tx - if (!tx) { - throw std::ios_base::failure("No unsigned transcation was provided"); - } - - // Read input data - unsigned int i = 0; - while (!s.empty() && i < tx->vin.size()) { - PSBTInput input; - s >> input; - inputs.push_back(input); - - // Make sure the non-witness utxo matches the outpoint - if (input.non_witness_utxo && input.non_witness_utxo->GetHash() != tx->vin[i].prevout.hash) { - throw std::ios_base::failure("Non-witness UTXO does not match outpoint hash"); - } - ++i; - } - // Make sure that the number of inputs matches the number of inputs in the transaction - if (inputs.size() != tx->vin.size()) { - throw std::ios_base::failure("Inputs provided does not match the number of inputs in transaction."); - } - - // Read output data - i = 0; - while (!s.empty() && i < tx->vout.size()) { - PSBTOutput output; - s >> output; - outputs.push_back(output); - ++i; - } - // Make sure that the number of outputs matches the number of outputs in the transaction - if (outputs.size() != tx->vout.size()) { - throw std::ios_base::failure("Outputs provided does not match the number of outputs in transaction."); - } - // Sanity check - if (!IsSane()) { - throw std::ios_base::failure("PSBT is not sane."); - } - } - - template <typename Stream> - PartiallySignedTransaction(deserialize_type, Stream& s) { - Unserialize(s); - } -}; - /** Produce a script signature using a generic signature creator. */ bool ProduceSignature(const SigningProvider& provider, const BaseSignatureCreator& creator, const CScript& scriptPubKey, SignatureData& sigdata); @@ -738,12 +222,6 @@ bool ProduceSignature(const SigningProvider& provider, const BaseSignatureCreato bool SignSignature(const SigningProvider &provider, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, const CAmount& amount, int nHashType); bool SignSignature(const SigningProvider &provider, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType); -/** Checks whether a PSBTInput is already signed. */ -bool PSBTInputSigned(PSBTInput& input); - -/** Signs a PSBTInput, verifying that all provided data matches what is being signed. */ -bool SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction& psbt, int index, int sighash = SIGHASH_ALL); - /** Extract signature data from a transaction input, and insert it. */ SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nIn, const CTxOut& txout); void UpdateInput(CTxIn& input, const SignatureData& data); diff --git a/src/support/lockedpool.cpp b/src/support/lockedpool.cpp index 627018083e..5c2050e4a2 100644 --- a/src/support/lockedpool.cpp +++ b/src/support/lockedpool.cpp @@ -10,10 +10,6 @@ #endif #ifdef WIN32 -#ifdef _WIN32_WINNT -#undef _WIN32_WINNT -#endif -#define _WIN32_WINNT 0x0501 #define WIN32_LEAN_AND_MEAN 1 #ifndef NOMINMAX #define NOMINMAX diff --git a/src/test/bloom_tests.cpp b/src/test/bloom_tests.cpp index c900bee199..f58dd20efc 100644 --- a/src/test/bloom_tests.cpp +++ b/src/test/bloom_tests.cpp @@ -461,6 +461,9 @@ static std::vector<unsigned char> RandomData() BOOST_AUTO_TEST_CASE(rolling_bloom) { + SeedInsecureRand(/* deterministic */ true); + g_mock_deterministic_tests = true; + // last-100-entry, 1% false positive: CRollingBloomFilter rb1(100, 0.01); @@ -485,12 +488,8 @@ BOOST_AUTO_TEST_CASE(rolling_bloom) if (rb1.contains(RandomData())) ++nHits; } - // Run test_bitcoin with --log_level=message to see BOOST_TEST_MESSAGEs: - BOOST_TEST_MESSAGE("RollingBloomFilter got " << nHits << " false positives (~100 expected)"); - - // Insanely unlikely to get a fp count outside this range: - BOOST_CHECK(nHits > 25); - BOOST_CHECK(nHits < 175); + // Expect about 100 hits + BOOST_CHECK_EQUAL(nHits, 75); BOOST_CHECK(rb1.contains(data[DATASIZE-1])); rb1.reset(); @@ -517,10 +516,8 @@ BOOST_AUTO_TEST_CASE(rolling_bloom) if (rb1.contains(data[i])) ++nHits; } - // Expect about 5 false positives, more than 100 means - // something is definitely broken. - BOOST_TEST_MESSAGE("RollingBloomFilter got " << nHits << " false positives (~5 expected)"); - BOOST_CHECK(nHits < 100); + // Expect about 5 false positives + BOOST_CHECK_EQUAL(nHits, 6); // last-1000-entry, 0.01% false positive: CRollingBloomFilter rb2(1000, 0.001); @@ -531,6 +528,7 @@ BOOST_AUTO_TEST_CASE(rolling_bloom) for (int i = 0; i < DATASIZE; i++) { BOOST_CHECK(rb2.contains(data[i])); } + g_mock_deterministic_tests = false; } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp index aa2e88477d..f6b97a6868 100644 --- a/src/test/coins_tests.cpp +++ b/src/test/coins_tests.cpp @@ -279,6 +279,8 @@ UtxoData::iterator FindRandomFrom(const std::set<COutPoint> &utxoSet) { // has the expected effect (the other duplicate is overwritten at all cache levels) BOOST_AUTO_TEST_CASE(updatecoins_simulation_test) { + SeedInsecureRand(/* deterministic */ true); + bool spent_a_duplicate_coinbase = false; // A simple map to track what we expect the cache stack to represent. std::map<COutPoint, Coin> result; diff --git a/src/test/descriptor_tests.cpp b/src/test/descriptor_tests.cpp index 8da8cfc00c..ff2b8d4fc9 100644 --- a/src/test/descriptor_tests.cpp +++ b/src/test/descriptor_tests.cpp @@ -18,8 +18,8 @@ void CheckUnparsable(const std::string& prv, const std::string& pub) FlatSigningProvider keys_priv, keys_pub; auto parse_priv = Parse(prv, keys_priv); auto parse_pub = Parse(pub, keys_pub); - BOOST_CHECK(!parse_priv); - BOOST_CHECK(!parse_pub); + BOOST_CHECK_MESSAGE(!parse_priv, prv); + BOOST_CHECK_MESSAGE(!parse_pub, pub); } constexpr int DEFAULT = 0; @@ -28,6 +28,18 @@ constexpr int HARDENED = 2; // Derivation needs access to private keys constexpr int UNSOLVABLE = 4; // This descriptor is not expected to be solvable constexpr int SIGNABLE = 8; // We can sign with this descriptor (this is not true when actual BIP32 derivation is used, as that's not integrated in our signing code) +/** Compare two descriptors. If only one of them has a checksum, the checksum is ignored. */ +bool EqualDescriptor(std::string a, std::string b) +{ + bool a_check = (a.size() > 9 && a[a.size() - 9] == '#'); + bool b_check = (b.size() > 9 && b[b.size() - 9] == '#'); + if (a_check != b_check) { + if (a_check) a = a.substr(0, a.size() - 9); + if (b_check) b = b.substr(0, b.size() - 9); + } + return a == b; +} + std::string MaybeUseHInsteadOfApostrophy(std::string ret) { if (InsecureRandBool()) { @@ -35,6 +47,7 @@ std::string MaybeUseHInsteadOfApostrophy(std::string ret) auto it = ret.find("'"); if (it != std::string::npos) { ret[it] = 'h'; + if (ret.size() > 9 && ret[ret.size() - 9] == '#') ret = ret.substr(0, ret.size() - 9); // Changing apostrophe to h breaks the checksum } else { break; } @@ -63,16 +76,16 @@ void Check(const std::string& prv, const std::string& pub, int flags, const std: // Check that both versions serialize back to the public version. std::string pub1 = parse_priv->ToString(); std::string pub2 = parse_pub->ToString(); - BOOST_CHECK_EQUAL(pub, pub1); - BOOST_CHECK_EQUAL(pub, pub2); + BOOST_CHECK(EqualDescriptor(pub, pub1)); + BOOST_CHECK(EqualDescriptor(pub, pub2)); // Check that both can be serialized with private key back to the private version, but not without private key. std::string prv1; BOOST_CHECK(parse_priv->ToPrivateString(keys_priv, prv1)); - BOOST_CHECK_EQUAL(prv, prv1); + BOOST_CHECK(EqualDescriptor(prv, prv1)); BOOST_CHECK(!parse_priv->ToPrivateString(keys_pub, prv1)); BOOST_CHECK(parse_pub->ToPrivateString(keys_priv, prv1)); - BOOST_CHECK_EQUAL(prv, prv1); + BOOST_CHECK(EqualDescriptor(prv, prv1)); BOOST_CHECK(!parse_pub->ToPrivateString(keys_pub, prv1)); // Check whether IsRange on both returns the expected result @@ -210,6 +223,15 @@ BOOST_AUTO_TEST_CASE(descriptor_test) CheckUnparsable("wsh(sh(pk(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)))", "wsh(sh(pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)))"); // Cannot embed P2SH inside P2WSH CheckUnparsable("sh(sh(pk(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)))", "sh(sh(pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)))"); // Cannot embed P2SH inside P2SH CheckUnparsable("wsh(wsh(pk(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)))", "wsh(wsh(pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)))"); // Cannot embed P2WSH inside P2WSH + + // Checksums + Check("sh(multi(2,[00000000/111'/222]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0))#ggrsrxfy", "sh(multi(2,[00000000/111'/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))#tjg09x5t", DEFAULT, {{"a91445a9a622a8b0a1269944be477640eedc447bbd8487"}}, {{0x8000006FUL,222},{0}}); + Check("sh(multi(2,[00000000/111'/222]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0))", "sh(multi(2,[00000000/111'/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))", DEFAULT, {{"a91445a9a622a8b0a1269944be477640eedc447bbd8487"}}, {{0x8000006FUL,222},{0}}); + CheckUnparsable("sh(multi(2,[00000000/111'/222]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0))#", "sh(multi(2,[00000000/111'/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))#"); // Empty checksum + CheckUnparsable("sh(multi(2,[00000000/111'/222]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0))#ggrsrxfyq", "sh(multi(2,[00000000/111'/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))#tjg09x5tq"); // Too long checksum + CheckUnparsable("sh(multi(2,[00000000/111'/222]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0))#ggrsrxf", "sh(multi(2,[00000000/111'/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))#tjg09x5"); // Too short checksum + CheckUnparsable("sh(multi(3,[00000000/111'/222]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0))#ggrsrxfy", "sh(multi(3,[00000000/111'/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))#tjg09x5t"); // Error in payload + CheckUnparsable("sh(multi(2,[00000000/111'/222]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0))#ggssrxfy", "sh(multi(2,[00000000/111'/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))#tjq09x4t"); // Error in checksum } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/test_bitcoin_fuzzy.cpp b/src/test/fuzz/deserialize.cpp index 859fba0bdc..859fba0bdc 100644 --- a/src/test/test_bitcoin_fuzzy.cpp +++ b/src/test/fuzz/deserialize.cpp diff --git a/src/test/fuzz/script_flags.cpp b/src/test/fuzz/script_flags.cpp new file mode 100644 index 0000000000..2c0bfa360c --- /dev/null +++ b/src/test/fuzz/script_flags.cpp @@ -0,0 +1,72 @@ +// Copyright (c) 2009-2019 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include <script/interpreter.h> +#include <script/script.h> +#include <streams.h> +#include <version.h> + +#include <test/fuzz/fuzz.h> + +/** Flags that are not forbidden by an assert */ +static bool IsValidFlagCombination(unsigned flags); + +void test_one_input(std::vector<uint8_t> buffer) +{ + CDataStream ds(buffer, SER_NETWORK, INIT_PROTO_VERSION); + try { + int nVersion; + ds >> nVersion; + ds.SetVersion(nVersion); + } catch (const std::ios_base::failure&) { + return; + } + + try { + const CTransaction tx(deserialize, ds); + const PrecomputedTransactionData txdata(tx); + + unsigned int verify_flags; + ds >> verify_flags; + + if (!IsValidFlagCombination(verify_flags)) return; + + unsigned int fuzzed_flags; + ds >> fuzzed_flags; + + for (unsigned i = 0; i < tx.vin.size(); ++i) { + CTxOut prevout; + ds >> prevout; + + const TransactionSignatureChecker checker{&tx, i, prevout.nValue, txdata}; + + ScriptError serror; + const bool ret = VerifyScript(tx.vin.at(i).scriptSig, prevout.scriptPubKey, &tx.vin.at(i).scriptWitness, verify_flags, checker, &serror); + assert(ret == (serror == SCRIPT_ERR_OK)); + + // Verify that removing flags from a passing test or adding flags to a failing test does not change the result + if (ret) { + verify_flags &= ~fuzzed_flags; + } else { + verify_flags |= fuzzed_flags; + } + if (!IsValidFlagCombination(verify_flags)) return; + + ScriptError serror_fuzzed; + const bool ret_fuzzed = VerifyScript(tx.vin.at(i).scriptSig, prevout.scriptPubKey, &tx.vin.at(i).scriptWitness, verify_flags, checker, &serror_fuzzed); + assert(ret_fuzzed == (serror_fuzzed == SCRIPT_ERR_OK)); + + assert(ret_fuzzed == ret); + } + } catch (const std::ios_base::failure&) { + return; + } +} + +static bool IsValidFlagCombination(unsigned flags) +{ + if (flags & SCRIPT_VERIFY_CLEANSTACK && ~flags & (SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS)) return false; + if (flags & SCRIPT_VERIFY_WITNESS && ~flags & SCRIPT_VERIFY_P2SH) return false; + return true; +} diff --git a/src/test/random_tests.cpp b/src/test/random_tests.cpp index 1057d09471..8194070aba 100644 --- a/src/test/random_tests.cpp +++ b/src/test/random_tests.cpp @@ -21,9 +21,14 @@ BOOST_AUTO_TEST_CASE(osrandom_tests) BOOST_AUTO_TEST_CASE(fastrandom_tests) { // Check that deterministic FastRandomContexts are deterministic + g_mock_deterministic_tests = true; FastRandomContext ctx1(true); FastRandomContext ctx2(true); + for (int i = 10; i > 0; --i) { + BOOST_CHECK_EQUAL(GetRand(std::numeric_limits<uint64_t>::max()), uint64_t{10393729187455219830U}); + BOOST_CHECK_EQUAL(GetRandInt(std::numeric_limits<int>::max()), int{769702006}); + } BOOST_CHECK_EQUAL(ctx1.rand32(), ctx2.rand32()); BOOST_CHECK_EQUAL(ctx1.rand32(), ctx2.rand32()); BOOST_CHECK_EQUAL(ctx1.rand64(), ctx2.rand64()); @@ -38,6 +43,11 @@ BOOST_AUTO_TEST_CASE(fastrandom_tests) BOOST_CHECK(ctx1.randbytes(50) == ctx2.randbytes(50)); // Check that a nondeterministic ones are not + g_mock_deterministic_tests = false; + for (int i = 10; i > 0; --i) { + BOOST_CHECK(GetRand(std::numeric_limits<uint64_t>::max()) != uint64_t{10393729187455219830U}); + BOOST_CHECK(GetRandInt(std::numeric_limits<int>::max()) != int{769702006}); + } { FastRandomContext ctx3, ctx4; BOOST_CHECK(ctx3.rand64() != ctx4.rand64()); // extremely unlikely to be equal diff --git a/src/test/test_bitcoin.h b/src/test/test_bitcoin.h index 71520232ac..4a06845683 100644 --- a/src/test/test_bitcoin.h +++ b/src/test/test_bitcoin.h @@ -35,6 +35,11 @@ std::ostream& operator<<(typename std::enable_if<std::is_enum<T>::value, std::os */ extern FastRandomContext g_insecure_rand_ctx; +/** + * Flag to make GetRand in random.h return the same number + */ +extern bool g_mock_deterministic_tests; + static inline void SeedInsecureRand(bool deterministic = false) { g_insecure_rand_ctx = FastRandomContext(deterministic); diff --git a/src/test/txindex_tests.cpp b/src/test/txindex_tests.cpp index 0301901bf0..d667c26c3c 100644 --- a/src/test/txindex_tests.cpp +++ b/src/test/txindex_tests.cpp @@ -69,7 +69,13 @@ BOOST_FIXTURE_TEST_CASE(txindex_initial_sync, TestChain100Setup) } } - txindex.Stop(); // Stop thread before calling destructor + // shutdown sequence (c.f. Shutdown() in init.cpp) + txindex.Stop(); + + threadGroup.interrupt_all(); + threadGroup.join_all(); + + // Rest of shutdown sequence and destructors happen in ~TestingSetup() } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/txvalidationcache_tests.cpp b/src/test/txvalidationcache_tests.cpp index c467f27836..4d04aae7e9 100644 --- a/src/test/txvalidationcache_tests.cpp +++ b/src/test/txvalidationcache_tests.cpp @@ -102,7 +102,7 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup) // should fail. // Capture this interaction with the upgraded_nop argument: set it when evaluating // any script flag that is implemented as an upgraded NOP code. -static void ValidateCheckInputsForAllFlags(const CTransaction &tx, uint32_t failing_flags, bool add_to_cache) +static void ValidateCheckInputsForAllFlags(const CTransaction &tx, uint32_t failing_flags, bool add_to_cache) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { PrecomputedTransactionData txdata(tx); // If we add many more flags, this loop can get too expensive, but we can @@ -219,11 +219,10 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup) CBlock block; block = CreateAndProcessBlock({spend_tx}, p2pk_scriptPubKey); + LOCK(cs_main); BOOST_CHECK(chainActive.Tip()->GetBlockHash() == block.GetHash()); BOOST_CHECK(pcoinsTip->GetBestBlock() == block.GetHash()); - LOCK(cs_main); - // Test P2SH: construct a transaction that is valid without P2SH, and // then test validity with P2SH. { diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index 71b6ec7425..860f64bb11 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -169,11 +169,6 @@ BOOST_AUTO_TEST_CASE(util_FormatISO8601Date) BOOST_CHECK_EQUAL(FormatISO8601Date(1317425777), "2011-09-30"); } -BOOST_AUTO_TEST_CASE(util_FormatISO8601Time) -{ - BOOST_CHECK_EQUAL(FormatISO8601Time(1317425777), "23:36:17Z"); -} - struct TestArgsManager : public ArgsManager { TestArgsManager() { m_network_only_args.clear(); } diff --git a/src/txmempool.h b/src/txmempool.h index b10c9f099f..f7afaec8fc 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -746,7 +746,8 @@ private: * This allows transaction replacement to work as expected, as you want to * have all inputs "available" to check signatures, and any cycles in the * dependency graph are checked directly in AcceptToMemoryPool. - * It also allows you to sign a double-spend directly in signrawtransaction, + * It also allows you to sign a double-spend directly in + * signrawtransactionwithkey and signrawtransactionwithwallet, * as long as the conflicting transaction is not yet confirmed. */ class CCoinsViewMemPool : public CCoinsViewBacked diff --git a/src/util/bip32.cpp b/src/util/bip32.cpp new file mode 100644 index 0000000000..6f176dd5ec --- /dev/null +++ b/src/util/bip32.cpp @@ -0,0 +1,66 @@ +// Copyright (c) 2019 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include <sstream> +#include <stdio.h> +#include <tinyformat.h> +#include <util/bip32.h> +#include <util/strencodings.h> + + +bool ParseHDKeypath(const std::string& keypath_str, std::vector<uint32_t>& keypath) +{ + std::stringstream ss(keypath_str); + std::string item; + bool first = true; + while (std::getline(ss, item, '/')) { + if (item.compare("m") == 0) { + if (first) { + first = false; + continue; + } + return false; + } + // Finds whether it is hardened + uint32_t path = 0; + size_t pos = item.find("'"); + if (pos != std::string::npos) { + // The hardened tick can only be in the last index of the string + if (pos != item.size() - 1) { + return false; + } + path |= 0x80000000; + item = item.substr(0, item.size() - 1); // Drop the last character which is the hardened tick + } + + // Ensure this is only numbers + if (item.find_first_not_of( "0123456789" ) != std::string::npos) { + return false; + } + uint32_t number; + if (!ParseUInt32(item, &number)) { + return false; + } + path |= number; + + keypath.push_back(path); + first = false; + } + return true; +} + +std::string FormatHDKeypath(const std::vector<uint32_t>& path) +{ + std::string ret; + for (auto i : path) { + ret += strprintf("/%i", (i << 1) >> 1); + if (i >> 31) ret += '\''; + } + return ret; +} + +std::string WriteHDKeypath(const std::vector<uint32_t>& keypath) +{ + return "m" + FormatHDKeypath(keypath); +} diff --git a/src/util/bip32.h b/src/util/bip32.h new file mode 100644 index 0000000000..7e58b79f38 --- /dev/null +++ b/src/util/bip32.h @@ -0,0 +1,19 @@ +// Copyright (c) 2019 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_UTIL_BIP32_H +#define BITCOIN_UTIL_BIP32_H + +#include <attributes.h> +#include <string> +#include <vector> + +/** Parse an HD keypaths like "m/7/0'/2000". */ +NODISCARD bool ParseHDKeypath(const std::string& keypath_str, std::vector<uint32_t>& keypath); + +/** Write HD keypaths as strings */ +std::string WriteHDKeypath(const std::vector<uint32_t>& keypath); +std::string FormatHDKeypath(const std::vector<uint32_t>& path); + +#endif // BITCOIN_UTIL_BIP32_H diff --git a/src/util/strencodings.cpp b/src/util/strencodings.cpp index fedeeac39b..0acbb4f117 100644 --- a/src/util/strencodings.cpp +++ b/src/util/strencodings.cpp @@ -141,7 +141,7 @@ std::string EncodeBase64(const std::string& str) return EncodeBase64((const unsigned char*)str.c_str(), str.size()); } -std::vector<unsigned char> DecodeBase64(const char* p, bool* pfInvalid) +std::vector<unsigned char> DecodeBase64(const char* p, bool* pf_invalid) { static const int decode64_table[256] = { @@ -183,14 +183,14 @@ std::vector<unsigned char> DecodeBase64(const char* p, bool* pfInvalid) ++p; } valid = valid && (p - e) % 4 == 0 && p - q < 4; - if (pfInvalid) *pfInvalid = !valid; + if (pf_invalid) *pf_invalid = !valid; return ret; } -std::string DecodeBase64(const std::string& str) +std::string DecodeBase64(const std::string& str, bool* pf_invalid) { - std::vector<unsigned char> vchRet = DecodeBase64(str.c_str()); + std::vector<unsigned char> vchRet = DecodeBase64(str.c_str(), pf_invalid); return std::string((const char*)vchRet.data(), vchRet.size()); } @@ -210,7 +210,7 @@ std::string EncodeBase32(const std::string& str) return EncodeBase32((const unsigned char*)str.c_str(), str.size()); } -std::vector<unsigned char> DecodeBase32(const char* p, bool* pfInvalid) +std::vector<unsigned char> DecodeBase32(const char* p, bool* pf_invalid) { static const int decode32_table[256] = { @@ -252,14 +252,14 @@ std::vector<unsigned char> DecodeBase32(const char* p, bool* pfInvalid) ++p; } valid = valid && (p - e) % 8 == 0 && p - q < 8; - if (pfInvalid) *pfInvalid = !valid; + if (pf_invalid) *pf_invalid = !valid; return ret; } -std::string DecodeBase32(const std::string& str) +std::string DecodeBase32(const std::string& str, bool* pf_invalid) { - std::vector<unsigned char> vchRet = DecodeBase32(str.c_str()); + std::vector<unsigned char> vchRet = DecodeBase32(str.c_str(), pf_invalid); return std::string((const char*)vchRet.data(), vchRet.size()); } @@ -546,47 +546,6 @@ bool ParseFixedPoint(const std::string &val, int decimals, int64_t *amount_out) return true; } -bool ParseHDKeypath(const std::string& keypath_str, std::vector<uint32_t>& keypath) -{ - std::stringstream ss(keypath_str); - std::string item; - bool first = true; - while (std::getline(ss, item, '/')) { - if (item.compare("m") == 0) { - if (first) { - first = false; - continue; - } - return false; - } - // Finds whether it is hardened - uint32_t path = 0; - size_t pos = item.find("'"); - if (pos != std::string::npos) { - // The hardened tick can only be in the last index of the string - if (pos != item.size() - 1) { - return false; - } - path |= 0x80000000; - item = item.substr(0, item.size() - 1); // Drop the last character which is the hardened tick - } - - // Ensure this is only numbers - if (item.find_first_not_of( "0123456789" ) != std::string::npos) { - return false; - } - uint32_t number; - if (!ParseUInt32(item, &number)) { - return false; - } - path |= number; - - keypath.push_back(path); - first = false; - } - return true; -} - void Downcase(std::string& str) { std::transform(str.begin(), str.end(), str.begin(), [](char c){return ToLower(c);}); diff --git a/src/util/strencodings.h b/src/util/strencodings.h index e392055f27..cf77044094 100644 --- a/src/util/strencodings.h +++ b/src/util/strencodings.h @@ -44,12 +44,12 @@ bool IsHex(const std::string& str); * Return true if the string is a hex number, optionally prefixed with "0x" */ bool IsHexNumber(const std::string& str); -std::vector<unsigned char> DecodeBase64(const char* p, bool* pfInvalid = nullptr); -std::string DecodeBase64(const std::string& str); +std::vector<unsigned char> DecodeBase64(const char* p, bool* pf_invalid = nullptr); +std::string DecodeBase64(const std::string& str, bool* pf_invalid = nullptr); std::string EncodeBase64(const unsigned char* pch, size_t len); std::string EncodeBase64(const std::string& str); -std::vector<unsigned char> DecodeBase32(const char* p, bool* pfInvalid = nullptr); -std::string DecodeBase32(const std::string& str); +std::vector<unsigned char> DecodeBase32(const char* p, bool* pf_invalid = nullptr); +std::string DecodeBase32(const std::string& str, bool* pf_invalid = nullptr); std::string EncodeBase32(const unsigned char* pch, size_t len); std::string EncodeBase32(const std::string& str); @@ -197,9 +197,6 @@ bool ConvertBits(const O& outfn, I it, I end) { return true; } -/** Parse an HD keypaths like "m/7/0'/2000". */ -NODISCARD bool ParseHDKeypath(const std::string& keypath_str, std::vector<uint32_t>& keypath); - /** * Converts the given character to its lowercase equivalent. * This function is locale independent. It only converts uppercase diff --git a/src/util/system.cpp b/src/util/system.cpp index 06317a3a90..6e82de743a 100644 --- a/src/util/system.cpp +++ b/src/util/system.cpp @@ -44,11 +44,6 @@ #pragma warning(disable:4717) #endif -#ifdef _WIN32_WINNT -#undef _WIN32_WINNT -#endif -#define _WIN32_WINNT 0x0501 - #ifdef _WIN32_IE #undef _WIN32_IE #endif @@ -79,7 +74,6 @@ const int64_t nStartupTime = GetTime(); const char * const BITCOIN_CONF_FILENAME = "bitcoin.conf"; -const char * const BITCOIN_PID_FILENAME = "bitcoind.pid"; ArgsManager gArgs; @@ -116,6 +110,12 @@ bool LockDirectory(const fs::path& directory, const std::string lockfile_name, b return true; } +void UnlockDirectory(const fs::path& directory, const std::string& lockfile_name) +{ + std::lock_guard<std::mutex> lock(cs_dir_locks); + dir_locks.erase((directory / lockfile_name).string()); +} + void ReleaseDirectoryLocks() { std::lock_guard<std::mutex> ulock(cs_dir_locks); @@ -634,6 +634,12 @@ bool HelpRequested(const ArgsManager& args) return args.IsArgSet("-?") || args.IsArgSet("-h") || args.IsArgSet("-help") || args.IsArgSet("-help-debug"); } +void SetupHelpOptions(ArgsManager& args) +{ + args.AddArg("-?", "Print this help message and exit", false, OptionsCategory::OPTIONS); + args.AddHiddenArgs({"-h", "-help"}); +} + static const int screenWidth = 79; static const int optIndent = 2; static const int msgIndent = 7; @@ -958,23 +964,6 @@ std::string ArgsManager::GetChainName() const return CBaseChainParams::MAIN; } -#ifndef WIN32 -fs::path GetPidFile() -{ - return AbsPathForConfigVal(fs::path(gArgs.GetArg("-pid", BITCOIN_PID_FILENAME))); -} - -void CreatePidFile(const fs::path &path, pid_t pid) -{ - FILE* file = fsbridge::fopen(path, "w"); - if (file) - { - fprintf(file, "%d\n", pid); - fclose(file); - } -} -#endif - bool RenameOver(fs::path src, fs::path dest) { #ifdef WIN32 diff --git a/src/util/system.h b/src/util/system.h index 5932e55793..69ae11d1ed 100644 --- a/src/util/system.h +++ b/src/util/system.h @@ -16,6 +16,7 @@ #include <attributes.h> #include <compat.h> +#include <compat/assumptions.h> #include <fs.h> #include <logging.h> #include <sync.h> @@ -39,7 +40,6 @@ int64_t GetStartupTime(); extern const char * const BITCOIN_CONF_FILENAME; -extern const char * const BITCOIN_PID_FILENAME; /** Translate a message to the native language of the user. */ const extern std::function<std::string(const char*)> G_TRANSLATION_FUN; @@ -70,6 +70,7 @@ int RaiseFileDescriptorLimit(int nMinFD); void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length); bool RenameOver(fs::path src, fs::path dest); bool LockDirectory(const fs::path& directory, const std::string lockfile_name, bool probe_only=false); +void UnlockDirectory(const fs::path& directory, const std::string& lockfile_name); bool DirIsWritable(const fs::path& directory); /** Release all directory locks. This is used for unit testing only, at runtime @@ -84,10 +85,6 @@ const fs::path &GetBlocksDir(); const fs::path &GetDataDir(bool fNetSpecific = true); void ClearDatadirCache(); fs::path GetConfigFile(const std::string& confPath); -#ifndef WIN32 -fs::path GetPidFile(); -void CreatePidFile(const fs::path &path, pid_t pid); -#endif #ifdef WIN32 fs::path GetSpecialFolderPath(int nFolder, bool fCreate = true); #endif @@ -294,6 +291,9 @@ extern ArgsManager gArgs; */ bool HelpRequested(const ArgsManager& args); +/** Add help options to the args manager */ +void SetupHelpOptions(ArgsManager& args); + /** * Format a string to be used as group of options in help messages * diff --git a/src/util/time.cpp b/src/util/time.cpp index 83a7937d8f..c0ede98701 100644 --- a/src/util/time.cpp +++ b/src/util/time.cpp @@ -97,14 +97,3 @@ std::string FormatISO8601Date(int64_t nTime) { #endif return strprintf("%04i-%02i-%02i", ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday); } - -std::string FormatISO8601Time(int64_t nTime) { - struct tm ts; - time_t time_val = nTime; -#ifdef _MSC_VER - gmtime_s(&ts, &time_val); -#else - gmtime_r(&time_val, &ts); -#endif - return strprintf("%02i:%02i:%02iZ", ts.tm_hour, ts.tm_min, ts.tm_sec); -} diff --git a/src/util/time.h b/src/util/time.h index f2e2747434..68de1c156e 100644 --- a/src/util/time.h +++ b/src/util/time.h @@ -33,6 +33,5 @@ void MilliSleep(int64_t n); */ std::string FormatISO8601DateTime(int64_t nTime); std::string FormatISO8601Date(int64_t nTime); -std::string FormatISO8601Time(int64_t nTime); #endif // BITCOIN_UTIL_TIME_H diff --git a/src/validation.cpp b/src/validation.cpp index de9c0d96db..f3d34dca70 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -152,7 +152,7 @@ private: public: CChain chainActive; - BlockMap mapBlockIndex; + BlockMap mapBlockIndex GUARDED_BY(cs_main); std::multimap<CBlockIndex*, CBlockIndex*> mapBlocksUnlinked; CBlockIndex *pindexBestInvalid = nullptr; @@ -2259,12 +2259,6 @@ void static UpdateTip(const CBlockIndex *pindexNew, const CChainParams& chainPar } if (nUpgraded > 0) AppendWarning(warningMessages, strprintf(_("%d of last 100 blocks have unexpected version"), nUpgraded)); - if (nUpgraded > 100/2) - { - std::string strWarning = _("Warning: Unknown block versions being mined! It's possible unknown rules are in effect"); - // notify GetWarnings(), called by Qt and the JSON-RPC code to warn the user: - DoWarning(strWarning); - } } LogPrintf("%s: new best=%s height=%d version=0x%08x log2_work=%.8g tx=%lu date='%s' progress=%f cache=%.1fMiB(%utxo)", __func__, /* Continued */ pindexNew->GetBlockHash().ToString(), pindexNew->nHeight, pindexNew->nVersion, @@ -4347,7 +4341,7 @@ bool CChainState::LoadGenesisBlock(const CChainParams& chainparams) return true; try { - CBlock &block = const_cast<CBlock&>(chainparams.GenesisBlock()); + const CBlock& block = chainparams.GenesisBlock(); CDiskBlockPos blockPos = SaveBlockToDisk(block, 0, chainparams, nullptr); if (blockPos.IsNull()) return error("%s: writing genesis block to disk failed", __func__); diff --git a/src/validation.h b/src/validation.h index b16d8438d7..1975846b69 100644 --- a/src/validation.h +++ b/src/validation.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2018 The Bitcoin Core developers +// Copyright (c) 2009-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -14,8 +14,8 @@ #include <coins.h> #include <crypto/common.h> // for ReadLE64 #include <fs.h> -#include <protocol.h> // For CMessageHeader::MessageStartChars #include <policy/feerate.h> +#include <protocol.h> // For CMessageHeader::MessageStartChars #include <script/script_error.h> #include <sync.h> #include <versionbits.h> @@ -151,9 +151,7 @@ extern CBlockPolicyEstimator feeEstimator; extern CTxMemPool mempool; extern std::atomic_bool g_is_mempool_loaded; typedef std::unordered_map<uint256, CBlockIndex*, BlockHasher> BlockMap; -extern BlockMap& mapBlockIndex; -extern uint64_t nLastBlockTx; -extern uint64_t nLastBlockWeight; +extern BlockMap& mapBlockIndex GUARDED_BY(cs_main); extern const std::string strMessageMagic; extern Mutex g_best_block_mutex; extern std::condition_variable g_best_block_cv; @@ -288,7 +286,7 @@ uint64_t CalculateCurrentUsage(); /** * Mark one block file as pruned. */ -void PruneOneBlockFile(const int fileNumber); +void PruneOneBlockFile(const int fileNumber) EXCLUSIVE_LOCKS_REQUIRED(cs_main); /** * Actually unlink the specified files diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp index 533d412888..70c274d20e 100644 --- a/src/validationinterface.cpp +++ b/src/validationinterface.cpp @@ -14,6 +14,7 @@ #include <list> #include <atomic> #include <future> +#include <utility> #include <boost/signals2/signal.hpp> @@ -77,7 +78,10 @@ size_t CMainSignals::CallbacksPending() { } void CMainSignals::RegisterWithMempoolSignals(CTxMemPool& pool) { - g_connNotifyEntryRemoved.emplace(&pool, pool.NotifyEntryRemoved.connect(std::bind(&CMainSignals::MempoolEntryRemoved, this, std::placeholders::_1, std::placeholders::_2))); + g_connNotifyEntryRemoved.emplace(std::piecewise_construct, + std::forward_as_tuple(&pool), + std::forward_as_tuple(pool.NotifyEntryRemoved.connect(std::bind(&CMainSignals::MempoolEntryRemoved, this, std::placeholders::_1, std::placeholders::_2))) + ); } void CMainSignals::UnregisterWithMempoolSignals(CTxMemPool& pool) { @@ -103,7 +107,9 @@ void RegisterValidationInterface(CValidationInterface* pwalletIn) { } void UnregisterValidationInterface(CValidationInterface* pwalletIn) { - g_signals.m_internals->m_connMainSignals.erase(pwalletIn); + if (g_signals.m_internals) { + g_signals.m_internals->m_connMainSignals.erase(pwalletIn); + } } void UnregisterAllValidationInterfaces() { diff --git a/src/wallet/crypter.cpp b/src/wallet/crypter.cpp index 1dc78255f6..a255177e36 100644 --- a/src/wallet/crypter.cpp +++ b/src/wallet/crypter.cpp @@ -182,7 +182,7 @@ bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn, bool accept_no if (!SetCrypted()) return false; - bool keyPass = false; + bool keyPass = mapCryptedKeys.empty(); // Always pass when there are no encrypted keys bool keyFail = false; CryptedKeyMap::const_iterator mi = mapCryptedKeys.begin(); for (; mi != mapCryptedKeys.end(); ++mi) diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp index ae40553268..99d880daa0 100644 --- a/src/wallet/db.cpp +++ b/src/wallet/db.cpp @@ -126,11 +126,18 @@ void BerkeleyEnvironment::Close() } } + FILE* error_file = nullptr; + dbenv->get_errfile(&error_file); + int ret = dbenv->close(0); if (ret != 0) LogPrintf("BerkeleyEnvironment::Close: Error %d closing database environment: %s\n", ret, DbEnv::strerror(ret)); if (!fMockDb) DbEnv((u_int32_t)0).remove(strPath.c_str(), 0); + + if (error_file) fclose(error_file); + + UnlockDirectory(strPath, ".walletlock"); } void BerkeleyEnvironment::Reset() @@ -147,6 +154,7 @@ BerkeleyEnvironment::BerkeleyEnvironment(const fs::path& dir_path) : strPath(dir BerkeleyEnvironment::~BerkeleyEnvironment() { + LOCK(cs_db); g_dbenvs.erase(strPath); Close(); } @@ -389,7 +397,7 @@ bool BerkeleyBatch::VerifyEnvironment(const fs::path& file_path, std::string& er fs::path walletDir = env->Directory(); LogPrintf("Using BerkeleyDB version %s\n", DbEnv::version(nullptr, nullptr, nullptr)); - LogPrintf("Using wallet %s\n", walletFile); + LogPrintf("Using wallet %s\n", file_path.string()); // Wallet file must be a plain filename without a directory if (walletFile != fs::basename(walletFile) + fs::extension(walletFile)) diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp index 87cd264c3d..20d540c8db 100644 --- a/src/wallet/init.cpp +++ b/src/wallet/init.cpp @@ -127,21 +127,6 @@ bool WalletInit::ParameterInteraction() const InitWarning(AmountHighWarn("-minrelaytxfee") + " " + _("The wallet will avoid paying less than the minimum relay fee.")); - if (gArgs.IsArgSet("-maxtxfee")) - { - CAmount nMaxFee = 0; - if (!ParseMoney(gArgs.GetArg("-maxtxfee", ""), nMaxFee)) - return InitError(AmountErrMsg("maxtxfee", gArgs.GetArg("-maxtxfee", ""))); - if (nMaxFee > HIGH_MAX_TX_FEE) - InitWarning(_("-maxtxfee is set very high! Fees this large could be paid on a single transaction.")); - maxTxFee = nMaxFee; - if (CFeeRate(maxTxFee, 1000) < ::minRelayTxFee) - { - return InitError(strprintf(_("Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)"), - gArgs.GetArg("-maxtxfee", ""), ::minRelayTxFee.ToString())); - } - } - return true; } diff --git a/src/wallet/psbtwallet.cpp b/src/wallet/psbtwallet.cpp new file mode 100644 index 0000000000..1b17b09763 --- /dev/null +++ b/src/wallet/psbtwallet.cpp @@ -0,0 +1,60 @@ +// Copyright (c) 2009-2018 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include <wallet/psbtwallet.h> + +TransactionError FillPSBT(const CWallet* pwallet, PartiallySignedTransaction& psbtx, bool& complete, int sighash_type, bool sign, bool bip32derivs) +{ + LOCK(pwallet->cs_wallet); + // Get all of the previous transactions + complete = true; + for (unsigned int i = 0; i < psbtx.tx->vin.size(); ++i) { + const CTxIn& txin = psbtx.tx->vin[i]; + PSBTInput& input = psbtx.inputs.at(i); + + if (PSBTInputSigned(input)) { + continue; + } + + // Verify input looks sane. This will check that we have at most one uxto, witness or non-witness. + if (!input.IsSane()) { + return TransactionError::INVALID_PSBT; + } + + // If we have no utxo, grab it from the wallet. + if (!input.non_witness_utxo && input.witness_utxo.IsNull()) { + const uint256& txhash = txin.prevout.hash; + const auto it = pwallet->mapWallet.find(txhash); + if (it != pwallet->mapWallet.end()) { + const CWalletTx& wtx = it->second; + // We only need the non_witness_utxo, which is a superset of the witness_utxo. + // The signing code will switch to the smaller witness_utxo if this is ok. + input.non_witness_utxo = wtx.tx; + } + } + + // Get the Sighash type + if (sign && input.sighash_type > 0 && input.sighash_type != sighash_type) { + return TransactionError::SIGHASH_MISMATCH; + } + + complete &= SignPSBTInput(HidingSigningProvider(pwallet, !sign, !bip32derivs), psbtx, i, sighash_type); + } + + // Fill in the bip32 keypaths and redeemscripts for the outputs so that hardware wallets can identify change + for (unsigned int i = 0; i < psbtx.tx->vout.size(); ++i) { + const CTxOut& out = psbtx.tx->vout.at(i); + PSBTOutput& psbt_out = psbtx.outputs.at(i); + + // Fill a SignatureData with output info + SignatureData sigdata; + psbt_out.FillSignatureData(sigdata); + + MutableTransactionSignatureCreator creator(psbtx.tx.get_ptr(), 0, out.nValue, 1); + ProduceSignature(HidingSigningProvider(pwallet, true, !bip32derivs), creator, out.scriptPubKey, sigdata); + psbt_out.FromSignatureData(sigdata); + } + + return TransactionError::OK; +} diff --git a/src/wallet/psbtwallet.h b/src/wallet/psbtwallet.h new file mode 100644 index 0000000000..a24a0967d2 --- /dev/null +++ b/src/wallet/psbtwallet.h @@ -0,0 +1,34 @@ +// Copyright (c) 2009-2019 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_WALLET_PSBTWALLET_H +#define BITCOIN_WALLET_PSBTWALLET_H + +#include <node/transaction.h> +#include <psbt.h> +#include <primitives/transaction.h> +#include <wallet/wallet.h> + +/** + * Fills out a PSBT with information from the wallet. Fills in UTXOs if we have + * them. Tries to sign if sign=true. Sets `complete` if the PSBT is now complete + * (i.e. has all required signatures or signature-parts, and is ready to + * finalize.) Sets `error` and returns false if something goes wrong. + * + * @param[in] pwallet pointer to a wallet + * @param[in] &psbtx reference to PartiallySignedTransaction to fill in + * @param[out] &complete indicates whether the PSBT is now complete + * @param[in] sighash_type the sighash type to use when signing (if PSBT does not specify) + * @param[in] sign whether to sign or not + * @param[in] bip32derivs whether to fill in bip32 derivation information if available + * return error + */ +NODISCARD TransactionError FillPSBT(const CWallet* pwallet, + PartiallySignedTransaction& psbtx, + bool& complete, + int sighash_type = 1 /* SIGHASH_ALL */, + bool sign = true, + bool bip32derivs = false); + +#endif // BITCOIN_WALLET_PSBTWALLET_H diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index 2e62a6979f..5b0592e06d 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -9,9 +9,11 @@ #include <merkleblock.h> #include <rpc/server.h> #include <rpc/util.h> +#include <script/descriptor.h> #include <script/script.h> #include <script/standard.h> #include <sync.h> +#include <util/bip32.h> #include <util/system.h> #include <util/time.h> #include <validation.h> @@ -66,7 +68,7 @@ static std::string DecodeDumpString(const std::string &str) { return ret.str(); } -static bool GetWalletAddressesForKey(CWallet * const pwallet, const CKeyID &keyid, std::string &strAddr, std::string &strLabel) +static bool GetWalletAddressesForKey(CWallet* const pwallet, const CKeyID& keyid, std::string& strAddr, std::string& strLabel) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet) { bool fLabelFound = false; CKey key; @@ -115,9 +117,9 @@ UniValue importprivkey(const JSONRPCRequest& request) "\nNote: This call can take over an hour to complete if rescan is true, during that time, other rpc calls\n" "may report that the imported key exists but related transactions are still missing, leading to temporarily incorrect/bogus balances and unspent outputs until rescan completes.\n", { - {"privkey", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The private key (see dumpprivkey)"}, - {"label", RPCArg::Type::STR, /* opt */ true, /* default_val */ "current label if address exists, otherwise \"\"", "An optional label"}, - {"rescan", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "true", "Rescan the wallet for transactions"}, + {"privkey", RPCArg::Type::STR, RPCArg::Optional::NO, "The private key (see dumpprivkey)"}, + {"label", RPCArg::Type::STR, /* default */ "current label if address exists, otherwise \"\"", "An optional label"}, + {"rescan", RPCArg::Type::BOOL, /* default */ "true", "Rescan the wallet for transactions"}, }, RPCResults{}, RPCExamples{ @@ -134,6 +136,9 @@ UniValue importprivkey(const JSONRPCRequest& request) }, }.ToString()); + if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) { + throw JSONRPCError(RPC_WALLET_ERROR, "Cannot import private keys to a wallet with private keys disabled"); + } WalletRescanReserver reserver(pwallet); bool fRescan = true; @@ -282,10 +287,10 @@ UniValue importaddress(const JSONRPCRequest& request) "\nNote: If you import a non-standard raw script in hex form, outputs sending to it will be treated\n" "as change, and not show up in many RPCs.\n", { - {"address", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The Bitcoin address (or hex-encoded script)"}, - {"label", RPCArg::Type::STR, /* opt */ true, /* default_val */ "\"\"", "An optional label"}, - {"rescan", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "true", "Rescan the wallet for transactions"}, - {"p2sh", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "Add the P2SH version of the script as well"}, + {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The Bitcoin address (or hex-encoded script)"}, + {"label", RPCArg::Type::STR, /* default */ "\"\"", "An optional label"}, + {"rescan", RPCArg::Type::BOOL, /* default */ "true", "Rescan the wallet for transactions"}, + {"p2sh", RPCArg::Type::BOOL, /* default */ "false", "Add the P2SH version of the script as well"}, }, RPCResults{}, RPCExamples{ @@ -360,8 +365,8 @@ UniValue importprunedfunds(const JSONRPCRequest& request) RPCHelpMan{"importprunedfunds", "\nImports funds without rescan. Corresponding address or script must previously be included in wallet. Aimed towards pruned wallets. The end-user is responsible to import additional transactions that subsequently spend the imported outputs or rescan after the point in the blockchain the transaction is included.\n", { - {"rawtransaction", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "A raw transaction in hex funding an already-existing address in wallet"}, - {"txoutproof", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "The hex output from gettxoutproof that contains the transaction"}, + {"rawtransaction", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "A raw transaction in hex funding an already-existing address in wallet"}, + {"txoutproof", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hex output from gettxoutproof that contains the transaction"}, }, RPCResults{}, RPCExamples{""}, @@ -427,7 +432,7 @@ UniValue removeprunedfunds(const JSONRPCRequest& request) RPCHelpMan{"removeprunedfunds", "\nDeletes the specified transaction from the wallet. Meant for use with pruned wallets and as a companion to importprunedfunds. This will affect wallet balances.\n", { - {"txid", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "The hex-encoded id of the transaction you are deleting"}, + {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hex-encoded id of the transaction you are deleting"}, }, RPCResults{}, RPCExamples{ @@ -471,9 +476,9 @@ UniValue importpubkey(const JSONRPCRequest& request) "\nNote: This call can take over an hour to complete if rescan is true, during that time, other rpc calls\n" "may report that the imported pubkey exists but related transactions are still missing, leading to temporarily incorrect/bogus balances and unspent outputs until rescan completes.\n", { - {"pubkey", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The hex-encoded public key"}, - {"label", RPCArg::Type::STR, /* opt */ true, /* default_val */ "\"\"", "An optional label"}, - {"rescan", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "true", "Rescan the wallet for transactions"}, + {"pubkey", RPCArg::Type::STR, RPCArg::Optional::NO, "The hex-encoded public key"}, + {"label", RPCArg::Type::STR, /* default */ "\"\"", "An optional label"}, + {"rescan", RPCArg::Type::BOOL, /* default */ "true", "Rescan the wallet for transactions"}, }, RPCResults{}, RPCExamples{ @@ -544,7 +549,7 @@ UniValue importwallet(const JSONRPCRequest& request) RPCHelpMan{"importwallet", "\nImports keys from a wallet dump file (see dumpwallet). Requires a new wallet backup to include imported keys.\n", { - {"filename", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The wallet file"}, + {"filename", RPCArg::Type::STR, RPCArg::Optional::NO, "The wallet file"}, }, RPCResults{}, RPCExamples{ @@ -587,8 +592,10 @@ UniValue importwallet(const JSONRPCRequest& request) // Use uiInterface.ShowProgress instead of pwallet.ShowProgress because pwallet.ShowProgress has a cancel button tied to AbortRescan which // we don't want for this progress bar showing the import progress. uiInterface.ShowProgress does not have a cancel button. uiInterface.ShowProgress(strprintf("%s " + _("Importing..."), pwallet->GetDisplayName()), 0, false); // show progress dialog in GUI + std::vector<std::tuple<CKey, int64_t, bool, std::string>> keys; + std::vector<std::pair<CScript, int64_t>> scripts; while (file.good()) { - uiInterface.ShowProgress("", std::max(1, std::min(99, (int)(((double)file.tellg() / (double)nFilesize) * 100))), false); + uiInterface.ShowProgress("", std::max(1, std::min(50, (int)(((double)file.tellg() / (double)nFilesize) * 100))), false); std::string line; std::getline(file, line); if (line.empty() || line[0] == '#') @@ -600,13 +607,6 @@ UniValue importwallet(const JSONRPCRequest& request) continue; CKey key = DecodeSecret(vstr[0]); if (key.IsValid()) { - CPubKey pubkey = key.GetPubKey(); - assert(key.VerifyPubKey(pubkey)); - CKeyID keyid = pubkey.GetID(); - if (pwallet->HaveKey(keyid)) { - pwallet->WalletLogPrintf("Skipping import of %s (key already present)\n", EncodeDestination(keyid)); - continue; - } int64_t nTime = DecodeDumpTime(vstr[1]); std::string strLabel; bool fLabel = true; @@ -622,36 +622,67 @@ UniValue importwallet(const JSONRPCRequest& request) fLabel = true; } } - pwallet->WalletLogPrintf("Importing %s...\n", EncodeDestination(keyid)); - if (!pwallet->AddKeyPubKey(key, pubkey)) { - fGood = false; - continue; - } - pwallet->mapKeyMetadata[keyid].nCreateTime = nTime; - if (fLabel) - pwallet->SetAddressBook(keyid, strLabel, "receive"); - nTimeBegin = std::min(nTimeBegin, nTime); + keys.push_back(std::make_tuple(key, nTime, fLabel, strLabel)); } else if(IsHex(vstr[0])) { - std::vector<unsigned char> vData(ParseHex(vstr[0])); - CScript script = CScript(vData.begin(), vData.end()); - CScriptID id(script); - if (pwallet->HaveCScript(id)) { - pwallet->WalletLogPrintf("Skipping import of %s (script already present)\n", vstr[0]); - continue; - } - if(!pwallet->AddCScript(script)) { - pwallet->WalletLogPrintf("Error importing script %s\n", vstr[0]); - fGood = false; - continue; - } - int64_t birth_time = DecodeDumpTime(vstr[1]); - if (birth_time > 0) { - pwallet->m_script_metadata[id].nCreateTime = birth_time; - nTimeBegin = std::min(nTimeBegin, birth_time); - } + std::vector<unsigned char> vData(ParseHex(vstr[0])); + CScript script = CScript(vData.begin(), vData.end()); + int64_t birth_time = DecodeDumpTime(vstr[1]); + scripts.push_back(std::pair<CScript, int64_t>(script, birth_time)); } } file.close(); + // We now know whether we are importing private keys, so we can error if private keys are disabled + if (keys.size() > 0 && pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) { + uiInterface.ShowProgress("", 100, false); // hide progress dialog in GUI + throw JSONRPCError(RPC_WALLET_ERROR, "Importing wallets is disabled when private keys are disabled"); + } + double total = (double)(keys.size() + scripts.size()); + double progress = 0; + for (const auto& key_tuple : keys) { + uiInterface.ShowProgress("", std::max(50, std::min(75, (int)((progress / total) * 100) + 50)), false); + const CKey& key = std::get<0>(key_tuple); + int64_t time = std::get<1>(key_tuple); + bool has_label = std::get<2>(key_tuple); + std::string label = std::get<3>(key_tuple); + + CPubKey pubkey = key.GetPubKey(); + assert(key.VerifyPubKey(pubkey)); + CKeyID keyid = pubkey.GetID(); + if (pwallet->HaveKey(keyid)) { + pwallet->WalletLogPrintf("Skipping import of %s (key already present)\n", EncodeDestination(keyid)); + continue; + } + pwallet->WalletLogPrintf("Importing %s...\n", EncodeDestination(keyid)); + if (!pwallet->AddKeyPubKey(key, pubkey)) { + fGood = false; + continue; + } + pwallet->mapKeyMetadata[keyid].nCreateTime = time; + if (has_label) + pwallet->SetAddressBook(keyid, label, "receive"); + nTimeBegin = std::min(nTimeBegin, time); + progress++; + } + for (const auto& script_pair : scripts) { + uiInterface.ShowProgress("", std::max(50, std::min(75, (int)((progress / total) * 100) + 50)), false); + const CScript& script = script_pair.first; + int64_t time = script_pair.second; + CScriptID id(script); + if (pwallet->HaveCScript(id)) { + pwallet->WalletLogPrintf("Skipping import of %s (script already present)\n", HexStr(script)); + continue; + } + if(!pwallet->AddCScript(script)) { + pwallet->WalletLogPrintf("Error importing script %s\n", HexStr(script)); + fGood = false; + continue; + } + if (time > 0) { + pwallet->m_script_metadata[id].nCreateTime = time; + nTimeBegin = std::min(nTimeBegin, time); + } + progress++; + } uiInterface.ShowProgress("", 100, false); // hide progress dialog in GUI pwallet->UpdateTimeFirstKey(nTimeBegin); } @@ -679,7 +710,7 @@ UniValue dumpprivkey(const JSONRPCRequest& request) "\nReveals the private key corresponding to 'address'.\n" "Then the importprivkey can be used with this output\n", { - {"address", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The bitcoin address for the private key"}, + {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The bitcoin address for the private key"}, }, RPCResult{ "\"key\" (string) The private key\n" @@ -729,7 +760,7 @@ UniValue dumpwallet(const JSONRPCRequest& request) "Note that if your wallet contains keys which are not derived from your HD seed (e.g. imported keys), these are not covered by\n" "only backing up the seed itself, and must be backed up too (e.g. ensure you back up the whole dumpfile).\n", { - {"filename", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The filename with path (either absolute or relative to bitcoind)"}, + {"filename", RPCArg::Type::STR, RPCArg::Optional::NO, "The filename with path (either absolute or relative to bitcoind)"}, }, RPCResult{ "{ (json object)\n" @@ -785,7 +816,7 @@ UniValue dumpwallet(const JSONRPCRequest& request) file << strprintf("# Wallet dump created by Bitcoin %s\n", CLIENT_BUILD); file << strprintf("# * Created on %s\n", FormatISO8601DateTime(GetTime())); const Optional<int> tip_height = locked_chain->getHeight(); - file << strprintf("# * Best block at time of backup was %i (%s),\n", tip_height.value_or(-1), tip_height ? locked_chain->getBlockHash(*tip_height).ToString() : "(missing block hash)"); + file << strprintf("# * Best block at time of backup was %i (%s),\n", tip_height.get_value_or(-1), tip_height ? locked_chain->getBlockHash(*tip_height).ToString() : "(missing block hash)"); file << strprintf("# mined on %s\n", tip_height ? FormatISO8601DateTime(locked_chain->getBlockTime(*tip_height)) : "(missing block time)"); file << "\n"; @@ -820,7 +851,7 @@ UniValue dumpwallet(const JSONRPCRequest& request) } else { file << "change=1"; } - file << strprintf(" # addr=%s%s\n", strAddr, (pwallet->mapKeyMetadata[keyid].hdKeypath.size() > 0 ? " hdkeypath="+pwallet->mapKeyMetadata[keyid].hdKeypath : "")); + file << strprintf(" # addr=%s%s\n", strAddr, (pwallet->mapKeyMetadata[keyid].has_key_origin ? " hdkeypath="+WriteHDKeypath(pwallet->mapKeyMetadata[keyid].key_origin.path) : "")); } } file << "\n"; @@ -857,6 +888,7 @@ struct ImportData // Output data std::set<CScript> import_scripts; std::map<CKeyID, bool> used_keys; //!< Import these private keys if available (the value indicates whether if the key is required for solvability) + std::map<CKeyID, KeyOriginInfo> key_origins; }; enum class ScriptContext @@ -935,154 +967,281 @@ static std::string RecurseImportData(const CScript& script, ImportData& import_d } } -static UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet) +static UniValue ProcessImportLegacy(ImportData& import_data, std::map<CKeyID, CPubKey>& pubkey_map, std::map<CKeyID, CKey>& privkey_map, std::set<CScript>& script_pub_keys, bool& have_solving_data, const UniValue& data, std::vector<CKeyID>& ordered_pubkeys) { UniValue warnings(UniValue::VARR); - UniValue result(UniValue::VOBJ); - try { - // First ensure scriptPubKey has either a script or JSON with "address" string - const UniValue& scriptPubKey = data["scriptPubKey"]; - bool isScript = scriptPubKey.getType() == UniValue::VSTR; - if (!isScript && !(scriptPubKey.getType() == UniValue::VOBJ && scriptPubKey.exists("address"))) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "scriptPubKey must be string with script or JSON with address string"); + // First ensure scriptPubKey has either a script or JSON with "address" string + const UniValue& scriptPubKey = data["scriptPubKey"]; + bool isScript = scriptPubKey.getType() == UniValue::VSTR; + if (!isScript && !(scriptPubKey.getType() == UniValue::VOBJ && scriptPubKey.exists("address"))) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "scriptPubKey must be string with script or JSON with address string"); + } + const std::string& output = isScript ? scriptPubKey.get_str() : scriptPubKey["address"].get_str(); + + // Optional fields. + const std::string& strRedeemScript = data.exists("redeemscript") ? data["redeemscript"].get_str() : ""; + const std::string& witness_script_hex = data.exists("witnessscript") ? data["witnessscript"].get_str() : ""; + const UniValue& pubKeys = data.exists("pubkeys") ? data["pubkeys"].get_array() : UniValue(); + const UniValue& keys = data.exists("keys") ? data["keys"].get_array() : UniValue(); + const bool internal = data.exists("internal") ? data["internal"].get_bool() : false; + const bool watchOnly = data.exists("watchonly") ? data["watchonly"].get_bool() : false; + + if (data.exists("range")) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Range should not be specified for a non-descriptor import"); + } + + // Generate the script and destination for the scriptPubKey provided + CScript script; + if (!isScript) { + CTxDestination dest = DecodeDestination(output); + if (!IsValidDestination(dest)) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address \"" + output + "\""); } - const std::string& output = isScript ? scriptPubKey.get_str() : scriptPubKey["address"].get_str(); + script = GetScriptForDestination(dest); + } else { + if (!IsHex(output)) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid scriptPubKey \"" + output + "\""); + } + std::vector<unsigned char> vData(ParseHex(output)); + script = CScript(vData.begin(), vData.end()); + CTxDestination dest; + if (!ExtractDestination(script, dest) && !internal) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Internal must be set to true for nonstandard scriptPubKey imports."); + } + } + script_pub_keys.emplace(script); - // Optional fields. - const std::string& strRedeemScript = data.exists("redeemscript") ? data["redeemscript"].get_str() : ""; - const std::string& witness_script_hex = data.exists("witnessscript") ? data["witnessscript"].get_str() : ""; - const UniValue& pubKeys = data.exists("pubkeys") ? data["pubkeys"].get_array() : UniValue(); - const UniValue& keys = data.exists("keys") ? data["keys"].get_array() : UniValue(); - const bool internal = data.exists("internal") ? data["internal"].get_bool() : false; - const bool watchOnly = data.exists("watchonly") ? data["watchonly"].get_bool() : false; - const std::string& label = data.exists("label") ? data["label"].get_str() : ""; + // Parse all arguments + if (strRedeemScript.size()) { + if (!IsHex(strRedeemScript)) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid redeem script \"" + strRedeemScript + "\": must be hex string"); + } + auto parsed_redeemscript = ParseHex(strRedeemScript); + import_data.redeemscript = MakeUnique<CScript>(parsed_redeemscript.begin(), parsed_redeemscript.end()); + } + if (witness_script_hex.size()) { + if (!IsHex(witness_script_hex)) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid witness script \"" + witness_script_hex + "\": must be hex string"); + } + auto parsed_witnessscript = ParseHex(witness_script_hex); + import_data.witnessscript = MakeUnique<CScript>(parsed_witnessscript.begin(), parsed_witnessscript.end()); + } + for (size_t i = 0; i < pubKeys.size(); ++i) { + const auto& str = pubKeys[i].get_str(); + if (!IsHex(str)) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Pubkey \"" + str + "\" must be a hex string"); + } + auto parsed_pubkey = ParseHex(str); + CPubKey pubkey(parsed_pubkey.begin(), parsed_pubkey.end()); + if (!pubkey.IsFullyValid()) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Pubkey \"" + str + "\" is not a valid public key"); + } + pubkey_map.emplace(pubkey.GetID(), pubkey); + ordered_pubkeys.push_back(pubkey.GetID()); + } + for (size_t i = 0; i < keys.size(); ++i) { + const auto& str = keys[i].get_str(); + CKey key = DecodeSecret(str); + if (!key.IsValid()) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key encoding"); + } + CPubKey pubkey = key.GetPubKey(); + CKeyID id = pubkey.GetID(); + if (pubkey_map.count(id)) { + pubkey_map.erase(id); + } + privkey_map.emplace(id, key); + } - // Generate the script and destination for the scriptPubKey provided - CScript script; - CTxDestination dest; - if (!isScript) { - dest = DecodeDestination(output); - if (!IsValidDestination(dest)) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address \"" + output + "\""); + + // Verify and process input data + have_solving_data = import_data.redeemscript || import_data.witnessscript || pubkey_map.size() || privkey_map.size(); + if (have_solving_data) { + // Match up data in import_data with the scriptPubKey in script. + auto error = RecurseImportData(script, import_data, ScriptContext::TOP); + + // Verify whether the watchonly option corresponds to the availability of private keys. + bool spendable = std::all_of(import_data.used_keys.begin(), import_data.used_keys.end(), [&](const std::pair<CKeyID, bool>& used_key){ return privkey_map.count(used_key.first) > 0; }); + if (!watchOnly && !spendable) { + warnings.push_back("Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag."); + } + if (watchOnly && spendable) { + warnings.push_back("All private keys are provided, outputs will be considered spendable. If this is intentional, do not specify the watchonly flag."); + } + + // Check that all required keys for solvability are provided. + if (error.empty()) { + for (const auto& require_key : import_data.used_keys) { + if (!require_key.second) continue; // Not a required key + if (pubkey_map.count(require_key.first) == 0 && privkey_map.count(require_key.first) == 0) { + error = "some required keys are missing"; + } } - script = GetScriptForDestination(dest); + } + + if (!error.empty()) { + warnings.push_back("Importing as non-solvable: " + error + ". If this is intentional, don't provide any keys, pubkeys, witnessscript, or redeemscript."); + import_data = ImportData(); + pubkey_map.clear(); + privkey_map.clear(); + have_solving_data = false; } else { - if (!IsHex(output)) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid scriptPubKey \"" + output + "\""); + // RecurseImportData() removes any relevant redeemscript/witnessscript from import_data, so we can use that to discover if a superfluous one was provided. + if (import_data.redeemscript) warnings.push_back("Ignoring redeemscript as this is not a P2SH script."); + if (import_data.witnessscript) warnings.push_back("Ignoring witnessscript as this is not a (P2SH-)P2WSH script."); + for (auto it = privkey_map.begin(); it != privkey_map.end(); ) { + auto oldit = it++; + if (import_data.used_keys.count(oldit->first) == 0) { + warnings.push_back("Ignoring irrelevant private key."); + privkey_map.erase(oldit); + } } - std::vector<unsigned char> vData(ParseHex(output)); - script = CScript(vData.begin(), vData.end()); - if (!ExtractDestination(script, dest) && !internal) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Internal must be set to true for nonstandard scriptPubKey imports."); + for (auto it = pubkey_map.begin(); it != pubkey_map.end(); ) { + auto oldit = it++; + auto key_data_it = import_data.used_keys.find(oldit->first); + if (key_data_it == import_data.used_keys.end() || !key_data_it->second) { + warnings.push_back("Ignoring public key \"" + HexStr(oldit->first) + "\" as it doesn't appear inside P2PKH or P2WPKH."); + pubkey_map.erase(oldit); + } } } + } - // Parse all arguments - ImportData import_data; - if (strRedeemScript.size()) { - if (!IsHex(strRedeemScript)) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid redeem script \"" + strRedeemScript + "\": must be hex string"); - } - auto parsed_redeemscript = ParseHex(strRedeemScript); - import_data.redeemscript = MakeUnique<CScript>(parsed_redeemscript.begin(), parsed_redeemscript.end()); + return warnings; +} + +static UniValue ProcessImportDescriptor(ImportData& import_data, std::map<CKeyID, CPubKey>& pubkey_map, std::map<CKeyID, CKey>& privkey_map, std::set<CScript>& script_pub_keys, bool& have_solving_data, const UniValue& data, std::vector<CKeyID>& ordered_pubkeys) +{ + UniValue warnings(UniValue::VARR); + + const std::string& descriptor = data["desc"].get_str(); + FlatSigningProvider keys; + auto parsed_desc = Parse(descriptor, keys, /* require_checksum = */ true); + if (!parsed_desc) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Descriptor is invalid"); + } + + have_solving_data = parsed_desc->IsSolvable(); + const bool watch_only = data.exists("watchonly") ? data["watchonly"].get_bool() : false; + + int64_t range_start = 0, range_end = 0; + if (!parsed_desc->IsRange() && data.exists("range")) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Range should not be specified for an un-ranged descriptor"); + } else if (parsed_desc->IsRange()) { + if (!data.exists("range")) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Descriptor is ranged, please specify the range"); } - if (witness_script_hex.size()) { - if (!IsHex(witness_script_hex)) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid witness script \"" + witness_script_hex + "\": must be hex string"); - } - auto parsed_witnessscript = ParseHex(witness_script_hex); - import_data.witnessscript = MakeUnique<CScript>(parsed_witnessscript.begin(), parsed_witnessscript.end()); + auto range = ParseRange(data["range"]); + range_start = range.first; + range_end = range.second; + if (range_start < 0 || (range_end >> 31) != 0 || range_end - range_start >= 1000000) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid descriptor range specified"); } - std::map<CKeyID, CPubKey> pubkey_map; - for (size_t i = 0; i < pubKeys.size(); ++i) { - const auto& str = pubKeys[i].get_str(); - if (!IsHex(str)) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Pubkey \"" + str + "\" must be a hex string"); - } - auto parsed_pubkey = ParseHex(str); - CPubKey pubkey(parsed_pubkey.begin(), parsed_pubkey.end()); - if (!pubkey.IsFullyValid()) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Pubkey \"" + str + "\" is not a valid public key"); - } - pubkey_map.emplace(pubkey.GetID(), pubkey); + } + + const UniValue& priv_keys = data.exists("keys") ? data["keys"].get_array() : UniValue(); + + // Expand all descriptors to get public keys and scripts. + // TODO: get private keys from descriptors too + for (int i = range_start; i <= range_end; ++i) { + FlatSigningProvider out_keys; + std::vector<CScript> scripts_temp; + parsed_desc->Expand(i, keys, scripts_temp, out_keys); + std::copy(scripts_temp.begin(), scripts_temp.end(), std::inserter(script_pub_keys, script_pub_keys.end())); + for (const auto& key_pair : out_keys.pubkeys) { + ordered_pubkeys.push_back(key_pair.first); } - std::map<CKeyID, CKey> privkey_map; - for (size_t i = 0; i < keys.size(); ++i) { - const auto& str = keys[i].get_str(); - CKey key = DecodeSecret(str); - if (!key.IsValid()) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key encoding"); - } - CPubKey pubkey = key.GetPubKey(); - CKeyID id = pubkey.GetID(); - if (pubkey_map.count(id)) { - pubkey_map.erase(id); - } + + for (const auto& x : out_keys.scripts) { + import_data.import_scripts.emplace(x.second); + } + + std::copy(out_keys.pubkeys.begin(), out_keys.pubkeys.end(), std::inserter(pubkey_map, pubkey_map.end())); + import_data.key_origins.insert(out_keys.origins.begin(), out_keys.origins.end()); + } + + for (size_t i = 0; i < priv_keys.size(); ++i) { + const auto& str = priv_keys[i].get_str(); + CKey key = DecodeSecret(str); + if (!key.IsValid()) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key encoding"); + } + CPubKey pubkey = key.GetPubKey(); + CKeyID id = pubkey.GetID(); + + // Check if this private key corresponds to a public key from the descriptor + if (!pubkey_map.count(id)) { + warnings.push_back("Ignoring irrelevant private key."); + } else { privkey_map.emplace(id, key); } + } + + // Check if all the public keys have corresponding private keys in the import for spendability. + // This does not take into account threshold multisigs which could be spendable without all keys. + // Thus, threshold multisigs without all keys will be considered not spendable here, even if they are, + // perhaps triggering a false warning message. This is consistent with the current wallet IsMine check. + bool spendable = std::all_of(pubkey_map.begin(), pubkey_map.end(), + [&](const std::pair<CKeyID, CPubKey>& used_key) { + return privkey_map.count(used_key.first) > 0; + }); + if (!watch_only && !spendable) { + warnings.push_back("Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag."); + } + if (watch_only && spendable) { + warnings.push_back("All private keys are provided, outputs will be considered spendable. If this is intentional, do not specify the watchonly flag."); + } + + return warnings; +} + +static UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet) +{ + UniValue warnings(UniValue::VARR); + UniValue result(UniValue::VOBJ); + try { + const bool internal = data.exists("internal") ? data["internal"].get_bool() : false; // Internal addresses should not have a label if (internal && data.exists("label")) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Internal addresses should not have a label"); } + const std::string& label = data.exists("label") ? data["label"].get_str() : ""; + const bool add_keypool = data.exists("keypool") ? data["keypool"].get_bool() : false; - // Verify and process input data - bool have_solving_data = import_data.redeemscript || import_data.witnessscript || pubkey_map.size() || privkey_map.size(); - if (have_solving_data) { - // Match up data in import_data with the scriptPubKey in script. - auto error = RecurseImportData(script, import_data, ScriptContext::TOP); - - // Verify whether the watchonly option corresponds to the availability of private keys. - bool spendable = std::all_of(import_data.used_keys.begin(), import_data.used_keys.end(), [&](const std::pair<CKeyID, bool>& used_key){ return privkey_map.count(used_key.first) > 0; }); - if (!watchOnly && !spendable) { - warnings.push_back("Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag."); - } - if (watchOnly && spendable) { - warnings.push_back("All private keys are provided, outputs will be considered spendable. If this is intentional, do not specify the watchonly flag."); - } + // Add to keypool only works with privkeys disabled + if (add_keypool && !pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Keys can only be imported to the keypool when private keys are disabled"); + } - // Check that all required keys for solvability are provided. - if (error.empty()) { - for (const auto& require_key : import_data.used_keys) { - if (!require_key.second) continue; // Not a required key - if (pubkey_map.count(require_key.first) == 0 && privkey_map.count(require_key.first) == 0) { - error = "some required keys are missing"; - } - } - } + ImportData import_data; + std::map<CKeyID, CPubKey> pubkey_map; + std::map<CKeyID, CKey> privkey_map; + std::set<CScript> script_pub_keys; + std::vector<CKeyID> ordered_pubkeys; + bool have_solving_data; + + if (data.exists("scriptPubKey") && data.exists("desc")) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Both a descriptor and a scriptPubKey should not be provided."); + } else if (data.exists("scriptPubKey")) { + warnings = ProcessImportLegacy(import_data, pubkey_map, privkey_map, script_pub_keys, have_solving_data, data, ordered_pubkeys); + } else if (data.exists("desc")) { + warnings = ProcessImportDescriptor(import_data, pubkey_map, privkey_map, script_pub_keys, have_solving_data, data, ordered_pubkeys); + } else { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Either a descriptor or scriptPubKey must be provided."); + } - if (!error.empty()) { - warnings.push_back("Importing as non-solvable: " + error + ". If this is intentional, don't provide any keys, pubkeys, witnessscript, or redeemscript."); - import_data = ImportData(); - pubkey_map.clear(); - privkey_map.clear(); - have_solving_data = false; - } else { - // RecurseImportData() removes any relevant redeemscript/witnessscript from import_data, so we can use that to discover if a superfluous one was provided. - if (import_data.redeemscript) warnings.push_back("Ignoring redeemscript as this is not a P2SH script."); - if (import_data.witnessscript) warnings.push_back("Ignoring witnessscript as this is not a (P2SH-)P2WSH script."); - for (auto it = privkey_map.begin(); it != privkey_map.end(); ) { - auto oldit = it++; - if (import_data.used_keys.count(oldit->first) == 0) { - warnings.push_back("Ignoring irrelevant private key."); - privkey_map.erase(oldit); - } - } - for (auto it = pubkey_map.begin(); it != pubkey_map.end(); ) { - auto oldit = it++; - auto key_data_it = import_data.used_keys.find(oldit->first); - if (key_data_it == import_data.used_keys.end() || !key_data_it->second) { - warnings.push_back("Ignoring public key \"" + HexStr(oldit->first) + "\" as it doesn't appear inside P2PKH or P2WPKH."); - pubkey_map.erase(oldit); - } - } - } + // If private keys are disabled, abort if private keys are being imported + if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) && !privkey_map.empty()) { + throw JSONRPCError(RPC_WALLET_ERROR, "Cannot import private keys to a wallet with private keys disabled"); } // Check whether we have any work to do - if (::IsMine(*pwallet, script) & ISMINE_SPENDABLE) { - throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script"); + for (const CScript& script : script_pub_keys) { + if (::IsMine(*pwallet, script) & ISMINE_SPENDABLE) { + throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script (\"" + HexStr(script.begin(), script.end()) + "\")"); + } } // All good, time to import @@ -1090,37 +1249,54 @@ static UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, con for (const auto& entry : import_data.import_scripts) { if (!pwallet->HaveCScript(CScriptID(entry)) && !pwallet->AddCScript(entry)) { throw JSONRPCError(RPC_WALLET_ERROR, "Error adding script to wallet"); + } + } + for (const auto& entry : privkey_map) { + const CKey& key = entry.second; + CPubKey pubkey = key.GetPubKey(); + const CKeyID& id = entry.first; + assert(key.VerifyPubKey(pubkey)); + pwallet->mapKeyMetadata[id].nCreateTime = timestamp; + // If the private key is not present in the wallet, insert it. + if (!pwallet->HaveKey(id) && !pwallet->AddKeyPubKey(key, pubkey)) { + throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet"); + } + pwallet->UpdateTimeFirstKey(timestamp); + } + for (const CKeyID& id : ordered_pubkeys) { + auto entry = pubkey_map.find(id); + if (entry == pubkey_map.end()) { + continue; + } + const CPubKey& pubkey = entry->second; + CPubKey temp; + if (!pwallet->GetPubKey(id, temp) && !pwallet->AddWatchOnly(GetScriptForRawPubKey(pubkey), timestamp)) { + throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet"); + } + const auto& key_orig_it = import_data.key_origins.find(id); + if (key_orig_it != import_data.key_origins.end()) { + pwallet->AddKeyOrigin(pubkey, key_orig_it->second); } - } - for (const auto& entry : privkey_map) { - const CKey& key = entry.second; - CPubKey pubkey = key.GetPubKey(); - const CKeyID& id = entry.first; - assert(key.VerifyPubKey(pubkey)); pwallet->mapKeyMetadata[id].nCreateTime = timestamp; - // If the private key is not present in the wallet, insert it. - if (!pwallet->HaveKey(id) && !pwallet->AddKeyPubKey(key, pubkey)) { - throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet"); + + // Add to keypool only works with pubkeys + if (add_keypool) { + pwallet->AddKeypoolPubkey(pubkey, internal); } - pwallet->UpdateTimeFirstKey(timestamp); } - for (const auto& entry : pubkey_map) { - const CPubKey& pubkey = entry.second; - const CKeyID& id = entry.first; - CPubKey temp; - if (!pwallet->GetPubKey(id, temp) && !pwallet->AddWatchOnly(GetScriptForRawPubKey(pubkey), timestamp)) { - throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet"); + + for (const CScript& script : script_pub_keys) { + if (!have_solving_data || !::IsMine(*pwallet, script)) { // Always call AddWatchOnly for non-solvable watch-only, so that watch timestamp gets updated + if (!pwallet->AddWatchOnly(script, timestamp)) { + throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet"); + } } - } - if (!have_solving_data || !::IsMine(*pwallet, script)) { // Always call AddWatchOnly for non-solvable watch-only, so that watch timestamp gets updated - if (!pwallet->AddWatchOnly(script, timestamp)) { - throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet"); + CTxDestination dest; + ExtractDestination(script, dest); + if (!internal && IsValidDestination(dest)) { + pwallet->SetAddressBook(dest, label, "receive"); } } - if (!internal) { - assert(IsValidDestination(dest)); - pwallet->SetAddressBook(dest, label, "receive"); - } result.pushKV("success", UniValue(true)); } catch (const UniValue& e) { @@ -1166,14 +1342,15 @@ UniValue importmulti(const JSONRPCRequest& mainRequest) "\nNote: This call can take over an hour to complete if rescan is true, during that time, other rpc calls\n" "may report that the imported keys, addresses or scripts exists but related transactions are still missing.\n", { - {"requests", RPCArg::Type::ARR, /* opt */ false, /* default_val */ "", "Data to be imported", + {"requests", RPCArg::Type::ARR, RPCArg::Optional::NO, "Data to be imported", { - {"", RPCArg::Type::OBJ, /* opt */ false, /* default_val */ "", "", + {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "", { - {"scriptPubKey", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "Type of scriptPubKey (string for script, json for address)", + {"desc", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Descriptor to import. If using descriptor, do not also provide address/scriptPubKey, scripts, or pubkeys"}, + {"scriptPubKey", RPCArg::Type::STR, RPCArg::Optional::NO, "Type of scriptPubKey (string for script, json for address). Should not be provided if using a descriptor", /* oneline_description */ "", {"\"<script>\" | { \"address\":\"<address>\" }", "string / json"} }, - {"timestamp", RPCArg::Type::NUM, /* opt */ false, /* default_val */ "", "Creation time of the key in seconds since epoch (Jan 1 1970 GMT),\n" + {"timestamp", RPCArg::Type::NUM, RPCArg::Optional::NO, "Creation time of the key in seconds since epoch (Jan 1 1970 GMT),\n" " or the string \"now\" to substitute the current synced blockchain time. The timestamp of the oldest\n" " key will determine how far back blockchain rescans need to begin for missing wallet transactions.\n" " \"now\" can be specified to bypass scanning, for keys which are known to never have been used, and\n" @@ -1181,28 +1358,30 @@ UniValue importmulti(const JSONRPCRequest& mainRequest) " creation time of all keys being imported by the importmulti call will be scanned.", /* oneline_description */ "", {"timestamp | \"now\"", "integer / string"} }, - {"redeemscript", RPCArg::Type::STR, /* opt */ true, /* default_val */ "omitted", "Allowed only if the scriptPubKey is a P2SH or P2SH-P2WSH address/scriptPubKey"}, - {"witnessscript", RPCArg::Type::STR, /* opt */ true, /* default_val */ "omitted", "Allowed only if the scriptPubKey is a P2SH-P2WSH or P2WSH address/scriptPubKey"}, - {"pubkeys", RPCArg::Type::ARR, /* opt */ true, /* default_val */ "empty array", "Array of strings giving pubkeys to import. They must occur in P2PKH or P2WPKH scripts. They are not required when the private key is also provided (see the \"keys\" argument).", + {"redeemscript", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Allowed only if the scriptPubKey is a P2SH or P2SH-P2WSH address/scriptPubKey"}, + {"witnessscript", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Allowed only if the scriptPubKey is a P2SH-P2WSH or P2WSH address/scriptPubKey"}, + {"pubkeys", RPCArg::Type::ARR, /* default */ "empty array", "Array of strings giving pubkeys to import. They must occur in P2PKH or P2WPKH scripts. They are not required when the private key is also provided (see the \"keys\" argument).", { - {"pubKey", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", ""}, + {"pubKey", RPCArg::Type::STR, RPCArg::Optional::OMITTED, ""}, } }, - {"keys", RPCArg::Type::ARR, /* opt */ true, /* default_val */ "empty array", "Array of strings giving private keys to import. The corresponding public keys must occur in the output or redeemscript.", + {"keys", RPCArg::Type::ARR, /* default */ "empty array", "Array of strings giving private keys to import. The corresponding public keys must occur in the output or redeemscript.", { - {"key", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", ""}, + {"key", RPCArg::Type::STR, RPCArg::Optional::OMITTED, ""}, } }, - {"internal", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "Stating whether matching outputs should be treated as not incoming payments (also known as change)"}, - {"watchonly", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "Stating whether matching outputs should be considered watchonly."}, - {"label", RPCArg::Type::STR, /* opt */ true, /* default_val */ "''", "Label to assign to the address, only allowed with internal=false"}, + {"range", RPCArg::Type::RANGE, RPCArg::Optional::OMITTED, "If a ranged descriptor is used, this specifies the end or the range (in the form [begin,end]) to import"}, + {"internal", RPCArg::Type::BOOL, /* default */ "false", "Stating whether matching outputs should be treated as not incoming payments (also known as change)"}, + {"watchonly", RPCArg::Type::BOOL, /* default */ "false", "Stating whether matching outputs should be considered watchonly."}, + {"label", RPCArg::Type::STR, /* default */ "''", "Label to assign to the address, only allowed with internal=false"}, + {"keypool", RPCArg::Type::BOOL, /* default */ "false", "Stating whether imported public keys should be added to the keypool for when users request new addresses. Only allowed when wallet private keys are disabled"}, }, }, }, "\"requests\""}, - {"options", RPCArg::Type::OBJ, /* opt */ true, /* default_val */ "null", "", + {"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "", { - {"rescan", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "true", "Stating if should rescan the blockchain after all imports"}, + {"rescan", RPCArg::Type::BOOL, /* default */ "true", "Stating if should rescan the blockchain after all imports"}, }, "\"options\""}, }, diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 213765209c..97c6c38be1 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -13,6 +13,7 @@ #include <validation.h> #include <key_io.h> #include <net.h> +#include <node/transaction.h> #include <outputtype.h> #include <policy/feerate.h> #include <policy/fees.h> @@ -26,10 +27,12 @@ #include <script/sign.h> #include <shutdown.h> #include <timedata.h> +#include <util/bip32.h> #include <util/system.h> #include <util/moneystr.h> #include <wallet/coincontrol.h> #include <wallet/feebumper.h> +#include <wallet/psbtwallet.h> #include <wallet/rpcwallet.h> #include <wallet/wallet.h> #include <wallet/walletdb.h> @@ -158,8 +161,8 @@ static UniValue getnewaddress(const JSONRPCRequest& request) "If 'label' is specified, it is added to the address book \n" "so payments received with the address will be associated with 'label'.\n", { - {"label", RPCArg::Type::STR, /* opt */ true, /* default_val */ "null", "The label name for the address to be linked to. If not provided, the default label \"\" is used. It can also be set to the empty string \"\" to represent the default label. The label does not need to exist, it will be created if there is no label by the given name."}, - {"address_type", RPCArg::Type::STR, /* opt */ true, /* default_val */ "set by -addresstype", "The address type to use. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."}, + {"label", RPCArg::Type::STR, /* default */ "\"\"", "The label name for the address to be linked to. It can also be set to the empty string \"\" to represent the default label. The label does not need to exist, it will be created if there is no label by the given name."}, + {"address_type", RPCArg::Type::STR, /* default */ "set by -addresstype", "The address type to use. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."}, }, RPCResult{ "\"address\" (string) The new bitcoin address\n" @@ -170,12 +173,12 @@ static UniValue getnewaddress(const JSONRPCRequest& request) }, }.ToString()); - if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) { - throw JSONRPCError(RPC_WALLET_ERROR, "Error: Private keys are disabled for this wallet"); - } - LOCK(pwallet->cs_wallet); + if (!pwallet->CanGetAddresses()) { + throw JSONRPCError(RPC_WALLET_ERROR, "Error: This wallet has no available keys"); + } + // Parse the label first so we don't generate a key if there's an error std::string label; if (!request.params[0].isNull()) @@ -220,7 +223,7 @@ static UniValue getrawchangeaddress(const JSONRPCRequest& request) "\nReturns a new Bitcoin address, for receiving change.\n" "This is for use with raw transactions, NOT normal use.\n", { - {"address_type", RPCArg::Type::STR, /* opt */ true, /* default_val */ "set by -changetype", "The address type to use. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."}, + {"address_type", RPCArg::Type::STR, /* default */ "set by -changetype", "The address type to use. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."}, }, RPCResult{ "\"address\" (string) The address\n" @@ -231,12 +234,12 @@ static UniValue getrawchangeaddress(const JSONRPCRequest& request) }, }.ToString()); - if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) { - throw JSONRPCError(RPC_WALLET_ERROR, "Error: Private keys are disabled for this wallet"); - } - LOCK(pwallet->cs_wallet); + if (!pwallet->CanGetAddresses(true)) { + throw JSONRPCError(RPC_WALLET_ERROR, "Error: This wallet has no available keys"); + } + if (!pwallet->IsLocked()) { pwallet->TopUpKeyPool(); } @@ -276,8 +279,8 @@ static UniValue setlabel(const JSONRPCRequest& request) RPCHelpMan{"setlabel", "\nSets the label associated with the given address.\n", { - {"address", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The bitcoin address to be associated with a label."}, - {"label", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The label to assign to the address."}, + {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The bitcoin address to be associated with a label."}, + {"label", RPCArg::Type::STR, RPCArg::Optional::NO, "The label to assign to the address."}, }, RPCResults{}, RPCExamples{ @@ -360,18 +363,18 @@ static UniValue sendtoaddress(const JSONRPCRequest& request) "\nSend an amount to a given address." + HelpRequiringPassphrase(pwallet) + "\n", { - {"address", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The bitcoin address to send to."}, - {"amount", RPCArg::Type::AMOUNT, /* opt */ false, /* default_val */ "", "The amount in " + CURRENCY_UNIT + " to send. eg 0.1"}, - {"comment", RPCArg::Type::STR, /* opt */ true, /* default_val */ "null", "A comment used to store what the transaction is for.\n" + {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The bitcoin address to send to."}, + {"amount", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "The amount in " + CURRENCY_UNIT + " to send. eg 0.1"}, + {"comment", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "A comment used to store what the transaction is for.\n" " This is not part of the transaction, just kept in your wallet."}, - {"comment_to", RPCArg::Type::STR, /* opt */ true, /* default_val */ "null", "A comment to store the name of the person or organization\n" + {"comment_to", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "A comment to store the name of the person or organization\n" " to which you're sending the transaction. This is not part of the \n" " transaction, just kept in your wallet."}, - {"subtractfeefromamount", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "The fee will be deducted from the amount being sent.\n" + {"subtractfeefromamount", RPCArg::Type::BOOL, /* default */ "false", "The fee will be deducted from the amount being sent.\n" " The recipient will receive less bitcoins than you enter in the amount field."}, - {"replaceable", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "fallback to wallet's default", "Allow this transaction to be replaced by a transaction with higher fees via BIP 125"}, - {"conf_target", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "fallback to wallet's default", "Confirmation target (in blocks)"}, - {"estimate_mode", RPCArg::Type::STR, /* opt */ true, /* default_val */ "UNSET", "The fee estimate mode, must be one of:\n" + {"replaceable", RPCArg::Type::BOOL, /* default */ "fallback to wallet's default", "Allow this transaction to be replaced by a transaction with higher fees via BIP 125"}, + {"conf_target", RPCArg::Type::NUM, /* default */ "fallback to wallet's default", "Confirmation target (in blocks)"}, + {"estimate_mode", RPCArg::Type::STR, /* default */ "UNSET", "The fee estimate mode, must be one of:\n" " \"UNSET\"\n" " \"ECONOMICAL\"\n" " \"CONSERVATIVE\""}, @@ -516,8 +519,8 @@ static UniValue signmessage(const JSONRPCRequest& request) "\nSign a message with the private key of an address" + HelpRequiringPassphrase(pwallet) + "\n", { - {"address", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The bitcoin address to use for the private key."}, - {"message", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The message to create a signature of."}, + {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The bitcoin address to use for the private key."}, + {"message", RPCArg::Type::STR, RPCArg::Optional::NO, "The message to create a signature of."}, }, RPCResult{ "\"signature\" (string) The signature of the message encoded in base 64\n" @@ -582,8 +585,8 @@ static UniValue getreceivedbyaddress(const JSONRPCRequest& request) RPCHelpMan{"getreceivedbyaddress", "\nReturns the total amount received by the given address in transactions with at least minconf confirmations.\n", { - {"address", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The bitcoin address for transactions."}, - {"minconf", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "1", "Only include transactions confirmed at least this many times."}, + {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The bitcoin address for transactions."}, + {"minconf", RPCArg::Type::NUM, /* default */ "1", "Only include transactions confirmed at least this many times."}, }, RPCResult{ "amount (numeric) The total amount in " + CURRENCY_UNIT + " received at this address.\n" @@ -654,8 +657,8 @@ static UniValue getreceivedbylabel(const JSONRPCRequest& request) RPCHelpMan{"getreceivedbylabel", "\nReturns the total amount received by addresses with <label> in transactions with at least [minconf] confirmations.\n", { - {"label", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The selected label, may be the default label using \"\"."}, - {"minconf", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "1", "Only include transactions confirmed at least this many times."}, + {"label", RPCArg::Type::STR, RPCArg::Optional::NO, "The selected label, may be the default label using \"\"."}, + {"minconf", RPCArg::Type::NUM, /* default */ "1", "Only include transactions confirmed at least this many times."}, }, RPCResult{ "amount (numeric) The total amount in " + CURRENCY_UNIT + " received for this label.\n" @@ -726,9 +729,9 @@ static UniValue getbalance(const JSONRPCRequest& request) "The available balance is what the wallet considers currently spendable, and is\n" "thus affected by options which limit spendability such as -spendzeroconfchange.\n", { - {"dummy", RPCArg::Type::STR, /* opt */ true, /* default_val */ "null", "Remains for backward compatibility. Must be excluded or set to \"*\"."}, - {"minconf", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "0", "Only include transactions confirmed at least this many times."}, - {"include_watchonly", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "Also include balance in watch-only addresses (see 'importaddress')"}, + {"dummy", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "Remains for backward compatibility. Must be excluded or set to \"*\"."}, + {"minconf", RPCArg::Type::NUM, /* default */ "0", "Only include transactions confirmed at least this many times."}, + {"include_watchonly", RPCArg::Type::BOOL, /* default */ "false", "Also include balance in watch-only addresses (see 'importaddress')"}, }, RPCResult{ "amount (numeric) The total amount in " + CURRENCY_UNIT + " received for this wallet.\n" @@ -812,25 +815,25 @@ static UniValue sendmany(const JSONRPCRequest& request) "\nSend multiple times. Amounts are double-precision floating point numbers." + HelpRequiringPassphrase(pwallet) + "\n", { - {"dummy", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "Must be set to \"\" for backwards compatibility.", "\"\""}, - {"amounts", RPCArg::Type::OBJ, /* opt */ false, /* default_val */ "", "A json object with addresses and amounts", + {"dummy", RPCArg::Type::STR, RPCArg::Optional::NO, "Must be set to \"\" for backwards compatibility.", "\"\""}, + {"amounts", RPCArg::Type::OBJ, RPCArg::Optional::NO, "A json object with addresses and amounts", { - {"address", RPCArg::Type::AMOUNT, /* opt */ false, /* default_val */ "", "The bitcoin address is the key, the numeric amount (can be string) in " + CURRENCY_UNIT + " is the value"}, + {"address", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "The bitcoin address is the key, the numeric amount (can be string) in " + CURRENCY_UNIT + " is the value"}, }, }, - {"minconf", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "1", "Only use the balance confirmed at least this many times."}, - {"comment", RPCArg::Type::STR, /* opt */ true, /* default_val */ "null", "A comment"}, - {"subtractfeefrom", RPCArg::Type::ARR, /* opt */ true, /* default_val */ "null", "A json array with addresses.\n" + {"minconf", RPCArg::Type::NUM, /* default */ "1", "Only use the balance confirmed at least this many times."}, + {"comment", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "A comment"}, + {"subtractfeefrom", RPCArg::Type::ARR, RPCArg::Optional::OMITTED_NAMED_ARG, "A json array with addresses.\n" " The fee will be equally deducted from the amount of each selected address.\n" " Those recipients will receive less bitcoins than you enter in their corresponding amount field.\n" " If no addresses are specified here, the sender pays the fee.", { - {"address", RPCArg::Type::STR, /* opt */ true, /* default_val */ "", "Subtract fee from this address"}, + {"address", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Subtract fee from this address"}, }, }, - {"replaceable", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "fallback to wallet's default", "Allow this transaction to be replaced by a transaction with higher fees via BIP 125"}, - {"conf_target", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "fallback to wallet's default", "Confirmation target (in blocks)"}, - {"estimate_mode", RPCArg::Type::STR, /* opt */ true, /* default_val */ "UNSET", "The fee estimate mode, must be one of:\n" + {"replaceable", RPCArg::Type::BOOL, /* default */ "fallback to wallet's default", "Allow this transaction to be replaced by a transaction with higher fees via BIP 125"}, + {"conf_target", RPCArg::Type::NUM, /* default */ "fallback to wallet's default", "Confirmation target (in blocks)"}, + {"estimate_mode", RPCArg::Type::STR, /* default */ "UNSET", "The fee estimate mode, must be one of:\n" " \"UNSET\"\n" " \"ECONOMICAL\"\n" " \"CONSERVATIVE\""}, @@ -972,14 +975,14 @@ static UniValue addmultisigaddress(const JSONRPCRequest& request) "See `importaddress` for watchonly p2sh address support.\n" "If 'label' is specified, assign address to that label.\n", { - {"nrequired", RPCArg::Type::NUM, /* opt */ false, /* default_val */ "", "The number of required signatures out of the n keys or addresses."}, - {"keys", RPCArg::Type::ARR, /* opt */ false, /* default_val */ "", "A json array of bitcoin addresses or hex-encoded public keys", + {"nrequired", RPCArg::Type::NUM, RPCArg::Optional::NO, "The number of required signatures out of the n keys or addresses."}, + {"keys", RPCArg::Type::ARR, RPCArg::Optional::NO, "A json array of bitcoin addresses or hex-encoded public keys", { - {"key", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "bitcoin address or hex-encoded public key"}, + {"key", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "bitcoin address or hex-encoded public key"}, }, }, - {"label", RPCArg::Type::STR, /* opt */ true, /* default_val */ "null", "A label to assign the addresses to."}, - {"address_type", RPCArg::Type::STR, /* opt */ true, /* default_val */ "set by -addresstype", "The address type to use. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."}, + {"label", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "A label to assign the addresses to."}, + {"address_type", RPCArg::Type::STR, /* default */ "set by -addresstype", "The address type to use. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."}, }, RPCResult{ "{\n" @@ -1206,10 +1209,10 @@ static UniValue listreceivedbyaddress(const JSONRPCRequest& request) RPCHelpMan{"listreceivedbyaddress", "\nList balances by receiving address.\n", { - {"minconf", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "1", "The minimum number of confirmations before payments are included."}, - {"include_empty", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "Whether to include addresses that haven't received any payments."}, - {"include_watchonly", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "Whether to include watch-only addresses (see 'importaddress')."}, - {"address_filter", RPCArg::Type::STR, /* opt */ true, /* default_val */ "null", "If present, only return information on this address."}, + {"minconf", RPCArg::Type::NUM, /* default */ "1", "The minimum number of confirmations before payments are included."}, + {"include_empty", RPCArg::Type::BOOL, /* default */ "false", "Whether to include addresses that haven't received any payments."}, + {"include_watchonly", RPCArg::Type::BOOL, /* default */ "false", "Whether to include watch-only addresses (see 'importaddress')."}, + {"address_filter", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "If present, only return information on this address."}, }, RPCResult{ "[\n" @@ -1259,9 +1262,9 @@ static UniValue listreceivedbylabel(const JSONRPCRequest& request) RPCHelpMan{"listreceivedbylabel", "\nList received transactions by label.\n", { - {"minconf", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "1", "The minimum number of confirmations before payments are included."}, - {"include_empty", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "Whether to include labels that haven't received any payments."}, - {"include_watchonly", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "Whether to include watch-only addresses (see 'importaddress')."}, + {"minconf", RPCArg::Type::NUM, /* default */ "1", "The minimum number of confirmations before payments are included."}, + {"include_empty", RPCArg::Type::BOOL, /* default */ "false", "Whether to include labels that haven't received any payments."}, + {"include_watchonly", RPCArg::Type::BOOL, /* default */ "false", "Whether to include watch-only addresses (see 'importaddress')."}, }, RPCResult{ "[\n" @@ -1309,7 +1312,7 @@ static void MaybePushAddress(UniValue & entry, const CTxDestination &dest) * @param filter_ismine The "is mine" filter flags. * @param filter_label Optional label string to filter incoming transactions. */ -static void ListTransactions(interfaces::Chain::Lock& locked_chain, CWallet* const pwallet, const CWalletTx& wtx, int nMinDepth, bool fLong, UniValue& ret, const isminefilter& filter_ismine, const std::string* filter_label) +static void ListTransactions(interfaces::Chain::Lock& locked_chain, CWallet* const pwallet, const CWalletTx& wtx, int nMinDepth, bool fLong, UniValue& ret, const isminefilter& filter_ismine, const std::string* filter_label) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet) { CAmount nFee; std::list<COutputEntry> listReceived; @@ -1400,11 +1403,11 @@ UniValue listtransactions(const JSONRPCRequest& request) "\nIf a label name is provided, this will return only incoming transactions paying to addresses with the specified label.\n" "\nReturns up to 'count' most recent transactions skipping the first 'from' transactions.\n", { - {"label", RPCArg::Type::STR, /* opt */ true, /* default_val */ "null", "If set, should be a valid label name to return only incoming transactions\n" + {"label", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "If set, should be a valid label name to return only incoming transactions\n" " with the specified label, or \"*\" to disable filtering and return all transactions."}, - {"count", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "10", "The number of transactions to return"}, - {"skip", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "0", "The number of transactions to skip"}, - {"include_watchonly", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "Include transactions to watch-only addresses (see 'importaddress')"}, + {"count", RPCArg::Type::NUM, /* default */ "10", "The number of transactions to return"}, + {"skip", RPCArg::Type::NUM, /* default */ "0", "The number of transactions to skip"}, + {"include_watchonly", RPCArg::Type::BOOL, /* default */ "false", "Include transactions to watch-only addresses (see 'importaddress')"}, }, RPCResult{ "[\n" @@ -1535,10 +1538,10 @@ static UniValue listsinceblock(const JSONRPCRequest& request) "If \"blockhash\" is no longer a part of the main chain, transactions from the fork point onward are included.\n" "Additionally, if include_removed is set, transactions affecting the wallet which were removed are returned in the \"removed\" array.\n", { - {"blockhash", RPCArg::Type::STR, /* opt */ true, /* default_val */ "null", "If set, the block hash to list transactions since, otherwise list all transactions."}, - {"target_confirmations", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "1", "Return the nth block hash from the main chain. e.g. 1 would mean the best block hash. Note: this is not used as a filter, but only affects [lastblock] in the return value"}, - {"include_watchonly", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "Include transactions to watch-only addresses (see 'importaddress')"}, - {"include_removed", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "true", "Show transactions that were removed due to a reorg in the \"removed\" array\n" + {"blockhash", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "If set, the block hash to list transactions since, otherwise list all transactions."}, + {"target_confirmations", RPCArg::Type::NUM, /* default */ "1", "Return the nth block hash from the main chain. e.g. 1 would mean the best block hash. Note: this is not used as a filter, but only affects [lastblock] in the return value"}, + {"include_watchonly", RPCArg::Type::BOOL, /* default */ "false", "Include transactions to watch-only addresses (see 'importaddress')"}, + {"include_removed", RPCArg::Type::BOOL, /* default */ "true", "Show transactions that were removed due to a reorg in the \"removed\" array\n" " (not guaranteed to work on pruned nodes)"}, }, RPCResult{ @@ -1678,8 +1681,8 @@ static UniValue gettransaction(const JSONRPCRequest& request) RPCHelpMan{"gettransaction", "\nGet detailed information about in-wallet transaction <txid>\n", { - {"txid", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The transaction id"}, - {"include_watchonly", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "Whether to include watch-only addresses in balance calculation and details[]"}, + {"txid", RPCArg::Type::STR, RPCArg::Optional::NO, "The transaction id"}, + {"include_watchonly", RPCArg::Type::BOOL, /* default */ "false", "Whether to include watch-only addresses in balance calculation and details[]"}, }, RPCResult{ "{\n" @@ -1784,7 +1787,7 @@ static UniValue abandontransaction(const JSONRPCRequest& request) "It only works on transactions which are not included in a block and are not currently in the mempool.\n" "It has no effect on transactions which are already abandoned.\n", { - {"txid", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "The transaction id"}, + {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"}, }, RPCResults{}, RPCExamples{ @@ -1828,7 +1831,7 @@ static UniValue backupwallet(const JSONRPCRequest& request) RPCHelpMan{"backupwallet", "\nSafely copies current wallet file to destination, which can be a directory or a path with filename.\n", { - {"destination", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The destination directory or file"}, + {"destination", RPCArg::Type::STR, RPCArg::Optional::NO, "The destination directory or file"}, }, RPCResults{}, RPCExamples{ @@ -1868,7 +1871,7 @@ static UniValue keypoolrefill(const JSONRPCRequest& request) "\nFills the keypool."+ HelpRequiringPassphrase(pwallet) + "\n", { - {"newsize", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "100", "The new keypool size"}, + {"newsize", RPCArg::Type::NUM, /* default */ "100", "The new keypool size"}, }, RPCResults{}, RPCExamples{ @@ -1921,8 +1924,8 @@ static UniValue walletpassphrase(const JSONRPCRequest& request) "Issuing the walletpassphrase command while the wallet is already unlocked will set a new unlock\n" "time that overrides the old one.\n", { - {"passphrase", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The wallet passphrase"}, - {"timeout", RPCArg::Type::NUM, /* opt */ false, /* default_val */ "", "The time to keep the decryption key in seconds; capped at 100000000 (~3 years)."}, + {"passphrase", RPCArg::Type::STR, RPCArg::Optional::NO, "The wallet passphrase"}, + {"timeout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The time to keep the decryption key in seconds; capped at 100000000 (~3 years)."}, }, RPCResults{}, RPCExamples{ @@ -2004,8 +2007,8 @@ static UniValue walletpassphrasechange(const JSONRPCRequest& request) RPCHelpMan{"walletpassphrasechange", "\nChanges the wallet passphrase from 'oldpassphrase' to 'newpassphrase'.\n", { - {"oldpassphrase", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The current passphrase"}, - {"newpassphrase", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The new passphrase"}, + {"oldpassphrase", RPCArg::Type::STR, RPCArg::Optional::NO, "The current passphrase"}, + {"newpassphrase", RPCArg::Type::STR, RPCArg::Optional::NO, "The new passphrase"}, }, RPCResults{}, RPCExamples{ @@ -2106,7 +2109,7 @@ static UniValue encryptwallet(const JSONRPCRequest& request) "Use the walletpassphrase call for this, and then walletlock call.\n" "If the wallet is already encrypted, use the walletpassphrasechange call.\n", { - {"passphrase", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The pass phrase to encrypt the wallet with. It must be at least 1 character, but should be long."}, + {"passphrase", RPCArg::Type::STR, RPCArg::Optional::NO, "The pass phrase to encrypt the wallet with. It must be at least 1 character, but should be long."}, }, RPCResults{}, RPCExamples{ @@ -2168,13 +2171,13 @@ static UniValue lockunspent(const JSONRPCRequest& request) "is always cleared (by virtue of process exit) when a node stops or fails.\n" "Also see the listunspent call\n", { - {"unlock", RPCArg::Type::BOOL, /* opt */ false, /* default_val */ "", "Whether to unlock (true) or lock (false) the specified transactions"}, - {"transactions", RPCArg::Type::ARR, /* opt */ true, /* default_val */ "empty array", "A json array of objects. Each object the txid (string) vout (numeric).", + {"unlock", RPCArg::Type::BOOL, RPCArg::Optional::NO, "Whether to unlock (true) or lock (false) the specified transactions"}, + {"transactions", RPCArg::Type::ARR, /* default */ "empty array", "A json array of objects. Each object the txid (string) vout (numeric).", { - {"", RPCArg::Type::OBJ, /* opt */ true, /* default_val */ "", "", + {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "", { - {"txid", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "The transaction id"}, - {"vout", RPCArg::Type::NUM, /* opt */ false, /* default_val */ "", "The output number"}, + {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"}, + {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"}, }, }, }, @@ -2348,7 +2351,7 @@ static UniValue settxfee(const JSONRPCRequest& request) RPCHelpMan{"settxfee", "\nSet the transaction fee per kB for this wallet. Overrides the global -paytxfee command line parameter.\n", { - {"amount", RPCArg::Type::AMOUNT, /* opt */ false, /* default_val */ "", "The transaction fee in " + CURRENCY_UNIT + "/kB"}, + {"amount", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "The transaction fee in " + CURRENCY_UNIT + "/kB"}, }, RPCResult{ "true|false (boolean) Returns true if successful\n" @@ -2405,7 +2408,6 @@ static UniValue getwalletinfo(const JSONRPCRequest& request) " \"unlocked_until\": ttt, (numeric) the timestamp in seconds since epoch (midnight Jan 1 1970 GMT) that the wallet is unlocked for transfers, or 0 if the wallet is locked\n" " \"paytxfee\": x.xxxx, (numeric) the transaction fee configuration, set in " + CURRENCY_UNIT + "/kB\n" " \"hdseedid\": \"<hash160>\" (string, optional) the Hash160 of the HD seed (only present when HD is enabled)\n" - " \"hdmasterkeyid\": \"<hash160>\" (string, optional) alias for hdseedid retained for backwards-compatibility. Will be removed in V0.18.\n" " \"private_keys_enabled\": true|false (boolean) false if privatekeys are disabled for this wallet (enforced watch-only wallet)\n" "}\n" }, @@ -2434,7 +2436,7 @@ static UniValue getwalletinfo(const JSONRPCRequest& request) obj.pushKV("keypoololdest", pwallet->GetOldestKeyPoolTime()); obj.pushKV("keypoolsize", (int64_t)kpExternalSize); CKeyID seed_id = pwallet->GetHDChain().seed_id; - if (!seed_id.IsNull() && pwallet->CanSupportFeature(FEATURE_HD_SPLIT)) { + if (pwallet->CanSupportFeature(FEATURE_HD_SPLIT)) { obj.pushKV("keypoolsize_hd_internal", (int64_t)(pwallet->GetKeyPoolSize() - kpExternalSize)); } if (pwallet->IsCrypted()) { @@ -2443,7 +2445,6 @@ static UniValue getwalletinfo(const JSONRPCRequest& request) obj.pushKV("paytxfee", ValueFromAmount(pwallet->m_pay_tx_fee.GetFeePerK())); if (!seed_id.IsNull()) { obj.pushKV("hdseedid", seed_id.GetHex()); - obj.pushKV("hdmasterkeyid", seed_id.GetHex()); } obj.pushKV("private_keys_enabled", !pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)); return obj; @@ -2529,7 +2530,7 @@ static UniValue loadwallet(const JSONRPCRequest& request) "\nNote that all wallet command-line options used when starting bitcoind will be" "\napplied to the new wallet (eg -zapwallettxes, upgradewallet, rescan, etc).\n", { - {"filename", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The wallet directory or .dat file."}, + {"filename", RPCArg::Type::STR, RPCArg::Optional::NO, "The wallet directory or .dat file."}, }, RPCResult{ "{\n" @@ -2544,7 +2545,6 @@ static UniValue loadwallet(const JSONRPCRequest& request) }.ToString()); WalletLocation location(request.params[0].get_str()); - std::string error; if (!location.Exists()) { throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Wallet " + location.GetName() + " not found."); @@ -2556,18 +2556,9 @@ static UniValue loadwallet(const JSONRPCRequest& request) } } - std::string warning; - if (!CWallet::Verify(*g_rpc_interfaces->chain, location, false, error, warning)) { - throw JSONRPCError(RPC_WALLET_ERROR, "Wallet file verification failed: " + error); - } - - std::shared_ptr<CWallet> const wallet = CWallet::CreateWalletFromFile(*g_rpc_interfaces->chain, location); - if (!wallet) { - throw JSONRPCError(RPC_WALLET_ERROR, "Wallet loading failed."); - } - AddWallet(wallet); - - wallet->postInitProcess(); + std::string error, warning; + std::shared_ptr<CWallet> const wallet = LoadWallet(*g_rpc_interfaces->chain, location, error, warning); + if (!wallet) throw JSONRPCError(RPC_WALLET_ERROR, error); UniValue obj(UniValue::VOBJ); obj.pushKV("name", wallet->GetName()); @@ -2578,13 +2569,14 @@ static UniValue loadwallet(const JSONRPCRequest& request) static UniValue createwallet(const JSONRPCRequest& request) { - if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) { + if (request.fHelp || request.params.size() < 1 || request.params.size() > 3) { throw std::runtime_error( RPCHelpMan{"createwallet", "\nCreates and loads a new wallet.\n", { - {"wallet_name", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The name for the new wallet. If this is a path, the wallet will be created at the path location."}, - {"disable_private_keys", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "Disable the possibility of private keys (only watchonlys are possible in this mode)."}, + {"wallet_name", RPCArg::Type::STR, RPCArg::Optional::NO, "The name for the new wallet. If this is a path, the wallet will be created at the path location."}, + {"disable_private_keys", RPCArg::Type::BOOL, /* default */ "false", "Disable the possibility of private keys (only watchonlys are possible in this mode)."}, + {"blank", RPCArg::Type::BOOL, /* default */ "false", "Create a blank wallet. A blank wallet has no keys or HD seed. One can be set using sethdseed."}, }, RPCResult{ "{\n" @@ -2601,9 +2593,13 @@ static UniValue createwallet(const JSONRPCRequest& request) std::string error; std::string warning; - bool disable_privatekeys = false; - if (!request.params[1].isNull()) { - disable_privatekeys = request.params[1].get_bool(); + uint64_t flags = 0; + if (!request.params[1].isNull() && request.params[1].get_bool()) { + flags |= WALLET_FLAG_DISABLE_PRIVATE_KEYS; + } + + if (!request.params[2].isNull() && request.params[2].get_bool()) { + flags |= WALLET_FLAG_BLANK_WALLET; } WalletLocation location(request.params[0].get_str()); @@ -2616,7 +2612,7 @@ static UniValue createwallet(const JSONRPCRequest& request) throw JSONRPCError(RPC_WALLET_ERROR, "Wallet file verification failed: " + error); } - std::shared_ptr<CWallet> const wallet = CWallet::CreateWalletFromFile(*g_rpc_interfaces->chain, location, (disable_privatekeys ? (uint64_t)WALLET_FLAG_DISABLE_PRIVATE_KEYS : 0)); + std::shared_ptr<CWallet> const wallet = CWallet::CreateWalletFromFile(*g_rpc_interfaces->chain, location, flags); if (!wallet) { throw JSONRPCError(RPC_WALLET_ERROR, "Wallet creation failed."); } @@ -2639,7 +2635,7 @@ static UniValue unloadwallet(const JSONRPCRequest& request) "Unloads the wallet referenced by the request endpoint otherwise unloads the wallet specified in the argument.\n" "Specifying the wallet name on a wallet endpoint is invalid.", { - {"wallet_name", RPCArg::Type::STR, /* opt */ true, /* default_val */ "the wallet name from the RPC request", "The name of the wallet to unload."}, + {"wallet_name", RPCArg::Type::STR, /* default */ "the wallet name from the RPC request", "The name of the wallet to unload."}, }, RPCResults{}, RPCExamples{ @@ -2734,21 +2730,21 @@ static UniValue listunspent(const JSONRPCRequest& request) "with between minconf and maxconf (inclusive) confirmations.\n" "Optionally filter to only include txouts paid to specified addresses.\n", { - {"minconf", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "1", "The minimum confirmations to filter"}, - {"maxconf", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "9999999", "The maximum confirmations to filter"}, - {"addresses", RPCArg::Type::ARR, /* opt */ true, /* default_val */ "empty array", "A json array of bitcoin addresses to filter", + {"minconf", RPCArg::Type::NUM, /* default */ "1", "The minimum confirmations to filter"}, + {"maxconf", RPCArg::Type::NUM, /* default */ "9999999", "The maximum confirmations to filter"}, + {"addresses", RPCArg::Type::ARR, /* default */ "empty array", "A json array of bitcoin addresses to filter", { - {"address", RPCArg::Type::STR, /* opt */ true, /* default_val */ "", "bitcoin address"}, + {"address", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "bitcoin address"}, }, }, - {"include_unsafe", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "true", "Include outputs that are not safe to spend\n" + {"include_unsafe", RPCArg::Type::BOOL, /* default */ "true", "Include outputs that are not safe to spend\n" " See description of \"safe\" attribute below."}, - {"query_options", RPCArg::Type::OBJ, /* opt */ true, /* default_val */ "null", "JSON with query options", + {"query_options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "JSON with query options", { - {"minimumAmount", RPCArg::Type::AMOUNT, /* opt */ true, /* default_val */ "0", "Minimum value of each UTXO in " + CURRENCY_UNIT + ""}, - {"maximumAmount", RPCArg::Type::AMOUNT, /* opt */ true, /* default_val */ "unlimited", "Maximum value of each UTXO in " + CURRENCY_UNIT + ""}, - {"maximumCount", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "unlimited", "Maximum number of UTXOs"}, - {"minimumSumAmount", RPCArg::Type::AMOUNT, /* opt */ true, /* default_val */ "unlimited", "Minimum sum value of all UTXOs in " + CURRENCY_UNIT + ""}, + {"minimumAmount", RPCArg::Type::AMOUNT, /* default */ "0", "Minimum value of each UTXO in " + CURRENCY_UNIT + ""}, + {"maximumAmount", RPCArg::Type::AMOUNT, /* default */ "unlimited", "Maximum value of each UTXO in " + CURRENCY_UNIT + ""}, + {"maximumCount", RPCArg::Type::NUM, /* default */ "unlimited", "Maximum number of UTXOs"}, + {"minimumSumAmount", RPCArg::Type::AMOUNT, /* default */ "unlimited", "Minimum sum value of all UTXOs in " + CURRENCY_UNIT + ""}, }, "query_options"}, }, @@ -2762,7 +2758,8 @@ static UniValue listunspent(const JSONRPCRequest& request) " \"scriptPubKey\" : \"key\", (string) the script key\n" " \"amount\" : x.xxx, (numeric) the transaction output amount in " + CURRENCY_UNIT + "\n" " \"confirmations\" : n, (numeric) The number of confirmations\n" - " \"redeemScript\" : n (string) The redeemScript if scriptPubKey is P2SH\n" + " \"redeemScript\" : \"script\" (string) The redeemScript if scriptPubKey is P2SH\n" + " \"witnessScript\" : \"script\" (string) witnessScript if the scriptPubKey is P2WSH or P2SH-P2WSH\n" " \"spendable\" : xxx, (bool) Whether we have the private keys to spend this output\n" " \"solvable\" : xxx, (bool) Whether we know how to spend this output, ignoring the lack of keys\n" " \"desc\" : xxx, (string, only when solvable) A descriptor for spending this output\n" @@ -2876,6 +2873,28 @@ static UniValue listunspent(const JSONRPCRequest& request) CScript redeemScript; if (pwallet->GetCScript(hash, redeemScript)) { entry.pushKV("redeemScript", HexStr(redeemScript.begin(), redeemScript.end())); + // Now check if the redeemScript is actually a P2WSH script + CTxDestination witness_destination; + if (redeemScript.IsPayToWitnessScriptHash()) { + bool extracted = ExtractDestination(redeemScript, witness_destination); + assert(extracted); + // Also return the witness script + const WitnessV0ScriptHash& whash = boost::get<WitnessV0ScriptHash>(witness_destination); + CScriptID id; + CRIPEMD160().Write(whash.begin(), whash.size()).Finalize(id.begin()); + CScript witnessScript; + if (pwallet->GetCScript(id, witnessScript)) { + entry.pushKV("witnessScript", HexStr(witnessScript.begin(), witnessScript.end())); + } + } + } + } else if (scriptPubKey.IsPayToWitnessScriptHash()) { + const WitnessV0ScriptHash& whash = boost::get<WitnessV0ScriptHash>(address); + CScriptID id; + CRIPEMD160().Write(whash.begin(), whash.size()).Finalize(id.begin()); + CScript witnessScript; + if (pwallet->GetCScript(id, witnessScript)) { + entry.pushKV("witnessScript", HexStr(witnessScript.begin(), witnessScript.end())); } } } @@ -3028,40 +3047,41 @@ static UniValue fundrawtransaction(const JSONRPCRequest& request) "This will not modify existing inputs, and will add at most one change output to the outputs.\n" "No existing outputs will be modified unless \"subtractFeeFromOutputs\" is specified.\n" "Note that inputs which were signed may need to be resigned after completion since in/outputs have been added.\n" - "The inputs added will not be signed, use signrawtransaction for that.\n" + "The inputs added will not be signed, use signrawtransactionwithkey\n" + " or signrawtransactionwithwallet for that.\n" "Note that all existing inputs must have their previous output transaction be in the wallet.\n" "Note that all inputs selected must be of standard form and P2SH scripts must be\n" "in the wallet using importaddress or addmultisigaddress (to calculate fees).\n" "You can see whether this is the case by checking the \"solvable\" field in the listunspent output.\n" "Only pay-to-pubkey, multisig, and P2SH versions thereof are currently supported for watch-only\n", { - {"hexstring", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "The hex string of the raw transaction"}, - {"options", RPCArg::Type::OBJ, /* opt */ true, /* default_val */ "null", "for backward compatibility: passing in a true instead of an object will result in {\"includeWatching\":true}", + {"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hex string of the raw transaction"}, + {"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "for backward compatibility: passing in a true instead of an object will result in {\"includeWatching\":true}", { - {"changeAddress", RPCArg::Type::STR, /* opt */ true, /* default_val */ "pool address", "The bitcoin address to receive the change"}, - {"changePosition", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "random", "The index of the change output"}, - {"change_type", RPCArg::Type::STR, /* opt */ true, /* default_val */ "set by -changetype", "The output type to use. Only valid if changeAddress is not specified. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."}, - {"includeWatching", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "Also select inputs which are watch only"}, - {"lockUnspents", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "Lock selected unspent outputs"}, - {"feeRate", RPCArg::Type::AMOUNT, /* opt */ true, /* default_val */ "not set: makes wallet determine the fee", "Set a specific fee rate in " + CURRENCY_UNIT + "/kB"}, - {"subtractFeeFromOutputs", RPCArg::Type::ARR, /* opt */ true, /* default_val */ "empty array", "A json array of integers.\n" + {"changeAddress", RPCArg::Type::STR, /* default */ "pool address", "The bitcoin address to receive the change"}, + {"changePosition", RPCArg::Type::NUM, /* default */ "random", "The index of the change output"}, + {"change_type", RPCArg::Type::STR, /* default */ "set by -changetype", "The output type to use. Only valid if changeAddress is not specified. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."}, + {"includeWatching", RPCArg::Type::BOOL, /* default */ "false", "Also select inputs which are watch only"}, + {"lockUnspents", RPCArg::Type::BOOL, /* default */ "false", "Lock selected unspent outputs"}, + {"feeRate", RPCArg::Type::AMOUNT, /* default */ "not set: makes wallet determine the fee", "Set a specific fee rate in " + CURRENCY_UNIT + "/kB"}, + {"subtractFeeFromOutputs", RPCArg::Type::ARR, /* default */ "empty array", "A json array of integers.\n" " The fee will be equally deducted from the amount of each specified output.\n" " Those recipients will receive less bitcoins than you enter in their corresponding amount field.\n" " If no outputs are specified here, the sender pays the fee.", { - {"vout_index", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "", "The zero-based output index, before a change output is added."}, + {"vout_index", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "The zero-based output index, before a change output is added."}, }, }, - {"replaceable", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "fallback to wallet's default", "Marks this transaction as BIP125 replaceable.\n" + {"replaceable", RPCArg::Type::BOOL, /* default */ "fallback to wallet's default", "Marks this transaction as BIP125 replaceable.\n" " Allows this transaction to be replaced by a transaction with higher fees"}, - {"conf_target", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "fallback to wallet's default", "Confirmation target (in blocks)"}, - {"estimate_mode", RPCArg::Type::STR, /* opt */ true, /* default_val */ "UNSET", "The fee estimate mode, must be one of:\n" + {"conf_target", RPCArg::Type::NUM, /* default */ "fallback to wallet's default", "Confirmation target (in blocks)"}, + {"estimate_mode", RPCArg::Type::STR, /* default */ "UNSET", "The fee estimate mode, must be one of:\n" " \"UNSET\"\n" " \"ECONOMICAL\"\n" " \"CONSERVATIVE\""}, }, "options"}, - {"iswitness", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "depends on heuristic tests", "Whether the transaction hex is a serialized witness transaction \n" + {"iswitness", RPCArg::Type::BOOL, /* default */ "depends on heuristic tests", "Whether the transaction hex is a serialized witness transaction \n" " If iswitness is not present, heuristic tests will be used in decoding"}, }, RPCResult{ @@ -3077,7 +3097,7 @@ static UniValue fundrawtransaction(const JSONRPCRequest& request) "\nAdd sufficient unsigned inputs to meet the output value\n" + HelpExampleCli("fundrawtransaction", "\"rawtransactionhex\"") + "\nSign the transaction\n" - + HelpExampleCli("signrawtransaction", "\"fundedtransactionhex\"") + + + HelpExampleCli("signrawtransactionwithwallet", "\"fundedtransactionhex\"") + "\nSend the transaction\n" + HelpExampleCli("sendrawtransaction", "\"signedtransactionhex\"") }, @@ -3122,21 +3142,22 @@ UniValue signrawtransactionwithwallet(const JSONRPCRequest& request) "this transaction depends on but may not yet be in the block chain." + HelpRequiringPassphrase(pwallet) + "\n", { - {"hexstring", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The transaction hex string"}, - {"prevtxs", RPCArg::Type::ARR, /* opt */ true, /* default_val */ "null", "A json array of previous dependent transaction outputs", + {"hexstring", RPCArg::Type::STR, RPCArg::Optional::NO, "The transaction hex string"}, + {"prevtxs", RPCArg::Type::ARR, RPCArg::Optional::OMITTED_NAMED_ARG, "A json array of previous dependent transaction outputs", { - {"", RPCArg::Type::OBJ, /* opt */ false, /* default_val */ "", "", + {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "", { - {"txid", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "The transaction id"}, - {"vout", RPCArg::Type::NUM, /* opt */ false, /* default_val */ "", "The output number"}, - {"scriptPubKey", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "script key"}, - {"redeemScript", RPCArg::Type::STR_HEX, /* opt */ true, /* default_val */ "omitted", "(required for P2SH or P2WSH)"}, - {"amount", RPCArg::Type::AMOUNT, /* opt */ false, /* default_val */ "", "The amount spent"}, + {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"}, + {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"}, + {"scriptPubKey", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "script key"}, + {"redeemScript", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "(required for P2SH) redeem script"}, + {"witnessScript", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "(required for P2WSH or P2SH-P2WSH) witness script"}, + {"amount", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "The amount spent"}, }, }, }, }, - {"sighashtype", RPCArg::Type::STR, /* opt */ true, /* default_val */ "ALL", "The signature hash type. Must be one of\n" + {"sighashtype", RPCArg::Type::STR, /* default */ "ALL", "The signature hash type. Must be one of\n" " \"ALL\"\n" " \"NONE\"\n" " \"SINGLE\"\n" @@ -3205,22 +3226,22 @@ static UniValue bumpfee(const JSONRPCRequest& request) "At a minimum, the new fee rate must be high enough to pay an additional new relay fee (incrementalfee\n" "returned by getnetworkinfo) to enter the node's mempool.\n", { - {"txid", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "The txid to be bumped"}, - {"options", RPCArg::Type::OBJ, /* opt */ true, /* default_val */ "null", "", + {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The txid to be bumped"}, + {"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "", { - {"confTarget", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "fallback to wallet's default", "Confirmation target (in blocks)"}, - {"totalFee", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "fallback to 'confTarget'", "Total fee (NOT feerate) to pay, in satoshis.\n" + {"confTarget", RPCArg::Type::NUM, /* default */ "fallback to wallet's default", "Confirmation target (in blocks)"}, + {"totalFee", RPCArg::Type::NUM, /* default */ "fallback to 'confTarget'", "Total fee (NOT feerate) to pay, in satoshis.\n" " In rare cases, the actual fee paid might be slightly higher than the specified\n" " totalFee if the tx change output has to be removed because it is too close to\n" " the dust threshold."}, - {"replaceable", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "true", "Whether the new transaction should still be\n" + {"replaceable", RPCArg::Type::BOOL, /* default */ "true", "Whether the new transaction should still be\n" " marked bip-125 replaceable. If true, the sequence numbers in the transaction will\n" " be left unchanged from the original. If false, any input sequence numbers in the\n" " original transaction that were less than 0xfffffffe will be increased to 0xfffffffe\n" " so the new transaction will not be explicitly bip-125 replaceable (though it may\n" " still be replaceable in practice, for example if it has unconfirmed ancestors which\n" " are replaceable)."}, - {"estimate_mode", RPCArg::Type::STR, /* opt */ true, /* default_val */ "UNSET", "The fee estimate mode, must be one of:\n" + {"estimate_mode", RPCArg::Type::STR, /* default */ "UNSET", "The fee estimate mode, must be one of:\n" " \"UNSET\"\n" " \"ECONOMICAL\"\n" " \"CONSERVATIVE\""}, @@ -3352,8 +3373,8 @@ UniValue generate(const JSONRPCRequest& request) RPCHelpMan{"generate", "\nMine up to nblocks blocks immediately (before the RPC call returns) to an address in the wallet.\n", { - {"nblocks", RPCArg::Type::NUM, /* opt */ false, /* default_val */ "", "How many blocks are generated immediately."}, - {"maxtries", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "1000000", "How many iterations to try."}, + {"nblocks", RPCArg::Type::NUM, RPCArg::Optional::NO, "How many blocks are generated immediately."}, + {"maxtries", RPCArg::Type::NUM, /* default */ "1000000", "How many iterations to try."}, }, RPCResult{ "[ blockhashes ] (array) hashes of blocks generated\n" @@ -3407,13 +3428,13 @@ UniValue rescanblockchain(const JSONRPCRequest& request) RPCHelpMan{"rescanblockchain", "\nRescan the local blockchain for wallet related transactions.\n", { - {"start_height", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "0", "block height where the rescan should start"}, - {"stop_height", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "", "the last block height that should be scanned. If none is provided it will rescan up to the tip at return time of this call."}, + {"start_height", RPCArg::Type::NUM, /* default */ "0", "block height where the rescan should start"}, + {"stop_height", RPCArg::Type::NUM, RPCArg::Optional::OMITTED_NAMED_ARG, "the last block height that should be scanned. If none is provided it will rescan up to the tip at return time of this call."}, }, RPCResult{ "{\n" - " \"start_height\" (numeric) The block height where the rescan has started.\n" - " \"stop_height\" (numeric) The height of the last rescanned block.\n" + " \"start_height\" (numeric) The block height where the rescan started (the requested height or 0)\n" + " \"stop_height\" (numeric) The height of the last rescanned block. May be null in rare cases if there was a reorg and the call didn't scan any blocks because they were already scanned in the background.\n" "}\n" }, RPCExamples{ @@ -3459,6 +3480,11 @@ UniValue rescanblockchain(const JSONRPCRequest& request) if (tip_height) { start_block = locked_chain->getBlockHash(start_height); + // If called with a stop_height, set the stop_height here to + // trigger a rescan to that height. + // If called without a stop height, leave stop_height as null here + // so rescan continues to the tip (even if the tip advances during + // rescan). if (stop_height) { stop_block = locked_chain->getBlockHash(*stop_height); } @@ -3478,7 +3504,7 @@ UniValue rescanblockchain(const JSONRPCRequest& request) } UniValue response(UniValue::VOBJ); response.pushKV("start_height", start_height); - response.pushKV("stop_height", result.stop_height ? *result.stop_height : UniValue()); + response.pushKV("stop_height", result.last_scanned_height ? *result.last_scanned_height : UniValue()); return response; } @@ -3616,7 +3642,7 @@ UniValue getaddressinfo(const JSONRPCRequest& request) "\nReturn information about the given bitcoin address. Some information requires the address\n" "to be in the wallet.\n", { - {"address", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The bitcoin address to get the information of."}, + {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The bitcoin address to get the information of."}, }, RPCResult{ "{\n" @@ -3646,7 +3672,7 @@ UniValue getaddressinfo(const JSONRPCRequest& request) " \"timestamp\" : timestamp, (number, optional) The creation time of the key if available in seconds since epoch (Jan 1 1970 GMT)\n" " \"hdkeypath\" : \"keypath\" (string, optional) The HD keypath if the key is HD and available\n" " \"hdseedid\" : \"<hash160>\" (string, optional) The Hash160 of the HD seed\n" - " \"hdmasterkeyid\" : \"<hash160>\" (string, optional) alias for hdseedid maintained for backwards compatibility. Will be removed in V0.18.\n" + " \"hdmasterfingerprint\" : \"<hash160>\" (string, optional) The fingperint of the master key.\n" " \"labels\" (object) Array of labels associated with the address.\n" " [\n" " { (json object of label data)\n" @@ -3709,10 +3735,10 @@ UniValue getaddressinfo(const JSONRPCRequest& request) } if (meta) { ret.pushKV("timestamp", meta->nCreateTime); - if (!meta->hdKeypath.empty()) { - ret.pushKV("hdkeypath", meta->hdKeypath); + if (meta->has_key_origin) { + ret.pushKV("hdkeypath", WriteHDKeypath(meta->key_origin.path)); ret.pushKV("hdseedid", meta->hd_seed_id.GetHex()); - ret.pushKV("hdmasterkeyid", meta->hd_seed_id.GetHex()); + ret.pushKV("hdmasterfingerprint", HexStr(meta->key_origin.fingerprint, meta->key_origin.fingerprint + 4)); } } @@ -3743,7 +3769,7 @@ static UniValue getaddressesbylabel(const JSONRPCRequest& request) RPCHelpMan{"getaddressesbylabel", "\nReturns the list of addresses assigned the specified label.\n", { - {"label", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The label."}, + {"label", RPCArg::Type::STR, RPCArg::Optional::NO, "The label."}, }, RPCResult{ "{ (json object with addresses as keys)\n" @@ -3791,7 +3817,7 @@ static UniValue listlabels(const JSONRPCRequest& request) RPCHelpMan{"listlabels", "\nReturns the list of all labels, or labels that are assigned to addresses with a specific purpose.\n", { - {"purpose", RPCArg::Type::STR, /* opt */ true, /* default_val */ "null", "Address purpose to list labels for ('send','receive'). An empty string is the same as not providing this argument."}, + {"purpose", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "Address purpose to list labels for ('send','receive'). An empty string is the same as not providing this argument."}, }, RPCResult{ "[ (json array of string)\n" @@ -3851,11 +3877,11 @@ UniValue sethdseed(const JSONRPCRequest& request) "\nNote that you will need to MAKE A NEW BACKUP of your wallet after setting the HD wallet seed." + HelpRequiringPassphrase(pwallet) + "\n", { - {"newkeypool", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "true", "Whether to flush old unused addresses, including change addresses, from the keypool and regenerate it.\n" + {"newkeypool", RPCArg::Type::BOOL, /* default */ "true", "Whether to flush old unused addresses, including change addresses, from the keypool and regenerate it.\n" " If true, the next address from getnewaddress and change address from getrawchangeaddress will be from this new seed.\n" " If false, addresses (including change addresses if the wallet already had HD Chain Split enabled) from the existing\n" " keypool will be used until it has been depleted."}, - {"seed", RPCArg::Type::STR, /* opt */ true, /* default_val */ "random seed", "The WIF private key to use as the new HD seed.\n" + {"seed", RPCArg::Type::STR, /* default */ "random seed", "The WIF private key to use as the new HD seed.\n" " The seed value can be retrieved using the dumpwallet command. It is the private key marked hdseed=1"}, }, RPCResults{}, @@ -3872,11 +3898,15 @@ UniValue sethdseed(const JSONRPCRequest& request) throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Cannot set a new HD seed while still in Initial Block Download"); } + if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) { + throw JSONRPCError(RPC_WALLET_ERROR, "Cannot set a HD seed to a wallet with private keys disabled"); + } + auto locked_chain = pwallet->chain().lock(); LOCK(pwallet->cs_wallet); // Do not do anything to non-HD wallets - if (!pwallet->IsHDEnabled()) { + if (!pwallet->CanSupportFeature(FEATURE_HD)) { throw JSONRPCError(RPC_WALLET_ERROR, "Cannot set a HD seed on a non-HD wallet. Start with -upgradewallet in order to upgrade a non-HD wallet to HD"); } @@ -3922,60 +3952,6 @@ void AddKeypathToMap(const CWallet* pwallet, const CKeyID& keyID, std::map<CPubK hd_keypaths.emplace(vchPubKey, std::move(info)); } -bool FillPSBT(const CWallet* pwallet, PartiallySignedTransaction& psbtx, int sighash_type, bool sign, bool bip32derivs) -{ - LOCK(pwallet->cs_wallet); - // Get all of the previous transactions - bool complete = true; - for (unsigned int i = 0; i < psbtx.tx->vin.size(); ++i) { - const CTxIn& txin = psbtx.tx->vin[i]; - PSBTInput& input = psbtx.inputs.at(i); - - if (PSBTInputSigned(input)) { - continue; - } - - // Verify input looks sane. This will check that we have at most one uxto, witness or non-witness. - if (!input.IsSane()) { - throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "PSBT input is not sane."); - } - - // If we have no utxo, grab it from the wallet. - if (!input.non_witness_utxo && input.witness_utxo.IsNull()) { - const uint256& txhash = txin.prevout.hash; - const auto it = pwallet->mapWallet.find(txhash); - if (it != pwallet->mapWallet.end()) { - const CWalletTx& wtx = it->second; - // We only need the non_witness_utxo, which is a superset of the witness_utxo. - // The signing code will switch to the smaller witness_utxo if this is ok. - input.non_witness_utxo = wtx.tx; - } - } - - // Get the Sighash type - if (sign && input.sighash_type > 0 && input.sighash_type != sighash_type) { - throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Specified Sighash and sighash in PSBT do not match."); - } - - complete &= SignPSBTInput(HidingSigningProvider(pwallet, !sign, !bip32derivs), psbtx, i, sighash_type); - } - - // Fill in the bip32 keypaths and redeemscripts for the outputs so that hardware wallets can identify change - for (unsigned int i = 0; i < psbtx.tx->vout.size(); ++i) { - const CTxOut& out = psbtx.tx->vout.at(i); - PSBTOutput& psbt_out = psbtx.outputs.at(i); - - // Fill a SignatureData with output info - SignatureData sigdata; - psbt_out.FillSignatureData(sigdata); - - MutableTransactionSignatureCreator creator(psbtx.tx.get_ptr(), 0, out.nValue, 1); - ProduceSignature(HidingSigningProvider(pwallet, true, !bip32derivs), creator, out.scriptPubKey, sigdata); - psbt_out.FromSignatureData(sigdata); - } - return complete; -} - UniValue walletprocesspsbt(const JSONRPCRequest& request) { std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request); @@ -3992,16 +3968,16 @@ UniValue walletprocesspsbt(const JSONRPCRequest& request) "that we can sign for." + HelpRequiringPassphrase(pwallet) + "\n", { - {"psbt", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The transaction base64 string"}, - {"sign", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "true", "Also sign the transaction when updating"}, - {"sighashtype", RPCArg::Type::STR, /* opt */ true, /* default_val */ "ALL", "The signature hash type to sign with if not specified by the PSBT. Must be one of\n" + {"psbt", RPCArg::Type::STR, RPCArg::Optional::NO, "The transaction base64 string"}, + {"sign", RPCArg::Type::BOOL, /* default */ "true", "Also sign the transaction when updating"}, + {"sighashtype", RPCArg::Type::STR, /* default */ "ALL", "The signature hash type to sign with if not specified by the PSBT. Must be one of\n" " \"ALL\"\n" " \"NONE\"\n" " \"SINGLE\"\n" " \"ALL|ANYONECANPAY\"\n" " \"NONE|ANYONECANPAY\"\n" " \"SINGLE|ANYONECANPAY\""}, - {"bip32derivs", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "If true, includes the BIP 32 derivation paths for public keys if we know them"}, + {"bip32derivs", RPCArg::Type::BOOL, /* default */ "false", "If true, includes the BIP 32 derivation paths for public keys if we know them"}, }, RPCResult{ "{\n" @@ -4020,7 +3996,7 @@ UniValue walletprocesspsbt(const JSONRPCRequest& request) // Unserialize the transaction PartiallySignedTransaction psbtx; std::string error; - if (!DecodePSBT(psbtx, request.params[0].get_str(), error)) { + if (!DecodeBase64PSBT(psbtx, request.params[0].get_str(), error)) { throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("TX decode failed %s", error)); } @@ -4030,7 +4006,11 @@ UniValue walletprocesspsbt(const JSONRPCRequest& request) // Fill transaction with our data and also sign bool sign = request.params[1].isNull() ? true : request.params[1].get_bool(); bool bip32derivs = request.params[3].isNull() ? false : request.params[3].get_bool(); - bool complete = FillPSBT(pwallet, psbtx, nHashType, sign, bip32derivs); + bool complete = true; + const TransactionError err = FillPSBT(pwallet, psbtx, complete, nHashType, sign, bip32derivs); + if (err != TransactionError::OK) { + throw JSONRPCTransactionError(err); + } UniValue result(UniValue::VOBJ); CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); @@ -4056,61 +4036,61 @@ UniValue walletcreatefundedpsbt(const JSONRPCRequest& request) "\nCreates and funds a transaction in the Partially Signed Transaction format. Inputs will be added if supplied inputs are not enough\n" "Implements the Creator and Updater roles.\n", { - {"inputs", RPCArg::Type::ARR, /* opt */ false, /* default_val */ "", "A json array of json objects", + {"inputs", RPCArg::Type::ARR, RPCArg::Optional::NO, "A json array of json objects", { - {"", RPCArg::Type::OBJ, /* opt */ false, /* default_val */ "", "", + {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "", { - {"txid", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "The transaction id"}, - {"vout", RPCArg::Type::NUM, /* opt */ false, /* default_val */ "", "The output number"}, - {"sequence", RPCArg::Type::NUM, /* opt */ false, /* default_val */ "", "The sequence number"}, + {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"}, + {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"}, + {"sequence", RPCArg::Type::NUM, RPCArg::Optional::NO, "The sequence number"}, }, }, }, }, - {"outputs", RPCArg::Type::ARR, /* opt */ false, /* default_val */ "", "a json array with outputs (key-value pairs), where none of the keys are duplicated.\n" + {"outputs", RPCArg::Type::ARR, RPCArg::Optional::NO, "a json array with outputs (key-value pairs), where none of the keys are duplicated.\n" "That is, each address can only appear once and there can only be one 'data' object.\n" "For compatibility reasons, a dictionary, which holds the key-value pairs directly, is also\n" " accepted as second parameter.", { - {"", RPCArg::Type::OBJ, /* opt */ true, /* default_val */ "", "", + {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "", { - {"address", RPCArg::Type::AMOUNT, /* opt */ false, /* default_val */ "", "A key-value pair. The key (string) is the bitcoin address, the value (float or string) is the amount in " + CURRENCY_UNIT + ""}, + {"address", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "A key-value pair. The key (string) is the bitcoin address, the value (float or string) is the amount in " + CURRENCY_UNIT + ""}, }, }, - {"", RPCArg::Type::OBJ, /* opt */ true, /* default_val */ "", "", + {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "", { - {"data", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "A key-value pair. The key must be \"data\", the value is hex-encoded data"}, + {"data", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "A key-value pair. The key must be \"data\", the value is hex-encoded data"}, }, }, }, }, - {"locktime", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "0", "Raw locktime. Non-0 value also locktime-activates inputs"}, - {"options", RPCArg::Type::OBJ, /* opt */ true, /* default_val */ "null", "", + {"locktime", RPCArg::Type::NUM, /* default */ "0", "Raw locktime. Non-0 value also locktime-activates inputs"}, + {"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "", { - {"changeAddress", RPCArg::Type::STR_HEX, /* opt */ true, /* default_val */ "pool address", "The bitcoin address to receive the change"}, - {"changePosition", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "random", "The index of the change output"}, - {"change_type", RPCArg::Type::STR, /* opt */ true, /* default_val */ "set by -changetype", "The output type to use. Only valid if changeAddress is not specified. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."}, - {"includeWatching", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "Also select inputs which are watch only"}, - {"lockUnspents", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "Lock selected unspent outputs"}, - {"feeRate", RPCArg::Type::AMOUNT, /* opt */ true, /* default_val */ "not set: makes wallet determine the fee", "Set a specific fee rate in " + CURRENCY_UNIT + "/kB"}, - {"subtractFeeFromOutputs", RPCArg::Type::ARR, /* opt */ true, /* default_val */ "empty array", "A json array of integers.\n" + {"changeAddress", RPCArg::Type::STR_HEX, /* default */ "pool address", "The bitcoin address to receive the change"}, + {"changePosition", RPCArg::Type::NUM, /* default */ "random", "The index of the change output"}, + {"change_type", RPCArg::Type::STR, /* default */ "set by -changetype", "The output type to use. Only valid if changeAddress is not specified. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."}, + {"includeWatching", RPCArg::Type::BOOL, /* default */ "false", "Also select inputs which are watch only"}, + {"lockUnspents", RPCArg::Type::BOOL, /* default */ "false", "Lock selected unspent outputs"}, + {"feeRate", RPCArg::Type::AMOUNT, /* default */ "not set: makes wallet determine the fee", "Set a specific fee rate in " + CURRENCY_UNIT + "/kB"}, + {"subtractFeeFromOutputs", RPCArg::Type::ARR, /* default */ "empty array", "A json array of integers.\n" " The fee will be equally deducted from the amount of each specified output.\n" " Those recipients will receive less bitcoins than you enter in their corresponding amount field.\n" " If no outputs are specified here, the sender pays the fee.", { - {"vout_index", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "", "The zero-based output index, before a change output is added."}, + {"vout_index", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "The zero-based output index, before a change output is added."}, }, }, - {"replaceable", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "Marks this transaction as BIP125 replaceable.\n" + {"replaceable", RPCArg::Type::BOOL, /* default */ "false", "Marks this transaction as BIP125 replaceable.\n" " Allows this transaction to be replaced by a transaction with higher fees"}, - {"conf_target", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "Fallback to wallet's confirmation target", "Confirmation target (in blocks)"}, - {"estimate_mode", RPCArg::Type::STR, /* opt */ true, /* default_val */ "UNSET", "The fee estimate mode, must be one of:\n" + {"conf_target", RPCArg::Type::NUM, /* default */ "Fallback to wallet's confirmation target", "Confirmation target (in blocks)"}, + {"estimate_mode", RPCArg::Type::STR, /* default */ "UNSET", "The fee estimate mode, must be one of:\n" " \"UNSET\"\n" " \"ECONOMICAL\"\n" " \"CONSERVATIVE\""}, }, "options"}, - {"bip32derivs", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "If true, includes the BIP 32 derivation paths for public keys if we know them"}, + {"bip32derivs", RPCArg::Type::BOOL, /* default */ "false", "If true, includes the BIP 32 derivation paths for public keys if we know them"}, }, RPCResult{ "{\n" @@ -4144,7 +4124,11 @@ UniValue walletcreatefundedpsbt(const JSONRPCRequest& request) // Fill transaction with out data but don't sign bool bip32derivs = request.params[4].isNull() ? false : request.params[4].get_bool(); - FillPSBT(pwallet, psbtx, 1, false, bip32derivs); + bool complete = true; + const TransactionError err = FillPSBT(pwallet, psbtx, complete, 1, false, bip32derivs); + if (err != TransactionError::OK) { + throw JSONRPCTransactionError(err); + } // Serialize the PSBT CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); @@ -4180,7 +4164,7 @@ static const CRPCCommand commands[] = { "wallet", "addmultisigaddress", &addmultisigaddress, {"nrequired","keys","label","address_type"} }, { "wallet", "backupwallet", &backupwallet, {"destination"} }, { "wallet", "bumpfee", &bumpfee, {"txid", "options"} }, - { "wallet", "createwallet", &createwallet, {"wallet_name", "disable_private_keys"} }, + { "wallet", "createwallet", &createwallet, {"wallet_name", "disable_private_keys", "blank"} }, { "wallet", "dumpprivkey", &dumpprivkey, {"address"} }, { "wallet", "dumpwallet", &dumpwallet, {"filename"} }, { "wallet", "encryptwallet", &encryptwallet, {"passphrase"} }, diff --git a/src/wallet/rpcwallet.h b/src/wallet/rpcwallet.h index abd7750874..58053bde59 100644 --- a/src/wallet/rpcwallet.h +++ b/src/wallet/rpcwallet.h @@ -30,5 +30,4 @@ bool EnsureWalletIsAvailable(CWallet *, bool avoidException); UniValue getaddressinfo(const JSONRPCRequest& request); UniValue signrawtransactionwithwallet(const JSONRPCRequest& request); -bool FillPSBT(const CWallet* pwallet, PartiallySignedTransaction& psbtx, int sighash_type = 1 /* SIGHASH_ALL */, bool sign = true, bool bip32derivs = false); #endif //BITCOIN_WALLET_RPCWALLET_H diff --git a/src/wallet/test/psbt_wallet_tests.cpp b/src/wallet/test/psbt_wallet_tests.cpp index 9918eeb89f..789e86e21b 100644 --- a/src/wallet/test/psbt_wallet_tests.cpp +++ b/src/wallet/test/psbt_wallet_tests.cpp @@ -4,7 +4,9 @@ #include <key_io.h> #include <script/sign.h> +#include <util/bip32.h> #include <util/strencodings.h> +#include <wallet/psbtwallet.h> #include <wallet/rpcwallet.h> #include <wallet/wallet.h> #include <univalue.h> @@ -60,7 +62,8 @@ BOOST_AUTO_TEST_CASE(psbt_updater_test) ssData >> psbtx; // Fill transaction with our data - FillPSBT(&m_wallet, psbtx, SIGHASH_ALL, false, true); + bool complete = true; + BOOST_REQUIRE_EQUAL(TransactionError::OK, FillPSBT(&m_wallet, psbtx, complete, SIGHASH_ALL, false, true)); // Get the final tx CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp index 8c380f1257..e674b2faea 100644 --- a/src/wallet/test/wallet_tests.cpp +++ b/src/wallet/test/wallet_tests.cpp @@ -44,6 +44,7 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup) CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())); CBlockIndex* newTip = chainActive.Tip(); + LockAnnotation lock(::cs_main); auto locked_chain = chain->lock(); // Verify ScanForWalletTransactions accommodates a null start block. @@ -54,9 +55,9 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup) reserver.reserve(); CWallet::ScanResult result = wallet.ScanForWalletTransactions({} /* start_block */, {} /* stop_block */, reserver, false /* update */); BOOST_CHECK_EQUAL(result.status, CWallet::ScanResult::SUCCESS); - BOOST_CHECK(result.failed_block.IsNull()); - BOOST_CHECK(result.stop_block.IsNull()); - BOOST_CHECK(!result.stop_height); + BOOST_CHECK(result.last_failed_block.IsNull()); + BOOST_CHECK(result.last_scanned_block.IsNull()); + BOOST_CHECK(!result.last_scanned_height); BOOST_CHECK_EQUAL(wallet.GetImmatureBalance(), 0); } @@ -69,9 +70,9 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup) reserver.reserve(); CWallet::ScanResult result = wallet.ScanForWalletTransactions(oldTip->GetBlockHash(), {} /* stop_block */, reserver, false /* update */); BOOST_CHECK_EQUAL(result.status, CWallet::ScanResult::SUCCESS); - BOOST_CHECK(result.failed_block.IsNull()); - BOOST_CHECK_EQUAL(result.stop_block, newTip->GetBlockHash()); - BOOST_CHECK_EQUAL(*result.stop_height, newTip->nHeight); + BOOST_CHECK(result.last_failed_block.IsNull()); + BOOST_CHECK_EQUAL(result.last_scanned_block, newTip->GetBlockHash()); + BOOST_CHECK_EQUAL(*result.last_scanned_height, newTip->nHeight); BOOST_CHECK_EQUAL(wallet.GetImmatureBalance(), 100 * COIN); } @@ -88,9 +89,9 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup) reserver.reserve(); CWallet::ScanResult result = wallet.ScanForWalletTransactions(oldTip->GetBlockHash(), {} /* stop_block */, reserver, false /* update */); BOOST_CHECK_EQUAL(result.status, CWallet::ScanResult::FAILURE); - BOOST_CHECK_EQUAL(result.failed_block, oldTip->GetBlockHash()); - BOOST_CHECK_EQUAL(result.stop_block, newTip->GetBlockHash()); - BOOST_CHECK_EQUAL(*result.stop_height, newTip->nHeight); + BOOST_CHECK_EQUAL(result.last_failed_block, oldTip->GetBlockHash()); + BOOST_CHECK_EQUAL(result.last_scanned_block, newTip->GetBlockHash()); + BOOST_CHECK_EQUAL(*result.last_scanned_height, newTip->nHeight); BOOST_CHECK_EQUAL(wallet.GetImmatureBalance(), 50 * COIN); } @@ -106,9 +107,9 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup) reserver.reserve(); CWallet::ScanResult result = wallet.ScanForWalletTransactions(oldTip->GetBlockHash(), {} /* stop_block */, reserver, false /* update */); BOOST_CHECK_EQUAL(result.status, CWallet::ScanResult::FAILURE); - BOOST_CHECK_EQUAL(result.failed_block, newTip->GetBlockHash()); - BOOST_CHECK(result.stop_block.IsNull()); - BOOST_CHECK(!result.stop_height); + BOOST_CHECK_EQUAL(result.last_failed_block, newTip->GetBlockHash()); + BOOST_CHECK(result.last_scanned_block.IsNull()); + BOOST_CHECK(!result.last_scanned_height); BOOST_CHECK_EQUAL(wallet.GetImmatureBalance(), 0); } } @@ -123,6 +124,7 @@ BOOST_FIXTURE_TEST_CASE(importmulti_rescan, TestChain100Setup) CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())); CBlockIndex* newTip = chainActive.Tip(); + LockAnnotation lock(::cs_main); auto locked_chain = chain->lock(); // Prune the older block file. @@ -268,6 +270,7 @@ static int64_t AddTx(CWallet& wallet, uint32_t lockTime, int64_t mockTime, int64 SetMockTime(mockTime); CBlockIndex* block = nullptr; if (blockTime > 0) { + LockAnnotation lock(::cs_main); auto locked_chain = wallet.chain().lock(); auto inserted = mapBlockIndex.emplace(GetRandHash(), new CBlockIndex); assert(inserted.second); @@ -345,9 +348,9 @@ public: reserver.reserve(); CWallet::ScanResult result = wallet->ScanForWalletTransactions(chainActive.Genesis()->GetBlockHash(), {} /* stop_block */, reserver, false /* update */); BOOST_CHECK_EQUAL(result.status, CWallet::ScanResult::SUCCESS); - BOOST_CHECK_EQUAL(result.stop_block, chainActive.Tip()->GetBlockHash()); - BOOST_CHECK_EQUAL(*result.stop_height, chainActive.Height()); - BOOST_CHECK(result.failed_block.IsNull()); + BOOST_CHECK_EQUAL(result.last_scanned_block, chainActive.Tip()->GetBlockHash()); + BOOST_CHECK_EQUAL(*result.last_scanned_height, chainActive.Height()); + BOOST_CHECK(result.last_failed_block.IsNull()); } ~ListCoinsTestingSetup() @@ -449,6 +452,7 @@ BOOST_FIXTURE_TEST_CASE(wallet_disableprivkeys, TestChain100Setup) { auto chain = interfaces::MakeChain(); std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(*chain, WalletLocation(), WalletDatabase::CreateDummy()); + wallet->SetMinVersion(FEATURE_LATEST); wallet->SetWalletFlag(WALLET_FLAG_DISABLE_PRIVATE_KEYS); BOOST_CHECK(!wallet->TopUpKeyPool(1000)); CPubKey pubkey; diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 5c379aacd6..388422bec8 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -27,6 +27,7 @@ #include <shutdown.h> #include <timedata.h> #include <txmempool.h> +#include <util/bip32.h> #include <util/moneystr.h> #include <wallet/fees.h> @@ -130,6 +131,28 @@ void UnloadWallet(std::shared_ptr<CWallet>&& wallet) } } +std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const WalletLocation& location, std::string& error, std::string& warning) +{ + if (!CWallet::Verify(chain, location, false, error, warning)) { + error = "Wallet file verification failed: " + error; + return nullptr; + } + + std::shared_ptr<CWallet> wallet = CWallet::CreateWalletFromFile(chain, location); + if (!wallet) { + error = "Wallet loading failed."; + return nullptr; + } + AddWallet(wallet); + wallet->postInitProcess(); + return wallet; +} + +std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const std::string& name, std::string& error, std::string& warning) +{ + return LoadWallet(chain, WalletLocation(name), error, warning); +} + const uint32_t BIP32_HARDENED_KEY_LIMIT = 0x80000000; const uint256 CMerkleTx::ABANDON_HASH(uint256S("0000000000000000000000000000000000000000000000000000000000000001")); @@ -168,6 +191,7 @@ const CWalletTx* CWallet::GetWalletTx(const uint256& hash) const CPubKey CWallet::GenerateNewKey(WalletBatch &batch, bool internal) { assert(!IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)); + assert(!IsWalletFlagSet(WALLET_FLAG_BLANK_WALLET)); AssertLockHeld(cs_wallet); // mapKeyMetadata bool fCompressed = CanSupportFeature(FEATURE_COMPRPUBKEY); // default to compressed public keys if we want 0.6.0 wallets @@ -177,7 +201,7 @@ CPubKey CWallet::GenerateNewKey(WalletBatch &batch, bool internal) int64_t nCreationTime = GetTime(); CKeyMetadata metadata(nCreationTime); - // use HD key derivation if HD was enabled during wallet creation + // use HD key derivation if HD was enabled during wallet creation and a seed is present if (IsHDEnabled()) { DeriveNewChildKey(batch, metadata, secret, (CanSupportFeature(FEATURE_HD_SPLIT) ? internal : false)); } else { @@ -232,16 +256,25 @@ void CWallet::DeriveNewChildKey(WalletBatch &batch, CKeyMetadata& metadata, CKey if (internal) { chainChildKey.Derive(childKey, hdChain.nInternalChainCounter | BIP32_HARDENED_KEY_LIMIT); metadata.hdKeypath = "m/0'/1'/" + std::to_string(hdChain.nInternalChainCounter) + "'"; + metadata.key_origin.path.push_back(0 | BIP32_HARDENED_KEY_LIMIT); + metadata.key_origin.path.push_back(1 | BIP32_HARDENED_KEY_LIMIT); + metadata.key_origin.path.push_back(hdChain.nInternalChainCounter | BIP32_HARDENED_KEY_LIMIT); hdChain.nInternalChainCounter++; } else { chainChildKey.Derive(childKey, hdChain.nExternalChainCounter | BIP32_HARDENED_KEY_LIMIT); metadata.hdKeypath = "m/0'/0'/" + std::to_string(hdChain.nExternalChainCounter) + "'"; + metadata.key_origin.path.push_back(0 | BIP32_HARDENED_KEY_LIMIT); + metadata.key_origin.path.push_back(0 | BIP32_HARDENED_KEY_LIMIT); + metadata.key_origin.path.push_back(hdChain.nExternalChainCounter | BIP32_HARDENED_KEY_LIMIT); hdChain.nExternalChainCounter++; } } while (HaveKey(childKey.key.GetPubKey().GetID())); secret = childKey.key; metadata.hd_seed_id = hdChain.seed_id; + CKeyID master_id = masterKey.key.GetPubKey().GetID(); + std::copy(master_id.begin(), master_id.begin() + 4, metadata.key_origin.fingerprint); + metadata.has_key_origin = true; // update the chain model in the database if (!batch.WriteHDChain(hdChain)) throw std::runtime_error(std::string(__func__) + ": Writing HD chain model failed"); @@ -251,6 +284,9 @@ bool CWallet::AddKeyPubKeyWithDB(WalletBatch &batch, const CKey& secret, const C { AssertLockHeld(cs_wallet); // mapKeyMetadata + // Make sure we aren't adding private keys to private key disabled wallets + assert(!IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)); + // CCryptoKeyStore has no concept of wallet databases, but calls AddCryptedKey // which is overridden below. To avoid flushes, the database handle is // tunneled through to it. @@ -280,6 +316,7 @@ bool CWallet::AddKeyPubKeyWithDB(WalletBatch &batch, const CKey& secret, const C secret.GetPrivKey(), mapKeyMetadata[pubkey.GetID()]); } + UnsetWalletFlag(WALLET_FLAG_BLANK_WALLET); return true; } @@ -321,6 +358,54 @@ void CWallet::LoadScriptMetadata(const CScriptID& script_id, const CKeyMetadata m_script_metadata[script_id] = meta; } +// Writes a keymetadata for a public key. overwrite specifies whether to overwrite an existing metadata for that key if there exists one. +bool CWallet::WriteKeyMetadata(const CKeyMetadata& meta, const CPubKey& pubkey, const bool overwrite) +{ + return WalletBatch(*database).WriteKeyMetadata(meta, pubkey, overwrite); +} + +void CWallet::UpgradeKeyMetadata() +{ + AssertLockHeld(cs_wallet); // mapKeyMetadata + if (IsLocked() || IsWalletFlagSet(WALLET_FLAG_KEY_ORIGIN_METADATA)) { + return; + } + + std::unique_ptr<WalletBatch> batch = MakeUnique<WalletBatch>(*database); + size_t cnt = 0; + for (auto& meta_pair : mapKeyMetadata) { + CKeyMetadata& meta = meta_pair.second; + if (!meta.hd_seed_id.IsNull() && !meta.has_key_origin && meta.hdKeypath != "s") { // If the hdKeypath is "s", that's the seed and it doesn't have a key origin + CKey key; + GetKey(meta.hd_seed_id, key); + CExtKey masterKey; + masterKey.SetSeed(key.begin(), key.size()); + // Add to map + CKeyID master_id = masterKey.key.GetPubKey().GetID(); + std::copy(master_id.begin(), master_id.begin() + 4, meta.key_origin.fingerprint); + if (!ParseHDKeypath(meta.hdKeypath, meta.key_origin.path)) { + throw std::runtime_error("Invalid stored hdKeypath"); + } + meta.has_key_origin = true; + if (meta.nVersion < CKeyMetadata::VERSION_WITH_KEY_ORIGIN) { + meta.nVersion = CKeyMetadata::VERSION_WITH_KEY_ORIGIN; + } + + // Write meta to wallet + CPubKey pubkey; + if (GetPubKey(meta_pair.first, pubkey)) { + batch->WriteKeyMetadata(meta, pubkey, true); + if (++cnt % 1000 == 0) { + // avoid creating overlarge in-memory batches in case the wallet contains large amounts of keys + batch.reset(new WalletBatch(*database)); + } + } + } + } + batch.reset(); //write before setting the flag + SetWalletFlag(WALLET_FLAG_KEY_ORIGIN_METADATA); +} + bool CWallet::LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret) { return CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret); @@ -346,7 +431,11 @@ bool CWallet::AddCScript(const CScript& redeemScript) { if (!CCryptoKeyStore::AddCScript(redeemScript)) return false; - return WalletBatch(*database).WriteCScript(Hash160(redeemScript), redeemScript); + if (WalletBatch(*database).WriteCScript(Hash160(redeemScript), redeemScript)) { + UnsetWalletFlag(WALLET_FLAG_BLANK_WALLET); + return true; + } + return false; } bool CWallet::LoadCScript(const CScript& redeemScript) @@ -371,7 +460,11 @@ bool CWallet::AddWatchOnly(const CScript& dest) const CKeyMetadata& meta = m_script_metadata[CScriptID(dest)]; UpdateTimeFirstKey(meta.nCreateTime); NotifyWatchonlyChanged(true); - return WalletBatch(*database).WriteWatchOnly(dest, meta); + if (WalletBatch(*database).WriteWatchOnly(dest, meta)) { + UnsetWalletFlag(WALLET_FLAG_BLANK_WALLET); + return true; + } + return false; } bool CWallet::AddWatchOnly(const CScript& dest, int64_t nCreateTime) @@ -411,8 +504,11 @@ bool CWallet::Unlock(const SecureString& strWalletPassphrase, bool accept_no_key return false; if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, _vMasterKey)) continue; // try another master key - if (CCryptoKeyStore::Unlock(_vMasterKey, accept_no_keys)) + if (CCryptoKeyStore::Unlock(_vMasterKey, accept_no_keys)) { + // Now that we've unlocked, upgrade the key metadata + UpgradeKeyMetadata(); return true; + } } } return false; @@ -1372,6 +1468,7 @@ CPubKey CWallet::DeriveNewSeed(const CKey& key) // set the hd keypath to "s" -> Seed, refers the seed to itself metadata.hdKeypath = "s"; + metadata.has_key_origin = false; metadata.hd_seed_id = seed.GetID(); { @@ -1399,6 +1496,7 @@ void CWallet::SetHDSeed(const CPubKey& seed) newHdChain.seed_id = seed.GetID(); SetHDChain(newHdChain, false); NotifyCanGetAddressesChanged(); + UnsetWalletFlag(WALLET_FLAG_BLANK_WALLET); } void CWallet::SetHDChain(const CHDChain& chain, bool memonly) @@ -1415,6 +1513,30 @@ bool CWallet::IsHDEnabled() const return !hdChain.seed_id.IsNull(); } +bool CWallet::CanGenerateKeys() +{ + // A wallet can generate keys if it has an HD seed (IsHDEnabled) or it is a non-HD wallet (pre FEATURE_HD) + LOCK(cs_wallet); + return IsHDEnabled() || !CanSupportFeature(FEATURE_HD); +} + +bool CWallet::CanGetAddresses(bool internal) +{ + LOCK(cs_wallet); + // Check if the keypool has keys + bool keypool_has_keys; + if (internal && CanSupportFeature(FEATURE_HD_SPLIT)) { + keypool_has_keys = setInternalKeyPool.size() > 0; + } else { + keypool_has_keys = KeypoolCountExternalKeys() > 0; + } + // If the keypool doesn't have keys, check if we can generate them + if (!keypool_has_keys) { + return CanGenerateKeys(); + } + return keypool_has_keys; +} + void CWallet::SetWalletFlag(uint64_t flags) { LOCK(cs_wallet); @@ -1423,6 +1545,14 @@ void CWallet::SetWalletFlag(uint64_t flags) throw std::runtime_error(std::string(__func__) + ": writing wallet flags failed"); } +void CWallet::UnsetWalletFlag(uint64_t flag) +{ + LOCK(cs_wallet); + m_wallet_flags &= ~flag; + if (!WalletBatch(*database).WriteWalletFlags(m_wallet_flags)) + throw std::runtime_error(std::string(__func__) + ": writing wallet flags failed"); +} + bool CWallet::IsWalletFlagSet(uint64_t flag) { return (m_wallet_flags & flag); @@ -1600,7 +1730,7 @@ int64_t CWallet::RescanFromTime(int64_t startTime, const WalletRescanReserver& r ScanResult result = ScanForWalletTransactions(start_block, {} /* stop_block */, reserver, update); if (result.status == ScanResult::FAILURE) { int64_t time_max; - if (!chain().findBlock(result.failed_block, nullptr /* block */, nullptr /* time */, &time_max)) { + if (!chain().findBlock(result.last_failed_block, nullptr /* block */, nullptr /* time */, &time_max)) { throw std::logic_error("ScanForWalletTransactions returned invalid block hash"); } return time_max + TIMESTAMP_WINDOW + 1; @@ -1614,15 +1744,17 @@ int64_t CWallet::RescanFromTime(int64_t startTime, const WalletRescanReserver& r * from or to us. If fUpdate is true, found transactions that already * exist in the wallet will be updated. * - * @param[in] start_block if not null, the scan will start at this block instead - * of the genesis block - * @param[in] stop_block if not null, the scan will stop at this block instead - * of the chain tip + * @param[in] start_block Scan starting block. If block is not on the active + * chain, the scan will return SUCCESS immediately. + * @param[in] stop_block Scan ending block. If block is not on the active + * chain, the scan will continue until it reaches the + * chain tip. * - * @return ScanResult indicating success or failure of the scan. SUCCESS if - * scan was successful. FAILURE if a complete rescan was not possible (due to - * pruning or corruption). USER_ABORT if the rescan was aborted before it - * could complete. + * @return ScanResult returning scan information and indicating success or + * failure. Return status will be set to SUCCESS if scan was + * successful. FAILURE if a complete rescan was not possible (due to + * pruning or corruption). USER_ABORT if the rescan was aborted before + * it could complete. * * @pre Caller needs to make sure start_block (and the optional stop_block) are on * the main chain after to the addition of any new keys you want to detect @@ -1675,7 +1807,7 @@ CWallet::ScanResult CWallet::ScanForWalletTransactions(const uint256& start_bloc // marking transactions as coming from the wrong block. // TODO: This should return success instead of failure, see // https://github.com/bitcoin/bitcoin/pull/14711#issuecomment-458342518 - result.failed_block = block_hash; + result.last_failed_block = block_hash; result.status = ScanResult::FAILURE; break; } @@ -1683,11 +1815,11 @@ CWallet::ScanResult CWallet::ScanForWalletTransactions(const uint256& start_bloc SyncTransaction(block.vtx[posInBlock], block_hash, posInBlock, fUpdate); } // scan succeeded, record block as most recent successfully scanned - result.stop_block = block_hash; - result.stop_height = *block_height; + result.last_scanned_block = block_hash; + result.last_scanned_height = *block_height; } else { // could not scan block, keep scanning but record this block as the most recent failure - result.failed_block = block_hash; + result.last_failed_block = block_hash; result.status = ScanResult::FAILURE; } if (block_hash == stop_block) { @@ -1717,10 +1849,10 @@ CWallet::ScanResult CWallet::ScanForWalletTransactions(const uint256& start_bloc } ShowProgress(strprintf("%s " + _("Rescanning..."), GetDisplayName()), 100); // hide progress dialog in GUI if (block_height && fAbortRescan) { - WalletLogPrintf("Rescan aborted at block %d. Progress=%f\n", block_height.value_or(0), progress_current); + WalletLogPrintf("Rescan aborted at block %d. Progress=%f\n", *block_height, progress_current); result.status = ScanResult::USER_ABORT; } else if (block_height && ShutdownRequested()) { - WalletLogPrintf("Rescan interrupted by shutdown request at block %d. Progress=%f\n", block_height.value_or(0), progress_current); + WalletLogPrintf("Rescan interrupted by shutdown request at block %d. Progress=%f\n", *block_height, progress_current); result.status = ScanResult::USER_ABORT; } } @@ -2581,7 +2713,7 @@ static bool IsCurrentForAntiFeeSniping(interfaces::Chain::Lock& locked_chain) */ static uint32_t GetLocktimeForNewTransaction(interfaces::Chain::Lock& locked_chain) { - uint32_t const height = locked_chain.getHeight().value_or(-1); + uint32_t const height = locked_chain.getHeight().get_value_or(-1); uint32_t locktime; // Discourage fee sniping. // @@ -2708,8 +2840,8 @@ bool CWallet::CreateTransaction(interfaces::Chain::Lock& locked_chain, const std // post-backup change. // Reserve a new key pair from key pool - if (IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) { - strFailReason = _("Can't generate a change-address key. Private keys are disabled for this wallet."); + if (!CanGetAddresses(true)) { + strFailReason = _("Can't generate a change-address key. No keys in the internal keypool and can't generate any keys."); return false; } CPubKey vchPubKey; @@ -3098,7 +3230,8 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet) { LOCK(cs_KeyStore); // This wallet is in its first run if all of these are empty - fFirstRunRet = mapKeys.empty() && mapCryptedKeys.empty() && mapWatchKeys.empty() && setWatchOnly.empty() && mapScripts.empty() && !IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS); + fFirstRunRet = mapKeys.empty() && mapCryptedKeys.empty() && mapWatchKeys.empty() && setWatchOnly.empty() && mapScripts.empty() + && !IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) && !IsWalletFlagSet(WALLET_FLAG_BLANK_WALLET); } if (nLoadWalletRet != DBErrors::LOAD_OK) @@ -3167,7 +3300,7 @@ bool CWallet::SetAddressBook(const CTxDestination& address, const std::string& s { bool fUpdated = false; { - LOCK(cs_wallet); // mapAddressBook + LOCK(cs_wallet); std::map<CTxDestination, CAddressBookData>::iterator mi = mapAddressBook.find(address); fUpdated = mi != mapAddressBook.end(); mapAddressBook[address].name = strName; @@ -3184,7 +3317,7 @@ bool CWallet::SetAddressBook(const CTxDestination& address, const std::string& s bool CWallet::DelAddressBook(const CTxDestination& address) { { - LOCK(cs_wallet); // mapAddressBook + LOCK(cs_wallet); // Delete destdata tuples associated with address std::string strAddress = EncodeDestination(address); @@ -3283,7 +3416,7 @@ void CWallet::LoadKeyPool(int64_t nIndex, const CKeyPool &keypool) bool CWallet::TopUpKeyPool(unsigned int kpSize) { - if (IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) { + if (!CanGenerateKeys()) { return false; } { @@ -3317,20 +3450,8 @@ bool CWallet::TopUpKeyPool(unsigned int kpSize) internal = true; } - assert(m_max_keypool_index < std::numeric_limits<int64_t>::max()); // How in the hell did you use so many keys? - int64_t index = ++m_max_keypool_index; - CPubKey pubkey(GenerateNewKey(batch, internal)); - if (!batch.WritePool(index, CKeyPool(pubkey, internal))) { - throw std::runtime_error(std::string(__func__) + ": writing generated key failed"); - } - - if (internal) { - setInternalKeyPool.insert(index); - } else { - setExternalKeyPool.insert(index); - } - m_pool_key_to_index[pubkey.GetID()] = index; + AddKeypoolPubkeyWithDB(pubkey, internal, batch); } if (missingInternal + missingExternal > 0) { WalletLogPrintf("keypool added %d keys (%d internal), size=%u (%u internal)\n", missingInternal + missingExternal, missingInternal, setInternalKeyPool.size() + setExternalKeyPool.size() + set_pre_split_keypool.size(), setInternalKeyPool.size()); @@ -3340,6 +3461,29 @@ bool CWallet::TopUpKeyPool(unsigned int kpSize) return true; } +void CWallet::AddKeypoolPubkey(const CPubKey& pubkey, const bool internal) +{ + WalletBatch batch(*database); + AddKeypoolPubkeyWithDB(pubkey, internal, batch); + NotifyCanGetAddressesChanged(); +} + +void CWallet::AddKeypoolPubkeyWithDB(const CPubKey& pubkey, const bool internal, WalletBatch& batch) +{ + LOCK(cs_wallet); + assert(m_max_keypool_index < std::numeric_limits<int64_t>::max()); // How in the hell did you use so many keys? + int64_t index = ++m_max_keypool_index; + if (!batch.WritePool(index, CKeyPool(pubkey, internal))) { + throw std::runtime_error(std::string(__func__) + ": writing imported pubkey failed"); + } + if (internal) { + setInternalKeyPool.insert(index); + } else { + setExternalKeyPool.insert(index); + } + m_pool_key_to_index[pubkey.GetID()] = index; +} + bool CWallet::ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool, bool fRequestedInternal) { nIndex = -1; @@ -3350,7 +3494,8 @@ bool CWallet::ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool, bool fRe if (!IsLocked()) TopUpKeyPool(); - bool fReturningInternal = IsHDEnabled() && CanSupportFeature(FEATURE_HD_SPLIT) && fRequestedInternal; + bool fReturningInternal = fRequestedInternal; + fReturningInternal &= (IsHDEnabled() && CanSupportFeature(FEATURE_HD_SPLIT)) || IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS); bool use_split_keypool = set_pre_split_keypool.empty(); std::set<int64_t>& setKeyPool = use_split_keypool ? (fReturningInternal ? setInternalKeyPool : setExternalKeyPool) : set_pre_split_keypool; @@ -3367,7 +3512,8 @@ bool CWallet::ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool, bool fRe if (!batch.ReadPool(nIndex, keypool)) { throw std::runtime_error(std::string(__func__) + ": read failed"); } - if (!HaveKey(keypool.vchPubKey.GetID())) { + CPubKey pk; + if (!GetPubKey(keypool.vchPubKey.GetID(), pk)) { throw std::runtime_error(std::string(__func__) + ": unknown key in key pool"); } // If the key was pre-split keypool, we don't care about what type it is @@ -3413,7 +3559,7 @@ void CWallet::ReturnKey(int64_t nIndex, bool fInternal, const CPubKey& pubkey) bool CWallet::GetKeyFromPool(CPubKey& result, bool internal) { - if (IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) { + if (!CanGetAddresses(internal)) { return false; } @@ -3421,7 +3567,7 @@ bool CWallet::GetKeyFromPool(CPubKey& result, bool internal) { LOCK(cs_wallet); int64_t nIndex; - if (!ReserveKeyFromKeyPool(nIndex, keypool, internal)) { + if (!ReserveKeyFromKeyPool(nIndex, keypool, internal) && !IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) { if (IsLocked()) return false; WalletBatch batch(*database); result = GenerateNewKey(batch, internal); @@ -3614,6 +3760,10 @@ std::set<CTxDestination> CWallet::GetLabelAddresses(const std::string& label) co bool CReserveKey::GetReservedKey(CPubKey& pubkey, bool internal) { + if (!pwallet->CanGetAddresses(internal)) { + return false; + } + if (nIndex == -1) { CKeyPool keypool; @@ -3864,7 +4014,6 @@ bool CWallet::GetDestData(const CTxDestination &dest, const std::string &key, st std::vector<std::string> CWallet::GetDestValues(const std::string& prefix) const { - LOCK(cs_wallet); std::vector<std::string> values; for (const auto& address : mapAddressBook) { for (const auto& data : address.second.destdata) { @@ -4068,20 +4217,22 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain, if ((wallet_creation_flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS)) { //selective allow to set flags walletInstance->SetWalletFlag(WALLET_FLAG_DISABLE_PRIVATE_KEYS); + } else if (wallet_creation_flags & WALLET_FLAG_BLANK_WALLET) { + walletInstance->SetWalletFlag(WALLET_FLAG_BLANK_WALLET); } else { // generate a new seed CPubKey seed = walletInstance->GenerateNewSeed(); walletInstance->SetHDSeed(seed); - } + } // Otherwise, do not generate a new seed // Top up the keypool - if (!walletInstance->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) && !walletInstance->TopUpKeyPool()) { + if (walletInstance->CanGenerateKeys() && !walletInstance->TopUpKeyPool()) { InitError(_("Unable to generate initial keys")); return nullptr; } auto locked_chain = chain.assumeLocked(); // Temporary. Removed in upcoming lock cleanup - walletInstance->ChainStateFlushed(locked_chain->getLocator()); + walletInstance->ChainStateFlushed(locked_chain->getTipLocator()); } else if (wallet_creation_flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS) { // Make it impossible to disable private keys after creation InitError(strprintf(_("Error loading %s: Private keys can only be disabled during creation"), walletFile)); @@ -4228,7 +4379,7 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain, } } walletInstance->WalletLogPrintf("Rescan completed in %15dms\n", GetTimeMillis() - nStart); - walletInstance->ChainStateFlushed(locked_chain->getLocator()); + walletInstance->ChainStateFlushed(locked_chain->getTipLocator()); walletInstance->database->IncrementUpdateCounter(); // Restore wallet transaction metadata after -zapwallettxes=1 @@ -4411,18 +4562,21 @@ bool CWallet::GetKeyOrigin(const CKeyID& keyID, KeyOriginInfo& info) const meta = it->second; } } - if (!meta.hdKeypath.empty()) { - if (!ParseHDKeypath(meta.hdKeypath, info.path)) return false; - // Get the proper master key id - CKey key; - GetKey(meta.hd_seed_id, key); - CExtKey masterKey; - masterKey.SetSeed(key.begin(), key.size()); - // Compute identifier - CKeyID masterid = masterKey.key.GetPubKey().GetID(); - std::copy(masterid.begin(), masterid.begin() + 4, info.fingerprint); + if (meta.has_key_origin) { + std::copy(meta.key_origin.fingerprint, meta.key_origin.fingerprint + 4, info.fingerprint); + info.path = meta.key_origin.path; } else { // Single pubkeys get the master fingerprint of themselves std::copy(keyID.begin(), keyID.begin() + 4, info.fingerprint); } return true; } + +bool CWallet::AddKeyOrigin(const CPubKey& pubkey, const KeyOriginInfo& info) +{ + LOCK(cs_wallet); + std::copy(info.fingerprint, info.fingerprint + 4, mapKeyMetadata[pubkey.GetID()].key_origin.fingerprint); + mapKeyMetadata[pubkey.GetID()].key_origin.path = info.path; + mapKeyMetadata[pubkey.GetID()].has_key_origin = true; + mapKeyMetadata[pubkey.GetID()].hdKeypath = WriteHDKeypath(info.path); + return WriteKeyMetadata(mapKeyMetadata[pubkey.GetID()], pubkey, true); +} diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 4776b0eacc..2a5d6caaf8 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -66,6 +66,7 @@ bool RemoveWallet(const std::shared_ptr<CWallet>& wallet); bool HasWallets(); std::vector<std::shared_ptr<CWallet>> GetWallets(); std::shared_ptr<CWallet> GetWallet(const std::string& name); +std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const WalletLocation& location, std::string& error, std::string& warning); //! Default for -keypool static const unsigned int DEFAULT_KEYPOOL_SIZE = 1000; @@ -134,11 +135,26 @@ enum WalletFlags : uint64_t { // wallet flags in the upper section (> 1 << 31) will lead to not opening the wallet if flag is unknown // unknown wallet flags in the lower section <= (1 << 31) will be tolerated + // Indicates that the metadata has already been upgraded to contain key origins + WALLET_FLAG_KEY_ORIGIN_METADATA = (1ULL << 1), + // will enforce the rule that the wallet can't contain any private keys (only watch-only/pubkeys) WALLET_FLAG_DISABLE_PRIVATE_KEYS = (1ULL << 32), + + //! Flag set when a wallet contains no HD seed and no private keys, scripts, + //! addresses, and other watch only things, and is therefore "blank." + //! + //! The only function this flag serves is to distinguish a blank wallet from + //! a newly created wallet when the wallet database is loaded, to avoid + //! initialization that should only happen on first run. + //! + //! This flag is also a mandatory flag to prevent previous versions of + //! bitcoin from opening the wallet, thinking it was newly created, and + //! then improperly reinitializing it. + WALLET_FLAG_BLANK_WALLET = (1ULL << 33), }; -static constexpr uint64_t g_known_wallet_flags = WALLET_FLAG_DISABLE_PRIVATE_KEYS; +static constexpr uint64_t g_known_wallet_flags = WALLET_FLAG_DISABLE_PRIVATE_KEYS | WALLET_FLAG_BLANK_WALLET | WALLET_FLAG_KEY_ORIGIN_METADATA; /** A key pool entry */ class CKeyPool @@ -763,6 +779,8 @@ public: // Map from Script ID to key metadata (for watch-only keys). std::map<CScriptID, CKeyMetadata> m_script_metadata GUARDED_BY(cs_wallet); + bool WriteKeyMetadata(const CKeyMetadata& meta, const CPubKey& pubkey, bool overwrite); + typedef std::map<unsigned int, CMasterKey> MasterKeyMap; MasterKeyMap mapMasterKeys; unsigned int nMasterKeyMaxID = 0; @@ -788,7 +806,7 @@ public: int64_t nOrderPosNext GUARDED_BY(cs_wallet) = 0; uint64_t nAccountingEntryNumber = 0; - std::map<CTxDestination, CAddressBookData> mapAddressBook; + std::map<CTxDestination, CAddressBookData> mapAddressBook GUARDED_BY(cs_wallet); std::set<COutPoint> setLockedCoins GUARDED_BY(cs_wallet); @@ -853,6 +871,8 @@ public: //! Load metadata (used by LoadWallet) void LoadKeyMetadata(const CKeyID& keyID, const CKeyMetadata &metadata) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); void LoadScriptMetadata(const CScriptID& script_id, const CKeyMetadata &metadata) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); + //! Upgrade stored CKeyMetadata objects to store key origin info as KeyOriginInfo + void UpgradeKeyMetadata() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); bool LoadMinVersion(int nVersion) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet) { AssertLockHeld(cs_wallet); nWalletVersion = nVersion; nWalletMaxVersion = std::max(nWalletMaxVersion, nVersion); return true; } void UpdateTimeFirstKey(int64_t nCreateTime) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); @@ -865,15 +885,15 @@ public: bool LoadCScript(const CScript& redeemScript); //! Adds a destination data tuple to the store, and saves it to disk - bool AddDestData(const CTxDestination &dest, const std::string &key, const std::string &value); + bool AddDestData(const CTxDestination& dest, const std::string& key, const std::string& value) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); //! Erases a destination data tuple in the store and on disk - bool EraseDestData(const CTxDestination &dest, const std::string &key); + bool EraseDestData(const CTxDestination& dest, const std::string& key) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); //! Adds a destination data tuple to the store, without saving it to disk - void LoadDestData(const CTxDestination &dest, const std::string &key, const std::string &value); + void LoadDestData(const CTxDestination& dest, const std::string& key, const std::string& value) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); //! Look up a destination data tuple in the store, return true if found false otherwise - bool GetDestData(const CTxDestination &dest, const std::string &key, std::string *value) const; + bool GetDestData(const CTxDestination& dest, const std::string& key, std::string* value) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); //! Get all destination values matching a prefix. - std::vector<std::string> GetDestValues(const std::string& prefix) const; + std::vector<std::string> GetDestValues(const std::string& prefix) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); //! Adds a watch-only address to the store, and saves it to disk. bool AddWatchOnly(const CScript& dest, int64_t nCreateTime) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); @@ -912,14 +932,14 @@ public: //! Hash and height of most recent block that was successfully scanned. //! Unset if no blocks were scanned due to read errors or the chain //! being empty. - uint256 stop_block; - Optional<int> stop_height; + uint256 last_scanned_block; + Optional<int> last_scanned_height; //! Height of the most recent block that could not be scanned due to //! read errors or pruning. Will be set if status is FAILURE, unset if //! status is SUCCESS, and may or may not be set if status is //! USER_ABORT. - uint256 failed_block; + uint256 last_failed_block; }; ScanResult ScanForWalletTransactions(const uint256& first_block, const uint256& last_block, const WalletRescanReserver& reserver, bool fUpdate); void TransactionRemovedFromMempool(const CTransactionRef &ptx) override; @@ -981,6 +1001,8 @@ public: bool NewKeyPool(); size_t KeypoolCountExternalKeys() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); bool TopUpKeyPool(unsigned int kpSize = 0); + void AddKeypoolPubkey(const CPubKey& pubkey, const bool internal); + void AddKeypoolPubkeyWithDB(const CPubKey& pubkey, const bool internal, WalletBatch& batch); /** * Reserves a key from the keypool and sets nIndex to its index @@ -1041,7 +1063,7 @@ public: bool DelAddressBook(const CTxDestination& address); - const std::string& GetLabelName(const CScript& scriptPubKey) const; + const std::string& GetLabelName(const CScript& scriptPubKey) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); void GetScriptForMining(std::shared_ptr<CReserveScript> &script); @@ -1132,6 +1154,12 @@ public: /* Returns true if HD is enabled */ bool IsHDEnabled() const; + /* Returns true if the wallet can generate new keys */ + bool CanGenerateKeys(); + + /* Returns true if the wallet can give out new addresses. This means it has keys in the keypool or can generate new keys */ + bool CanGetAddresses(bool internal = false); + /* Generates a new HD seed (will not be activated) */ CPubKey GenerateNewSeed(); @@ -1169,6 +1197,9 @@ public: /** set a single wallet flag */ void SetWalletFlag(uint64_t flags); + /** Unsets a single wallet flag */ + void UnsetWalletFlag(uint64_t flag); + /** check if a certain wallet flag is set */ bool IsWalletFlagSet(uint64_t flag); @@ -1190,6 +1221,9 @@ public: /** Implement lookup of key origin information through wallet key metadata. */ bool GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const override; + + /** Add a KeyOriginInfo to the wallet */ + bool AddKeyOrigin(const CPubKey& pubkey, const KeyOriginInfo& info); }; /** A key allocated from the key pool. */ diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index 6e037808e3..2783f83fd6 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -57,9 +57,14 @@ bool WalletBatch::EraseTx(uint256 hash) return EraseIC(std::make_pair(std::string("tx"), hash)); } +bool WalletBatch::WriteKeyMetadata(const CKeyMetadata& meta, const CPubKey& pubkey, const bool overwrite) +{ + return WriteIC(std::make_pair(std::string("keymeta"), pubkey), meta, overwrite); +} + bool WalletBatch::WriteKey(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey, const CKeyMetadata& keyMeta) { - if (!WriteIC(std::make_pair(std::string("keymeta"), vchPubKey), keyMeta, false)) { + if (!WriteKeyMetadata(keyMeta, vchPubKey, false)) { return false; } @@ -76,7 +81,7 @@ bool WalletBatch::WriteCryptedKey(const CPubKey& vchPubKey, const std::vector<unsigned char>& vchCryptedSecret, const CKeyMetadata &keyMeta) { - if (!WriteIC(std::make_pair(std::string("keymeta"), vchPubKey), keyMeta)) { + if (!WriteKeyMetadata(keyMeta, vchPubKey, true)) { return false; } @@ -529,6 +534,14 @@ DBErrors WalletBatch::LoadWallet(CWallet* pwallet) if (wss.fAnyUnordered) result = pwallet->ReorderTransactions(); + // Upgrade all of the wallet keymetadata to have the hd master key id + // This operation is not atomic, but if it fails, updated entries are still backwards compatible with older software + try { + pwallet->UpgradeKeyMetadata(); + } catch (...) { + result = DBErrors::CORRUPT; + } + return result; } diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h index 5584407a56..0532a55ff5 100644 --- a/src/wallet/walletdb.h +++ b/src/wallet/walletdb.h @@ -8,6 +8,7 @@ #include <amount.h> #include <primitives/transaction.h> +#include <script/sign.h> #include <wallet/db.h> #include <key.h> @@ -93,11 +94,14 @@ class CKeyMetadata public: static const int VERSION_BASIC=1; static const int VERSION_WITH_HDDATA=10; - static const int CURRENT_VERSION=VERSION_WITH_HDDATA; + static const int VERSION_WITH_KEY_ORIGIN = 12; + static const int CURRENT_VERSION=VERSION_WITH_KEY_ORIGIN; int nVersion; int64_t nCreateTime; // 0 means unknown - std::string hdKeypath; //optional HD/bip32 keypath + std::string hdKeypath; //optional HD/bip32 keypath. Still used to determine whether a key is a seed. Also kept for backwards compatibility CKeyID hd_seed_id; //id of the HD seed used to derive this key + KeyOriginInfo key_origin; // Key origin info with path and fingerprint + bool has_key_origin = false; //< Whether the key_origin is useful CKeyMetadata() { @@ -120,6 +124,11 @@ public: READWRITE(hdKeypath); READWRITE(hd_seed_id); } + if (this->nVersion >= VERSION_WITH_KEY_ORIGIN) + { + READWRITE(key_origin); + READWRITE(has_key_origin); + } } void SetNull() @@ -128,6 +137,8 @@ public: nCreateTime = 0; hdKeypath.clear(); hd_seed_id.SetNull(); + key_origin.clear(); + has_key_origin = false; } }; @@ -177,6 +188,7 @@ public: bool WriteTx(const CWalletTx& wtx); bool EraseTx(uint256 hash); + bool WriteKeyMetadata(const CKeyMetadata& meta, const CPubKey& pubkey, const bool overwrite); bool WriteKey(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey, const CKeyMetadata &keyMeta); bool WriteCryptedKey(const CPubKey& vchPubKey, const std::vector<unsigned char>& vchCryptedSecret, const CKeyMetadata &keyMeta); bool WriteMasterKey(unsigned int nID, const CMasterKey& kMasterKey); diff --git a/src/wallet/wallettool.cpp b/src/wallet/wallettool.cpp index 30b0c48eef..797f051189 100644 --- a/src/wallet/wallettool.cpp +++ b/src/wallet/wallettool.cpp @@ -17,7 +17,7 @@ namespace WalletTool { static void WalletToolReleaseWallet(CWallet* wallet) { wallet->WalletLogPrintf("Releasing wallet\n"); - wallet->Flush(); + wallet->Flush(true); delete wallet; } @@ -94,7 +94,6 @@ static std::shared_ptr<CWallet> LoadWallet(const std::string& name, const fs::pa static void WalletShowInfo(CWallet* wallet_instance) { - // lock required because of some AssertLockHeld() LOCK(wallet_instance->cs_wallet); fprintf(stdout, "Wallet info\n===========\n"); @@ -113,7 +112,7 @@ bool ExecuteWalletToolFunc(const std::string& command, const std::string& name) std::shared_ptr<CWallet> wallet_instance = CreateWallet(name, path); if (wallet_instance) { WalletShowInfo(wallet_instance.get()); - wallet_instance->Flush(); + wallet_instance->Flush(true); } } else if (command == "info") { if (!fs::exists(path)) { @@ -128,7 +127,7 @@ bool ExecuteWalletToolFunc(const std::string& command, const std::string& name) std::shared_ptr<CWallet> wallet_instance = LoadWallet(name, path); if (!wallet_instance) return false; WalletShowInfo(wallet_instance.get()); - wallet_instance->Flush(); + wallet_instance->Flush(true); } else { fprintf(stderr, "Invalid command: %s\n", command.c_str()); return false; diff --git a/src/wallet/walletutil.cpp b/src/wallet/walletutil.cpp index 6db4c63acb..d779251d56 100644 --- a/src/wallet/walletutil.cpp +++ b/src/wallet/walletutil.cpp @@ -35,7 +35,7 @@ static bool IsBerkeleyBtree(const fs::path& path) boost::system::error_code ec; if (fs::file_size(path, ec) < 4096) return false; - fs::ifstream file(path.string(), std::ios::binary); + fsbridge::ifstream file(path, std::ios::binary); if (!file.is_open()) return false; file.seekg(12, std::ios::beg); // Magic bytes start at offset 12 diff --git a/test/README.md b/test/README.md index a6fb9c9d73..9d4351b1de 100644 --- a/test/README.md +++ b/test/README.md @@ -178,6 +178,26 @@ gdb /home/example/bitcoind <pid> Note: gdb attach step may require ptrace_scope to be modified, or `sudo` preceding the `gdb`. See this link for considerations: https://www.kernel.org/doc/Documentation/security/Yama.txt +##### Profiling + +An easy way to profile node performance during functional tests is provided +for Linux platforms using `perf`. + +Perf will sample the running node and will generate profile data in the node's +datadir. The profile data can then be presented using `perf report` or a graphical +tool like [hotspot](https://github.com/KDAB/hotspot). + +To generate a profile during test suite runs, use the `--perf` flag. + +To see render the output to text, run + +```sh +perf report -i /path/to/datadir/send-big-msgs.perf.data.xxxx --stdio | c++filt | less +``` + +For ways to generate more granular profiles, see the README in +[test/functional](/test/functional). + ### Util tests Util tests can be run locally by running `test/util/bitcoin-util-test.py`. diff --git a/test/config.ini.in b/test/config.ini.in index 28abee2a3d..6b7ef70659 100644 --- a/test/config.ini.in +++ b/test/config.ini.in @@ -16,4 +16,5 @@ RPCAUTH=@abs_top_srcdir@/share/rpcauth/rpcauth.py @ENABLE_WALLET_TRUE@ENABLE_WALLET=true @BUILD_BITCOIN_CLI_TRUE@ENABLE_CLI=true @BUILD_BITCOIND_TRUE@ENABLE_BITCOIND=true +@ENABLE_FUZZ_TRUE@ENABLE_FUZZ=true @ENABLE_ZMQ_TRUE@ENABLE_ZMQ=true diff --git a/test/functional/README.md b/test/functional/README.md index 628c77eb11..5e3009e6af 100644 --- a/test/functional/README.md +++ b/test/functional/README.md @@ -43,6 +43,7 @@ don't have test cases for. - `mining` for tests for mining features, eg `mining_prioritisetransaction.py` - `p2p` for tests that explicitly test the p2p interface, eg `p2p_disconnect_ban.py` - `rpc` for tests for individual RPC methods or features, eg `rpc_listtransactions.py` + - `tool` for tests for tools, eg `tool_wallet.py` - `wallet` for tests for wallet features, eg `wallet_keypool.py` - use an underscore to separate words - exception: for tests for specific RPCs or command line options which don't include underscores, name the test after the exact RPC or argument name, eg `rpc_decodescript.py`, not `rpc_decode_script.py` @@ -122,3 +123,36 @@ Helpers for script.py #### [test_framework/blocktools.py](test_framework/blocktools.py) Helper functions for creating blocks and transactions. + +### Benchmarking with perf + +An easy way to profile node performance during functional tests is provided +for Linux platforms using `perf`. + +Perf will sample the running node and will generate profile data in the node's +datadir. The profile data can then be presented using `perf report` or a graphical +tool like [hotspot](https://github.com/KDAB/hotspot). + +There are two ways of invoking perf: one is to use the `--perf` flag when +running tests, which will profile each node during the entire test run: perf +begins to profile when the node starts and ends when it shuts down. The other +way is the use the `profile_with_perf` context manager, e.g. + +```python +with node.profile_with_perf("send-big-msgs"): + # Perform activity on the node you're interested in profiling, e.g.: + for _ in range(10000): + node.p2p.send_message(some_large_message) +``` + +To see useful textual output, run + +```sh +perf report -i /path/to/datadir/send-big-msgs.perf.data.xxxx --stdio | c++filt | less +``` + +#### See also: + +- [Installing perf](https://askubuntu.com/q/50145) +- [Perf examples](http://www.brendangregg.com/perf.html) +- [Hotspot](https://github.com/KDAB/hotspot): a GUI for perf output analysis diff --git a/test/functional/feature_assumevalid.py b/test/functional/feature_assumevalid.py index 12a4ce9aff..0eb3dd440b 100755 --- a/test/functional/feature_assumevalid.py +++ b/test/functional/feature_assumevalid.py @@ -180,7 +180,7 @@ class AssumeValidTest(BitcoinTestFramework): for i in range(2202): p2p1.send_message(msg_block(self.blocks[i])) # Syncing 2200 blocks can take a while on slow systems. Give it plenty of time to sync. - p2p1.sync_with_ping(150) + p2p1.sync_with_ping(200) assert_equal(self.nodes[1].getblock(self.nodes[1].getbestblockhash())['height'], 2202) # Send blocks to node2. Block 102 will be rejected. diff --git a/test/functional/feature_cltv.py b/test/functional/feature_cltv.py index 302a5ec1cb..96c5e49b0e 100755 --- a/test/functional/feature_cltv.py +++ b/test/functional/feature_cltv.py @@ -60,6 +60,7 @@ class BIP65Test(BitcoinTestFramework): self.num_nodes = 1 self.extra_args = [['-whitelist=127.0.0.1', '-par=1']] # Use only one script thread to get the exact reject reason for testing self.setup_clean_chain = True + self.rpc_timeout = 120 def skip_test_if_missing_module(self): self.skip_if_no_wallet() diff --git a/test/functional/feature_dersig.py b/test/functional/feature_dersig.py index 9cbc1b39bd..8ff9498ef3 100755 --- a/test/functional/feature_dersig.py +++ b/test/functional/feature_dersig.py @@ -47,6 +47,7 @@ class BIP66Test(BitcoinTestFramework): self.num_nodes = 1 self.extra_args = [['-whitelist=127.0.0.1', '-par=1', '-enablebip61']] # Use only one script thread to get the exact reject reason for testing self.setup_clean_chain = True + self.rpc_timeout = 120 def skip_test_if_missing_module(self): self.skip_if_no_wallet() diff --git a/test/functional/feature_notifications.py b/test/functional/feature_notifications.py index d8083b2840..b98dd6d26c 100755 --- a/test/functional/feature_notifications.py +++ b/test/functional/feature_notifications.py @@ -66,23 +66,7 @@ class NotificationsTest(BitcoinTestFramework): txids_rpc = list(map(lambda t: t['txid'], self.nodes[1].listtransactions("*", block_count))) assert_equal(sorted(txids_rpc), sorted(os.listdir(self.walletnotify_dir))) - # Mine another 41 up-version blocks. -alertnotify should trigger on the 51st. - self.log.info("test -alertnotify") - self.nodes[1].generatetoaddress(41, ADDRESS_BCRT1_UNSPENDABLE) - self.sync_all() - - # Give bitcoind 10 seconds to write the alert notification - wait_until(lambda: len(os.listdir(self.alertnotify_dir)), timeout=10) - - for notify_file in os.listdir(self.alertnotify_dir): - os.remove(os.path.join(self.alertnotify_dir, notify_file)) - - # Mine more up-version blocks, should not get more alerts: - self.nodes[1].generatetoaddress(2, ADDRESS_BCRT1_UNSPENDABLE) - self.sync_all() - - self.log.info("-alertnotify should not continue notifying for more unknown version blocks") - assert_equal(len(os.listdir(self.alertnotify_dir)), 0) + # TODO: add test for `-alertnotify` large fork notifications if __name__ == '__main__': NotificationsTest().main() diff --git a/test/functional/feature_proxy.py b/test/functional/feature_proxy.py index 31d2ee8e13..f042adb7aa 100755 --- a/test/functional/feature_proxy.py +++ b/test/functional/feature_proxy.py @@ -44,6 +44,7 @@ RANGE_BEGIN = PORT_MIN + 2 * PORT_RANGE # Start after p2p and rpc ports class ProxyTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 4 + self.setup_clean_chain = True def setup_nodes(self): self.have_ipv6 = test_ipv6_local() @@ -198,4 +199,3 @@ class ProxyTest(BitcoinTestFramework): if __name__ == '__main__': ProxyTest().main() - diff --git a/test/functional/feature_segwit.py b/test/functional/feature_segwit.py index 1efc50e71f..658a8cd75e 100755 --- a/test/functional/feature_segwit.py +++ b/test/functional/feature_segwit.py @@ -38,31 +38,29 @@ def find_spendable_utxo(node, min_value): raise AssertionError("Unspent output equal or higher than %s not found" % min_value) +txs_mined = {} # txindex from txid to blockhash + class SegWitTest(BitcoinTestFramework): def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 3 # This test tests SegWit both pre and post-activation, so use the normal BIP9 activation. - # TODO: remove -txindex. Currently required for getrawtransaction call. self.extra_args = [ [ "-rpcserialversion=0", "-vbparams=segwit:0:999999999999", "-addresstype=legacy", - "-txindex" ], [ "-blockversion=4", "-rpcserialversion=1", "-vbparams=segwit:0:999999999999", "-addresstype=legacy", - "-txindex" ], [ "-blockversion=536870915", "-vbparams=segwit:0:999999999999", "-addresstype=legacy", - "-txindex" ], ] @@ -157,10 +155,10 @@ class SegWitTest(BitcoinTestFramework): self.log.info("Verify previous witness txs skipped for mining can now be mined") assert_equal(len(self.nodes[2].getrawmempool()), 4) - block = self.nodes[2].generate(1) # block 432 (first block with new rules; 432 = 144 * 3) + blockhash = self.nodes[2].generate(1)[0] # block 432 (first block with new rules; 432 = 144 * 3) sync_blocks(self.nodes) assert_equal(len(self.nodes[2].getrawmempool()), 0) - segwit_tx_list = self.nodes[2].getblock(block[0])["tx"] + segwit_tx_list = self.nodes[2].getblock(blockhash)["tx"] assert_equal(len(segwit_tx_list), 5) self.log.info("Verify default node can't accept txs with missing witness") @@ -174,15 +172,16 @@ class SegWitTest(BitcoinTestFramework): self.fail_accept(self.nodes[0], "mandatory-script-verify-flag", p2sh_ids[NODE_0][WIT_V1][0], False, witness_script(True, self.pubkey[0])) self.log.info("Verify block and transaction serialization rpcs return differing serializations depending on rpc serialization flag") - assert(self.nodes[2].getblock(block[0], False) != self.nodes[0].getblock(block[0], False)) - assert(self.nodes[1].getblock(block[0], False) == self.nodes[2].getblock(block[0], False)) - for i in range(len(segwit_tx_list)): - tx = FromHex(CTransaction(), self.nodes[2].gettransaction(segwit_tx_list[i])["hex"]) - assert(self.nodes[2].getrawtransaction(segwit_tx_list[i]) != self.nodes[0].getrawtransaction(segwit_tx_list[i])) - assert(self.nodes[1].getrawtransaction(segwit_tx_list[i], 0) == self.nodes[2].getrawtransaction(segwit_tx_list[i])) - assert(self.nodes[0].getrawtransaction(segwit_tx_list[i]) != self.nodes[2].gettransaction(segwit_tx_list[i])["hex"]) - assert(self.nodes[1].getrawtransaction(segwit_tx_list[i]) == self.nodes[2].gettransaction(segwit_tx_list[i])["hex"]) - assert(self.nodes[0].getrawtransaction(segwit_tx_list[i]) == bytes_to_hex_str(tx.serialize_without_witness())) + assert(self.nodes[2].getblock(blockhash, False) != self.nodes[0].getblock(blockhash, False)) + assert(self.nodes[1].getblock(blockhash, False) == self.nodes[2].getblock(blockhash, False)) + + for tx_id in segwit_tx_list: + tx = FromHex(CTransaction(), self.nodes[2].gettransaction(tx_id)["hex"]) + assert(self.nodes[2].getrawtransaction(tx_id, False, blockhash) != self.nodes[0].getrawtransaction(tx_id, False, blockhash)) + assert(self.nodes[1].getrawtransaction(tx_id, False, blockhash) == self.nodes[2].getrawtransaction(tx_id, False, blockhash)) + assert(self.nodes[0].getrawtransaction(tx_id, False, blockhash) != self.nodes[2].gettransaction(tx_id)["hex"]) + assert(self.nodes[1].getrawtransaction(tx_id, False, blockhash) == self.nodes[2].gettransaction(tx_id)["hex"]) + assert(self.nodes[0].getrawtransaction(tx_id, False, blockhash) == bytes_to_hex_str(tx.serialize_without_witness())) self.log.info("Verify witness txs without witness data are invalid after the fork") self.fail_accept(self.nodes[2], 'non-mandatory-script-verify-flag (Witness program hash mismatch) (code 64)', wit_ids[NODE_2][WIT_V0][2], sign=False) @@ -538,7 +537,7 @@ class SegWitTest(BitcoinTestFramework): tx.rehash() signresults = self.nodes[0].signrawtransactionwithwallet(bytes_to_hex_str(tx.serialize_without_witness()))['hex'] txid = self.nodes[0].sendrawtransaction(signresults, True) - self.nodes[0].generate(1) + txs_mined[txid] = self.nodes[0].generate(1)[0] sync_blocks(self.nodes) watchcount = 0 spendcount = 0 @@ -581,7 +580,7 @@ class SegWitTest(BitcoinTestFramework): tx = CTransaction() for i in txids: txtmp = CTransaction() - txraw = self.nodes[0].getrawtransaction(i) + txraw = self.nodes[0].getrawtransaction(i, 0, txs_mined[i]) f = BytesIO(hex_str_to_bytes(txraw)) txtmp.deserialize(f) for j in range(len(txtmp.vout)): diff --git a/test/functional/feature_versionbits_warning.py b/test/functional/feature_versionbits_warning.py index 88df61cabc..1ced618d47 100755 --- a/test/functional/feature_versionbits_warning.py +++ b/test/functional/feature_versionbits_warning.py @@ -22,7 +22,6 @@ VB_TOP_BITS = 0x20000000 VB_UNKNOWN_BIT = 27 # Choose a bit unassigned to any deployment VB_UNKNOWN_VERSION = VB_TOP_BITS | (1 << VB_UNKNOWN_BIT) -WARN_UNKNOWN_RULES_MINED = "Unknown block versions being mined! It's possible unknown rules are in effect" WARN_UNKNOWN_RULES_ACTIVE = "unknown new rules activated (versionbit {})".format(VB_UNKNOWN_BIT) VB_PATTERN = re.compile("Warning: unknown new rules activated.*versionbit") @@ -78,15 +77,10 @@ class VersionBitsWarningTest(BitcoinTestFramework): assert(not VB_PATTERN.match(node.getmininginfo()["warnings"])) assert(not VB_PATTERN.match(node.getnetworkinfo()["warnings"])) - self.log.info("Check that there is a warning if >50 blocks in the last 100 were an unknown version") # Build one period of blocks with VB_THRESHOLD blocks signaling some unknown bit self.send_blocks_with_version(node.p2p, VB_THRESHOLD, VB_UNKNOWN_VERSION) node.generatetoaddress(VB_PERIOD - VB_THRESHOLD, node_deterministic_address) - # Check that get*info() shows the 51/100 unknown block version error. - assert(WARN_UNKNOWN_RULES_MINED in node.getmininginfo()["warnings"]) - assert(WARN_UNKNOWN_RULES_MINED in node.getnetworkinfo()["warnings"]) - self.log.info("Check that there is a warning if previous VB_BLOCKS have >=VB_THRESHOLD blocks with unknown versionbits version.") # Mine a period worth of expected blocks so the generic block-version warning # is cleared. This will move the versionbit state to ACTIVE. diff --git a/test/functional/interface_rest.py b/test/functional/interface_rest.py index f850a54462..f33040242c 100755 --- a/test/functional/interface_rest.py +++ b/test/functional/interface_rest.py @@ -22,6 +22,8 @@ from test_framework.util import ( hex_str_to_bytes, ) +from test_framework.messages import BLOCK_HEADER_SIZE + class ReqType(Enum): JSON = 1 BIN = 2 @@ -41,8 +43,7 @@ class RESTTest (BitcoinTestFramework): def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 2 - # TODO: remove -txindex. Currently required for getrawtransaction call. - self.extra_args = [["-rest", "-txindex"], []] + self.extra_args = [["-rest"], []] def skip_test_if_missing_module(self): self.skip_if_no_wallet() @@ -89,15 +90,17 @@ class RESTTest (BitcoinTestFramework): txid = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 0.1) self.sync_all() - self.nodes[1].generatetoaddress(1, not_related_address) - self.sync_all() - bb_hash = self.nodes[0].getbestblockhash() - assert_equal(self.nodes[1].getbalance(), Decimal("0.1")) - - self.log.info("Load the transaction using the /tx URI") + self.log.info("Test the /tx URI") json_obj = self.test_rest_request("/tx/{}".format(txid)) + assert_equal(json_obj['txid'], txid) + + # Check hex format response + hex_response = self.test_rest_request("/tx/{}".format(txid), req_type=ReqType.HEX, ret_type=RetType.OBJ) + assert_greater_than_or_equal(int(hex_response.getheader('content-length')), + json_obj['size']*2) + spent = (json_obj['vin'][0]['txid'], json_obj['vin'][0]['vout']) # get the vin to later check for utxo (should be spent by then) # get n of 0.1 outpoint n, = filter_output_indices_by_value(json_obj['vout'], Decimal('0.1')) @@ -105,9 +108,14 @@ class RESTTest (BitcoinTestFramework): self.log.info("Query an unspent TXO using the /getutxos URI") - json_obj = self.test_rest_request("/getutxos/{}-{}".format(*spending)) + self.nodes[1].generatetoaddress(1, not_related_address) + self.sync_all() + bb_hash = self.nodes[0].getbestblockhash() + + assert_equal(self.nodes[1].getbalance(), Decimal("0.1")) # Check chainTip response + json_obj = self.test_rest_request("/getutxos/{}-{}".format(*spending)) assert_equal(json_obj['chaintipHash'], bb_hash) # Make sure there is one utxo @@ -214,26 +222,26 @@ class RESTTest (BitcoinTestFramework): # Check binary format response = self.test_rest_request("/block/{}".format(bb_hash), req_type=ReqType.BIN, ret_type=RetType.OBJ) - assert_greater_than(int(response.getheader('content-length')), 80) + assert_greater_than(int(response.getheader('content-length')), BLOCK_HEADER_SIZE) response_bytes = response.read() # Compare with block header response_header = self.test_rest_request("/headers/1/{}".format(bb_hash), req_type=ReqType.BIN, ret_type=RetType.OBJ) - assert_equal(int(response_header.getheader('content-length')), 80) + assert_equal(int(response_header.getheader('content-length')), BLOCK_HEADER_SIZE) response_header_bytes = response_header.read() - assert_equal(response_bytes[:80], response_header_bytes) + assert_equal(response_bytes[:BLOCK_HEADER_SIZE], response_header_bytes) # Check block hex format response_hex = self.test_rest_request("/block/{}".format(bb_hash), req_type=ReqType.HEX, ret_type=RetType.OBJ) - assert_greater_than(int(response_hex.getheader('content-length')), 160) + assert_greater_than(int(response_hex.getheader('content-length')), BLOCK_HEADER_SIZE*2) response_hex_bytes = response_hex.read().strip(b'\n') assert_equal(binascii.hexlify(response_bytes), response_hex_bytes) # Compare with hex block header response_header_hex = self.test_rest_request("/headers/1/{}".format(bb_hash), req_type=ReqType.HEX, ret_type=RetType.OBJ) - assert_greater_than(int(response_header_hex.getheader('content-length')), 160) - response_header_hex_bytes = response_header_hex.read(160) - assert_equal(binascii.hexlify(response_bytes[:80]), response_header_hex_bytes) + assert_greater_than(int(response_header_hex.getheader('content-length')), BLOCK_HEADER_SIZE*2) + response_header_hex_bytes = response_header_hex.read(BLOCK_HEADER_SIZE*2) + assert_equal(binascii.hexlify(response_bytes[:BLOCK_HEADER_SIZE]), response_header_hex_bytes) # Check json format block_json_obj = self.test_rest_request("/block/{}".format(bb_hash)) @@ -272,17 +280,6 @@ class RESTTest (BitcoinTestFramework): json_obj = self.test_rest_request("/headers/5/{}".format(bb_hash)) assert_equal(len(json_obj), 5) # now we should have 5 header objects - self.log.info("Test the /tx URI") - - tx_hash = block_json_obj['tx'][0]['txid'] - json_obj = self.test_rest_request("/tx/{}".format(tx_hash)) - assert_equal(json_obj['txid'], tx_hash) - - # Check hex format response - hex_response = self.test_rest_request("/tx/{}".format(tx_hash), req_type=ReqType.HEX, ret_type=RetType.OBJ) - assert_greater_than_or_equal(int(hex_response.getheader('content-length')), - json_obj['size']*2) - self.log.info("Test tx inclusion in the /mempool and /block URIs") # Make 3 tx and mine them on node 1 diff --git a/test/functional/mempool_accept.py b/test/functional/mempool_accept.py index e2a219b85a..efe720b9b1 100755 --- a/test/functional/mempool_accept.py +++ b/test/functional/mempool_accept.py @@ -29,7 +29,6 @@ from test_framework.util import ( assert_raises_rpc_error, bytes_to_hex_str, hex_str_to_bytes, - wait_until, ) @@ -38,7 +37,6 @@ class MempoolAcceptanceTest(BitcoinTestFramework): self.num_nodes = 1 self.extra_args = [[ '-txindex', - '-reindex', # Need reindex for txindex '-acceptnonstdtxn=0', # Try to mimic main-net ]] * self.num_nodes @@ -56,7 +54,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework): self.log.info('Start with empty mempool, and 200 blocks') self.mempool_size = 0 - wait_until(lambda: node.getblockcount() == 200) + assert_equal(node.getblockcount(), 200) assert_equal(node.getmempoolinfo()['size'], self.mempool_size) coins = node.listunspent() diff --git a/test/functional/mining_basic.py b/test/functional/mining_basic.py index 661d9f4c97..d0bef48cb6 100755 --- a/test/functional/mining_basic.py +++ b/test/functional/mining_basic.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2014-2018 The Bitcoin Core developers +# Copyright (c) 2014-2019 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test mining RPCs @@ -11,10 +11,14 @@ import copy from decimal import Decimal -from test_framework.blocktools import create_coinbase +from test_framework.blocktools import ( + create_coinbase, + TIME_GENESIS_BLOCK, +) from test_framework.messages import ( CBlock, CBlockHeader, + BLOCK_HEADER_SIZE ) from test_framework.mininode import ( P2PDataStore, @@ -24,9 +28,11 @@ from test_framework.util import ( assert_equal, assert_raises_rpc_error, bytes_to_hex_str as b2x, + connect_nodes_bi, ) from test_framework.script import CScriptNum + def assert_template(node, block, expect, rehash=True): if rehash: block.hashMerkleRoot = block.calc_merkle_root() @@ -37,9 +43,22 @@ def assert_template(node, block, expect, rehash=True): class MiningTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 2 - self.setup_clean_chain = False + self.setup_clean_chain = True + + def mine_chain(self): + self.log.info('Create some old blocks') + for t in range(TIME_GENESIS_BLOCK, TIME_GENESIS_BLOCK + 200 * 600, 600): + self.nodes[0].setmocktime(t) + self.nodes[0].generate(1) + mining_info = self.nodes[0].getmininginfo() + assert_equal(mining_info['blocks'], 200) + assert_equal(mining_info['currentblocktx'], 0) + assert_equal(mining_info['currentblockweight'], 4000) + self.restart_node(0) + connect_nodes_bi(self.nodes, 0, 1) def run_test(self): + self.mine_chain() node = self.nodes[0] def assert_submitblock(block, result_str_1, result_str_2=None): @@ -52,8 +71,8 @@ class MiningTest(BitcoinTestFramework): mining_info = node.getmininginfo() assert_equal(mining_info['blocks'], 200) assert_equal(mining_info['chain'], 'regtest') - assert_equal(mining_info['currentblocktx'], 0) - assert_equal(mining_info['currentblockweight'], 0) + assert 'currentblocktx' not in mining_info + assert 'currentblockweight' not in mining_info assert_equal(mining_info['difficulty'], Decimal('4.656542373906925E-10')) assert_equal(mining_info['networkhashps'], Decimal('0.003333333333333334')) assert_equal(mining_info['pooledtx'], 0) @@ -131,10 +150,9 @@ class MiningTest(BitcoinTestFramework): self.log.info("getblocktemplate: Test bad tx count") # The tx count is immediately after the block header - TX_COUNT_OFFSET = 80 bad_block_sn = bytearray(block.serialize()) - assert_equal(bad_block_sn[TX_COUNT_OFFSET], 1) - bad_block_sn[TX_COUNT_OFFSET] += 1 + assert_equal(bad_block_sn[BLOCK_HEADER_SIZE], 1) + bad_block_sn[BLOCK_HEADER_SIZE] += 1 assert_raises_rpc_error(-22, "Block decode failed", node.getblocktemplate, {'data': b2x(bad_block_sn), 'mode': 'proposal', 'rules': ['segwit']}) self.log.info("getblocktemplate: Test bad bits") @@ -164,9 +182,9 @@ class MiningTest(BitcoinTestFramework): assert_submitblock(bad_block, 'prev-blk-not-found', 'prev-blk-not-found') self.log.info('submitheader tests') - assert_raises_rpc_error(-22, 'Block header decode failed', lambda: node.submitheader(hexdata='xx' * 80)) - assert_raises_rpc_error(-22, 'Block header decode failed', lambda: node.submitheader(hexdata='ff' * 78)) - assert_raises_rpc_error(-25, 'Must submit previous header', lambda: node.submitheader(hexdata='ff' * 80)) + assert_raises_rpc_error(-22, 'Block header decode failed', lambda: node.submitheader(hexdata='xx' * BLOCK_HEADER_SIZE)) + assert_raises_rpc_error(-22, 'Block header decode failed', lambda: node.submitheader(hexdata='ff' * (BLOCK_HEADER_SIZE-2))) + assert_raises_rpc_error(-25, 'Must submit previous header', lambda: node.submitheader(hexdata=b2x(super(CBlock, bad_block).serialize()))) block.nTime += 1 block.solve() diff --git a/test/functional/p2p_invalid_messages.py b/test/functional/p2p_invalid_messages.py index dcc0d1d235..700fdf6e04 100755 --- a/test/functional/p2p_invalid_messages.py +++ b/test/functional/p2p_invalid_messages.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2015-2018 The Bitcoin Core developers +# Copyright (c) 2015-2019 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test node responses to invalid network messages.""" @@ -143,6 +143,7 @@ class InvalidMessagesTest(BitcoinTestFramework): def test_magic_bytes(self): conn = self.nodes[0].add_p2p_connection(P2PDataStore()) + conn._on_data = lambda: None # Need to ignore all incoming messages from now, since they come with "invalid" magic bytes conn.magic_bytes = b'\x00\x11\x22\x32' with self.nodes[0].assert_debug_log(['PROCESSMESSAGE: INVALID MESSAGESTART ping']): conn.send_message(messages.msg_ping(nonce=0xff)) @@ -211,6 +212,5 @@ class InvalidMessagesTest(BitcoinTestFramework): return raw_msg_with_wrong_size - if __name__ == '__main__': InvalidMessagesTest().main() diff --git a/test/functional/p2p_sendheaders.py b/test/functional/p2p_sendheaders.py index c7ae57de86..7d7d251765 100755 --- a/test/functional/p2p_sendheaders.py +++ b/test/functional/p2p_sendheaders.py @@ -490,7 +490,7 @@ class SendHeadersTest(BitcoinTestFramework): # Now announce a header that forks the last two blocks tip = blocks[0].sha256 - height -= 1 + height -= 2 blocks = [] # Create extra blocks for later diff --git a/test/functional/rpc_blockchain.py b/test/functional/rpc_blockchain.py index 31e60f1cea..af150a09af 100755 --- a/test/functional/rpc_blockchain.py +++ b/test/functional/rpc_blockchain.py @@ -35,6 +35,7 @@ from test_framework.util import ( from test_framework.blocktools import ( create_block, create_coinbase, + TIME_GENESIS_BLOCK, ) from test_framework.messages import ( msg_block, @@ -46,9 +47,11 @@ from test_framework.mininode import ( class BlockchainTest(BitcoinTestFramework): def set_test_params(self): + self.setup_clean_chain = True self.num_nodes = 1 def run_test(self): + self.mine_chain() self.restart_node(0, extra_args=['-stopatheight=207', '-prune=1']) # Set extra args with pruning after rescan is complete self._test_getblockchaininfo() @@ -61,6 +64,15 @@ class BlockchainTest(BitcoinTestFramework): self._test_waitforblockheight() assert self.nodes[0].verifychain(4, 0) + def mine_chain(self): + self.log.info('Create some old blocks') + address = self.nodes[0].get_deterministic_priv_key().address + for t in range(TIME_GENESIS_BLOCK, TIME_GENESIS_BLOCK + 200 * 600, 600): + # ten-minute steps from genesis block time + self.nodes[0].setmocktime(t) + self.nodes[0].generatetoaddress(1, address) + assert_equal(self.nodes[0].getblockchaininfo()['blocks'], 200) + def _test_getblockchaininfo(self): self.log.info("Test getblockchaininfo") diff --git a/test/functional/rpc_deriveaddresses.py b/test/functional/rpc_deriveaddresses.py new file mode 100755 index 0000000000..185dffd51c --- /dev/null +++ b/test/functional/rpc_deriveaddresses.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python3 +# Copyright (c) 2018 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +"""Test the deriveaddresses rpc call.""" +from test_framework.test_framework import BitcoinTestFramework +from test_framework.descriptors import descsum_create +from test_framework.util import assert_equal, assert_raises_rpc_error + +class DeriveaddressesTest(BitcoinTestFramework): + def set_test_params(self): + self.num_nodes = 1 + self.supports_cli = 1 + + def run_test(self): + assert_raises_rpc_error(-5, "Invalid descriptor", self.nodes[0].deriveaddresses, "a") + + descriptor = "wpkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/0)#t6wfjs64" + address = "bcrt1qjqmxmkpmxt80xz4y3746zgt0q3u3ferr34acd5" + assert_equal(self.nodes[0].deriveaddresses(descriptor), [address]) + + descriptor = descriptor[:-9] + assert_raises_rpc_error(-5, "Invalid descriptor", self.nodes[0].deriveaddresses, descriptor) + + descriptor_pubkey = "wpkh(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/0)#s9ga3alw" + address = "bcrt1qjqmxmkpmxt80xz4y3746zgt0q3u3ferr34acd5" + assert_equal(self.nodes[0].deriveaddresses(descriptor_pubkey), [address]) + + ranged_descriptor = "wpkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/*)#kft60nuy" + assert_equal(self.nodes[0].deriveaddresses(ranged_descriptor, [1, 2]), ["bcrt1qhku5rq7jz8ulufe2y6fkcpnlvpsta7rq4442dy", "bcrt1qpgptk2gvshyl0s9lqshsmx932l9ccsv265tvaq"]) + assert_equal(self.nodes[0].deriveaddresses(ranged_descriptor, 2), [address, "bcrt1qhku5rq7jz8ulufe2y6fkcpnlvpsta7rq4442dy", "bcrt1qpgptk2gvshyl0s9lqshsmx932l9ccsv265tvaq"]) + + assert_raises_rpc_error(-8, "Range should not be specified for an un-ranged descriptor", self.nodes[0].deriveaddresses, descsum_create("wpkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/0)"), [0, 2]) + + assert_raises_rpc_error(-8, "Range must be specified for a ranged descriptor", self.nodes[0].deriveaddresses, descsum_create("wpkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/*)")) + + assert_raises_rpc_error(-8, "End of range is too high", self.nodes[0].deriveaddresses, descsum_create("wpkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/*)"), 10000000000) + + assert_raises_rpc_error(-8, "Range is too large", self.nodes[0].deriveaddresses, descsum_create("wpkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/*)"), [1000000000, 2000000000]) + + assert_raises_rpc_error(-8, "Range specified as [begin,end] must not have begin after end", self.nodes[0].deriveaddresses, descsum_create("wpkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/*)"), [2, 0]) + + assert_raises_rpc_error(-8, "Range should be greater or equal than 0", self.nodes[0].deriveaddresses, descsum_create("wpkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/*)"), [-1, 0]) + + combo_descriptor = descsum_create("combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/0)") + assert_equal(self.nodes[0].deriveaddresses(combo_descriptor), ["mtfUoUax9L4tzXARpw1oTGxWyoogp52KhJ", "mtfUoUax9L4tzXARpw1oTGxWyoogp52KhJ", address, "2NDvEwGfpEqJWfybzpKPHF2XH3jwoQV3D7x"]) + + hardened_without_privkey_descriptor = descsum_create("wpkh(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1'/1/0)") + assert_raises_rpc_error(-5, "Cannot derive script without private keys", self.nodes[0].deriveaddresses, hardened_without_privkey_descriptor) + + bare_multisig_descriptor = descsum_create("multi(1,tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/0,tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/1)") + assert_raises_rpc_error(-5, "Descriptor does not have a corresponding address", self.nodes[0].deriveaddresses, bare_multisig_descriptor) + +if __name__ == '__main__': + DeriveaddressesTest().main() diff --git a/test/functional/rpc_getblockstats.py b/test/functional/rpc_getblockstats.py index ca9e24367a..feba16f1b3 100755 --- a/test/functional/rpc_getblockstats.py +++ b/test/functional/rpc_getblockstats.py @@ -178,5 +178,10 @@ class GetblockstatsTest(BitcoinTestFramework): assert_raises_rpc_error(-5, 'Block not found', self.nodes[0].getblockstats, hash_or_height='000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f') + # Invalid number of args + assert_raises_rpc_error(-1, 'getblockstats hash_or_height ( stats )', self.nodes[0].getblockstats, '00', 1, 2) + assert_raises_rpc_error(-1, 'getblockstats hash_or_height ( stats )', self.nodes[0].getblockstats) + + if __name__ == '__main__': GetblockstatsTest().main() diff --git a/test/functional/rpc_psbt.py b/test/functional/rpc_psbt.py index 1e10280e60..e9098e4f5a 100755 --- a/test/functional/rpc_psbt.py +++ b/test/functional/rpc_psbt.py @@ -5,8 +5,9 @@ """Test the Partially Signed Transaction RPCs. """ +from decimal import Decimal from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import assert_equal, assert_raises_rpc_error, find_output, disconnect_nodes, connect_nodes_bi, sync_blocks +from test_framework.util import assert_equal, assert_raises_rpc_error, connect_nodes_bi, disconnect_nodes, find_output, sync_blocks import json import os @@ -19,8 +20,6 @@ class PSBTTest(BitcoinTestFramework): def set_test_params(self): self.setup_clean_chain = False self.num_nodes = 3 - # TODO: remove -txindex. Currently required for getrawtransaction call. - self.extra_args = [[], ["-txindex"], ["-txindex"]] def skip_test_if_missing_module(self): self.skip_if_no_wallet() @@ -160,11 +159,11 @@ class PSBTTest(BitcoinTestFramework): node1_addr = self.nodes[1].getnewaddress() node2_addr = self.nodes[2].getnewaddress() txid1 = self.nodes[0].sendtoaddress(node1_addr, 13) - txid2 =self.nodes[0].sendtoaddress(node2_addr, 13) - self.nodes[0].generate(6) + txid2 = self.nodes[0].sendtoaddress(node2_addr, 13) + blockhash = self.nodes[0].generate(6)[0] self.sync_all() - vout1 = find_output(self.nodes[1], txid1, 13) - vout2 = find_output(self.nodes[2], txid2, 13) + vout1 = find_output(self.nodes[1], txid1, 13, blockhash=blockhash) + vout2 = find_output(self.nodes[2], txid2, 13, blockhash=blockhash) # Create a psbt spending outputs from nodes 1 and 2 psbt_orig = self.nodes[0].createpsbt([{"txid":txid1, "vout":vout1}, {"txid":txid2, "vout":vout2}], {self.nodes[0].getnewaddress():25.999}) @@ -269,6 +268,9 @@ class PSBTTest(BitcoinTestFramework): combined = self.nodes[2].combinepsbt(combiner['combine']) assert_equal(combined, combiner['result']) + # Empty combiner test + assert_raises_rpc_error(-8, "Parameter 'txs' cannot be empty", self.nodes[0].combinepsbt, []) + # Finalizer test for finalizer in finalizers: finalized = self.nodes[2].finalizepsbt(finalizer['finalize'], False)['psbt'] @@ -290,5 +292,75 @@ class PSBTTest(BitcoinTestFramework): psbt = self.nodes[1].walletcreatefundedpsbt([], [{p2pkh : 1}], 0, {"includeWatching" : True}, True) self.nodes[0].decodepsbt(psbt['psbt']) + # Test decoding error: invalid base64 + assert_raises_rpc_error(-22, "TX decode failed invalid base64", self.nodes[0].decodepsbt, ";definitely not base64;") + + # Send to all types of addresses + addr1 = self.nodes[1].getnewaddress("", "bech32") + txid1 = self.nodes[0].sendtoaddress(addr1, 11) + vout1 = find_output(self.nodes[0], txid1, 11) + addr2 = self.nodes[1].getnewaddress("", "legacy") + txid2 = self.nodes[0].sendtoaddress(addr2, 11) + vout2 = find_output(self.nodes[0], txid2, 11) + addr3 = self.nodes[1].getnewaddress("", "p2sh-segwit") + txid3 = self.nodes[0].sendtoaddress(addr3, 11) + vout3 = find_output(self.nodes[0], txid3, 11) + self.sync_all() + + # Update a PSBT with UTXOs from the node + # Bech32 inputs should be filled with witness UTXO. Other inputs should not be filled because they are non-witness + psbt = self.nodes[1].createpsbt([{"txid":txid1, "vout":vout1},{"txid":txid2, "vout":vout2},{"txid":txid3, "vout":vout3}], {self.nodes[0].getnewaddress():32.999}) + decoded = self.nodes[1].decodepsbt(psbt) + assert "witness_utxo" not in decoded['inputs'][0] and "non_witness_utxo" not in decoded['inputs'][0] + assert "witness_utxo" not in decoded['inputs'][1] and "non_witness_utxo" not in decoded['inputs'][1] + assert "witness_utxo" not in decoded['inputs'][2] and "non_witness_utxo" not in decoded['inputs'][2] + updated = self.nodes[1].utxoupdatepsbt(psbt) + decoded = self.nodes[1].decodepsbt(updated) + assert "witness_utxo" in decoded['inputs'][0] and "non_witness_utxo" not in decoded['inputs'][0] + assert "witness_utxo" not in decoded['inputs'][1] and "non_witness_utxo" not in decoded['inputs'][1] + assert "witness_utxo" not in decoded['inputs'][2] and "non_witness_utxo" not in decoded['inputs'][2] + + # Two PSBTs with a common input should not be joinable + psbt1 = self.nodes[1].createpsbt([{"txid":txid1, "vout":vout1}], {self.nodes[0].getnewaddress():Decimal('10.999')}) + assert_raises_rpc_error(-8, "exists in multiple PSBTs", self.nodes[1].joinpsbts, [psbt1, updated]) + + # Join two distinct PSBTs + addr4 = self.nodes[1].getnewaddress("", "p2sh-segwit") + txid4 = self.nodes[0].sendtoaddress(addr4, 5) + vout4 = find_output(self.nodes[0], txid4, 5) + self.nodes[0].generate(6) + self.sync_all() + psbt2 = self.nodes[1].createpsbt([{"txid":txid4, "vout":vout4}], {self.nodes[0].getnewaddress():Decimal('4.999')}) + psbt2 = self.nodes[1].walletprocesspsbt(psbt2)['psbt'] + psbt2_decoded = self.nodes[0].decodepsbt(psbt2) + assert "final_scriptwitness" in psbt2_decoded['inputs'][0] and "final_scriptSig" in psbt2_decoded['inputs'][0] + joined = self.nodes[0].joinpsbts([psbt, psbt2]) + joined_decoded = self.nodes[0].decodepsbt(joined) + assert len(joined_decoded['inputs']) == 4 and len(joined_decoded['outputs']) == 2 and "final_scriptwitness" not in joined_decoded['inputs'][3] and "final_scriptSig" not in joined_decoded['inputs'][3] + + # Newly created PSBT needs UTXOs and updating + addr = self.nodes[1].getnewaddress("", "p2sh-segwit") + txid = self.nodes[0].sendtoaddress(addr, 7) + addrinfo = self.nodes[1].getaddressinfo(addr) + blockhash = self.nodes[0].generate(6)[0] + self.sync_all() + vout = find_output(self.nodes[0], txid, 7, blockhash=blockhash) + psbt = self.nodes[1].createpsbt([{"txid":txid, "vout":vout}], {self.nodes[0].getnewaddress("", "p2sh-segwit"):Decimal('6.999')}) + analyzed = self.nodes[0].analyzepsbt(psbt) + assert not analyzed['inputs'][0]['has_utxo'] and not analyzed['inputs'][0]['is_final'] and analyzed['inputs'][0]['next'] == 'updater' and analyzed['next'] == 'updater' + + # After update with wallet, only needs signing + updated = self.nodes[1].walletprocesspsbt(psbt, False, 'ALL', True)['psbt'] + analyzed = self.nodes[0].analyzepsbt(updated) + assert analyzed['inputs'][0]['has_utxo'] and not analyzed['inputs'][0]['is_final'] and analyzed['inputs'][0]['next'] == 'signer' and analyzed['next'] == 'signer' and analyzed['inputs'][0]['missing']['signatures'][0] == addrinfo['embedded']['witness_program'] + + # Check fee and size things + assert analyzed['fee'] == Decimal('0.001') and analyzed['estimated_vsize'] == 134 and analyzed['estimated_feerate'] == '0.00746268 BTC/kB' + + # After signing and finalizing, needs extracting + signed = self.nodes[1].walletprocesspsbt(updated)['psbt'] + analyzed = self.nodes[0].analyzepsbt(signed) + assert analyzed['inputs'][0]['has_utxo'] and analyzed['inputs'][0]['is_final'] and analyzed['next'] == 'extractor' + if __name__ == '__main__': PSBTTest().main() diff --git a/test/functional/rpc_rawtransaction.py b/test/functional/rpc_rawtransaction.py index a97d753626..c793cf00de 100755 --- a/test/functional/rpc_rawtransaction.py +++ b/test/functional/rpc_rawtransaction.py @@ -42,7 +42,6 @@ class RawTransactionsTest(BitcoinTestFramework): def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 3 - # TODO: remove -txindex. Currently required for getrawtransaction call. self.extra_args = [["-addresstype=legacy", "-txindex"], ["-addresstype=legacy", "-txindex"], ["-addresstype=legacy", "-txindex"]] def skip_test_if_missing_module(self): diff --git a/test/functional/rpc_scantxoutset.py b/test/functional/rpc_scantxoutset.py index 11b4db6ec5..18258f5df3 100755 --- a/test/functional/rpc_scantxoutset.py +++ b/test/functional/rpc_scantxoutset.py @@ -95,11 +95,12 @@ class ScantxoutsetTest(BitcoinTestFramework): assert_equal(self.nodes[0].scantxoutset("start", [ {"desc": "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/*)", "range": 1500}])['total_amount'], Decimal("28.672")) assert_equal(self.nodes[0].scantxoutset("start", [ {"desc": "combo(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/*)", "range": 1499}])['total_amount'], Decimal("12.288")) assert_equal(self.nodes[0].scantxoutset("start", [ {"desc": "combo(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/*)", "range": 1500}])['total_amount'], Decimal("28.672")) + assert_equal(self.nodes[0].scantxoutset("start", [ {"desc": "combo(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/*)", "range": [1500,1500]}])['total_amount'], Decimal("16.384")) # Test the reported descriptors for a few matches - assert_equal(descriptors(self.nodes[0].scantxoutset("start", [ {"desc": "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0h/0'/*)", "range": 1499}])), ["pkh([0c5f9a1e/0'/0'/0]026dbd8b2315f296d36e6b6920b1579ca75569464875c7ebe869b536a7d9503c8c)", "pkh([0c5f9a1e/0'/0'/1]033e6f25d76c00bedb3a8993c7d5739ee806397f0529b1b31dda31ef890f19a60c)"]) - assert_equal(descriptors(self.nodes[0].scantxoutset("start", [ "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/0)"])), ["pkh([0c5f9a1e/1/1/0]03e1c5b6e650966971d7e71ef2674f80222752740fc1dfd63bbbd220d2da9bd0fb)"]) - assert_equal(descriptors(self.nodes[0].scantxoutset("start", [ {"desc": "combo(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/*)", "range": 1500}])), ['pkh([0c5f9a1e/1/1/0]03e1c5b6e650966971d7e71ef2674f80222752740fc1dfd63bbbd220d2da9bd0fb)', 'pkh([0c5f9a1e/1/1/1500]03832901c250025da2aebae2bfb38d5c703a57ab66ad477f9c578bfbcd78abca6f)', 'pkh([0c5f9a1e/1/1/1]030d820fc9e8211c4169be8530efbc632775d8286167afd178caaf1089b77daba7)']) + assert_equal(descriptors(self.nodes[0].scantxoutset("start", [ {"desc": "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0h/0'/*)", "range": 1499}])), ["pkh([0c5f9a1e/0'/0'/0]026dbd8b2315f296d36e6b6920b1579ca75569464875c7ebe869b536a7d9503c8c)#dzxw429x", "pkh([0c5f9a1e/0'/0'/1]033e6f25d76c00bedb3a8993c7d5739ee806397f0529b1b31dda31ef890f19a60c)#43rvceed"]) + assert_equal(descriptors(self.nodes[0].scantxoutset("start", [ "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/0)"])), ["pkh([0c5f9a1e/1/1/0]03e1c5b6e650966971d7e71ef2674f80222752740fc1dfd63bbbd220d2da9bd0fb)#cxmct4w8"]) + assert_equal(descriptors(self.nodes[0].scantxoutset("start", [ {"desc": "combo(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/*)", "range": 1500}])), ['pkh([0c5f9a1e/1/1/0]03e1c5b6e650966971d7e71ef2674f80222752740fc1dfd63bbbd220d2da9bd0fb)#cxmct4w8', 'pkh([0c5f9a1e/1/1/1500]03832901c250025da2aebae2bfb38d5c703a57ab66ad477f9c578bfbcd78abca6f)#vchwd07g', 'pkh([0c5f9a1e/1/1/1]030d820fc9e8211c4169be8530efbc632775d8286167afd178caaf1089b77daba7)#z2t3ypsa']) if __name__ == '__main__': ScantxoutsetTest().main() diff --git a/test/functional/rpc_signrawtransaction.py b/test/functional/rpc_signrawtransaction.py index 291538df64..56e2c73a90 100755 --- a/test/functional/rpc_signrawtransaction.py +++ b/test/functional/rpc_signrawtransaction.py @@ -5,14 +5,17 @@ """Test transaction signing using the signrawtransaction* RPCs.""" from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import assert_equal, assert_raises_rpc_error +from test_framework.util import assert_equal, assert_raises_rpc_error, bytes_to_hex_str, hex_str_to_bytes +from test_framework.messages import sha256 +from test_framework.script import CScript, OP_0 +from decimal import Decimal class SignRawTransactionsTest(BitcoinTestFramework): def set_test_params(self): self.setup_clean_chain = True - self.num_nodes = 1 - self.extra_args = [["-deprecatedrpc=signrawtransaction"]] + self.num_nodes = 2 + self.extra_args = [["-deprecatedrpc=signrawtransaction"], []] def skip_test_if_missing_module(self): self.skip_if_no_wallet() @@ -143,9 +146,33 @@ class SignRawTransactionsTest(BitcoinTestFramework): assert_equal(rawTxSigned['errors'][1]['witness'], ["304402203609e17b84f6a7d30c80bfa610b5b4542f32a8a0d5447a12fb1366d7f01cc44a0220573a954c4518331561406f90300e8f3358f51928d43c212a8caed02de67eebee01", "025476c2e83188368da1ff3e292e7acafcdb3566bb0ad253f62fc70f07aeee6357"]) assert not rawTxSigned['errors'][0]['witness'] + def witness_script_test(self): + # Now test signing transaction to P2SH-P2WSH addresses without wallet + # Create a new P2SH-P2WSH 1-of-1 multisig address: + embedded_address = self.nodes[1].getaddressinfo(self.nodes[1].getnewaddress()) + embedded_privkey = self.nodes[1].dumpprivkey(embedded_address["address"]) + p2sh_p2wsh_address = self.nodes[1].addmultisigaddress(1, [embedded_address["pubkey"]], "", "p2sh-segwit") + # send transaction to P2SH-P2WSH 1-of-1 multisig address + self.nodes[0].generate(101) + self.nodes[0].sendtoaddress(p2sh_p2wsh_address["address"], 49.999) + self.nodes[0].generate(1) + self.sync_all() + # Find the UTXO for the transaction node[1] should have received, check witnessScript matches + unspent_output = self.nodes[1].listunspent(0, 999999, [p2sh_p2wsh_address["address"]])[0] + assert_equal(unspent_output["witnessScript"], p2sh_p2wsh_address["redeemScript"]) + p2sh_redeemScript = CScript([OP_0, sha256(hex_str_to_bytes(p2sh_p2wsh_address["redeemScript"]))]) + assert_equal(unspent_output["redeemScript"], bytes_to_hex_str(p2sh_redeemScript)) + # Now create and sign a transaction spending that output on node[0], which doesn't know the scripts or keys + spending_tx = self.nodes[0].createrawtransaction([unspent_output], {self.nodes[1].getnewaddress(): Decimal("49.998")}) + spending_tx_signed = self.nodes[0].signrawtransactionwithkey(spending_tx, [embedded_privkey], [unspent_output]) + # Check the signing completed successfully + assert 'complete' in spending_tx_signed + assert_equal(spending_tx_signed['complete'], True) + def run_test(self): self.successful_signing_test() self.script_verification_error_test() + self.witness_script_test() self.test_with_lock_outputs() diff --git a/test/functional/test_framework/blocktools.py b/test/functional/test_framework/blocktools.py index 6b47cae4c3..15f4502994 100644 --- a/test/functional/test_framework/blocktools.py +++ b/test/functional/test_framework/blocktools.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2015-2018 The Bitcoin Core developers +# Copyright (c) 2015-2019 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Utilities for manipulating blocks and transactions.""" @@ -43,9 +43,13 @@ from io import BytesIO MAX_BLOCK_SIGOPS = 20000 +# Genesis block time (regtest) +TIME_GENESIS_BLOCK = 1296688602 + # From BIP141 WITNESS_COMMITMENT_HEADER = b"\xaa\x21\xa9\xed" + def create_block(hashprev, coinbase, ntime=None, *, version=1): """Create a block (with regtest difficulty).""" block = CBlock() diff --git a/test/functional/test_framework/descriptors.py b/test/functional/test_framework/descriptors.py new file mode 100644 index 0000000000..29482ce01e --- /dev/null +++ b/test/functional/test_framework/descriptors.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python3 +# Copyright (c) 2019 Pieter Wuille +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +"""Utility functions related to output descriptors""" + +INPUT_CHARSET = "0123456789()[],'/*abcdefgh@:$%{}IJKLMNOPQRSTUVWXYZ&+-.;<=>?!^_|~ijklmnopqrstuvwxyzABCDEFGH`#\"\\ " +CHECKSUM_CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l" +GENERATOR = [0xf5dee51989, 0xa9fdca3312, 0x1bab10e32d, 0x3706b1677a, 0x644d626ffd] + +def descsum_polymod(symbols): + """Internal function that computes the descriptor checksum.""" + chk = 1 + for value in symbols: + top = chk >> 35 + chk = (chk & 0x7ffffffff) << 5 ^ value + for i in range(5): + chk ^= GENERATOR[i] if ((top >> i) & 1) else 0 + return chk + +def descsum_expand(s): + """Internal function that does the character to symbol expansion""" + groups = [] + symbols = [] + for c in s: + if not c in INPUT_CHARSET: + return None + v = INPUT_CHARSET.find(c) + symbols.append(v & 31) + groups.append(v >> 5) + if len(groups) == 3: + symbols.append(groups[0] * 9 + groups[1] * 3 + groups[2]) + groups = [] + if len(groups) == 1: + symbols.append(groups[0]) + elif len(groups) == 2: + symbols.append(groups[0] * 3 + groups[1]) + return symbols + +def descsum_create(s): + """Add a checksum to a descriptor without""" + symbols = descsum_expand(s) + [0, 0, 0, 0, 0, 0, 0, 0] + checksum = descsum_polymod(symbols) ^ 1 + return s + '#' + ''.join(CHECKSUM_CHARSET[(checksum >> (5 * (7 - i))) & 31] for i in range(8)) + +def descsum_check(s, require=True): + """Verify that the checksum is correct in a descriptor""" + if not '#' in s: + return not require + if s[-9] != '#': + return False + if not all(x in CHECKSUM_CHARSET for x in s[-8:]): + return False + symbols = descsum_expand(s[:-9]) + [CHECKSUM_CHARSET.find(x) for x in s[-8:]] + return descsum_polymod(symbols) == 1 diff --git a/test/functional/test_framework/messages.py b/test/functional/test_framework/messages.py index 356a45d6d0..4bd58519c5 100755 --- a/test/functional/test_framework/messages.py +++ b/test/functional/test_framework/messages.py @@ -28,7 +28,7 @@ import struct import time from test_framework.siphash import siphash256 -from test_framework.util import hex_str_to_bytes, bytes_to_hex_str +from test_framework.util import hex_str_to_bytes, bytes_to_hex_str, assert_equal MIN_VERSION_SUPPORTED = 60001 MY_VERSION = 70014 # past bip-31 for ping/pong @@ -591,6 +591,8 @@ class CBlockHeader: % (self.nVersion, self.hashPrevBlock, self.hashMerkleRoot, time.ctime(self.nTime), self.nBits, self.nNonce) +BLOCK_HEADER_SIZE = len(CBlockHeader().serialize()) +assert_equal(BLOCK_HEADER_SIZE, 80) class CBlock(CBlockHeader): __slots__ = ("vtx",) diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py index 6dcaff0696..09d7d877a7 100755 --- a/test/functional/test_framework/test_framework.py +++ b/test/functional/test_framework/test_framework.py @@ -29,11 +29,11 @@ from .util import ( get_datadir_path, initialize_datadir, p2p_port, - set_node_times, sync_blocks, sync_mempools, ) + class TestStatus(Enum): PASSED = 1 FAILED = 2 @@ -94,7 +94,6 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass): self.setup_clean_chain = False self.nodes = [] self.network_thread = None - self.mocktime = 0 self.rpc_timeout = 60 # Wait for up to 60 seconds for the RPC server to respond self.supports_cli = False self.bind_to_localhost_only = True @@ -128,6 +127,8 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass): help="Attach a python debugger if test fails") parser.add_argument("--usecli", dest="usecli", default=False, action="store_true", help="use bitcoin-cli instead of RPC for all commands") + parser.add_argument("--perf", dest="perf", default=False, action="store_true", + help="profile running nodes with perf for the duration of the test") self.add_options(parser) self.options = parser.parse_args() @@ -202,11 +203,20 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass): node.cleanup_on_exit = False self.log.info("Note: bitcoinds were not stopped and may still be running") - if not self.options.nocleanup and not self.options.noshutdown and success != TestStatus.FAILED: + should_clean_up = ( + not self.options.nocleanup and + not self.options.noshutdown and + success != TestStatus.FAILED and + not self.options.perf + ) + if should_clean_up: self.log.info("Cleaning up {} on exit".format(self.options.tmpdir)) cleanup_tree_on_exit = True + elif self.options.perf: + self.log.warning("Not cleaning up dir {} due to perf data".format(self.options.tmpdir)) + cleanup_tree_on_exit = False else: - self.log.warning("Not cleaning up dir %s" % self.options.tmpdir) + self.log.warning("Not cleaning up dir {}".format(self.options.tmpdir)) cleanup_tree_on_exit = False if success == TestStatus.PASSED: @@ -264,6 +274,19 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass): self.add_nodes(self.num_nodes, extra_args) self.start_nodes() self.import_deterministic_coinbase_privkeys() + if not self.setup_clean_chain: + for n in self.nodes: + assert_equal(n.getblockchaininfo()["blocks"], 199) + # To ensure that all nodes are out of IBD, the most recent block + # must have a timestamp not too old (see IsInitialBlockDownload()). + self.log.debug('Generate a block with current time') + block_hash = self.nodes[0].generate(1)[0] + block = self.nodes[0].getblock(blockhash=block_hash, verbosity=0) + for n in self.nodes: + n.submitblock(block) + chain_info = n.getblockchaininfo() + assert_equal(chain_info["blocks"], 200) + assert_equal(chain_info["initialblockdownload"], False) def import_deterministic_coinbase_privkeys(self): for n in self.nodes: @@ -305,11 +328,12 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass): timewait=self.rpc_timeout, bitcoind=binary[i], bitcoin_cli=self.options.bitcoincli, - mocktime=self.mocktime, coverage_dir=self.options.coveragedir, + cwd=self.options.tmpdir, extra_conf=extra_confs[i], extra_args=extra_args[i], use_cli=self.options.usecli, + start_perf=self.options.perf, )) def start_node(self, i, *args, **kwargs): @@ -422,7 +446,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass): def _initialize_chain(self): """Initialize a pre-mined blockchain for use by the test. - Create a cache of a 200-block-long chain (with wallet) for MAX_NODES + Create a cache of a 199-block-long chain (with wallet) for MAX_NODES Afterward, create num_nodes copies from the cache.""" assert self.num_nodes <= MAX_NODES @@ -455,8 +479,8 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass): timewait=self.rpc_timeout, bitcoind=self.options.bitcoind, bitcoin_cli=self.options.bitcoincli, - mocktime=self.mocktime, coverage_dir=None, + cwd=self.options.tmpdir, )) self.nodes[i].args = args self.start_node(i) @@ -465,32 +489,22 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass): for node in self.nodes: node.wait_for_rpc_connection() - # For backward compatibility of the python scripts with previous - # versions of the cache, set mocktime to Jan 1, - # 2014 + (201 * 10 * 60)""" - self.mocktime = 1388534400 + (201 * 10 * 60) - - # Create a 200-block-long chain; each of the 4 first nodes + # Create a 199-block-long chain; each of the 4 first nodes # gets 25 mature blocks and 25 immature. - # Note: To preserve compatibility with older versions of - # initialize_chain, only 4 nodes will generate coins. - # - # blocks are created with timestamps 10 minutes apart - # starting from 2010 minutes in the past - block_time = self.mocktime - (201 * 10 * 60) - for i in range(2): - for peer in range(4): - for j in range(25): - set_node_times(self.nodes, block_time) - self.nodes[peer].generatetoaddress(1, self.nodes[peer].get_deterministic_priv_key().address) - block_time += 10 * 60 - # Must sync before next peer starts generating blocks - sync_blocks(self.nodes) + # The 4th node gets only 24 immature blocks so that the very last + # block in the cache does not age too much (have an old tip age). + # This is needed so that we are out of IBD when the test starts, + # see the tip age check in IsInitialBlockDownload(). + for i in range(8): + self.nodes[0].generatetoaddress(25 if i != 7 else 24, self.nodes[i % 4].get_deterministic_priv_key().address) + sync_blocks(self.nodes) + + for n in self.nodes: + assert_equal(n.getblockchaininfo()["blocks"], 199) # Shut them down, and clean up cache directories: self.stop_nodes() self.nodes = [] - self.mocktime = 0 def cache_path(n, *paths): return os.path.join(get_datadir_path(self.options.cachedir, n), "regtest", *paths) diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py index 031a8824b1..37fd2a8744 100755 --- a/test/functional/test_framework/test_node.py +++ b/test/functional/test_framework/test_node.py @@ -18,6 +18,8 @@ import tempfile import time import urllib.parse import collections +import shlex +import sys from .authproxy import JSONRPCException from .util import ( @@ -59,7 +61,13 @@ class TestNode(): To make things easier for the test writer, any unrecognised messages will be dispatched to the RPC connection.""" - def __init__(self, i, datadir, *, rpchost, timewait, bitcoind, bitcoin_cli, mocktime, coverage_dir, extra_conf=None, extra_args=None, use_cli=False): + def __init__(self, i, datadir, *, rpchost, timewait, bitcoind, bitcoin_cli, coverage_dir, cwd, extra_conf=None, extra_args=None, use_cli=False, start_perf=False): + """ + Kwargs: + start_perf (bool): If True, begin profiling the node with `perf` as soon as + the node starts. + """ + self.index = i self.datadir = datadir self.stdout_dir = os.path.join(self.datadir, "stdout") @@ -68,6 +76,7 @@ class TestNode(): self.rpc_timeout = timewait self.binary = bitcoind self.coverage_dir = coverage_dir + self.cwd = cwd if extra_conf is not None: append_config(datadir, extra_conf) # Most callers will just need to add extra args to the standard list below. @@ -81,12 +90,12 @@ class TestNode(): "-debug", "-debugexclude=libevent", "-debugexclude=leveldb", - "-mocktime=" + str(mocktime), - "-uacomment=testnode%d" % i + "-uacomment=testnode%d" % i, ] self.cli = TestNodeCLI(bitcoin_cli, self.datadir) self.use_cli = use_cli + self.start_perf = start_perf self.running = False self.process = None @@ -95,6 +104,8 @@ class TestNode(): self.url = None self.log = logging.getLogger('TestFramework.node%d' % i) self.cleanup_on_exit = True # Whether to kill the node when this object goes away + # Cache perf subprocesses here by their data output filename. + self.perf_subprocesses = {} self.p2ps = [] @@ -160,7 +171,7 @@ class TestNode(): assert self.rpc_connected and self.rpc is not None, self._node_msg("Error: no RPC connection") return getattr(self.rpc, name) - def start(self, extra_args=None, *, stdout=None, stderr=None, **kwargs): + def start(self, extra_args=None, *, cwd=None, stdout=None, stderr=None, **kwargs): """Start the node.""" if extra_args is None: extra_args = self.extra_args @@ -173,6 +184,9 @@ class TestNode(): self.stderr = stderr self.stdout = stdout + if cwd is None: + cwd = self.cwd + # Delete any existing cookie file -- if such a file exists (eg due to # unclean shutdown), it will get overwritten anyway by bitcoind, and # potentially interfere with our attempt to authenticate @@ -181,11 +195,14 @@ class TestNode(): # add environment variable LIBC_FATAL_STDERR_=1 so that libc errors are written to stderr and not the terminal subp_env = dict(os.environ, LIBC_FATAL_STDERR_="1") - self.process = subprocess.Popen(self.args + extra_args, env=subp_env, stdout=stdout, stderr=stderr, **kwargs) + self.process = subprocess.Popen(self.args + extra_args, env=subp_env, stdout=stdout, stderr=stderr, cwd=cwd, **kwargs) self.running = True self.log.debug("bitcoind started, waiting for RPC to come up") + if self.start_perf: + self._start_perf() + def wait_for_rpc_connection(self): """Sets up an RPC connection to the bitcoind process. Returns False if unable to connect.""" # Poll at a rate of four times per second @@ -195,12 +212,15 @@ class TestNode(): raise FailedToStartError(self._node_msg( 'bitcoind exited with status {} during initialization'.format(self.process.returncode))) try: - self.rpc = get_rpc_proxy(rpc_url(self.datadir, self.index, self.rpchost), self.index, timeout=self.rpc_timeout, coveragedir=self.coverage_dir) - self.rpc.getblockcount() + rpc = get_rpc_proxy(rpc_url(self.datadir, self.index, self.rpchost), self.index, timeout=self.rpc_timeout, coveragedir=self.coverage_dir) + rpc.getblockcount() # If the call to getblockcount() succeeds then the RPC connection is up + self.log.debug("RPC successfully started") + if self.use_cli: + return + self.rpc = rpc self.rpc_connected = True self.url = self.rpc.url - self.log.debug("RPC successfully started") return except IOError as e: if e.errno != errno.ECONNREFUSED: # Port not yet open? @@ -238,6 +258,10 @@ class TestNode(): except http.client.CannotSendRequest: self.log.exception("Unable to stop node.") + # If there are any running perf processes, stop them. + for profile_name in tuple(self.perf_subprocesses.keys()): + self._stop_perf(profile_name) + # Check that stderr is as expected self.stderr.seek(0) stderr = self.stderr.read().decode('utf-8').strip() @@ -317,6 +341,84 @@ class TestNode(): increase_allowed * 100, before_memory_usage, after_memory_usage, perc_increase_memory_usage * 100)) + @contextlib.contextmanager + def profile_with_perf(self, profile_name): + """ + Context manager that allows easy profiling of node activity using `perf`. + + See `test/functional/README.md` for details on perf usage. + + Args: + profile_name (str): This string will be appended to the + profile data filename generated by perf. + """ + subp = self._start_perf(profile_name) + + yield + + if subp: + self._stop_perf(profile_name) + + def _start_perf(self, profile_name=None): + """Start a perf process to profile this node. + + Returns the subprocess running perf.""" + subp = None + + def test_success(cmd): + return subprocess.call( + # shell=True required for pipe use below + cmd, shell=True, + stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL) == 0 + + if not sys.platform.startswith('linux'): + self.log.warning("Can't profile with perf; only availabe on Linux platforms") + return None + + if not test_success('which perf'): + self.log.warning("Can't profile with perf; must install perf-tools") + return None + + if not test_success('readelf -S {} | grep .debug_str'.format(shlex.quote(self.binary))): + self.log.warning( + "perf output won't be very useful without debug symbols compiled into bitcoind") + + output_path = tempfile.NamedTemporaryFile( + dir=self.datadir, + prefix="{}.perf.data.".format(profile_name or 'test'), + delete=False, + ).name + + cmd = [ + 'perf', 'record', + '-g', # Record the callgraph. + '--call-graph', 'dwarf', # Compatibility for gcc's --fomit-frame-pointer. + '-F', '101', # Sampling frequency in Hz. + '-p', str(self.process.pid), + '-o', output_path, + ] + subp = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + self.perf_subprocesses[profile_name] = subp + + return subp + + def _stop_perf(self, profile_name): + """Stop (and pop) a perf subprocess.""" + subp = self.perf_subprocesses.pop(profile_name) + output_path = subp.args[subp.args.index('-o') + 1] + + subp.terminate() + subp.wait(timeout=10) + + stderr = subp.stderr.read().decode() + if 'Consider tweaking /proc/sys/kernel/perf_event_paranoid' in stderr: + self.log.warning( + "perf couldn't collect data! Try " + "'sudo sysctl -w kernel.perf_event_paranoid=-1'") + else: + report_cmd = "perf report -i {}".format(output_path) + self.log.info("See perf output by running '{}'".format(report_cmd)) + def assert_start_raises_init_error(self, extra_args=None, expected_msg=None, match=ErrorMatch.FULL_TEXT, *args, **kwargs): """Attempt to start the node and expect it to raise an error. @@ -402,6 +504,14 @@ class TestNodeCLIAttr: def get_request(self, *args, **kwargs): return lambda: self(*args, **kwargs) +def arg_to_cli(arg): + if isinstance(arg, bool): + return str(arg).lower() + elif isinstance(arg, dict) or isinstance(arg, list): + return json.dumps(arg) + else: + return str(arg) + class TestNodeCLI(): """Interface to bitcoin-cli for an individual node""" @@ -433,8 +543,8 @@ class TestNodeCLI(): def send_cli(self, command=None, *args, **kwargs): """Run bitcoin-cli command. Deserializes returned string as python object.""" - pos_args = [str(arg).lower() if type(arg) is bool else str(arg) for arg in args] - named_args = [str(key) + "=" + str(value) for (key, value) in kwargs.items()] + pos_args = [arg_to_cli(arg) for arg in args] + named_args = [str(key) + "=" + arg_to_cli(value) for (key, value) in kwargs.items()] assert not (pos_args and named_args), "Cannot use positional arguments and named arguments in the same bitcoin-cli call" p_args = [self.binary, "-datadir=" + self.datadir] + self.options if named_args: diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py index d0a78d8dfd..fef9982412 100644 --- a/test/functional/test_framework/util.py +++ b/test/functional/test_framework/util.py @@ -410,12 +410,12 @@ def sync_mempools(rpc_connections, *, wait=1, timeout=60, flush_scheduler=True): # Transaction/Block functions ############################# -def find_output(node, txid, amount): +def find_output(node, txid, amount, *, blockhash=None): """ Return index to output of txid with value amount Raises exception if there is none. """ - txdata = node.getrawtransaction(txid, 1) + txdata = node.getrawtransaction(txid, 1, blockhash) for i in range(len(txdata["vout"])): if txdata["vout"][i]["value"] == amount: return i diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index 057fd175b7..bb9ac58e46 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -7,8 +7,6 @@ This module calls down into individual test cases via subprocess. It will forward all unrecognized arguments onto the individual test scripts. -Functional tests are disabled on Windows by default. Use --force to run them anyway. - For a description of arguments recognized by test scripts, see `test/functional/test_framework/test_framework.py:BitcoinTestFramework.main`. @@ -119,8 +117,8 @@ BASE_SCRIPTS = [ 'mempool_persist.py', 'wallet_multiwallet.py', 'wallet_multiwallet.py --usecli', - 'wallet_disableprivatekeys.py', - 'wallet_disableprivatekeys.py --usecli', + 'wallet_createwallet.py', + 'wallet_createwallet.py --usecli', 'interface_http.py', 'interface_rpc.py', 'rpc_psbt.py', @@ -183,6 +181,8 @@ BASE_SCRIPTS = [ 'feature_filelock.py', 'p2p_unrequested_blocks.py', 'feature_includeconf.py', + 'rpc_deriveaddresses.py', + 'rpc_deriveaddresses.py --usecli', 'rpc_scantxoutset.py', 'feature_logging.py', 'p2p_node_network_limited.py', @@ -225,7 +225,6 @@ def main(): parser.add_argument('--ci', action='store_true', help='Run checks and code that are usually only enabled in a continuous integration environment') parser.add_argument('--exclude', '-x', help='specify a comma-separated-list of scripts to exclude.') parser.add_argument('--extended', action='store_true', help='run the extended test suite in addition to the basic tests') - parser.add_argument('--force', '-f', action='store_true', help='run tests even on platforms where they are disabled by default (e.g. windows).') parser.add_argument('--help', '-h', '-?', action='store_true', help='print help text and exit') parser.add_argument('--jobs', '-j', type=int, default=4, help='how many test scripts to run in parallel. Default=4.') parser.add_argument('--keepcache', '-k', action='store_true', help='the default behavior is to flush the cache directory on startup. --keepcache retains the cache from the previous testrun.') @@ -252,22 +251,12 @@ def main(): # Create base test directory tmpdir = "%s/test_runner_₿_🏃_%s" % (args.tmpdirprefix, datetime.datetime.now().strftime("%Y%m%d_%H%M%S")) - # If we fixed the command-line and filename encoding issue on Windows, these two lines could be removed - if config["environment"]["EXEEXT"] == ".exe": - tmpdir = "%s/test_runner_%s" % (args.tmpdirprefix, datetime.datetime.now().strftime("%Y%m%d_%H%M%S")) - os.makedirs(tmpdir) logging.debug("Temporary test directory at %s" % tmpdir) enable_bitcoind = config["components"].getboolean("ENABLE_BITCOIND") - if config["environment"]["EXEEXT"] == ".exe" and not args.force: - # https://github.com/bitcoin/bitcoin/commit/d52802551752140cf41f0d9a225a43e84404d3e9 - # https://github.com/bitcoin/bitcoin/pull/5677#issuecomment-136646964 - print("Tests currently disabled on Windows by default. Use --force option to enable") - sys.exit(0) - if not enable_bitcoind: print("No functional tests to run.") print("Rerun ./configure with --with-daemon and then make") diff --git a/test/functional/wallet_abandonconflict.py b/test/functional/wallet_abandonconflict.py index 2b684349ce..b0b151d2d6 100755 --- a/test/functional/wallet_abandonconflict.py +++ b/test/functional/wallet_abandonconflict.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2014-2018 The Bitcoin Core developers +# Copyright (c) 2014-2019 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test the abandontransaction RPC. @@ -13,13 +13,20 @@ from decimal import Decimal from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import assert_equal, assert_raises_rpc_error, connect_nodes, disconnect_nodes, sync_blocks, sync_mempools +from test_framework.util import ( + assert_equal, + assert_raises_rpc_error, + connect_nodes, + disconnect_nodes, + sync_blocks, + sync_mempools, +) + class AbandonConflictTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 2 - # TODO: remove -txindex. Currently required for getrawtransaction call. - self.extra_args = [["-minrelaytxfee=0.00001", "-txindex"], []] + self.extra_args = [["-minrelaytxfee=0.00001"], []] def skip_test_if_missing_module(self): self.skip_if_no_wallet() @@ -41,21 +48,21 @@ class AbandonConflictTest(BitcoinTestFramework): sync_blocks(self.nodes) newbalance = self.nodes[0].getbalance() - assert(balance - newbalance < Decimal("0.001")) #no more than fees lost + assert balance - newbalance < Decimal("0.001") #no more than fees lost balance = newbalance # Disconnect nodes so node0's transactions don't get into node1's mempool disconnect_nodes(self.nodes[0], 1) # Identify the 10btc outputs - nA = next(i for i, vout in enumerate(self.nodes[0].getrawtransaction(txA, 1)["vout"]) if vout["value"] == Decimal("10")) - nB = next(i for i, vout in enumerate(self.nodes[0].getrawtransaction(txB, 1)["vout"]) if vout["value"] == Decimal("10")) - nC = next(i for i, vout in enumerate(self.nodes[0].getrawtransaction(txC, 1)["vout"]) if vout["value"] == Decimal("10")) + nA = next(tx_out["vout"] for tx_out in self.nodes[0].gettransaction(txA)["details"] if tx_out["amount"] == Decimal("10")) + nB = next(tx_out["vout"] for tx_out in self.nodes[0].gettransaction(txB)["details"] if tx_out["amount"] == Decimal("10")) + nC = next(tx_out["vout"] for tx_out in self.nodes[0].gettransaction(txC)["details"] if tx_out["amount"] == Decimal("10")) - inputs =[] + inputs = [] # spend 10btc outputs from txA and txB - inputs.append({"txid":txA, "vout":nA}) - inputs.append({"txid":txB, "vout":nB}) + inputs.append({"txid": txA, "vout": nA}) + inputs.append({"txid": txB, "vout": nB}) outputs = {} outputs[self.nodes[0].getnewaddress()] = Decimal("14.99998") @@ -64,12 +71,12 @@ class AbandonConflictTest(BitcoinTestFramework): txAB1 = self.nodes[0].sendrawtransaction(signed["hex"]) # Identify the 14.99998btc output - nAB = next(i for i, vout in enumerate(self.nodes[0].getrawtransaction(txAB1, 1)["vout"]) if vout["value"] == Decimal("14.99998")) + nAB = next(tx_out["vout"] for tx_out in self.nodes[0].gettransaction(txAB1)["details"] if tx_out["amount"] == Decimal("14.99998")) #Create a child tx spending AB1 and C inputs = [] - inputs.append({"txid":txAB1, "vout":nAB}) - inputs.append({"txid":txC, "vout":nC}) + inputs.append({"txid": txAB1, "vout": nAB}) + inputs.append({"txid": txC, "vout": nC}) outputs = {} outputs[self.nodes[0].getnewaddress()] = Decimal("24.9996") signed2 = self.nodes[0].signrawtransactionwithwallet(self.nodes[0].createrawtransaction(inputs, outputs)) @@ -77,8 +84,8 @@ class AbandonConflictTest(BitcoinTestFramework): # Create a child tx spending ABC2 signed3_change = Decimal("24.999") - inputs = [ {"txid":txABC2, "vout":0} ] - outputs = { self.nodes[0].getnewaddress(): signed3_change } + inputs = [{"txid": txABC2, "vout": 0}] + outputs = {self.nodes[0].getnewaddress(): signed3_change} signed3 = self.nodes[0].signrawtransactionwithwallet(self.nodes[0].createrawtransaction(inputs, outputs)) # note tx is never directly referenced, only abandoned as a child of the above self.nodes[0].sendrawtransaction(signed3["hex"]) @@ -106,7 +113,7 @@ class AbandonConflictTest(BitcoinTestFramework): unconfbalance = self.nodes[0].getunconfirmedbalance() + self.nodes[0].getbalance() assert_equal(unconfbalance, newbalance) # Also shouldn't show up in listunspent - assert(not txABC2 in [utxo["txid"] for utxo in self.nodes[0].listunspent(0)]) + assert not txABC2 in [utxo["txid"] for utxo in self.nodes[0].listunspent(0)] balance = newbalance # Abandon original transaction and verify inputs are available again @@ -146,8 +153,8 @@ class AbandonConflictTest(BitcoinTestFramework): # Create a double spend of AB1 by spending again from only A's 10 output # Mine double spend from node 1 - inputs =[] - inputs.append({"txid":txA, "vout":nA}) + inputs = [] + inputs.append({"txid": txA, "vout": nA}) outputs = {} outputs[self.nodes[1].getnewaddress()] = Decimal("9.9999") tx = self.nodes[0].createrawtransaction(inputs, outputs) @@ -173,5 +180,6 @@ class AbandonConflictTest(BitcoinTestFramework): self.log.info("conflicted has not resumed causing its inputs to be seen as spent. See Issue #7315") self.log.info(str(balance) + " -> " + str(newbalance) + " ?") + if __name__ == '__main__': AbandonConflictTest().main() diff --git a/test/functional/wallet_address_types.py b/test/functional/wallet_address_types.py index bafa556aad..380dd9c0ad 100755 --- a/test/functional/wallet_address_types.py +++ b/test/functional/wallet_address_types.py @@ -54,6 +54,10 @@ from decimal import Decimal import itertools from test_framework.test_framework import BitcoinTestFramework +from test_framework.descriptors import ( + descsum_create, + descsum_check, +) from test_framework.util import ( assert_equal, assert_greater_than, @@ -167,24 +171,31 @@ class AddressTypeTest(BitcoinTestFramework): assert_equal(deriv['path'][0], 'm') key_descs[deriv['pubkey']] = '[' + deriv['master_fingerprint'] + deriv['path'][1:] + ']' + deriv['pubkey'] + # Verify the descriptor checksum against the Python implementation + assert(descsum_check(info['desc'])) + # Verify that stripping the checksum and recreating it using Python roundtrips + assert(info['desc'] == descsum_create(info['desc'][:-9])) + # Verify that stripping the checksum and feeding it to getdescriptorinfo roundtrips + assert(info['desc'] == self.nodes[0].getdescriptorinfo(info['desc'][:-9])['descriptor']) + if not multisig and typ == 'legacy': # P2PKH - assert_equal(info['desc'], "pkh(%s)" % key_descs[info['pubkey']]) + assert_equal(info['desc'], descsum_create("pkh(%s)" % key_descs[info['pubkey']])) elif not multisig and typ == 'p2sh-segwit': # P2SH-P2WPKH - assert_equal(info['desc'], "sh(wpkh(%s))" % key_descs[info['pubkey']]) + assert_equal(info['desc'], descsum_create("sh(wpkh(%s))" % key_descs[info['pubkey']])) elif not multisig and typ == 'bech32': # P2WPKH - assert_equal(info['desc'], "wpkh(%s)" % key_descs[info['pubkey']]) + assert_equal(info['desc'], descsum_create("wpkh(%s)" % key_descs[info['pubkey']])) elif typ == 'legacy': # P2SH-multisig - assert_equal(info['desc'], "sh(multi(2,%s,%s))" % (key_descs[info['pubkeys'][0]], key_descs[info['pubkeys'][1]])) + assert_equal(info['desc'], descsum_create("sh(multi(2,%s,%s))" % (key_descs[info['pubkeys'][0]], key_descs[info['pubkeys'][1]]))) elif typ == 'p2sh-segwit': # P2SH-P2WSH-multisig - assert_equal(info['desc'], "sh(wsh(multi(2,%s,%s)))" % (key_descs[info['embedded']['pubkeys'][0]], key_descs[info['embedded']['pubkeys'][1]])) + assert_equal(info['desc'], descsum_create("sh(wsh(multi(2,%s,%s)))" % (key_descs[info['embedded']['pubkeys'][0]], key_descs[info['embedded']['pubkeys'][1]]))) elif typ == 'bech32': # P2WSH-multisig - assert_equal(info['desc'], "wsh(multi(2,%s,%s))" % (key_descs[info['pubkeys'][0]], key_descs[info['pubkeys'][1]])) + assert_equal(info['desc'], descsum_create("wsh(multi(2,%s,%s))" % (key_descs[info['pubkeys'][0]], key_descs[info['pubkeys'][1]]))) else: # Unknown type assert(False) diff --git a/test/functional/wallet_basic.py b/test/functional/wallet_basic.py index 10b51ecdac..0477164b6b 100755 --- a/test/functional/wallet_basic.py +++ b/test/functional/wallet_basic.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2014-2018 The Bitcoin Core developers +# Copyright (c) 2014-2019 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test the wallet.""" @@ -18,12 +18,11 @@ from test_framework.util import ( wait_until, ) + class WalletTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 4 self.setup_clean_chain = True - # TODO: remove -txindex. Currently required for getrawtransaction call. - self.extra_args = [[], [], ["-txindex"], []] def skip_test_if_missing_module(self): self.skip_if_no_wallet() @@ -190,7 +189,7 @@ class WalletTest(BitcoinTestFramework): txid = self.nodes[2].sendtoaddress(address, 10, "", "", False) self.nodes[2].generate(1) self.sync_all([self.nodes[0:3]]) - node_2_bal = self.check_fee_amount(self.nodes[2].getbalance(), Decimal('84'), fee_per_byte, self.get_vsize(self.nodes[2].getrawtransaction(txid))) + node_2_bal = self.check_fee_amount(self.nodes[2].getbalance(), Decimal('84'), fee_per_byte, self.get_vsize(self.nodes[2].gettransaction(txid)['hex'])) assert_equal(self.nodes[0].getbalance(), Decimal('10')) # Send 10 BTC with subtract fee from amount @@ -199,14 +198,14 @@ class WalletTest(BitcoinTestFramework): self.sync_all([self.nodes[0:3]]) node_2_bal -= Decimal('10') assert_equal(self.nodes[2].getbalance(), node_2_bal) - node_0_bal = self.check_fee_amount(self.nodes[0].getbalance(), Decimal('20'), fee_per_byte, self.get_vsize(self.nodes[2].getrawtransaction(txid))) + node_0_bal = self.check_fee_amount(self.nodes[0].getbalance(), Decimal('20'), fee_per_byte, self.get_vsize(self.nodes[2].gettransaction(txid)['hex'])) # Sendmany 10 BTC txid = self.nodes[2].sendmany('', {address: 10}, 0, "", []) self.nodes[2].generate(1) self.sync_all([self.nodes[0:3]]) node_0_bal += Decimal('10') - node_2_bal = self.check_fee_amount(self.nodes[2].getbalance(), node_2_bal - Decimal('10'), fee_per_byte, self.get_vsize(self.nodes[2].getrawtransaction(txid))) + node_2_bal = self.check_fee_amount(self.nodes[2].getbalance(), node_2_bal - Decimal('10'), fee_per_byte, self.get_vsize(self.nodes[2].gettransaction(txid)['hex'])) assert_equal(self.nodes[0].getbalance(), node_0_bal) # Sendmany 10 BTC with subtract fee from amount @@ -215,7 +214,7 @@ class WalletTest(BitcoinTestFramework): self.sync_all([self.nodes[0:3]]) node_2_bal -= Decimal('10') assert_equal(self.nodes[2].getbalance(), node_2_bal) - node_0_bal = self.check_fee_amount(self.nodes[0].getbalance(), node_0_bal + Decimal('10'), fee_per_byte, self.get_vsize(self.nodes[2].getrawtransaction(txid))) + node_0_bal = self.check_fee_amount(self.nodes[0].getbalance(), node_0_bal + Decimal('10'), fee_per_byte, self.get_vsize(self.nodes[2].gettransaction(txid)['hex'])) # Test ResendWalletTransactions: # Create a couple of transactions, then start up a fourth @@ -233,7 +232,7 @@ class WalletTest(BitcoinTestFramework): assert_equal(set(relayed), {txid1, txid2}) sync_mempools(self.nodes) - assert(txid1 in self.nodes[3].getrawmempool()) + assert txid1 in self.nodes[3].getrawmempool() # check if we can list zero value tx as available coins # 1. create raw_tx @@ -260,7 +259,7 @@ class WalletTest(BitcoinTestFramework): if uTx['txid'] == zero_value_txid: found = True assert_equal(uTx['amount'], Decimal('0')) - assert(found) + assert found # do some -walletbroadcast tests self.stop_nodes() @@ -320,12 +319,38 @@ class WalletTest(BitcoinTestFramework): tx_obj = self.nodes[0].gettransaction(txid) assert_equal(tx_obj['amount'], Decimal('-0.0001')) + # General checks for errors from incorrect inputs # This will raise an exception because the amount type is wrong assert_raises_rpc_error(-3, "Invalid amount", self.nodes[0].sendtoaddress, self.nodes[2].getnewaddress(), "1f-4") # This will raise an exception since generate does not accept a string assert_raises_rpc_error(-1, "not an integer", self.nodes[0].generate, "2") + # This will raise an exception for the invalid private key format + assert_raises_rpc_error(-5, "Invalid private key encoding", self.nodes[0].importprivkey, "invalid") + + # This will raise an exception for importing an address with the PS2H flag + temp_address = self.nodes[1].getnewaddress() + assert_raises_rpc_error(-5, "Cannot use the p2sh flag with an address - use a script instead", self.nodes[0].importaddress, temp_address, "label", False, True) + + # This will raise an exception for attempting to dump the private key of an address you do not own + assert_raises_rpc_error(-3, "Address does not refer to a key", self.nodes[0].dumpprivkey, temp_address) + + # This will raise an exception for attempting to get the private key of an invalid Bitcoin address + assert_raises_rpc_error(-5, "Invalid Bitcoin address", self.nodes[0].dumpprivkey, "invalid") + + # This will raise an exception for attempting to set a label for an invalid Bitcoin address + assert_raises_rpc_error(-5, "Invalid Bitcoin address", self.nodes[0].setlabel, "invalid address", "label") + + # This will raise an exception for importing an invalid address + assert_raises_rpc_error(-5, "Invalid Bitcoin address or script", self.nodes[0].importaddress, "invalid") + + # This will raise an exception for attempting to import a pubkey that isn't in hex + assert_raises_rpc_error(-5, "Pubkey must be a hex string", self.nodes[0].importpubkey, "not hex") + + # This will raise an exception for importing an invalid pubkey + assert_raises_rpc_error(-5, "Pubkey is not a valid public key", self.nodes[0].importpubkey, "5361746f736869204e616b616d6f746f") + # Import address and private key to check correct behavior of spendable unspents # 1. Send some coins to generate new UTXO address_to_import = self.nodes[2].getnewaddress() @@ -337,7 +362,7 @@ class WalletTest(BitcoinTestFramework): self.nodes[1].importaddress(address_to_import) # 3. Validate that the imported address is watch-only on node1 - assert(self.nodes[1].getaddressinfo(address_to_import)["iswatchonly"]) + assert self.nodes[1].getaddressinfo(address_to_import)["iswatchonly"] # 4. Check that the unspents after import are not spendable assert_array_result(self.nodes[1].listunspent(), @@ -379,7 +404,7 @@ class WalletTest(BitcoinTestFramework): addr = self.nodes[0].getnewaddress() self.nodes[0].setlabel(addr, label) assert_equal(self.nodes[0].getaddressinfo(addr)['label'], label) - assert(label in self.nodes[0].listlabels()) + assert label in self.nodes[0].listlabels() self.nodes[0].rpc.ensure_ascii = True # restore to default # maintenance tests @@ -438,8 +463,8 @@ class WalletTest(BitcoinTestFramework): # Without walletrejectlongchains, we will still generate a txid # The tx will be stored in the wallet but not accepted to the mempool extra_txid = self.nodes[0].sendtoaddress(sending_addr, Decimal('0.0001')) - assert(extra_txid not in self.nodes[0].getrawmempool()) - assert(extra_txid in [tx["txid"] for tx in self.nodes[0].listtransactions()]) + assert extra_txid not in self.nodes[0].getrawmempool() + assert extra_txid in [tx["txid"] for tx in self.nodes[0].listtransactions()] self.nodes[0].abandontransaction(extra_txid) total_txs = len(self.nodes[0].listtransactions("*", 99999)) @@ -476,7 +501,7 @@ class WalletTest(BitcoinTestFramework): self.nodes[0].generate(1) destination = self.nodes[1].getnewaddress() txid = self.nodes[0].sendtoaddress(destination, 0.123) - tx = self.nodes[0].decoderawtransaction(self.nodes[0].getrawtransaction(txid)) + tx = self.nodes[0].decoderawtransaction(self.nodes[0].gettransaction(txid)['hex']) output_addresses = [vout['scriptPubKey']['addresses'][0] for vout in tx["vout"]] assert len(output_addresses) > 1 for address in output_addresses: @@ -487,5 +512,6 @@ class WalletTest(BitcoinTestFramework): self.nodes[0].setlabel(change, 'foobar') assert_equal(self.nodes[0].getaddressinfo(change)['ischange'], False) + if __name__ == '__main__': WalletTest().main() diff --git a/test/functional/wallet_create_tx.py b/test/functional/wallet_create_tx.py index 27dc0fb279..7b749235e2 100755 --- a/test/functional/wallet_create_tx.py +++ b/test/functional/wallet_create_tx.py @@ -7,17 +7,25 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, ) +from test_framework.blocktools import ( + TIME_GENESIS_BLOCK, +) class CreateTxWalletTest(BitcoinTestFramework): def set_test_params(self): - self.setup_clean_chain = False + self.setup_clean_chain = True self.num_nodes = 1 def skip_test_if_missing_module(self): self.skip_if_no_wallet() def run_test(self): + self.log.info('Create some old blocks') + self.nodes[0].setmocktime(TIME_GENESIS_BLOCK) + self.nodes[0].generate(200) + self.nodes[0].setmocktime(0) + self.log.info('Check that we have some (old) blocks and that anti-fee-sniping is disabled') assert_equal(self.nodes[0].getblockchaininfo()['blocks'], 200) txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1) diff --git a/test/functional/wallet_createwallet.py b/test/functional/wallet_createwallet.py new file mode 100755 index 0000000000..7ec72b8649 --- /dev/null +++ b/test/functional/wallet_createwallet.py @@ -0,0 +1,100 @@ +#!/usr/bin/env python3 +# Copyright (c) 2018 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +"""Test createwallet arguments. +""" + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import ( + assert_equal, + assert_raises_rpc_error, +) + +class CreateWalletTest(BitcoinTestFramework): + def set_test_params(self): + self.setup_clean_chain = False + self.num_nodes = 1 + self.supports_cli = True + + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + + def run_test(self): + node = self.nodes[0] + node.generate(1) # Leave IBD for sethdseed + + self.nodes[0].createwallet(wallet_name='w0') + w0 = node.get_wallet_rpc('w0') + address1 = w0.getnewaddress() + + self.log.info("Test disableprivatekeys creation.") + self.nodes[0].createwallet(wallet_name='w1', disable_private_keys=True) + w1 = node.get_wallet_rpc('w1') + assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w1.getnewaddress) + assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w1.getrawchangeaddress) + w1.importpubkey(w0.getaddressinfo(address1)['pubkey']) + + self.log.info('Test that private keys cannot be imported') + addr = w0.getnewaddress('', 'legacy') + privkey = w0.dumpprivkey(addr) + assert_raises_rpc_error(-4, 'Cannot import private keys to a wallet with private keys disabled', w1.importprivkey, privkey) + result = w1.importmulti([{'scriptPubKey': {'address': addr}, 'timestamp': 'now', 'keys': [privkey]}]) + assert(not result[0]['success']) + assert('warning' not in result[0]) + assert_equal(result[0]['error']['code'], -4) + assert_equal(result[0]['error']['message'], 'Cannot import private keys to a wallet with private keys disabled') + + self.log.info("Test blank creation with private keys disabled.") + self.nodes[0].createwallet(wallet_name='w2', disable_private_keys=True, blank=True) + w2 = node.get_wallet_rpc('w2') + assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w2.getnewaddress) + assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w2.getrawchangeaddress) + w2.importpubkey(w0.getaddressinfo(address1)['pubkey']) + + self.log.info("Test blank creation with private keys enabled.") + self.nodes[0].createwallet(wallet_name='w3', disable_private_keys=False, blank=True) + w3 = node.get_wallet_rpc('w3') + assert_equal(w3.getwalletinfo()['keypoolsize'], 0) + assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w3.getnewaddress) + assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w3.getrawchangeaddress) + # Import private key + w3.importprivkey(w0.dumpprivkey(address1)) + # Imported private keys are currently ignored by the keypool + assert_equal(w3.getwalletinfo()['keypoolsize'], 0) + assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w3.getnewaddress) + # Set the seed + w3.sethdseed() + assert_equal(w3.getwalletinfo()['keypoolsize'], 1) + w3.getnewaddress() + w3.getrawchangeaddress() + + self.log.info("Test blank creation with privkeys enabled and then encryption") + self.nodes[0].createwallet(wallet_name='w4', disable_private_keys=False, blank=True) + w4 = node.get_wallet_rpc('w4') + assert_equal(w4.getwalletinfo()['keypoolsize'], 0) + assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w4.getnewaddress) + assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w4.getrawchangeaddress) + # Encrypt the wallet. Nothing should change about the keypool + w4.encryptwallet('pass') + assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w4.getnewaddress) + assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w4.getrawchangeaddress) + # Now set a seed and it should work. Wallet should also be encrypted + w4.walletpassphrase('pass', 2) + w4.sethdseed() + w4.getnewaddress() + w4.getrawchangeaddress() + + self.log.info("Test blank creation with privkeys disabled and then encryption") + self.nodes[0].createwallet(wallet_name='w5', disable_private_keys=True, blank=True) + w5 = node.get_wallet_rpc('w5') + assert_equal(w5.getwalletinfo()['keypoolsize'], 0) + assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w5.getnewaddress) + assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w5.getrawchangeaddress) + # Encrypt the wallet + w5.encryptwallet('pass') + assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w5.getnewaddress) + assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w5.getrawchangeaddress) + +if __name__ == '__main__': + CreateWalletTest().main() diff --git a/test/functional/wallet_disableprivatekeys.py b/test/functional/wallet_disableprivatekeys.py deleted file mode 100755 index 34ff525255..0000000000 --- a/test/functional/wallet_disableprivatekeys.py +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/env python3 -# Copyright (c) 2018 The Bitcoin Core developers -# Distributed under the MIT software license, see the accompanying -# file COPYING or http://www.opensource.org/licenses/mit-license.php. -"""Test disable-privatekeys mode. -""" - -from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import ( - assert_raises_rpc_error, -) - - -class DisablePrivateKeysTest(BitcoinTestFramework): - def set_test_params(self): - self.setup_clean_chain = False - self.num_nodes = 1 - self.supports_cli = True - - def skip_test_if_missing_module(self): - self.skip_if_no_wallet() - - def run_test(self): - node = self.nodes[0] - self.log.info("Test disableprivatekeys creation.") - self.nodes[0].createwallet('w1', True) - self.nodes[0].createwallet('w2') - w1 = node.get_wallet_rpc('w1') - w2 = node.get_wallet_rpc('w2') - assert_raises_rpc_error(-4,"Error: Private keys are disabled for this wallet", w1.getnewaddress) - assert_raises_rpc_error(-4,"Error: Private keys are disabled for this wallet", w1.getrawchangeaddress) - w1.importpubkey(w2.getaddressinfo(w2.getnewaddress())['pubkey']) - -if __name__ == '__main__': - DisablePrivateKeysTest().main() diff --git a/test/functional/wallet_hd.py b/test/functional/wallet_hd.py index eb42531693..61245e5104 100755 --- a/test/functional/wallet_hd.py +++ b/test/functional/wallet_hd.py @@ -27,7 +27,6 @@ class WalletHDTest(BitcoinTestFramework): def run_test(self): # Make sure we use hd, keep masterkeyid masterkeyid = self.nodes[1].getwalletinfo()['hdseedid'] - assert_equal(masterkeyid, self.nodes[1].getwalletinfo()['hdmasterkeyid']) assert_equal(len(masterkeyid), 40) # create an internal key @@ -53,7 +52,6 @@ class WalletHDTest(BitcoinTestFramework): hd_info = self.nodes[1].getaddressinfo(hd_add) assert_equal(hd_info["hdkeypath"], "m/0'/0'/"+str(i)+"'") assert_equal(hd_info["hdseedid"], masterkeyid) - assert_equal(hd_info["hdmasterkeyid"], masterkeyid) self.nodes[0].sendtoaddress(hd_add, 1) self.nodes[0].generate(1) self.nodes[0].sendtoaddress(non_hd_add, 1) @@ -83,7 +81,6 @@ class WalletHDTest(BitcoinTestFramework): hd_info_2 = self.nodes[1].getaddressinfo(hd_add_2) assert_equal(hd_info_2["hdkeypath"], "m/0'/0'/"+str(i)+"'") assert_equal(hd_info_2["hdseedid"], masterkeyid) - assert_equal(hd_info_2["hdmasterkeyid"], masterkeyid) assert_equal(hd_add, hd_add_2) connect_nodes_bi(self.nodes, 0, 1) self.sync_all() diff --git a/test/functional/wallet_importmulti.py b/test/functional/wallet_importmulti.py index f122f19e3a..c6d0425f22 100755 --- a/test/functional/wallet_importmulti.py +++ b/test/functional/wallet_importmulti.py @@ -20,6 +20,7 @@ from test_framework.script import ( OP_NOP, ) from test_framework.test_framework import BitcoinTestFramework +from test_framework.descriptors import descsum_create from test_framework.util import ( assert_equal, assert_greater_than, @@ -203,7 +204,7 @@ class ImportMultiTest(BitcoinTestFramework): "keys": [key.privkey]}, success=False, error_code=-4, - error_message='The wallet already contains the private key for this address or script') + error_message='The wallet already contains the private key for this address or script ("' + key.p2pkh_script + '")') # Address + Private key + watchonly self.log.info("Should import an address with private key and with watchonly") @@ -543,5 +544,275 @@ class ImportMultiTest(BitcoinTestFramework): solvable=True, ismine=False) + # Test importing of a P2SH-P2WPKH address via descriptor + private key + key = get_key(self.nodes[0]) + self.log.info("Should not import a p2sh-p2wpkh address from descriptor without checksum and private key") + self.test_importmulti({"desc": "sh(wpkh(" + key.pubkey + "))", + "timestamp": "now", + "label": "Descriptor import test", + "keys": [key.privkey]}, + success=False, + error_code=-5, + error_message="Descriptor is invalid") + + # Test importing of a P2SH-P2WPKH address via descriptor + private key + key = get_key(self.nodes[0]) + self.log.info("Should import a p2sh-p2wpkh address from descriptor and private key") + self.test_importmulti({"desc": descsum_create("sh(wpkh(" + key.pubkey + "))"), + "timestamp": "now", + "label": "Descriptor import test", + "keys": [key.privkey]}, + success=True) + test_address(self.nodes[1], + key.p2sh_p2wpkh_addr, + solvable=True, + ismine=True, + label="Descriptor import test") + + # Test ranged descriptor fails if range is not specified + xpriv = "tprv8ZgxMBicQKsPeuVhWwi6wuMQGfPKi9Li5GtX35jVNknACgqe3CY4g5xgkfDDJcmtF7o1QnxWDRYw4H5P26PXq7sbcUkEqeR4fg3Kxp2tigg" + addresses = ["2N7yv4p8G8yEaPddJxY41kPihnWvs39qCMf", "2MsHxyb2JS3pAySeNUsJ7mNnurtpeenDzLA"] # hdkeypath=m/0'/0'/0' and 1' + desc = "sh(wpkh(" + xpriv + "/0'/0'/*'" + "))" + self.log.info("Ranged descriptor import should fail without a specified range") + self.test_importmulti({"desc": descsum_create(desc), + "timestamp": "now"}, + success=False, + error_code=-8, + error_message='Descriptor is ranged, please specify the range') + + # Test importing of a ranged descriptor without keys + self.log.info("Should import the ranged descriptor with specified range as solvable") + self.test_importmulti({"desc": descsum_create(desc), + "timestamp": "now", + "range": 1}, + success=True, + warnings=["Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag."]) + for address in addresses: + test_address(self.nodes[1], + key.p2sh_p2wpkh_addr, + solvable=True) + + # Test importing of a P2PKH address via descriptor + key = get_key(self.nodes[0]) + self.log.info("Should import a p2pkh address from descriptor") + self.test_importmulti({"desc": descsum_create("pkh(" + key.pubkey + ")"), + "timestamp": "now", + "label": "Descriptor import test"}, + True, + warnings=["Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag."]) + test_address(self.nodes[1], + key.p2pkh_addr, + solvable=True, + ismine=False, + label="Descriptor import test") + + # Test import fails if both desc and scriptPubKey are provided + key = get_key(self.nodes[0]) + self.log.info("Import should fail if both scriptPubKey and desc are provided") + self.test_importmulti({"desc": descsum_create("pkh(" + key.pubkey + ")"), + "scriptPubKey": {"address": key.p2pkh_addr}, + "timestamp": "now"}, + success=False, + error_code=-8, + error_message='Both a descriptor and a scriptPubKey should not be provided.') + + # Test import fails if neither desc nor scriptPubKey are present + key = get_key(self.nodes[0]) + self.log.info("Import should fail if neither a descriptor nor a scriptPubKey are provided") + self.test_importmulti({"timestamp": "now"}, + success=False, + error_code=-8, + error_message='Either a descriptor or scriptPubKey must be provided.') + + # Test importing of a multisig via descriptor + key1 = get_key(self.nodes[0]) + key2 = get_key(self.nodes[0]) + self.log.info("Should import a 1-of-2 bare multisig from descriptor") + self.test_importmulti({"desc": descsum_create("multi(1," + key1.pubkey + "," + key2.pubkey + ")"), + "timestamp": "now"}, + success=True) + self.log.info("Should not treat individual keys from the imported bare multisig as watchonly") + test_address(self.nodes[1], + key1.p2pkh_addr, + ismine=False, + iswatchonly=False) + + # Import pubkeys with key origin info + self.log.info("Addresses should have hd keypath and master key id after import with key origin") + pub_addr = self.nodes[1].getnewaddress() + pub_addr = self.nodes[1].getnewaddress() + info = self.nodes[1].getaddressinfo(pub_addr) + pub = info['pubkey'] + pub_keypath = info['hdkeypath'] + pub_fpr = info['hdmasterfingerprint'] + result = self.nodes[0].importmulti( + [{ + 'desc' : descsum_create("wpkh([" + pub_fpr + pub_keypath[1:] +"]" + pub + ")"), + "timestamp": "now", + }] + ) + assert result[0]['success'] + pub_import_info = self.nodes[0].getaddressinfo(pub_addr) + assert_equal(pub_import_info['hdmasterfingerprint'], pub_fpr) + assert_equal(pub_import_info['pubkey'], pub) + assert_equal(pub_import_info['hdkeypath'], pub_keypath) + + # Import privkeys with key origin info + priv_addr = self.nodes[1].getnewaddress() + info = self.nodes[1].getaddressinfo(priv_addr) + priv = self.nodes[1].dumpprivkey(priv_addr) + priv_keypath = info['hdkeypath'] + priv_fpr = info['hdmasterfingerprint'] + result = self.nodes[0].importmulti( + [{ + 'desc' : descsum_create("wpkh([" + priv_fpr + priv_keypath[1:] + "]" + priv + ")"), + "timestamp": "now", + }] + ) + assert result[0]['success'] + priv_import_info = self.nodes[0].getaddressinfo(priv_addr) + assert_equal(priv_import_info['hdmasterfingerprint'], priv_fpr) + assert_equal(priv_import_info['hdkeypath'], priv_keypath) + + # Make sure the key origin info are still there after a restart + self.stop_nodes() + self.start_nodes() + import_info = self.nodes[0].getaddressinfo(pub_addr) + assert_equal(import_info['hdmasterfingerprint'], pub_fpr) + assert_equal(import_info['hdkeypath'], pub_keypath) + import_info = self.nodes[0].getaddressinfo(priv_addr) + assert_equal(import_info['hdmasterfingerprint'], priv_fpr) + assert_equal(import_info['hdkeypath'], priv_keypath) + + # Check legacy import does not import key origin info + self.log.info("Legacy imports don't have key origin info") + pub_addr = self.nodes[1].getnewaddress() + info = self.nodes[1].getaddressinfo(pub_addr) + pub = info['pubkey'] + result = self.nodes[0].importmulti( + [{ + 'scriptPubKey': {'address': pub_addr}, + 'pubkeys': [pub], + "timestamp": "now", + }] + ) + assert result[0]['success'] + pub_import_info = self.nodes[0].getaddressinfo(pub_addr) + assert_equal(pub_import_info['pubkey'], pub) + assert 'hdmasterfingerprint' not in pub_import_info + assert 'hdkeypath' not in pub_import_info + + # Import some public keys to the keypool of a no privkey wallet + self.log.info("Adding pubkey to keypool of disableprivkey wallet") + self.nodes[1].createwallet(wallet_name="noprivkeys", disable_private_keys=True) + wrpc = self.nodes[1].get_wallet_rpc("noprivkeys") + + addr1 = self.nodes[0].getnewaddress() + addr2 = self.nodes[0].getnewaddress() + pub1 = self.nodes[0].getaddressinfo(addr1)['pubkey'] + pub2 = self.nodes[0].getaddressinfo(addr2)['pubkey'] + result = wrpc.importmulti( + [{ + 'desc': descsum_create('wpkh(' + pub1 + ')'), + 'keypool': True, + "timestamp": "now", + }, + { + 'desc': descsum_create('wpkh(' + pub2 + ')'), + 'keypool': True, + "timestamp": "now", + }] + ) + assert result[0]['success'] + assert result[1]['success'] + assert_equal(wrpc.getwalletinfo()["keypoolsize"], 2) + newaddr1 = wrpc.getnewaddress() + assert_equal(addr1, newaddr1) + newaddr2 = wrpc.getnewaddress() + assert_equal(addr2, newaddr2) + + # Import some public keys to the internal keypool of a no privkey wallet + self.log.info("Adding pubkey to internal keypool of disableprivkey wallet") + addr1 = self.nodes[0].getnewaddress() + addr2 = self.nodes[0].getnewaddress() + pub1 = self.nodes[0].getaddressinfo(addr1)['pubkey'] + pub2 = self.nodes[0].getaddressinfo(addr2)['pubkey'] + result = wrpc.importmulti( + [{ + 'desc': descsum_create('wpkh(' + pub1 + ')'), + 'keypool': True, + 'internal': True, + "timestamp": "now", + }, + { + 'desc': descsum_create('wpkh(' + pub2 + ')'), + 'keypool': True, + 'internal': True, + "timestamp": "now", + }] + ) + assert result[0]['success'] + assert result[1]['success'] + assert_equal(wrpc.getwalletinfo()["keypoolsize_hd_internal"], 2) + newaddr1 = wrpc.getrawchangeaddress() + assert_equal(addr1, newaddr1) + newaddr2 = wrpc.getrawchangeaddress() + assert_equal(addr2, newaddr2) + + # Import a multisig and make sure the keys don't go into the keypool + self.log.info('Imported scripts with pubkeys shoud not have their pubkeys go into the keypool') + addr1 = self.nodes[0].getnewaddress() + addr2 = self.nodes[0].getnewaddress() + pub1 = self.nodes[0].getaddressinfo(addr1)['pubkey'] + pub2 = self.nodes[0].getaddressinfo(addr2)['pubkey'] + result = wrpc.importmulti( + [{ + 'desc': descsum_create('wsh(multi(2,' + pub1 + ',' + pub2 + '))'), + 'keypool': True, + "timestamp": "now", + }] + ) + assert result[0]['success'] + assert_equal(wrpc.getwalletinfo()["keypoolsize"], 0) + + # Cannot import those pubkeys to keypool of wallet with privkeys + self.log.info("Pubkeys cannot be added to the keypool of a wallet with private keys") + wrpc = self.nodes[1].get_wallet_rpc("") + assert wrpc.getwalletinfo()['private_keys_enabled'] + result = wrpc.importmulti( + [{ + 'desc': descsum_create('wpkh(' + pub1 + ')'), + 'keypool': True, + "timestamp": "now", + }] + ) + assert_equal(result[0]['error']['code'], -8) + assert_equal(result[0]['error']['message'], "Keys can only be imported to the keypool when private keys are disabled") + + # Make sure ranged imports import keys in order + self.log.info('Key ranges should be imported in order') + wrpc = self.nodes[1].get_wallet_rpc("noprivkeys") + assert_equal(wrpc.getwalletinfo()["keypoolsize"], 0) + assert_equal(wrpc.getwalletinfo()["private_keys_enabled"], False) + xpub = "tpubDAXcJ7s7ZwicqjprRaEWdPoHKrCS215qxGYxpusRLLmJuT69ZSicuGdSfyvyKpvUNYBW1s2U3NSrT6vrCYB9e6nZUEvrqnwXPF8ArTCRXMY" + addresses = [ + 'bcrt1qtmp74ayg7p24uslctssvjm06q5phz4yrxucgnv', # m/0'/0'/0 + 'bcrt1q8vprchan07gzagd5e6v9wd7azyucksq2xc76k8', # m/0'/0'/1 + 'bcrt1qtuqdtha7zmqgcrr26n2rqxztv5y8rafjp9lulu', # m/0'/0'/2 + 'bcrt1qau64272ymawq26t90md6an0ps99qkrse58m640', # m/0'/0'/3 + 'bcrt1qsg97266hrh6cpmutqen8s4s962aryy77jp0fg0', # m/0'/0'/4 + ] + result = wrpc.importmulti( + [{ + 'desc': descsum_create('wpkh([80002067/0h/0h]' + xpub + '/*)'), + 'keypool': True, + 'timestamp': 'now', + 'range' : [0, 4], + }] + ) + for i in range(0, 5): + addr = wrpc.getnewaddress('', 'bech32') + assert_equal(addr, addresses[i]) + if __name__ == '__main__': ImportMultiTest().main() diff --git a/test/functional/wallet_keypool.py b/test/functional/wallet_keypool.py index ceb9709712..1116196268 100755 --- a/test/functional/wallet_keypool.py +++ b/test/functional/wallet_keypool.py @@ -21,7 +21,6 @@ class KeyPoolTest(BitcoinTestFramework): addr_before_encrypting = nodes[0].getnewaddress() addr_before_encrypting_data = nodes[0].getaddressinfo(addr_before_encrypting) wallet_info_old = nodes[0].getwalletinfo() - assert_equal(wallet_info_old['hdseedid'], wallet_info_old['hdmasterkeyid']) assert(addr_before_encrypting_data['hdseedid'] == wallet_info_old['hdseedid']) # Encrypt wallet and wait to terminate @@ -30,7 +29,6 @@ class KeyPoolTest(BitcoinTestFramework): addr = nodes[0].getnewaddress() addr_data = nodes[0].getaddressinfo(addr) wallet_info = nodes[0].getwalletinfo() - assert_equal(wallet_info['hdseedid'], wallet_info['hdmasterkeyid']) assert(addr_before_encrypting_data['hdseedid'] != wallet_info['hdseedid']) assert(addr_data['hdseedid'] == wallet_info['hdseedid']) assert_raises_rpc_error(-12, "Error: Keypool ran out, please call keypoolrefill first", nodes[0].getnewaddress) diff --git a/test/functional/wallet_multiwallet.py b/test/functional/wallet_multiwallet.py index 8ab569a3c3..df778f57df 100755 --- a/test/functional/wallet_multiwallet.py +++ b/test/functional/wallet_multiwallet.py @@ -315,6 +315,14 @@ class MultiWalletTest(BitcoinTestFramework): self.nodes[0].loadwallet(wallet_name) assert_equal(rpc.getaddressinfo(addr)['ismine'], True) + # Test .walletlock file is closed + self.start_node(1) + wallet = os.path.join(self.options.tmpdir, 'my_wallet') + self.nodes[0].createwallet(wallet) + assert_raises_rpc_error(-4, "Error initializing wallet database environment", self.nodes[1].loadwallet, wallet) + self.nodes[0].unloadwallet(wallet) + self.nodes[1].loadwallet(wallet) + if __name__ == '__main__': MultiWalletTest().main() diff --git a/test/functional/wallet_txn_clone.py b/test/functional/wallet_txn_clone.py index 1c2e0a9cb7..a0a35bf43d 100755 --- a/test/functional/wallet_txn_clone.py +++ b/test/functional/wallet_txn_clone.py @@ -4,13 +4,16 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test the wallet accounts properly when there are cloned transactions with malleated scriptsigs.""" +import io from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, + bytes_to_hex_str as b2x, connect_nodes, disconnect_nodes, sync_blocks, ) +from test_framework.messages import CTransaction, COIN class TxnMallTest(BitcoinTestFramework): def set_test_params(self): @@ -72,19 +75,14 @@ class TxnMallTest(BitcoinTestFramework): clone_raw = self.nodes[0].createrawtransaction(clone_inputs, clone_outputs, clone_locktime) # createrawtransaction randomizes the order of its outputs, so swap them if necessary. - # output 0 is at version+#inputs+input+sigstub+sequence+#outputs - # 40 BTC serialized is 00286bee00000000 - pos0 = 2 * (4 + 1 + 36 + 1 + 4 + 1) - hex40 = "00286bee00000000" - output_len = 16 + 2 + 2 * int("0x" + clone_raw[pos0 + 16:pos0 + 16 + 2], 0) - if (rawtx1["vout"][0]["value"] == 40 and clone_raw[pos0:pos0 + 16] != hex40 or rawtx1["vout"][0]["value"] != 40 and clone_raw[pos0:pos0 + 16] == hex40): - output0 = clone_raw[pos0:pos0 + output_len] - output1 = clone_raw[pos0 + output_len:pos0 + 2 * output_len] - clone_raw = clone_raw[:pos0] + output1 + output0 + clone_raw[pos0 + 2 * output_len:] + clone_tx = CTransaction() + clone_tx.deserialize(io.BytesIO(bytes.fromhex(clone_raw))) + if (rawtx1["vout"][0]["value"] == 40 and clone_tx.vout[0].nValue != 40*COIN or rawtx1["vout"][0]["value"] != 40 and clone_tx.vout[0].nValue == 40*COIN): + (clone_tx.vout[0], clone_tx.vout[1]) = (clone_tx.vout[1], clone_tx.vout[0]) # Use a different signature hash type to sign. This creates an equivalent but malleated clone. # Don't send the clone anywhere yet - tx1_clone = self.nodes[0].signrawtransactionwithwallet(clone_raw, None, "ALL|ANYONECANPAY") + tx1_clone = self.nodes[0].signrawtransactionwithwallet(b2x(clone_tx.serialize()), None, "ALL|ANYONECANPAY") assert_equal(tx1_clone["complete"], True) # Have node0 mine a block, if requested: diff --git a/test/functional/wallet_txn_doublespend.py b/test/functional/wallet_txn_doublespend.py index f114d5ab68..9050e21247 100755 --- a/test/functional/wallet_txn_doublespend.py +++ b/test/functional/wallet_txn_doublespend.py @@ -34,6 +34,14 @@ class TxnMallTest(BitcoinTestFramework): def run_test(self): # All nodes should start with 1,250 BTC: starting_balance = 1250 + + # All nodes should be out of IBD. + # If the nodes are not all out of IBD, that can interfere with + # blockchain sync later in the test when nodes are connected, due to + # timing issues. + for n in self.nodes: + assert n.getblockchaininfo()["initialblockdownload"] == False + for i in range(4): assert_equal(self.nodes[i].getbalance(), starting_balance) self.nodes[i].getnewaddress("") # bug workaround, coins generated assigned to first getnewaddress! diff --git a/test/fuzz/test_runner.py b/test/fuzz/test_runner.py new file mode 100755 index 0000000000..1869f71753 --- /dev/null +++ b/test/fuzz/test_runner.py @@ -0,0 +1,138 @@ +#!/usr/bin/env python3 +# Copyright (c) 2019 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +"""Run fuzz test targets. +""" + +import argparse +import configparser +import os +import sys +import subprocess +import logging + + +def main(): + parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter) + parser.add_argument( + "-l", + "--loglevel", + dest="loglevel", + default="INFO", + help="log events at this level and higher to the console. Can be set to DEBUG, INFO, WARNING, ERROR or CRITICAL. Passing --loglevel DEBUG will output all logs to console.", + ) + parser.add_argument( + '--export_coverage', + action='store_true', + help='If true, export coverage information to files in the seed corpus', + ) + parser.add_argument( + 'seed_dir', + help='The seed corpus to run on (must contain subfolders for each fuzz target).', + ) + parser.add_argument( + 'target', + nargs='*', + help='The target(s) to run. Default is to run all targets.', + ) + + args = parser.parse_args() + + # Set up logging + logging.basicConfig( + format='%(message)s', + level=int(args.loglevel) if args.loglevel.isdigit() else args.loglevel.upper(), + ) + + # Read config generated by configure. + config = configparser.ConfigParser() + configfile = os.path.abspath(os.path.dirname(__file__)) + "/../config.ini" + config.read_file(open(configfile, encoding="utf8")) + + if not config["components"].getboolean("ENABLE_FUZZ"): + logging.error("Must have fuzz targets built") + sys.exit(1) + + # Build list of tests + test_list_all = parse_test_list(makefile=os.path.join(config["environment"]["SRCDIR"], 'src', 'Makefile.test.include')) + + if not test_list_all: + logging.error("No fuzz targets found") + sys.exit(1) + + logging.info("Fuzz targets found: {}".format(test_list_all)) + + args.target = args.target or test_list_all # By default run all + test_list_error = list(set(args.target).difference(set(test_list_all))) + if test_list_error: + logging.error("Unknown fuzz targets selected: {}".format(test_list_error)) + test_list_selection = list(set(test_list_all).intersection(set(args.target))) + if not test_list_selection: + logging.error("No fuzz targets selected") + logging.info("Fuzz targets selected: {}".format(test_list_selection)) + + try: + help_output = subprocess.run( + args=[ + os.path.join(config["environment"]["BUILDDIR"], 'src', 'test', 'fuzz', test_list_selection[0]), + '-help=1', + ], + timeout=1, + check=True, + stderr=subprocess.PIPE, + universal_newlines=True, + ).stderr + if "libFuzzer" not in help_output: + logging.error("Must be built with libFuzzer") + sys.exit(1) + except subprocess.TimeoutExpired: + logging.error("subprocess timed out: Currently only libFuzzer is supported") + sys.exit(1) + + run_once( + corpus=args.seed_dir, + test_list=test_list_selection, + build_dir=config["environment"]["BUILDDIR"], + export_coverage=args.export_coverage, + ) + + +def run_once(*, corpus, test_list, build_dir, export_coverage): + for t in test_list: + args = [ + os.path.join(build_dir, 'src', 'test', 'fuzz', t), + '-runs=1', + os.path.join(corpus, t), + ] + logging.debug('Run {} with args {}'.format(t, args)) + output = subprocess.run(args, check=True, stderr=subprocess.PIPE, universal_newlines=True).stderr + logging.debug('Output: {}'.format(output)) + if not export_coverage: + continue + for l in output.splitlines(): + if 'INITED' in l: + with open(os.path.join(corpus, t + '_coverage'), 'w', encoding='utf-8') as cov_file: + cov_file.write(l) + break + + +def parse_test_list(makefile): + with open(makefile, encoding='utf-8') as makefile_test: + test_list_all = [] + read_targets = False + for line in makefile_test.readlines(): + line = line.strip().replace('test/fuzz/', '').replace(' \\', '') + if read_targets: + if not line: + break + test_list_all.append(line) + continue + + if line == 'FUZZ_TARGETS =': + read_targets = True + return test_list_all + + +if __name__ == '__main__': + main() diff --git a/test/lint/lint-locale-dependence.sh b/test/lint/lint-locale-dependence.sh index 1534d5ef68..2b6c78c2c8 100755 --- a/test/lint/lint-locale-dependence.sh +++ b/test/lint/lint-locale-dependence.sh @@ -8,6 +8,7 @@ KNOWN_VIOLATIONS=( "src/dbwrapper.cpp:.*vsnprintf" "src/httprpc.cpp.*trim" "src/init.cpp:.*atoi" + "src/init.cpp:.*fprintf" "src/qt/rpcconsole.cpp:.*atoi" "src/rest.cpp:.*strtol" "src/test/dbwrapper_tests.cpp:.*snprintf" @@ -18,7 +19,6 @@ KNOWN_VIOLATIONS=( "src/util/strencodings.cpp:.*strtoul" "src/util/strencodings.h:.*atoi" "src/util/system.cpp:.*atoi" - "src/util/system.cpp:.*fprintf" ) REGEXP_IGNORE_EXTERNAL_DEPENDENCIES="^src/(crypto/ctaes/|leveldb/|secp256k1/|tinyformat.h|univalue/)" diff --git a/test/lint/lint-python-dead-code.sh b/test/lint/lint-python-dead-code.sh index 1b897cd131..863caa9d5c 100755 --- a/test/lint/lint-python-dead-code.sh +++ b/test/lint/lint-python-dead-code.sh @@ -15,5 +15,5 @@ fi vulture \ --min-confidence 60 \ - --ignore-names "argtypes,connection_lost,connection_made,converter,data_received,daemon,errcheck,get_ecdh_key,get_privkey,is_compressed,is_fullyvalid,msg_generic,on_*,optionxform,restype,set_privkey" \ + --ignore-names "argtypes,connection_lost,connection_made,converter,data_received,daemon,errcheck,get_ecdh_key,get_privkey,is_compressed,is_fullyvalid,msg_generic,on_*,optionxform,restype,set_privkey,profile_with_perf" \ $(git ls-files -- "*.py" ":(exclude)contrib/" ":(exclude)test/functional/data/invalid_txs.py") diff --git a/test/lint/lint-whitespace.sh b/test/lint/lint-whitespace.sh index f318e19071..d5c1dee42d 100755 --- a/test/lint/lint-whitespace.sh +++ b/test/lint/lint-whitespace.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash # -# Copyright (c) 2017 The Bitcoin Core developers +# Copyright (c) 2017-2019 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. # @@ -12,11 +12,11 @@ export LC_ALL=C while getopts "?" opt; do case $opt in ?) - echo "Usage: .lint-whitespace.sh [N]" - echo " TRAVIS_COMMIT_RANGE='<commit range>' .lint-whitespace.sh" - echo " .lint-whitespace.sh -?" + echo "Usage: $0 [N]" + echo " TRAVIS_COMMIT_RANGE='<commit range>' $0" + echo " $0 -?" echo "Checks unstaged changes, the previous N commits, or a commit range." - echo "TRAVIS_COMMIT_RANGE='47ba2c3...ee50c9e' .lint-whitespace.sh" + echo "TRAVIS_COMMIT_RANGE='47ba2c3...ee50c9e' $0" exit 0 ;; esac diff --git a/test/sanitizer_suppressions/ubsan b/test/sanitizer_suppressions/ubsan index f0107f1361..d55119b266 100644 --- a/test/sanitizer_suppressions/ubsan +++ b/test/sanitizer_suppressions/ubsan @@ -4,7 +4,6 @@ bool:wallet/wallet.cpp float-divide-by-zero:policy/fees.cpp float-divide-by-zero:validation.cpp float-divide-by-zero:wallet/wallet.cpp -nonnull-attribute:support/cleanse.cpp unsigned-integer-overflow:arith_uint256.h unsigned-integer-overflow:basic_string.h unsigned-integer-overflow:bench/bench.h |