diff options
352 files changed, 20658 insertions, 5149 deletions
diff --git a/.appveyor.yml b/.appveyor.yml index 2aebf1cd54..eb2d32e1bc 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -7,7 +7,7 @@ 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: boost-filesystem boost-signals2 boost-test libevent openssl zeromq berkeleydb PATH: 'C:\Python37-x64;C:\Python37-x64\Scripts;%PATH%' PYTHONUTF8: 1 cache: @@ -33,7 +33,7 @@ before_build: - ps: Start-Process clcache-server - ps: fsutil behavior set disablelastaccess 0 # Enable Access time feature on Windows (for clcache) build_script: -- cmd: msbuild /p:TrackFileAccess=false /p:CLToolExe=clcache.exe build_msvc\bitcoin.sln /m /v:q /nowarn:C4244;C4267;C4715 /nologo +- cmd: msbuild /p:TrackFileAccess=false /p:CLToolExe=clcache.exe build_msvc\bitcoin.sln /m /v:q /nologo after_build: - ps: fsutil behavior set disablelastaccess 1 # Disable Access time feature on Windows (better performance) - ps: clcache -z diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 55cebc008f..8768a8ca6b 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -17,5 +17,7 @@ If the node is "stuck" during sync or giving "block checksum mismatch" errors, p <!-- What type of machine are you observing the error on (OS/CPU and disk type)? --> +<!-- For the GUI-related issue on Linux provide names and versions of a distro, a desktop environment and a graphical shell (if relevant). --> + <!-- Any extra information that might be useful in the debugging process. --> <!--- This is normally the contents of a `debug.log` or `config.log` file. Raw text or a link to a pastebin type site are preferred. --> diff --git a/.gitignore b/.gitignore index 380d2eab98..994d67402f 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ src/bitcoin src/bitcoind src/bitcoin-cli src/bitcoin-tx +src/bitcoin-wallet src/test/test_bitcoin src/test/test_bitcoin_fuzzy src/qt/test/test_bitcoin-qt diff --git a/.travis.yml b/.travis.yml index 258fd1b1c5..b43418f84e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -32,14 +32,16 @@ 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 1500 ]; 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 jobs: include: -# lint stage + - stage: lint + name: 'lint' env: cache: false language: python @@ -50,8 +52,9 @@ jobs: - set -o errexit; source .travis/lint_05_before_script.sh script: - set -o errexit; source .travis/lint_06_script.sh -# ARM + - stage: test + name: 'ARM [GOAL: install] [no unit or functional tests]' env: >- HOST=arm-linux-gnueabihf PACKAGES="python3 g++-arm-linux-gnueabihf" @@ -61,39 +64,55 @@ jobs: # -Wno-psabi is to disable ABI warnings: "note: parameter passing for argument of type ... changed in GCC 7.1" # This could be removed once the ABI change warning does not show up by default BITCOIN_CONFIG="--enable-glibc-back-compat --enable-reduce-exports CXXFLAGS=-Wno-psabi" -# Win32 + - stage: test + name: 'Win32 [GOAL: deploy] [no gui tests]' env: >- HOST=i686-w64-mingw32 DPKG_ADD_ARCH="i386" PACKAGES="python3 nsis g++-mingw-w64-i686 wine-binfmt wine32" GOAL="deploy" BITCOIN_CONFIG="--enable-reduce-exports --disable-gui-tests" -# Win64 + - stage: test + name: 'Win64 [GOAL: deploy] [no gui tests]' env: >- HOST=x86_64-w64-mingw32 PACKAGES="python3 nsis g++-mingw-w64-x86-64 wine-binfmt wine64" GOAL="deploy" BITCOIN_CONFIG="--enable-reduce-exports --disable-gui-tests" -# 32-bit + dash + - stage: test + name: '32-bit + dash [GOAL: install]' 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++" CONFIG_SHELL="/bin/dash" -# x86_64 Linux (uses qt5 dev package instead of depends Qt to speed up build and avoid timeout) + - stage: test + name: 'x86_64 Linux [GOAL: install] [bionic] [uses qt5 dev package instead of depends Qt to speed up build and avoid timeout]' env: >- HOST=x86_64-unknown-linux-gnu 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-glibc-back-compat --enable-reduce-exports --enable-debug CXXFLAGS=\"-g0 -O2\"" -# x86_64 Linux (xenial, no depends, only system libs, sanitizers: thread (TSan)) + BITCOIN_CONFIG="--enable-zmq --with-gui=qt5 --enable-fuzz --enable-glibc-back-compat --enable-reduce-exports --enable-debug CXXFLAGS=\"-g0 -O2\"" + - stage: test + 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" + + - stage: test + name: 'x86_64 Linux [GOAL: install] [xenial] [no depends, only system libs, sanitizers: thread (TSan), no wallet]' env: >- HOST=x86_64-unknown-linux-gnu DOCKER_NAME_TAG=ubuntu:16.04 @@ -101,25 +120,27 @@ jobs: NO_DEPENDS=1 GOAL="install" BITCOIN_CONFIG="--enable-zmq --disable-wallet --with-gui=qt5 CPPFLAGS=-DDEBUG_LOCKORDER --with-sanitizers=thread --disable-hardening --disable-asm CC=clang CXX=clang++" -# x86_64 Linux (no depends, only system libs, sanitizers: address/leak (ASan + LSan) + undefined (UBSan) + integer) + - stage: test + name: 'x86_64 Linux [GOAL: install] [bionic] [no depends, only system libs, sanitizers: address/leak (ASan + LSan) + undefined (UBSan) + integer]' env: >- 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++" -# x86_64 Linux, No wallet + - stage: test + name: 'x86_64 Linux [GOAL: install] [bionic] [no wallet]' env: >- HOST=x86_64-unknown-linux-gnu PACKAGES="python3-zmq" DEP_OPTS="NO_WALLET=1" GOAL="install" BITCOIN_CONFIG="--enable-glibc-back-compat --enable-reduce-exports" -# Cross-Mac + - stage: test + 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/lint_04_install.sh b/.travis/lint_04_install.sh index 723e7c56f1..9a22773e57 100755 --- a/.travis/lint_04_install.sh +++ b/.travis/lint_04_install.sh @@ -9,3 +9,7 @@ export LC_ALL=C travis_retry pip install codespell==1.13.0 travis_retry pip install flake8==3.5.0 travis_retry pip install vulture==0.29 + +SHELLCHECK_VERSION=v0.6.0 +curl -s "https://storage.googleapis.com/shellcheck/shellcheck-${SHELLCHECK_VERSION}.linux.x86_64.tar.xz" | tar --xz -xf - --directory /tmp/ +export PATH="/tmp/shellcheck-${SHELLCHECK_VERSION}:${PATH}" 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..b6b5925be8 --- /dev/null +++ b/.travis/test_06_script_b.sh @@ -0,0 +1,21 @@ +#!/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 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/build_msvc/bench_bitcoin/bench_bitcoin.vcxproj b/build_msvc/bench_bitcoin/bench_bitcoin.vcxproj index b987a337c0..771e8a56f4 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> diff --git a/build_msvc/bitcoin-tx/bitcoin-tx.vcxproj b/build_msvc/bitcoin-tx/bitcoin-tx.vcxproj index a9fae6b739..86fd614990 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> diff --git a/build_msvc/bitcoin-wallet/bitcoin-wallet.vcxproj b/build_msvc/bitcoin-wallet/bitcoin-wallet.vcxproj new file mode 100644 index 0000000000..367e68ee51 --- /dev/null +++ b/build_msvc/bitcoin-wallet/bitcoin-wallet.vcxproj @@ -0,0 +1,198 @@ +<?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\bitcoin-wallet.cpp" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="..\libbitcoinconsensus\libbitcoinconsensus.vcxproj"> + <Project>{2b384fa8-9ee1-4544-93cb-0d733c25e8ce}</Project> + </ProjectReference> + <ProjectReference Include="..\libbitcoin_cli\libbitcoin_cli.vcxproj"> + <Project>{0667528c-d734-4009-adf9-c0d6c4a5a5a6}</Project> + </ProjectReference> + <ProjectReference Include="..\libbitcoin_common\libbitcoin_common.vcxproj"> + <Project>{7c87e378-df58-482e-aa2f-1bc129bc19ce}</Project> + </ProjectReference> + <ProjectReference Include="..\libbitcoin_crypto\libbitcoin_crypto.vcxproj"> + <Project>{6190199c-6cf4-4dad-bfbd-93fa72a760c1}</Project> + </ProjectReference> + <ProjectReference Include="..\libbitcoin_server\libbitcoin_server.vcxproj"> + <Project>{460fee33-1fe1-483f-b3bf-931ff8e969a5}</Project> + </ProjectReference> + <ProjectReference Include="..\libbitcoin_util\libbitcoin_util.vcxproj"> + <Project>{b53a5535-ee9d-4c6f-9a26-f79ee3bc3754}</Project> + </ProjectReference> + <ProjectReference Include="..\libbitcoin_wallet\libbitcoin_wallet.vcxproj"> + <Project>{93b86837-b543-48a5-a89b-7c87abb77df2}</Project> + </ProjectReference> + <ProjectReference Include="..\libbitcoin_zmq\libbitcoin_zmq.vcxproj"> + <Project>{792d487f-f14c-49fc-a9de-3fc150f31c3f}</Project> + </ProjectReference> + <ProjectReference Include="..\libunivalue\libunivalue.vcxproj"> + <Project>{5724ba7d-a09a-4ba8-800b-c4c1561b3d69}</Project> + </ProjectReference> + <ProjectReference Include="..\libbitcoin_wallet_tool\libbitcoin_wallet_tool.vcxproj"> + <Project>{f91ac55e-6f5e-4c58-9ac5-b40db7deef93}</Project> + </ProjectReference> + <ProjectReference Include="..\libsecp256k1\libsecp256k1.vcxproj"> + <Project>{bb493552-3b8c-4a8c-bf69-a6e7a51d2ea6}</Project> + </ProjectReference> + </ItemGroup> + <PropertyGroup Label="Globals"> + <VCProjectVersion>15.0</VCProjectVersion> + <ProjectGuid>{84DE8790-EDE3-4483-81AC-C32F15E861F4}</ProjectGuid> + <Keyword>Win32Proj</Keyword> + <RootNamespace>bitcointx</RootNamespace> + <VcpkgTriplet Condition="'$(Platform)'=='Win32'">x86-windows-static</VcpkgTriplet> + <VcpkgTriplet Condition="'$(Platform)'=='x64'">x64-windows-static</VcpkgTriplet> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>v141</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <PlatformToolset>v141</PlatformToolset> + <WholeProgramOptimization>true</WholeProgramOptimization> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>v141</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> + <ConfigurationType>Application</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)'=='Release|Win32'"> + <LinkIncremental>false</LinkIncremental> + </PropertyGroup> + <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|x64'"> + <LinkIncremental>false</LinkIncremental> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <PrecompiledHeader>NotUsing</PrecompiledHeader> + <WarningLevel>Level3</WarningLevel> + <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> + <SDLCheck>true</SDLCheck> + <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;</AdditionalIncludeDirectories> + <RuntimeLibrary>MultiThreaded</RuntimeLibrary> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + <GenerateDebugInformation>true</GenerateDebugInformation> + <AdditionalDependencies>crypt32.lib;Iphlpapi.lib;ws2_32.lib;Shlwapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <PrecompiledHeader>NotUsing</PrecompiledHeader> + <WarningLevel>Level3</WarningLevel> + <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> + <SubSystem>Console</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + <AdditionalDependencies>crypt32.lib;Iphlpapi.lib;ws2_32.lib;Shlwapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <PrecompiledHeader>NotUsing</PrecompiledHeader> + <WarningLevel>Level3</WarningLevel> + <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> + <SubSystem>Console</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + <AdditionalDependencies>crypt32.lib;Iphlpapi.lib;ws2_32.lib;Shlwapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies> + </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>HAVE_CONFIG_H;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <SDLCheck>true</SDLCheck> + <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;</AdditionalIncludeDirectories> + <RuntimeLibrary>MultiThreaded</RuntimeLibrary> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + <GenerateDebugInformation>true</GenerateDebugInformation> + <AdditionalDependencies>crypt32.lib;Iphlpapi.lib;ws2_32.lib;Shlwapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <Import Label="configTarget" Project="..\common.vcxproj" /> +</Project> diff --git a/build_msvc/bitcoin.sln b/build_msvc/bitcoin.sln index 32068d81f6..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 @@ -32,6 +32,14 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bench_bitcoin", "bench_bitc EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bitcoin-tx", "bitcoin-tx\bitcoin-tx.vcxproj", "{D3022AF6-AD33-4CE3-B358-87CB6A1B29CF}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bitcoin-wallet", "bitcoin-wallet\bitcoin-wallet.vcxproj", "{84DE8790-EDE3-4483-81AC-C32F15E861F4}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libbitcoin_wallet_tool", "libbitcoin_wallet_tool\libbitcoin_wallet_tool.vcxproj", "{F91AC55E-6F5E-4C58-9AC5-B40DB7DEEF93}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libsecp256k1", "libsecp256k1\libsecp256k1.vcxproj", "{BB493552-3B8C-4A8C-BF69-A6E7A51D2EA6}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libleveldb", "libleveldb\libleveldb.vcxproj", "{18430FEF-6B61-4C53-B396-718E02850F1B}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -160,6 +168,38 @@ Global {D3022AF6-AD33-4CE3-B358-87CB6A1B29CF}.Release|x64.Build.0 = Release|x64 {D3022AF6-AD33-4CE3-B358-87CB6A1B29CF}.Release|x86.ActiveCfg = Release|Win32 {D3022AF6-AD33-4CE3-B358-87CB6A1B29CF}.Release|x86.Build.0 = Release|Win32 + {84DE8790-EDE3-4483-81AC-C32F15E861F4}.Debug|x64.ActiveCfg = Debug|x64 + {84DE8790-EDE3-4483-81AC-C32F15E861F4}.Debug|x64.Build.0 = Debug|x64 + {84DE8790-EDE3-4483-81AC-C32F15E861F4}.Debug|x86.ActiveCfg = Debug|Win32 + {84DE8790-EDE3-4483-81AC-C32F15E861F4}.Debug|x86.Build.0 = Debug|Win32 + {84DE8790-EDE3-4483-81AC-C32F15E861F4}.Release|x64.ActiveCfg = Release|x64 + {84DE8790-EDE3-4483-81AC-C32F15E861F4}.Release|x64.Build.0 = Release|x64 + {84DE8790-EDE3-4483-81AC-C32F15E861F4}.Release|x86.ActiveCfg = Release|Win32 + {84DE8790-EDE3-4483-81AC-C32F15E861F4}.Release|x86.Build.0 = Release|Win32 + {F91AC55E-6F5E-4C58-9AC5-B40DB7DEEF93}.Debug|x64.ActiveCfg = Debug|x64 + {F91AC55E-6F5E-4C58-9AC5-B40DB7DEEF93}.Debug|x64.Build.0 = Debug|x64 + {F91AC55E-6F5E-4C58-9AC5-B40DB7DEEF93}.Debug|x86.ActiveCfg = Debug|Win32 + {F91AC55E-6F5E-4C58-9AC5-B40DB7DEEF93}.Debug|x86.Build.0 = Debug|Win32 + {F91AC55E-6F5E-4C58-9AC5-B40DB7DEEF93}.Release|x64.ActiveCfg = Release|x64 + {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 @@ -170,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..9a071f3bdd 100644 --- a/build_msvc/bitcoind/bitcoind.vcxproj +++ b/build_msvc/bitcoind/bitcoind.vcxproj @@ -180,6 +180,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 5c87026efe..93004dda7c 100644 --- a/build_msvc/common.vcxproj +++ b/build_msvc/common.vcxproj @@ -3,18 +3,27 @@ <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> </ClCompile> </ItemDefinitionGroup> -</Project>
\ No newline at end of file +</Project> diff --git a/build_msvc/libbitcoin_common/libbitcoin_common.vcxproj.in b/build_msvc/libbitcoin_common/libbitcoin_common.vcxproj.in index 42145c15ad..b51cdb2991 100644 --- a/build_msvc/libbitcoin_common/libbitcoin_common.vcxproj.in +++ b/build_msvc/libbitcoin_common/libbitcoin_common.vcxproj.in @@ -91,7 +91,7 @@ <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> + <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;..\..\src\secp256k1\include;</AdditionalIncludeDirectories> <SuppressStartupBanner>false</SuppressStartupBanner> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> </ClCompile> @@ -109,7 +109,7 @@ <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> + <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;..\..\src\secp256k1\include;</AdditionalIncludeDirectories> <SuppressStartupBanner>false</SuppressStartupBanner> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> </ClCompile> @@ -129,7 +129,7 @@ <IntrinsicFunctions>true</IntrinsicFunctions> <PreprocessorDefinitions>WIN32;HAVE_CONFIG_H;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;..\..\src\secp256k1\include;</AdditionalIncludeDirectories> <SuppressStartupBanner>false</SuppressStartupBanner> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> </ClCompile> @@ -151,7 +151,7 @@ <IntrinsicFunctions>true</IntrinsicFunctions> <PreprocessorDefinitions>WIN32;HAVE_CONFIG_H;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;..\..\src\secp256k1\include;</AdditionalIncludeDirectories> <SuppressStartupBanner>false</SuppressStartupBanner> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> </ClCompile> diff --git a/build_msvc/libbitcoin_qt/libbitcoin_qt.vcxproj b/build_msvc/libbitcoin_qt/libbitcoin_qt.vcxproj index 2e8ecb2d2c..43bfb271fb 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> diff --git a/build_msvc/libbitcoin_server/libbitcoin_server.vcxproj.in b/build_msvc/libbitcoin_server/libbitcoin_server.vcxproj.in index 0a165d0b75..acb827bd95 100644 --- a/build_msvc/libbitcoin_server/libbitcoin_server.vcxproj.in +++ b/build_msvc/libbitcoin_server/libbitcoin_server.vcxproj.in @@ -91,7 +91,7 @@ <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> + <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;..\..\src\leveldb\include;..\..\src\leveldb\helpers\memenv;</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> </ClCompile> <Link> @@ -106,7 +106,7 @@ <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> + <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;..\..\src\leveldb\include;..\..\src\leveldb\helpers\memenv;</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> <SuppressStartupBanner>false</SuppressStartupBanner> </ClCompile> @@ -124,7 +124,7 @@ <IntrinsicFunctions>true</IntrinsicFunctions> <PreprocessorDefinitions>WIN32;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;..\..\src\leveldb\include;..\..\src\leveldb\helpers\memenv;</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> </ClCompile> <Link> @@ -143,7 +143,7 @@ <IntrinsicFunctions>true</IntrinsicFunctions> <PreprocessorDefinitions>WIN32;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;..\..\src\leveldb\include;..\..\src\leveldb\helpers\memenv;</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> </ClCompile> <Link> @@ -154,12 +154,6 @@ </Link> </ItemDefinitionGroup> <ItemGroup> - <ClCompile Include="..\..\src\rpc\net.cpp"> - <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)\netrpc.obj</ObjectFileName> - <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(IntDir)\netrpc.obj</ObjectFileName> - <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(IntDir)\netrpc.obj</ObjectFileName> - <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(IntDir)\netrpc.obj</ObjectFileName> - </ClCompile> @SOURCE_FILES@ </ItemGroup> <ItemGroup> diff --git a/build_msvc/libbitcoin_wallet_tool/libbitcoin_wallet_tool.vcxproj.in b/build_msvc/libbitcoin_wallet_tool/libbitcoin_wallet_tool.vcxproj.in new file mode 100644 index 0000000000..b9cf68aee0 --- /dev/null +++ b/build_msvc/libbitcoin_wallet_tool/libbitcoin_wallet_tool.vcxproj.in @@ -0,0 +1,166 @@ +<?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> +@SOURCE_FILES@ + </ItemGroup> + <ItemGroup> + <None Include="packages.config" /> + </ItemGroup> + <PropertyGroup Label="Globals"> + <VCProjectVersion>15.0</VCProjectVersion> + <ProjectGuid>{F91AC55E-6F5E-4C58-9AC5-B40DB7DEEF93}</ProjectGuid> + <Keyword>Win32Proj</Keyword> + <RootNamespace>libbitcoin_zmq</RootNamespace> + <VcpkgTriplet Condition="'$(Platform)'=='Win32'">x86-windows-static</VcpkgTriplet> + <VcpkgTriplet Condition="'$(Platform)'=='x64'">x64-windows-static</VcpkgTriplet> + </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>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> + <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>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> + <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>NOMINMAX;ZMQ_STATIC;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <SDLCheck>true</SDLCheck> + <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;</AdditionalIncludeDirectories> + <RuntimeLibrary>MultiThreaded</RuntimeLibrary> + <SuppressStartupBanner>false</SuppressStartupBanner> + </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>NOMINMAX;ZMQ_STATIC;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <SDLCheck>true</SDLCheck> + <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;</AdditionalIncludeDirectories> + <RuntimeLibrary>MultiThreaded</RuntimeLibrary> + <SuppressStartupBanner>false</SuppressStartupBanner> + </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/libbitcoinconsensus/libbitcoinconsensus.vcxproj b/build_msvc/libbitcoinconsensus/libbitcoinconsensus.vcxproj index 2c6c0a8b7c..961225f9ba 100644 --- a/build_msvc/libbitcoinconsensus/libbitcoinconsensus.vcxproj +++ b/build_msvc/libbitcoinconsensus/libbitcoinconsensus.vcxproj @@ -126,7 +126,7 @@ <Optimization>Disabled</Optimization> <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>false</SDLCheck> - <AdditionalIncludeDirectories>..\..\src;</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>..\..\src;..\..\src\secp256k1\include;</AdditionalIncludeDirectories> <ExceptionHandling>Sync</ExceptionHandling> <SuppressStartupBanner>false</SuppressStartupBanner> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> @@ -143,7 +143,7 @@ <Optimization>Disabled</Optimization> <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>false</SDLCheck> - <AdditionalIncludeDirectories>..\..\src;</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>..\..\src;..\..\src\secp256k1\include;</AdditionalIncludeDirectories> <ExceptionHandling>Sync</ExceptionHandling> <SuppressStartupBanner>false</SuppressStartupBanner> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> @@ -162,7 +162,7 @@ <IntrinsicFunctions>true</IntrinsicFunctions> <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>false</SDLCheck> - <AdditionalIncludeDirectories>..\..\src;</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>..\..\src;..\..\src\secp256k1\include;</AdditionalIncludeDirectories> <ExceptionHandling>Sync</ExceptionHandling> <SuppressStartupBanner>false</SuppressStartupBanner> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> @@ -183,7 +183,7 @@ <IntrinsicFunctions>true</IntrinsicFunctions> <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>false</SDLCheck> - <AdditionalIncludeDirectories>..\..\src;</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>..\..\src;..\..\src\secp256k1\include;</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..6de3a2b282 --- /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;NDEBUG;_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;NDEBUG;_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..699c7d6871 --- /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;NDEBUG;_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;NDEBUG;_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/msvc-autogen.py b/build_msvc/msvc-autogen.py index f351532f9d..c8df29eecb 100644 --- a/build_msvc/msvc-autogen.py +++ b/build_msvc/msvc-autogen.py @@ -11,6 +11,7 @@ libs = [ 'libbitcoin_crypto', 'libbitcoin_server', 'libbitcoin_util', + 'libbitcoin_wallet_tool', 'libbitcoin_wallet', 'libbitcoin_zmq', ] diff --git a/build_msvc/test_bitcoin/test_bitcoin.vcxproj b/build_msvc/test_bitcoin/test_bitcoin.vcxproj index 2316e473aa..8f39132a22 100644 --- a/build_msvc/test_bitcoin/test_bitcoin.vcxproj +++ b/build_msvc/test_bitcoin/test_bitcoin.vcxproj @@ -54,6 +54,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 +133,7 @@ <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> + <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;..\..\src\leveldb\include;..\..\src\test;</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> </ClCompile> <Link> @@ -144,7 +150,7 @@ <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> + <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;..\..\src\leveldb\include;..\..\src\test;</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> </ClCompile> <Link> @@ -162,7 +168,7 @@ <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> + <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;..\..\src\leveldb\include;..\..\src\test;</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> </ClCompile> <Link> @@ -182,7 +188,7 @@ <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> + <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;..\..\src\leveldb\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..db2f8a6216 100644 --- a/build_msvc/testconsensus/testconsensus.vcxproj +++ b/build_msvc/testconsensus/testconsensus.vcxproj @@ -168,6 +168,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 4b34082270..ddd6c7f8eb 100644 --- a/configure.ac +++ b/configure.ac @@ -19,6 +19,7 @@ BITCOIN_DAEMON_NAME=bitcoind BITCOIN_GUI_NAME=bitcoin-qt BITCOIN_CLI_NAME=bitcoin-cli BITCOIN_TX_NAME=bitcoin-tx +BITCOIN_WALLET_TOOL_NAME=bitcoin-wallet dnl Unless the user specified ARFLAGS, force it to be cr AC_ARG_VAR(ARFLAGS, [Flags for the archiver, defaults to <cr> if not set]) @@ -102,7 +103,6 @@ AM_CONDITIONAL([HAVE_DOXYGEN], [test -n "$DOXYGEN"]) AC_ARG_VAR(PYTHONPATH, Augments the default search path for python module files) -# Enable wallet AC_ARG_ENABLE([wallet], [AS_HELP_STRING([--disable-wallet], [disable wallet (enabled by default)])], @@ -147,6 +147,11 @@ AC_ARG_ENABLE([extended-functional-tests], [use_extended_functional_tests=$enableval], [use_extended_functional_tests=no]) +AC_ARG_ENABLE([fuzz], + AS_HELP_STRING([--enable-fuzz],[enable building of fuzz targets (default no)]), + [enable_fuzz=$enableval], + [enable_fuzz=no]) + AC_ARG_WITH([qrencode], [AS_HELP_STRING([--with-qrencode], [enable QR code support (default is yes if qt is enabled and libqrencode is found)])], @@ -295,7 +300,14 @@ if test x$use_sanitizers != x; then AX_CHECK_LINK_FLAG( [[-fsanitize=$use_sanitizers]], [[SANITIZER_LDFLAGS=-fsanitize=$use_sanitizers]], - [AC_MSG_ERROR([linker did not accept requested flags, you are missing required libraries])]) + [AC_MSG_ERROR([linker did not accept requested flags, you are missing required libraries])], + [], + [AC_LANG_PROGRAM([[ + #include <cstdint> + #include <cstddef> + extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { return 0; } + __attribute__((weak)) // allow for libFuzzer linking + ]],[[]])]) fi ERROR_CXXFLAGS= @@ -408,7 +420,7 @@ CPPFLAGS="$CPPFLAGS -DHAVE_BUILD_INFO -D__STDC_FORMAT_MACROS" AC_ARG_WITH([utils], [AS_HELP_STRING([--with-utils], - [build bitcoin-cli bitcoin-tx (default=yes)])], + [build bitcoin-cli bitcoin-tx bitcoin-wallet (default=yes)])], [build_bitcoin_utils=$withval], [build_bitcoin_utils=yes]) @@ -424,6 +436,12 @@ AC_ARG_ENABLE([util-tx], [build_bitcoin_tx=$enableval], [build_bitcoin_tx=$build_bitcoin_utils]) +AC_ARG_ENABLE([util-wallet], + [AS_HELP_STRING([--enable-util-wallet], + [build bitcoin-wallet])], + [build_bitcoin_wallet=$enableval], + [build_bitcoin_wallet=$build_bitcoin_utils]) + AC_ARG_WITH([libs], [AS_HELP_STRING([--with-libs], [build libraries (default=yes)])], @@ -478,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" @@ -504,17 +522,6 @@ case $host in LEVELDB_TARGET_FLAGS="-DOS_MACOSX" if test x$cross_compiling != xyes; then BUILD_OS=darwin - AC_CHECK_PROG([PORT],port, port) - if test x$PORT = xport; then - dnl add default macports paths - CPPFLAGS="$CPPFLAGS -isystem /opt/local/include" - LIBS="$LIBS -L/opt/local/lib" - if test -d /opt/local/include/db48; then - CPPFLAGS="$CPPFLAGS -I/opt/local/include/db48" - LIBS="$LIBS -L/opt/local/lib/db48" - fi - fi - AC_PATH_PROGS([RSVG_CONVERT], [rsvg-convert rsvg],rsvg-convert) AC_CHECK_PROG([BREW],brew, brew) if test x$BREW = xbrew; then @@ -904,7 +911,7 @@ BITCOIN_QT_INIT dnl sets $bitcoin_enable_qt, $bitcoin_enable_qt_test, $bitcoin_enable_qt_dbus BITCOIN_QT_CONFIGURE([$use_pkgconfig]) -if test x$build_bitcoin_cli$build_bitcoin_tx$build_bitcoind$bitcoin_enable_qt$use_tests$use_bench = xnononononono; then +if test x$build_bitcoin_wallet$build_bitcoin_cli$build_bitcoin_tx$build_bitcoind$bitcoin_enable_qt$use_tests$use_bench = xnonononononono; then use_boost=no else use_boost=yes @@ -1094,7 +1101,7 @@ if test x$use_pkgconfig = xyes; then if test x$use_qr != xno; then BITCOIN_QT_CHECK([PKG_CHECK_MODULES([QR], [libqrencode], [have_qrencode=yes], [have_qrencode=no])]) fi - if test x$build_bitcoin_cli$build_bitcoin_tx$build_bitcoind$bitcoin_enable_qt$use_tests != xnonononono; then + if test x$build_bitcoin_cli$build_bitcoind$bitcoin_enable_qt$use_tests != xnononono; then PKG_CHECK_MODULES([EVENT], [libevent],, [AC_MSG_ERROR(libevent not found.)]) if test x$TARGET_OS != xwindows; then PKG_CHECK_MODULES([EVENT_PTHREADS], [libevent_pthreads],, [AC_MSG_ERROR(libevent_pthreads not found.)]) @@ -1119,7 +1126,7 @@ else AC_CHECK_HEADER([openssl/ssl.h],, AC_MSG_ERROR(libssl headers missing),) AC_CHECK_LIB([ssl], [main],SSL_LIBS=-lssl, AC_MSG_ERROR(libssl missing)) - if test x$build_bitcoin_cli$build_bitcoin_tx$build_bitcoind$bitcoin_enable_qt$use_tests != xnonononono; then + if test x$build_bitcoin_cli$build_bitcoind$bitcoin_enable_qt$use_tests != xnononono; then AC_CHECK_HEADER([event2/event.h],, AC_MSG_ERROR(libevent headers missing),) AC_CHECK_LIB([event],[main],EVENT_LIBS=-levent,AC_MSG_ERROR(libevent missing)) if test x$TARGET_OS != xwindows; then @@ -1186,7 +1193,7 @@ dnl univalue check need_bundled_univalue=yes -if test x$build_bitcoin_cli$build_bitcoin_tx$build_bitcoind$bitcoin_enable_qt$use_tests$use_bench = xnononononono; then +if test x$build_bitcoin_wallet$build_bitcoin_cli$build_bitcoin_tx$build_bitcoind$bitcoin_enable_qt$use_tests$use_bench = xnonononononono; then need_bundled_univalue=no else @@ -1248,6 +1255,10 @@ AC_MSG_CHECKING([whether to build bitcoin-tx]) AM_CONDITIONAL([BUILD_BITCOIN_TX], [test x$build_bitcoin_tx = xyes]) AC_MSG_RESULT($build_bitcoin_tx) +AC_MSG_CHECKING([whether to build bitcoin-wallet]) +AM_CONDITIONAL([BUILD_BITCOIN_WALLET], [test x$build_bitcoin_wallet = xyes]) +AC_MSG_RESULT($build_bitcoin_wallet) + AC_MSG_CHECKING([whether to build libraries]) AM_CONDITIONAL([BUILD_BITCOIN_LIBS], [test x$build_bitcoin_libs = xyes]) if test x$build_bitcoin_libs = xyes; then @@ -1389,7 +1400,7 @@ else AC_MSG_RESULT([no]) fi -if test x$build_bitcoin_cli$build_bitcoin_tx$build_bitcoin_libs$build_bitcoind$bitcoin_enable_qt$use_bench$use_tests = xnonononononono; then +if test x$build_bitcoin_wallet$build_bitcoin_cli$build_bitcoin_tx$build_bitcoin_libs$build_bitcoind$bitcoin_enable_qt$use_bench$use_tests = xnononononononono; then AC_MSG_ERROR([No targets! Please specify at least one of: --with-utils --with-libs --with-daemon --with-gui --enable-bench or --enable-tests]) fi @@ -1398,6 +1409,7 @@ AM_CONDITIONAL([BUILD_DARWIN], [test x$BUILD_OS = xdarwin]) AM_CONDITIONAL([TARGET_WINDOWS], [test x$TARGET_OS = xwindows]) AM_CONDITIONAL([ENABLE_WALLET],[test x$enable_wallet = xyes]) AM_CONDITIONAL([ENABLE_TESTS],[test x$BUILD_TEST = xyes]) +AM_CONDITIONAL([ENABLE_FUZZ],[test x$enable_fuzz = xyes]) AM_CONDITIONAL([ENABLE_QT],[test x$bitcoin_enable_qt = xyes]) AM_CONDITIONAL([ENABLE_QT_TESTS],[test x$BUILD_TEST_QT = xyes]) AM_CONDITIONAL([ENABLE_BIP70],[test x$enable_bip70 = xyes]) @@ -1435,6 +1447,7 @@ AC_SUBST(BITCOIN_DAEMON_NAME) AC_SUBST(BITCOIN_GUI_NAME) AC_SUBST(BITCOIN_CLI_NAME) AC_SUBST(BITCOIN_TX_NAME) +AC_SUBST(BITCOIN_WALLET_TOOL_NAME) AC_SUBST(RELDFLAGS) AC_SUBST(DEBUG_CPPFLAGS) @@ -1540,6 +1553,9 @@ if test x$bitcoin_enable_qt != xno; then fi echo " with zmq = $use_zmq" echo " with test = $use_tests" +if test x$use_tests != xno; then + echo " with fuzz = $enable_fuzz" +fi echo " with bench = $use_bench" echo " with upnp = $use_upnp" echo " use asm = $use_asm" 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/README.md b/contrib/devtools/README.md index a0b6225345..6ee65f40be 100644 --- a/contrib/devtools/README.md +++ b/contrib/devtools/README.md @@ -119,7 +119,25 @@ Configuring the github-merge tool for the bitcoin repository is done in the foll git config githubmerge.repository bitcoin/bitcoin git config githubmerge.testcmd "make -j4 check" (adapt to whatever you want to use for testing) - git config --global user.signingkey mykeyid (if you want to GPG sign) + git config --global user.signingkey mykeyid + +Authentication (optional) +-------------------------- + +The API request limit for unauthenticated requests is quite low, but the +limit for authenticated requests is much higher. If you start running +into rate limiting errors it can be useful to set an authentication token +so that the script can authenticate requests. + +- First, go to [Personal access tokens](https://github.com/settings/tokens). +- Click 'Generate new token'. +- Fill in an arbitrary token description. No further privileges are needed. +- Click the `Generate token` button at the bottom of the form. +- Copy the generated token (should be a hexadecimal string) + +Then do: + + git config --global user.ghtoken "pasted token" Create and verify timestamps of merge commits --------------------------------------------- diff --git a/contrib/devtools/copyright_header.py b/contrib/devtools/copyright_header.py index 6d7a592f01..f2987f2260 100755 --- a/contrib/devtools/copyright_header.py +++ b/contrib/devtools/copyright_header.py @@ -48,15 +48,22 @@ def applies_to_file(filename): # obtain list of files in repo according to INCLUDE and EXCLUDE ################################################################################ -GIT_LS_CMD = 'git ls-files' +GIT_LS_CMD = 'git ls-files --full-name'.split(' ') +GIT_TOPLEVEL_CMD = 'git rev-parse --show-toplevel'.split(' ') -def call_git_ls(): - out = subprocess.check_output(GIT_LS_CMD.split(' ')) +def call_git_ls(base_directory): + out = subprocess.check_output([*GIT_LS_CMD, base_directory]) return [f for f in out.decode("utf-8").split('\n') if f != ''] -def get_filenames_to_examine(): - filenames = call_git_ls() - return sorted([filename for filename in filenames if +def call_git_toplevel(): + "Returns the absolute path to the project root" + return subprocess.check_output(GIT_TOPLEVEL_CMD).strip().decode("utf-8") + +def get_filenames_to_examine(base_directory): + "Returns an array of absolute paths to any project files in the base_directory that pass the include/exclude filters" + root = call_git_toplevel() + filenames = call_git_ls(base_directory) + return sorted([os.path.join(root, filename) for filename in filenames if applies_to_file(filename)]) ################################################################################ @@ -83,24 +90,12 @@ def compile_copyright_regex(copyright_style, year_style, name): EXPECTED_HOLDER_NAMES = [ "Satoshi Nakamoto\n", "The Bitcoin Core developers\n", - "The Bitcoin Core developers \n", "Bitcoin Core Developers\n", - "the Bitcoin Core developers\n", - "The Bitcoin developers\n", - "The LevelDB Authors\. All rights reserved\.\n", "BitPay Inc\.\n", - "BitPay, Inc\.\n", "University of Illinois at Urbana-Champaign\.\n", - "MarcoFalke\n", "Pieter Wuille\n", - "Pieter Wuille +\*\n", - "Pieter Wuille, Gregory Maxwell +\*\n", - "Pieter Wuille, Andrew Poelstra +\*\n", - "Andrew Poelstra +\*\n", "Wladimir J. van der Laan\n", "Jeff Garzik\n", - "Diederik Huys, Pieter Wuille +\*\n", - "Thomas Daede, Cory Fields +\*\n", "Jan-Klaas Kollhof\n", "Sam Rushing\n", "ArtForz -- public domain half-a-node\n", @@ -146,7 +141,7 @@ def file_has_without_c_style_copyright_for_holder(contents, holder_name): ################################################################################ def read_file(filename): - return open(os.path.abspath(filename), 'r', encoding="utf8").read() + return open(filename, 'r', encoding="utf8").read() def gather_file_info(filename): info = {} @@ -260,12 +255,9 @@ def print_report(file_infos, verbose): print(SEPARATOR) def exec_report(base_directory, verbose): - original_cwd = os.getcwd() - os.chdir(base_directory) - filenames = get_filenames_to_examine() + filenames = get_filenames_to_examine(base_directory) file_infos = [gather_file_info(f) for f in filenames] print_report(file_infos, verbose) - os.chdir(original_cwd) ################################################################################ # report cmd @@ -325,13 +317,13 @@ def get_most_recent_git_change_year(filename): ################################################################################ def read_file_lines(filename): - f = open(os.path.abspath(filename), 'r', encoding="utf8") + f = open(filename, 'r', encoding="utf8") file_lines = f.readlines() f.close() return file_lines def write_file_lines(filename, file_lines): - f = open(os.path.abspath(filename), 'w', encoding="utf8") + f = open(filename, 'w', encoding="utf8") f.write(''.join(file_lines)) f.close() @@ -399,11 +391,8 @@ def update_updatable_copyright(filename): "Copyright updated! -> %s" % last_git_change_year) def exec_update_header_year(base_directory): - original_cwd = os.getcwd() - os.chdir(base_directory) - for filename in get_filenames_to_examine(): + for filename in get_filenames_to_examine(base_directory): update_updatable_copyright(filename) - os.chdir(original_cwd) ################################################################################ # update cmd diff --git a/contrib/devtools/github-merge.py b/contrib/devtools/github-merge.py index 4f827401fb..ab834b7623 100755 --- a/contrib/devtools/github-merge.py +++ b/contrib/devtools/github-merge.py @@ -23,6 +23,7 @@ import sys import json import codecs from urllib.request import Request, urlopen +from urllib.error import HTTPError # External tools (can be overridden using environment) GIT = os.getenv('GIT','git') @@ -46,17 +47,24 @@ def git_config_get(option, default=None): except subprocess.CalledProcessError: return default -def retrieve_pr_info(repo,pull): +def retrieve_pr_info(repo,pull,ghtoken): ''' Retrieve pull request information from github. Return None if no title can be found, or an error happens. ''' try: req = Request("https://api.github.com/repos/"+repo+"/pulls/"+pull) + if ghtoken is not None: + req.add_header('Authorization', 'token ' + ghtoken) result = urlopen(req) reader = codecs.getreader('utf-8') obj = json.load(reader(result)) return obj + except HTTPError as e: + error_message = e.read() + print('Warning: unable to retrieve pull information from github: %s' % e) + print('Detailed error: %s' % error_message) + return None except Exception as e: print('Warning: unable to retrieve pull information from github: %s' % e) return None @@ -134,6 +142,7 @@ def parse_arguments(): In addition, you can set the following git configuration variables: githubmerge.repository (mandatory), user.signingkey (mandatory), + user.ghtoken (default: none). githubmerge.host (default: git@github.com), githubmerge.branch (no default), githubmerge.testcmd (default: none). @@ -152,6 +161,7 @@ def main(): host = git_config_get('githubmerge.host','git@github.com') opt_branch = git_config_get('githubmerge.branch',None) testcmd = git_config_get('githubmerge.testcmd') + ghtoken = git_config_get('user.ghtoken') signingkey = git_config_get('user.signingkey') if repo is None: print("ERROR: No repository configured. Use this command to set:", file=stderr) @@ -162,14 +172,17 @@ def main(): print("git config --global user.signingkey <key>",file=stderr) sys.exit(1) - host_repo = host+":"+repo # shortcut for push/pull target + if host.startswith(('https:','http:')): + host_repo = host+"/"+repo+".git" + else: + host_repo = host+":"+repo # Extract settings from command line args = parse_arguments() pull = str(args.pull[0]) # Receive pull information from github - info = retrieve_pr_info(repo,pull) + info = retrieve_pr_info(repo,pull,ghtoken) if info is None: sys.exit(1) title = info['title'].strip() diff --git a/contrib/gitian-build.py b/contrib/gitian-build.py index faf8b014aa..fc7fbb764d 100755 --- a/contrib/gitian-build.py +++ b/contrib/gitian-build.py @@ -51,8 +51,10 @@ def build(): os.chdir('gitian-builder') os.makedirs('inputs', exist_ok=True) - subprocess.check_call(['wget', '-N', '-P', 'inputs', 'http://downloads.sourceforge.net/project/osslsigncode/osslsigncode/osslsigncode-1.7.1.tar.gz']) + subprocess.check_call(['wget', '-N', '-P', 'inputs', 'https://downloads.sourceforge.net/project/osslsigncode/osslsigncode/osslsigncode-1.7.1.tar.gz']) subprocess.check_call(['wget', '-N', '-P', 'inputs', 'https://bitcoincore.org/cfields/osslsigncode-Backports-to-1.7.1.patch']) + subprocess.check_call(["echo 'a8c4e9cafba922f89de0df1f2152e7be286aba73f78505169bc351a7938dd911 inputs/osslsigncode-Backports-to-1.7.1.patch' | sha256sum -c"], shell=True) + subprocess.check_call(["echo 'f9a8cdb38b9c309326764ebc937cba1523a3a751a7ab05df3ecc99d18ae466c9 inputs/osslsigncode-1.7.1.tar.gz' | sha256sum -c"], shell=True) subprocess.check_call(['make', '-C', '../bitcoin/depends', 'download', 'SOURCES_PATH=' + os.getcwd() + '/cache/common']) if args.linux: diff --git a/contrib/gitian-keys/keys.txt b/contrib/gitian-keys/keys.txt index 593fba1d09..80c18aa889 100644 --- a/contrib/gitian-keys/keys.txt +++ b/contrib/gitian-keys/keys.txt @@ -9,6 +9,7 @@ BF6273FAEF7CC0BA1F562E50989F6B3048A116B5 Dev Random 9A1689B60D1B3CCE9262307A2F40A9BF167FBA47 Erik Mossberg (erkmos) D35176BE9264832E4ACA8986BF0792FBE95DC863 fivepiece 01CDF4627A3B88AAE4A571C87588242FBE38D3A8 Gavin Andresen +D1DBF2C4B96F2DEBF4C16654410108112E7EA81F Hennadii Stepanov (hebasto) D3CC177286005BB8FF673294C5242A1AB3936517 jl2012 32EE5C4C3FA15CCADB46ABE529D4BCB6416F53EC Jonas Schnelli 4B4E840451149DD7FB0D633477DFAB5C3108B9A8 Jorge Timon 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/macdeploy/macdeployqtplus b/contrib/macdeploy/macdeployqtplus index 17ce6c44f9..9da03e5b02 100755 --- a/contrib/macdeploy/macdeployqtplus +++ b/contrib/macdeploy/macdeployqtplus @@ -172,12 +172,6 @@ class DeploymentInfo(object): if os.path.exists(os.path.join(parentDir, "translations")): # Classic layout, e.g. "/usr/local/Trolltech/Qt-4.x.x" self.qtPath = parentDir - elif os.path.exists(os.path.join(parentDir, "share", "qt4", "translations")): - # MacPorts layout, e.g. "/opt/local/share/qt4" - self.qtPath = os.path.join(parentDir, "share", "qt4") - elif os.path.exists(os.path.join(os.path.dirname(parentDir), "share", "qt4", "translations")): - # Newer Macports layout - self.qtPath = os.path.join(os.path.dirname(parentDir), "share", "qt4") else: self.qtPath = os.getenv("QTDIR", None) diff --git a/contrib/verify-commits/verify-commits.py b/contrib/verify-commits/verify-commits.py index b3c8064ec2..6bbed01073 100755 --- a/contrib/verify-commits/verify-commits.py +++ b/contrib/verify-commits/verify-commits.py @@ -91,7 +91,7 @@ def main(): no_sha1 = True prev_commit = "" initial_commit = current_commit - branch = subprocess.check_output([GIT, 'show', '-s', '--format=%H', initial_commit], universal_newlines=True, encoding='utf8').splitlines()[0] + branch = subprocess.check_output([GIT, 'show', '-s', '--format=%H', initial_commit]).decode('utf8').splitlines()[0] # Iterate through commits while True: @@ -112,7 +112,7 @@ def main(): if prev_commit != "": print("No parent of {} was signed with a trusted key!".format(prev_commit), file=sys.stderr) print("Parents are:", file=sys.stderr) - parents = subprocess.check_output([GIT, 'show', '-s', '--format=format:%P', prev_commit], universal_newlines=True, encoding='utf8').splitlines()[0].split(' ') + parents = subprocess.check_output([GIT, 'show', '-s', '--format=format:%P', prev_commit]).decode('utf8').splitlines()[0].split(' ') for parent in parents: subprocess.call([GIT, 'show', '-s', parent], stdout=sys.stderr) else: @@ -122,25 +122,25 @@ def main(): # Check the Tree-SHA512 if (verify_tree or prev_commit == "") and current_commit not in incorrect_sha512_allowed: tree_hash = tree_sha512sum(current_commit) - if ("Tree-SHA512: {}".format(tree_hash)) not in subprocess.check_output([GIT, 'show', '-s', '--format=format:%B', current_commit], universal_newlines=True, encoding='utf8').splitlines(): + if ("Tree-SHA512: {}".format(tree_hash)) not in subprocess.check_output([GIT, 'show', '-s', '--format=format:%B', current_commit]).decode('utf8').splitlines(): print("Tree-SHA512 did not match for commit " + current_commit, file=sys.stderr) sys.exit(1) # Merge commits should only have two parents - parents = subprocess.check_output([GIT, 'show', '-s', '--format=format:%P', current_commit], universal_newlines=True, encoding='utf8').splitlines()[0].split(' ') + parents = subprocess.check_output([GIT, 'show', '-s', '--format=format:%P', current_commit]).decode('utf8').splitlines()[0].split(' ') if len(parents) > 2: print("Commit {} is an octopus merge".format(current_commit), file=sys.stderr) sys.exit(1) # Check that the merge commit is clean - commit_time = int(subprocess.check_output([GIT, 'show', '-s', '--format=format:%ct', current_commit], universal_newlines=True, encoding='utf8').splitlines()[0]) + commit_time = int(subprocess.check_output([GIT, 'show', '-s', '--format=format:%ct', current_commit]).decode('utf8').splitlines()[0]) check_merge = commit_time > time.time() - args.clean_merge * 24 * 60 * 60 # Only check commits in clean_merge days allow_unclean = current_commit in unclean_merge_allowed if len(parents) == 2 and check_merge and not allow_unclean: - current_tree = subprocess.check_output([GIT, 'show', '--format=%T', current_commit], universal_newlines=True, encoding='utf8').splitlines()[0] + current_tree = subprocess.check_output([GIT, 'show', '--format=%T', current_commit]).decode('utf8').splitlines()[0] subprocess.call([GIT, 'checkout', '--force', '--quiet', parents[0]]) subprocess.call([GIT, 'merge', '--no-ff', '--quiet', '--no-gpg-sign', parents[1]], stdout=subprocess.DEVNULL) - recreated_tree = subprocess.check_output([GIT, 'show', '--format=format:%T', 'HEAD'], universal_newlines=True, encoding='utf8').splitlines()[0] + recreated_tree = subprocess.check_output([GIT, 'show', '--format=format:%T', 'HEAD']).decode('utf8').splitlines()[0] if current_tree != recreated_tree: print("Merge commit {} is not clean".format(current_commit), file=sys.stderr) subprocess.call([GIT, 'diff', current_commit]) diff --git a/depends/packages/bdb.mk b/depends/packages/bdb.mk index 6c9876c2c7..3cd2e28858 100644 --- a/depends/packages/bdb.mk +++ b/depends/packages/bdb.mk @@ -10,6 +10,7 @@ $(package)_config_opts=--disable-shared --enable-cxx --disable-replication $(package)_config_opts_mingw32=--enable-mingw $(package)_config_opts_linux=--with-pic $(package)_cxxflags=-std=c++11 +$(package)_cppflags_mingw32=-DUNICODE -D_UNICODE endef define $(package)_preprocess_cmds diff --git a/depends/packages/zeromq.mk b/depends/packages/zeromq.mk index c9068e83a5..dfbc50580c 100644 --- a/depends/packages/zeromq.mk +++ b/depends/packages/zeromq.mk @@ -1,8 +1,8 @@ package=zeromq -$(package)_version=4.2.5 +$(package)_version=4.3.1 $(package)_download_path=https://github.com/zeromq/libzmq/releases/download/v$($(package)_version)/ $(package)_file_name=$(package)-$($(package)_version).tar.gz -$(package)_sha256_hash=cc9090ba35713d59bb2f7d7965f877036c49c5558ea0c290b0dcc6f2a17e489f +$(package)_sha256_hash=bcbabe1e2c7d0eec4ed612e10b94b112dd5f06fcefa994a0c79a45d835cd21eb $(package)_patches=0001-fix-build-with-older-mingw64.patch 0002-disable-pthread_set_name_np.patch define $(package)_set_vars diff --git a/doc/JSON-RPC-interface.md b/doc/JSON-RPC-interface.md index 59df541567..982afd5d56 100644 --- a/doc/JSON-RPC-interface.md +++ b/doc/JSON-RPC-interface.md @@ -5,6 +5,85 @@ The headless daemon `bitcoind` has the JSON-RPC API enabled by default, the GUI option. In the GUI it is possible to execute RPC methods in the Debug Console Dialog. +## Security + +The RPC interface allows other programs to control Bitcoin Core, +including the ability to spend funds from your wallets, affect consensus +verification, read private data, and otherwise perform operations that +can cause loss of money, data, or privacy. This section suggests how +you should use and configure Bitcoin Core to reduce the risk that its +RPC interface will be abused. + +- **Securing the executable:** Anyone with physical or remote access to + the computer, container, or virtual machine running Bitcoin Core can + compromise either the whole program or just the RPC interface. This + includes being able to record any passphrases you enter for unlocking + your encrypted wallets or changing settings so that your Bitcoin Core + program tells you that certain transactions have multiple + confirmations even when they aren't part of the best block chain. For + this reason, you should not use Bitcoin Core for security sensitive + operations on systems you do not exclusively control, such as shared + computers or virtual private servers. + +- **Securing local network access:** By default, the RPC interface can + only be accessed by a client running on the same computer and only + after the client provides a valid authentication credential (username + and passphrase). Any program on your computer with access to the file + system and local network can obtain this level of access. + Additionally, other programs on your computer can attempt to provide + an RPC interface on the same port as used by Bitcoin Core in order to + trick you into revealing your authentication credentials. For this + reason, it is important to only use Bitcoin Core for + security-sensitive operations on a computer whose other programs you + trust. + +- **Securing remote network access:** You may optionally allow other + computers to remotely control Bitcoin Core by setting the `rpcallowip` + and `rpcbind` configuration parameters. These settings are only meant + for enabling connections over secure private networks or connections + that have been otherwise secured (e.g. using a VPN or port forwarding + with SSH or stunnel). **Do not enable RPC connections over the public + Internet.** Although Bitcoin Core's RPC interface does use + authentication, it does not use encryption, so your login credentials + are sent as clear text that can be read by anyone on your network + path. Additionally, the RPC interface has not been hardened to + withstand arbitrary Internet traffic, so changing the above settings + to expose it to the Internet (even using something like a Tor hidden + service) could expose you to unconsidered vulnerabilities. See + `bitcoind -help` for more information about these settings and other + settings described in this document. + + Related, if you use Bitcoin Core inside a Docker container, you may + need to expose the RPC port to the host system. The default way to + do this in Docker also exposes the port to the public Internet. + Instead, expose it only on the host system's localhost, for example: + `-p 127.0.0.1:8332:8332` + +- **Secure authentication:** By default, Bitcoin Core generates unique + login credentials each time it restarts and puts them into a file + readable only by the user that started Bitcoin Core, allowing any of + that user's RPC clients with read access to the file to login + automatically. The file is `.cookie` in the Bitcoin Core + configuration directory, and using these credentials is the preferred + RPC authentication method. If you need to generate static login + credentials for your programs, you can use the script in the + `share/rpcauth` directory in the Bitcoin Core source tree. As a final + fallback, you can directly use manually-chosen `rpcuser` and + `rpcpassword` configuration parameters---but you must ensure that you + choose a strong and unique passphrase (and still don't use insecure + networks, as mentioned above). + +- **Secure string handling:** The RPC interface does not guarantee any + escaping of data beyond what's necessary to encode it as JSON, + although it does usually provide serialized data using a hex + representation of the bytes. If you use RPC data in your programs or + provide its data to other programs, you must ensure any problem + strings are properly escaped. For example, multiple websites have + been manipulated because they displayed decoded hex strings that + included HTML `<script>` tags. For this reason, and other + non-security reasons, it is recommended to display all serialized data + in hex form only. + ## RPC consistency guarantees State that can be queried via RPCs is guaranteed to be at least up-to-date with diff --git a/doc/README.md b/doc/README.md index 344b1be5c4..51950d4a13 100644 --- a/doc/README.md +++ b/doc/README.md @@ -5,7 +5,7 @@ Setup --------------------- Bitcoin Core is the original Bitcoin client and it builds the backbone of the network. It downloads and, by default, stores the entire history of Bitcoin transactions, which requires a few hundred gigabytes of disk space. Depending on the speed of your computer and network connection, the synchronization process can take anywhere from a few hours to a day or more. -To download Bitcoin Core, visit [bitcoincore.org](https://bitcoincore.org/en/releases/). +To download Bitcoin Core, visit [bitcoincore.org](https://bitcoincore.org/en/download/). Running --------------------- @@ -41,9 +41,10 @@ The following are developer notes on how to build Bitcoin Core on your native pl - [macOS Build Notes](build-osx.md) - [Unix Build Notes](build-unix.md) - [Windows Build Notes](build-windows.md) +- [FreeBSD Build Notes](build-freebsd.md) - [OpenBSD Build Notes](build-openbsd.md) - [NetBSD Build Notes](build-netbsd.md) -- [Gitian Building Guide](gitian-building.md) +- [Gitian Building Guide (External Link)](https://github.com/bitcoin-core/docs/blob/master/gitian-building.md) Development --------------------- diff --git a/doc/README_osx.md b/doc/README_osx.md deleted file mode 100644 index 739e22d634..0000000000 --- a/doc/README_osx.md +++ /dev/null @@ -1,97 +0,0 @@ -Deterministic macOS DMG Notes. - -Working macOS DMGs are created in Linux by combining a recent clang, -the Apple binutils (ld, ar, etc) and DMG authoring tools. - -Apple uses clang extensively for development and has upstreamed the necessary -functionality so that a vanilla clang can take advantage. It supports the use -of -F, -target, -mmacosx-version-min, and --sysroot, which are all necessary -when building for macOS. - -Apple's version of binutils (called cctools) contains lots of functionality -missing in the FSF's binutils. In addition to extra linker options for -frameworks and sysroots, several other tools are needed as well such as -install_name_tool, lipo, and nmedit. These do not build under linux, so they -have been patched to do so. The work here was used as a starting point: -[mingwandroid/toolchain4](https://github.com/mingwandroid/toolchain4). - -In order to build a working toolchain, the following source packages are needed -from Apple: cctools, dyld, and ld64. - -These tools inject timestamps by default, which produce non-deterministic -binaries. The ZERO_AR_DATE environment variable is used to disable that. - -This version of cctools has been patched to use the current version of clang's -headers and its libLTO.so rather than those from llvmgcc, as it was -originally done in toolchain4. - -To complicate things further, all builds must target an Apple SDK. These SDKs -are free to download, but not redistributable. -To obtain it, register for a developer account, then download the [Xcode 7.3.1 dmg](https://developer.apple.com/devcenter/download.action?path=/Developer_Tools/Xcode_7.3.1/Xcode_7.3.1.dmg). - -This file is several gigabytes in size, but only a single directory inside is -needed: -``` -Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk -``` - -Unfortunately, the usual linux tools (7zip, hpmount, loopback mount) are incapable of opening this file. -To create a tarball suitable for Gitian input, there are two options: - -Using macOS, you can mount the dmg, and then create it with: -``` - $ hdiutil attach Xcode_7.3.1.dmg - $ tar -C /Volumes/Xcode/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/ -czf MacOSX10.11.sdk.tar.gz MacOSX10.11.sdk -``` - -Alternatively, you can use 7zip and SleuthKit to extract the files one by one. -The script contrib/macdeploy/extract-osx-sdk.sh automates this. First ensure -the dmg file is in the current directory, and then run the script. You may wish -to delete the intermediate 5.hfs file and MacOSX10.11.sdk (the directory) when -you've confirmed the extraction succeeded. - -```bash -apt-get install p7zip-full sleuthkit -contrib/macdeploy/extract-osx-sdk.sh -rm -rf 5.hfs MacOSX10.11.sdk -``` - -The Gitian descriptors build 2 sets of files: Linux tools, then Apple binaries -which are created using these tools. The build process has been designed to -avoid including the SDK's files in Gitian's outputs. All interim tarballs are -fully deterministic and may be freely redistributed. - -genisoimage is used to create the initial DMG. It is not deterministic as-is, -so it has been patched. A system genisoimage will work fine, but it will not -be deterministic because the file-order will change between invocations. -The patch can be seen here: [theuni/osx-cross-depends](https://raw.githubusercontent.com/theuni/osx-cross-depends/master/patches/cdrtools/genisoimage.diff). -No effort was made to fix this cleanly, so it likely leaks memory badly. But -it's only used for a single invocation, so that's no real concern. - -genisoimage cannot compress DMGs, so afterwards, the 'dmg' tool from the -libdmg-hfsplus project is used to compress it. There are several bugs in this -tool and its maintainer has seemingly abandoned the project. It has been forked -and is available (with fixes) here: [theuni/libdmg-hfsplus](https://github.com/theuni/libdmg-hfsplus). - -The 'dmg' tool has the ability to create DMGs from scratch as well, but this -functionality is broken. Only the compression feature is currently used. -Ideally, the creation could be fixed and genisoimage would no longer be necessary. - -Background images and other features can be added to DMG files by inserting a -.DS_Store before creation. This is generated by the script -contrib/macdeploy/custom_dsstore.py. - -As of OS X 10.9 Mavericks, using an Apple-blessed key to sign binaries is a -requirement in order to satisfy the new Gatekeeper requirements. Because this -private key cannot be shared, we'll have to be a bit creative in order for the -build process to remain somewhat deterministic. Here's how it works: - -- Builders use Gitian to create an unsigned release. This outputs an unsigned - dmg which users may choose to bless and run. It also outputs an unsigned app - structure in the form of a tarball, which also contains all of the tools - that have been previously (deterministically) built in order to create a - final dmg. -- The Apple keyholder uses this unsigned app to create a detached signature, - using the script that is also included there. Detached signatures are available from this [repository](https://github.com/bitcoin-core/bitcoin-detached-sigs). -- Builders feed the unsigned app + detached signature back into Gitian. It - uses the pre-built tools to recombine the pieces into a deterministic dmg. diff --git a/doc/REST-interface.md b/doc/REST-interface.md index 44df698382..d21df36130 100644 --- a/doc/REST-interface.md +++ b/doc/REST-interface.md @@ -27,6 +27,7 @@ For full TX query capability, one must enable the transaction index via "txindex `GET /rest/block/notxdetails/<BLOCK-HASH>.<bin|hex|json>` Given a block hash: returns a block, in binary, hex-encoded binary or JSON formats. +Responds with 404 if the block doesn't exist. The HTTP request and response are both handled entirely in-memory, thus making maximum memory usage at least 2.66MB (1 MB max block, plus hex encoding) per request. @@ -36,6 +37,12 @@ With the /notxdetails/ option JSON response will only contain the transaction ha `GET /rest/headers/<COUNT>/<BLOCK-HASH>.<bin|hex|json>` Given a block hash: returns <COUNT> amount of blockheaders in upward direction. +Returns empty if the block doesn't exist or it isn't in the active chain. + +#### Blockhash by height +`GET /rest/blockhashbyheight/<HEIGHT>.<bin|hex|json>` + +Given a height: returns hash of block in best-block-chain at height provided. #### Chaininfos `GET /rest/chaininfo.json` diff --git a/doc/build-osx.md b/doc/build-osx.md index c9a59bab83..119896dc67 100644 --- a/doc/build-osx.md +++ b/doc/build-osx.md @@ -105,3 +105,103 @@ Notes * Tested on OS X 10.10 Yosemite through macOS 10.13 High Sierra on 64-bit Intel processors only. * Building with downloaded Qt binaries is not officially supported. See the notes in [#7714](https://github.com/bitcoin/bitcoin/issues/7714) + +Deterministic macOS DMG Notes +----------------------------- + +Working macOS DMGs are created in Linux by combining a recent clang, +the Apple binutils (ld, ar, etc) and DMG authoring tools. + +Apple uses clang extensively for development and has upstreamed the necessary +functionality so that a vanilla clang can take advantage. It supports the use +of -F, -target, -mmacosx-version-min, and --sysroot, which are all necessary +when building for macOS. + +Apple's version of binutils (called cctools) contains lots of functionality +missing in the FSF's binutils. In addition to extra linker options for +frameworks and sysroots, several other tools are needed as well such as +install_name_tool, lipo, and nmedit. These do not build under linux, so they +have been patched to do so. The work here was used as a starting point: +[mingwandroid/toolchain4](https://github.com/mingwandroid/toolchain4). + +In order to build a working toolchain, the following source packages are needed +from Apple: cctools, dyld, and ld64. + +These tools inject timestamps by default, which produce non-deterministic +binaries. The ZERO_AR_DATE environment variable is used to disable that. + +This version of cctools has been patched to use the current version of clang's +headers and its libLTO.so rather than those from llvmgcc, as it was +originally done in toolchain4. + +To complicate things further, all builds must target an Apple SDK. These SDKs +are free to download, but not redistributable. +To obtain it, register for a developer account, then download the [Xcode 7.3.1 dmg](https://developer.apple.com/devcenter/download.action?path=/Developer_Tools/Xcode_7.3.1/Xcode_7.3.1.dmg). + +This file is several gigabytes in size, but only a single directory inside is +needed: +``` +Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk +``` + +Unfortunately, the usual linux tools (7zip, hpmount, loopback mount) are incapable of opening this file. +To create a tarball suitable for Gitian input, there are two options: + +Using macOS, you can mount the dmg, and then create it with: +``` + $ hdiutil attach Xcode_7.3.1.dmg + $ tar -C /Volumes/Xcode/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/ -czf MacOSX10.11.sdk.tar.gz MacOSX10.11.sdk +``` + +Alternatively, you can use 7zip and SleuthKit to extract the files one by one. +The script contrib/macdeploy/extract-osx-sdk.sh automates this. First ensure +the dmg file is in the current directory, and then run the script. You may wish +to delete the intermediate 5.hfs file and MacOSX10.11.sdk (the directory) when +you've confirmed the extraction succeeded. + +```bash +apt-get install p7zip-full sleuthkit +contrib/macdeploy/extract-osx-sdk.sh +rm -rf 5.hfs MacOSX10.11.sdk +``` + +The Gitian descriptors build 2 sets of files: Linux tools, then Apple binaries +which are created using these tools. The build process has been designed to +avoid including the SDK's files in Gitian's outputs. All interim tarballs are +fully deterministic and may be freely redistributed. + +genisoimage is used to create the initial DMG. It is not deterministic as-is, +so it has been patched. A system genisoimage will work fine, but it will not +be deterministic because the file-order will change between invocations. +The patch can be seen here: [theuni/osx-cross-depends](https://raw.githubusercontent.com/theuni/osx-cross-depends/master/patches/cdrtools/genisoimage.diff). +No effort was made to fix this cleanly, so it likely leaks memory badly. But +it's only used for a single invocation, so that's no real concern. + +genisoimage cannot compress DMGs, so afterwards, the 'dmg' tool from the +libdmg-hfsplus project is used to compress it. There are several bugs in this +tool and its maintainer has seemingly abandoned the project. It has been forked +and is available (with fixes) here: [theuni/libdmg-hfsplus](https://github.com/theuni/libdmg-hfsplus). + +The 'dmg' tool has the ability to create DMGs from scratch as well, but this +functionality is broken. Only the compression feature is currently used. +Ideally, the creation could be fixed and genisoimage would no longer be necessary. + +Background images and other features can be added to DMG files by inserting a +.DS_Store before creation. This is generated by the script +contrib/macdeploy/custom_dsstore.py. + +As of OS X 10.9 Mavericks, using an Apple-blessed key to sign binaries is a +requirement in order to satisfy the new Gatekeeper requirements. Because this +private key cannot be shared, we'll have to be a bit creative in order for the +build process to remain somewhat deterministic. Here's how it works: + +- Builders use Gitian to create an unsigned release. This outputs an unsigned + dmg which users may choose to bless and run. It also outputs an unsigned app + structure in the form of a tarball, which also contains all of the tools + that have been previously (deterministically) built in order to create a + final dmg. +- The Apple keyholder uses this unsigned app to create a detached signature, + using the script that is also included there. Detached signatures are available from this [repository](https://github.com/bitcoin-core/bitcoin-detached-sigs). +- Builders feed the unsigned app + detached signature back into Gitian. It + uses the pre-built tools to recombine the pieces into a deterministic dmg. + diff --git a/doc/dependencies.md b/doc/dependencies.md index 50dde02fad..b833e9151f 100644 --- a/doc/dependencies.md +++ b/doc/dependencies.md @@ -26,5 +26,5 @@ These are the dependencies currently used by Bitcoin Core. You can find instruct | Qt | [5.9.7](https://download.qt.io/official_releases/qt/) | [5.2](https://github.com/bitcoin/bitcoin/pull/14725) | 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.2.5](https://github.com/zeromq/libzmq/releases) | 4.0.0 | No | | | +| ZeroMQ | [4.3.1](https://github.com/zeromq/libzmq/releases) | 4.0.0 | No | | | | zlib | [1.2.11](https://zlib.net/) | | | | No | diff --git a/doc/developer-notes.md b/doc/developer-notes.md index 40861608a6..1deb5d791a 100644 --- a/doc/developer-notes.md +++ b/doc/developer-notes.md @@ -7,8 +7,8 @@ Developer Notes - [Developer Notes](#developer-notes) - [Coding Style (General)](#coding-style-general) - [Coding Style (C++)](#coding-style-c) - - [Doxygen comments](#doxygen-comments) - [Coding Style (Python)](#coding-style-python) + - [Coding Style (Doxygen-compatible comments)](#coding-style-doxygen-compatible-comments) - [Development tips and tricks](#development-tips-and-tricks) - [Compiling for debugging](#compiling-for-debugging) - [Compiling for gprof profiling](#compiling-for-gprof-profiling) @@ -36,6 +36,7 @@ Developer Notes - [Subtrees](#subtrees) - [Git and GitHub tips](#git-and-github-tips) - [Scripted diffs](#scripted-diffs) + - [Release notes](#release-notes) - [RPC interface guidelines](#rpc-interface-guidelines) <!-- markdown-toc end --> @@ -121,10 +122,17 @@ public: } // namespace foo ``` -Doxygen comments ------------------ +Coding Style (Python) +--------------------- + +Refer to [/test/functional/README.md#style-guidelines](/test/functional/README.md#style-guidelines). + +Coding Style (Doxygen-compatible comments) +------------------------------------------ -To facilitate the generation of documentation, use doxygen-compatible comment blocks for functions, methods and fields. +Bitcoin Core uses [Doxygen](http://www.doxygen.nl/) to generate its official documentation. + +Use Doxygen-compatible comment blocks for functions, methods, and fields. For example, to describe a function use: ```c++ @@ -157,7 +165,7 @@ int var; //!< Detailed description after the member ``` or -```cpp +```c++ //! Description before the member int var; ``` @@ -177,15 +185,15 @@ Not OK (used plenty in the current source, but not picked up): // ``` -A full list of comment syntaxes picked up by doxygen can be found at http://www.stack.nl/~dimitri/doxygen/manual/docblocks.html, -but if possible use one of the above styles. +A full list of comment syntaxes picked up by Doxygen can be found at https://www.stack.nl/~dimitri/doxygen/manual/docblocks.html, +but the above styles are favored. -Documentation can be generated with `make docs` and cleaned up with `make clean-docs`. +Documentation can be generated with `make docs` and cleaned up with `make clean-docs`. The resulting files are located in `doc/doxygen/html`; open `index.html` to view the homepage. -Coding Style (Python) ---------------------- - -Refer to [/test/functional/README.md#style-guidelines](/test/functional/README.md#style-guidelines). +Before running `make docs`, you will need to install dependencies `doxygen` and `dot`. For example, on MacOS via Homebrew: +``` +brew install doxygen --with-graphviz +``` Development tips and tricks --------------------------- @@ -913,6 +921,21 @@ test/lint/commit-script-check.sh origin/master..HEAD Commit [`bb81e173`](https://github.com/bitcoin/bitcoin/commit/bb81e173) is an example of a scripted-diff. +Release notes +------------- + +Release notes should be written for any PR that: + +- introduces a notable new feature +- fixes a significant bug +- changes an API or configuration model +- makes any other visible change to the end-user experience. + +Release notes should be added to a PR-specific release note file at +`/doc/release-notes-<PR number>.md` to avoid conflicts between multiple PRs. +All `release-notes*` files are merged into a single +[/doc/release-notes.md](/doc/release-notes.md) file prior to the release. + RPC interface guidelines -------------------------- diff --git a/doc/fuzzing.md b/doc/fuzzing.md index 5dedcb51c8..08b73d3b3c 100644 --- a/doc/fuzzing.md +++ b/doc/fuzzing.md @@ -1,12 +1,13 @@ Fuzz-testing Bitcoin Core ========================== -A special test harness `test_bitcoin_fuzzy` is provided to provide an easy -entry point for fuzzers and the like. In this document we'll describe how to -use it with AFL. +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. -Building AFL -------------- +## AFL + +### Building AFL It is recommended to always use the latest version of afl: ``` @@ -17,16 +18,15 @@ make export AFLPATH=$PWD ``` -Instrumentation ----------------- +### Instrumentation To build Bitcoin Core using AFL instrumentation (this assumes that the `AFLPATH` was set as above): ``` -./configure --disable-ccache --disable-shared --enable-tests CC=${AFLPATH}/afl-gcc CXX=${AFLPATH}/afl-g++ +./configure --disable-ccache --disable-shared --enable-tests --enable-fuzz CC=${AFLPATH}/afl-gcc CXX=${AFLPATH}/afl-g++ export AFL_HARDEN=1 cd src/ -make test/test_bitcoin_fuzzy +make ``` We disable ccache because we don't want to pollute the ccache with instrumented objects, and similarly don't want to use non-instrumented cached objects linked @@ -35,12 +35,11 @@ in. The fuzzing can be sped up significantly (~200x) by using `afl-clang-fast` and `afl-clang-fast++` in place of `afl-gcc` and `afl-g++` when compiling. When compiling using `afl-clang-fast`/`afl-clang-fast++` the resulting -`test_bitcoin_fuzzy` binary will be instrumented in such a way that the AFL +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 ------------------- +### 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, @@ -60,13 +59,30 @@ Example inputs are available from: Extract these (or other starting inputs) into the `inputs` directory before starting fuzzing. -Fuzzing --------- +### Fuzzing To start the actual fuzzing use: ``` -$AFLPATH/afl-fuzz -i ${AFLIN} -o ${AFLOUT} -m52 -- test/test_bitcoin_fuzzy +$AFLPATH/afl-fuzz -i ${AFLIN} -o ${AFLOUT} -m52 -- test/fuzz/fuzz_target_foo ``` You may have to change a few kernel parameters to test optimally - `afl-fuzz` will print an error and suggestion if so. + +## libFuzzer + +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 + +``` +./configure --disable-ccache --enable-fuzz --with-sanitizers=fuzzer,address CC=clang CXX=clang++ +make +``` + +The fuzzer needs some inputs to work on, but the inputs or seeds can be used +interchangeably between libFuzzer and AFL. + +See https://llvm.org/docs/LibFuzzer.html#running on how to run the libFuzzer +instrumented executable. 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/release-notes-14060.md b/doc/release-notes-14060.md deleted file mode 100644 index 2cc5ab49fb..0000000000 --- a/doc/release-notes-14060.md +++ /dev/null @@ -1,21 +0,0 @@ -Configuration -------------- - -The outbound message high water mark of the ZMQ PUB sockets are now -configurable via the options: - -`-zmqpubhashtxhwm=n` - -`-zmqpubhashblockhwm=n` - -`-zmqpubrawblockhwm=n` - -`-zmqpubrawtxhwm=n` - -Each high water mark value must be an integer greater than or equal to 0. -The high water mark limits the maximum number of messages that ZMQ will -queue in memory for any single subscriber. A value of 0 means no limit. -When not specified, the default value continues to be 1000. -When a ZMQ PUB socket reaches its high water mark for a subscriber, then -additional messages to the subscriber are dropped until the number of -queued messages again falls below the high water mark value. diff --git a/doc/release-notes-14477.md b/doc/release-notes-14477.md deleted file mode 100644 index bb8c0a623e..0000000000 --- a/doc/release-notes-14477.md +++ /dev/null @@ -1,5 +0,0 @@ -Miscellaneous RPC changes ------------- - -- `getaddressinfo` now reports `solvable`, a boolean indicating whether all information necessary for signing is present in the wallet (ignoring private keys). -- `getaddressinfo`, `listunspent`, and `scantxoutset` have a new output field `desc`, an output descriptor that encapsulates all signing information and key paths for the address (only available when `solvable` is true for `getaddressinfo` and `listunspent`). diff --git a/doc/release-notes-14565.md b/doc/release-notes-14565.md deleted file mode 100644 index 38d76fee46..0000000000 --- a/doc/release-notes-14565.md +++ /dev/null @@ -1,5 +0,0 @@ -Low-level RPC changes ---------------------- - -The `importmulti` RPC will now contain a new per-request `warnings` field with strings -that explain when fields are being ignored or inconsistant, if any. diff --git a/doc/release-notes-14941.md b/doc/release-notes-14941.md new file mode 100644 index 0000000000..c3820d0368 --- /dev/null +++ b/doc/release-notes-14941.md @@ -0,0 +1,5 @@ +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 new file mode 100644 index 0000000000..3f0bf8aacd --- /dev/null +++ b/doc/release-notes-14982.md @@ -0,0 +1,5 @@ +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-pr13381.md b/doc/release-notes-pr13381.md deleted file mode 100644 index 75faad9906..0000000000 --- a/doc/release-notes-pr13381.md +++ /dev/null @@ -1,29 +0,0 @@ -RPC importprivkey: new label behavior -------------------------------------- - -Previously, `importprivkey` automatically added the default empty label -("") to all addresses associated with the imported private key. Now it -defaults to using any existing label for those addresses. For example: - -- Old behavior: you import a watch-only address with the label "cold - wallet". Later, you import the corresponding private key using the - default settings. The address's label is changed from "cold wallet" - to "". - -- New behavior: you import a watch-only address with the label "cold - wallet". Later, you import the corresponding private key using the - default settings. The address's label remains "cold wallet". - -In both the previous and current case, if you directly specify a label -during the import, that label will override whatever previous label the -addresses may have had. Also in both cases, if none of the addresses -previously had a label, they will still receive the default empty label -(""). Examples: - -- You import a watch-only address with the label "temporary". Later you - import the corresponding private key with the label "final". The - address's label will be changed to "final". - -- You use the default settings to import a private key for an address that - was not previously in the wallet. Its addresses will receive the default - empty label (""). diff --git a/doc/release-notes.md b/doc/release-notes.md index 6b4bb478e9..c23a7f6e0a 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -72,16 +72,52 @@ Mining - Calls to `getblocktemplate` will fail if the segwit rule is not specified. Calling `getblocktemplate` without segwit specified is almost certainly a misconfiguration since doing so results in lower rewards for the miner. - -Command line option changes ---------------------------- - -The `-enablebip61` command line option (introduced in Bitcoin Core 0.17.0) is -used to toggle sending of BIP 61 reject messages. Reject messages have no use -case on the P2P network and are only logged for debugging by most network -nodes. The option will now by default be off for improved privacy and security -as well as reduced upload usage. The option can explicitly be turned on for -local-network debugging purposes. + Failed calls will produce an error message describing how to enable the + segwit rule. + +Configuration option changes +---------------------------- + +- A warning is printed if an unrecognized section name is used in the + configuration file. Recognized sections are `[test]`, `[main]`, and + `[regtest]`. + +- Four new options are available for configuring the maximum number of + messages that ZMQ will queue in memory (the "high water mark") before + dropping additional messages. The default value is 1,000, the same as + was used for previous releases. See the [ZMQ + documentation](https://github.com/bitcoin/bitcoin/blob/master/doc/zmq.md#usage) + for details. + +- The `enablebip61` option (introduced in Bitcoin Core 0.17.0) is + used to toggle sending of BIP 61 reject messages. Reject messages have no use + case on the P2P network and are only logged for debugging by most network + nodes. The option will now by default be off for improved privacy and security + as well as reduced upload usage. The option can explicitly be turned on for + local-network debugging purposes. + +- The `rpcallowip` option can no longer be used to automatically listen + on all network interfaces. Instead, the `rpcbind` parameter must also + be used to specify the IP addresses to listen on. Listening for RPC + commands over a public network connection is insecure and should be + disabled, so a warning is now printed if a user selects such a + configuration. If you need to expose RPC in order to use a tool + like Docker, ensure you only bind RPC to your localhost, e.g. `docker + run [...] -p 127.0.0.1:8332:8332` (this is an extra `:8332` over the + normal Docker port specification). + +- The `rpcpassword` option now causes a startup error if the password + set in the configuration file contains a hash character (#), as it's + ambiguous whether the hash character is meant for the password or as a + comment. + +- The `whitelistforcerelay` option is used to relay transactions from + whitelisted peers even when not accepted to the mempool. This option now + 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 + use-case, as this feature could be deprecated in the future). Documentation ------------- @@ -168,7 +204,7 @@ Updated RPCs Note: some low-level RPC changes mainly useful for testing are described in the Low-level Changes section below. -- The `getpeerinfo` RPC now returns an additional "minfeefilter" field +- The `getpeerinfo` RPC now returns an additional `minfeefilter` field set to the peer's BIP133 fee filter. You can use this to detect that you have peers that are willing to accept transactions below the default minimum relay fee. @@ -190,8 +226,62 @@ in the Low-level Changes section below. P2SH-P2WPKH, and P2SH-P2WSH. Requests for P2WSH and P2SH-P2WSH accept an additional `witnessscript` parameter. +- The `importmulti` RPC now returns an additional `warnings` field for + each request with an array of strings explaining when fields are being + ignored or are inconsistent, if there are any. + +- The `getaddressinfo` RPC now returns an additional `solvable` boolean + field when Bitcoin Core knows enough about the address's scriptPubKey, + optional redeemScript, and optional witnessScript in order for the + wallet to be able to generate an unsigned input spending funds sent to + that address. + +- The `getaddressinfo`, `listunspent`, and `scantxoutset` RPCs now + return an additional `desc` field that contains an output descriptor + containing all key paths and signing information for the address + (except for the private key). The `desc` field is only returned for + `getaddressinfo` and `listunspent` when the address is solvable. + +- The `importprivkey` RPC will preserve previously-set labels for + addresses or public keys corresponding to the private key being + imported. For example, if you imported a watch-only address with the + label "cold wallet" in earlier releases of Bitcoin Core, subsequently + importing the private key would default to resetting the address's + label to the default empty-string label (""). In this release, the + previous label of "cold wallet" will be retained. If you optionally + specify any label besides the default when calling `importprivkey`, + the new label will be applied to the address. + - See the [Mining](#mining) section for changes to `getblocktemplate`. +- 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. + +Graphical User Interface (GUI) +------------------------------ + +- A new Window menu is added alongside the existing File, Settings, and + Help menus. Several items from the other menus that opened new + windows have been moved to this new Window menu. + +- In the Send tab, the checkbox for "pay only the required fee" + has been removed. Instead, the user can simply decrease the value in + the Custom Feerate field all the way down to the node's configured + minimum relay fee. + +- In the Overview tab, the watch-only balance will be the only + balance shown if the wallet was created using the `createwallet` RPC + and the `disable_private_keys` parameter was set to true. + +- The launch-on-startup option is no longer available on macOS if + compiled with macosx min version greater than 10.11 (use + CXXFLAGS="-mmacosx-version-min=10.11" + CFLAGS="-mmacosx-version-min=10.11" for setting the deployment + sdk version) + Low-level changes ================= @@ -216,6 +306,16 @@ Configuration deterministic wallets. This release makes specifying `-usehd` an invalid configuration option. +Changes for particular platforms +-------------------------------- + +- On macOS, Bitcoin Core now opts out of application CPU throttling + ("app nap") during initial blockchain download, when catching up from + over 100 blocks behind the current chain tip, or when reindexing chain + data. This helps prevent these operations from taking an excessively + long time because the operating system is attempting to conserve + power. + Credits ======= 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 97fedb6e24..d20a3dc6b3 100644 --- a/doc/release-process.md +++ b/doc/release-process.md @@ -23,7 +23,7 @@ Before every minor and major release: Before every major release: * Update hardcoded [seeds](/contrib/seeds/README.md), see [this pull request](https://github.com/bitcoin/bitcoin/pull/7415) for an example. -* Update [`BLOCK_CHAIN_SIZE`](/src/qt/intro.cpp) to the current size plus some overhead. +* Update [`src/chainparams.cpp`](/src/chainparams.cpp) m_assumed_blockchain_size and m_assumed_chain_state_size with the current size plus some overhead. * Update `src/chainparams.cpp` chainTxData with statistics about the transaction count and rate. Use the output of the RPC `getchaintxstats`, see [this pull request](https://github.com/bitcoin/bitcoin/pull/12270) for an example. Reviewers can verify the results by running `getchaintxstats <window_block_count> <window_last_block_hash>` with the `window_block_count` and `window_last_block_hash` from your output. * Update version of `contrib/gitian-descriptors/*.yml`: usually one'd want to do this on master after branching off the release - but be sure to at least do it before a new major release @@ -87,10 +87,12 @@ Ensure gitian-builder is up-to-date: pushd ./gitian-builder mkdir -p inputs wget -P inputs https://bitcoincore.org/cfields/osslsigncode-Backports-to-1.7.1.patch + echo 'a8c4e9cafba922f89de0df1f2152e7be286aba73f78505169bc351a7938dd911 inputs/osslsigncode-Backports-to-1.7.1.patch' | sha256sum -c wget -P inputs https://downloads.sourceforge.net/project/osslsigncode/osslsigncode/osslsigncode-1.7.1.tar.gz + echo 'f9a8cdb38b9c309326764ebc937cba1523a3a751a7ab05df3ecc99d18ae466c9 inputs/osslsigncode-1.7.1.tar.gz' | sha256sum -c popd -Create the macOS SDK tarball, see the [macOS readme](README_osx.md) for details, and copy it into the inputs directory. +Create the macOS SDK tarball, see the [macOS build instructions](build-osx.md#deterministic-macos-dmg-notes) for details, and copy it into the inputs directory. ### Optional: Seed the Gitian sources cache and offline git repositories 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/src/Makefile.am b/src/Makefile.am index 09daaebd23..a57fcb0711 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -41,6 +41,7 @@ LIBBITCOINCONSENSUS=libbitcoinconsensus.la endif if ENABLE_WALLET LIBBITCOIN_WALLET=libbitcoin_wallet.a +LIBBITCOIN_WALLET_TOOL=libbitcoin_wallet_tool.a endif LIBBITCOIN_CRYPTO= $(LIBBITCOIN_CRYPTO_BASE) @@ -70,6 +71,7 @@ EXTRA_LIBRARIES += \ $(LIBBITCOIN_SERVER) \ $(LIBBITCOIN_CLI) \ $(LIBBITCOIN_WALLET) \ + $(LIBBITCOIN_WALLET_TOOL) \ $(LIBBITCOIN_ZMQ) lib_LTLIBRARIES = $(LIBBITCOINCONSENSUS) @@ -89,6 +91,11 @@ endif if BUILD_BITCOIN_TX bin_PROGRAMS += bitcoin-tx endif +if ENABLE_WALLET +if BUILD_BITCOIN_WALLET + bin_PROGRAMS += bitcoin-wallet +endif +endif .PHONY: FORCE check-symbols check-security # bitcoin core # @@ -96,6 +103,7 @@ BITCOIN_CORE_H = \ addrdb.h \ addrman.h \ attributes.h \ + banman.h \ base58.h \ bech32.h \ bloom.h \ @@ -145,6 +153,7 @@ BITCOIN_CORE_H = \ netbase.h \ netmessagemaker.h \ noui.h \ + optional.h \ outputtype.h \ policy/feerate.h \ policy/fees.h \ @@ -203,6 +212,7 @@ BITCOIN_CORE_H = \ wallet/rpcwallet.h \ wallet/wallet.h \ wallet/walletdb.h \ + wallet/wallettool.h \ wallet/walletutil.h \ wallet/coinselection.h \ warnings.h \ @@ -225,6 +235,7 @@ libbitcoin_server_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_server_a_SOURCES = \ addrdb.cpp \ addrman.cpp \ + banman.cpp \ bloom.cpp \ blockencodings.cpp \ blockfilter.cpp \ @@ -305,6 +316,12 @@ libbitcoin_wallet_a_SOURCES = \ wallet/coinselection.cpp \ $(BITCOIN_CORE_H) +libbitcoin_wallet_tool_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) +libbitcoin_wallet_tool_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) +libbitcoin_wallet_tool_a_SOURCES = \ + wallet/wallettool.cpp \ + $(BITCOIN_CORE_H) + # crypto primitives library crypto_libbitcoin_crypto_base_a_CPPFLAGS = $(AM_CPPFLAGS) crypto_libbitcoin_crypto_base_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) @@ -522,6 +539,32 @@ bitcoin_tx_LDADD = \ bitcoin_tx_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS) # +# bitcoin-wallet binary # +bitcoin_wallet_SOURCES = bitcoin-wallet.cpp +bitcoin_wallet_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) +bitcoin_wallet_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) +bitcoin_wallet_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) + +if TARGET_WINDOWS +bitcoin_wallet_SOURCES += bitcoin-wallet-res.rc +endif + +bitcoin_wallet_LDADD = \ + $(LIBBITCOIN_WALLET_TOOL) \ + $(LIBBITCOIN_WALLET) \ + $(LIBBITCOIN_SERVER) \ + $(LIBBITCOIN_COMMON) \ + $(LIBBITCOIN_CONSENSUS) \ + $(LIBBITCOIN_UTIL) \ + $(LIBBITCOIN_CRYPTO) \ + $(LIBLEVELDB) \ + $(LIBLEVELDB_SSE42) \ + $(LIBMEMENV) \ + $(LIBSECP256K1) + +bitcoin_wallet_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) +# + # bitcoinconsensus library # if BUILD_BITCOIN_LIBS include_HEADERS = script/bitcoinconsensus.h 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.qt.include b/src/Makefile.qt.include index 445849e3d8..ba6523d7c2 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -120,6 +120,7 @@ QT_MOC_CPP = \ qt/moc_bantablemodel.cpp \ qt/moc_bitcoinaddressvalidator.cpp \ qt/moc_bitcoinamountfield.cpp \ + qt/moc_bitcoin.cpp \ qt/moc_bitcoingui.cpp \ qt/moc_bitcoinunits.cpp \ qt/moc_clientmodel.cpp \ @@ -156,6 +157,7 @@ QT_MOC_CPP = \ qt/moc_transactiontablemodel.cpp \ qt/moc_transactionview.cpp \ qt/moc_utilitydialog.cpp \ + qt/moc_walletcontroller.cpp \ qt/moc_walletframe.cpp \ qt/moc_walletmodel.cpp \ qt/moc_walletview.cpp @@ -166,7 +168,6 @@ BITCOIN_MM = \ qt/macos_appnap.mm QT_MOC = \ - qt/bitcoin.moc \ qt/bitcoinamountfield.moc \ qt/intro.moc \ qt/overviewpage.moc \ @@ -194,6 +195,7 @@ BITCOIN_QT_H = \ qt/bantablemodel.h \ qt/bitcoinaddressvalidator.h \ qt/bitcoinamountfield.h \ + qt/bitcoin.h \ qt/bitcoingui.h \ qt/bitcoinunits.h \ qt/clientmodel.h \ @@ -236,6 +238,7 @@ BITCOIN_QT_H = \ qt/transactiontablemodel.h \ qt/transactionview.h \ qt/utilitydialog.h \ + qt/walletcontroller.h \ qt/walletframe.h \ qt/walletmodel.h \ qt/walletmodeltransaction.h \ @@ -302,6 +305,7 @@ RES_ICONS = \ BITCOIN_QT_BASE_CPP = \ qt/bantablemodel.cpp \ + qt/bitcoin.cpp \ qt/bitcoinaddressvalidator.cpp \ qt/bitcoinamountfield.cpp \ qt/bitcoingui.cpp \ @@ -348,6 +352,7 @@ BITCOIN_QT_WALLET_CPP = \ qt/transactionrecord.cpp \ qt/transactiontablemodel.cpp \ qt/transactionview.cpp \ + qt/walletcontroller.cpp \ qt/walletframe.cpp \ qt/walletmodel.cpp \ qt/walletmodeltransaction.cpp \ @@ -382,6 +387,9 @@ qt_libbitcoinqt_a_OBJCXXFLAGS = $(AM_OBJCXXFLAGS) $(QT_PIE_FLAGS) qt_libbitcoinqt_a_SOURCES = $(BITCOIN_QT_CPP) $(BITCOIN_QT_H) $(QT_FORMS_UI) \ $(QT_QRC) $(QT_QRC_LOCALE) $(QT_TS) $(PROTOBUF_PROTO) $(RES_ICONS) $(RES_IMAGES) $(RES_MOVIES) +if TARGET_DARWIN + qt_libbitcoinqt_a_SOURCES += $(BITCOIN_MM) +endif nodist_qt_libbitcoinqt_a_SOURCES = $(QT_MOC_CPP) $(QT_MOC) $(PROTOBUF_CC) \ $(PROTOBUF_H) $(QT_QRC_CPP) $(QT_QRC_LOCALE_CPP) @@ -404,10 +412,7 @@ qt_bitcoin_qt_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BITCOIN_QT_INCLUDE $(QT_INCLUDES) $(PROTOBUF_CFLAGS) $(QR_CFLAGS) qt_bitcoin_qt_CXXFLAGS = $(AM_CXXFLAGS) $(QT_PIE_FLAGS) -qt_bitcoin_qt_SOURCES = qt/bitcoin.cpp -if TARGET_DARWIN - qt_bitcoin_qt_SOURCES += $(BITCOIN_MM) -endif +qt_bitcoin_qt_SOURCES = qt/main.cpp if TARGET_WINDOWS qt_bitcoin_qt_SOURCES += $(BITCOIN_RC) endif diff --git a/src/Makefile.qttest.include b/src/Makefile.qttest.include index db7873e8b7..61977b50cd 100644 --- a/src/Makefile.qttest.include +++ b/src/Makefile.qttest.include @@ -6,6 +6,7 @@ bin_PROGRAMS += qt/test/test_bitcoin-qt TESTS += qt/test/test_bitcoin-qt TEST_QT_MOC_CPP = \ + qt/test/moc_apptests.cpp \ qt/test/moc_compattests.cpp \ qt/test/moc_rpcnestedtests.cpp \ qt/test/moc_uritests.cpp @@ -22,6 +23,7 @@ endif # ENABLE_WALLET TEST_QT_H = \ qt/test/addressbooktests.h \ + qt/test/apptests.h \ qt/test/compattests.h \ qt/test/rpcnestedtests.h \ qt/test/uritests.h \ @@ -40,6 +42,7 @@ qt_test_test_bitcoin_qt_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BITCOIN_ $(QT_INCLUDES) $(QT_TEST_INCLUDES) $(PROTOBUF_CFLAGS) qt_test_test_bitcoin_qt_SOURCES = \ + qt/test/apptests.cpp \ qt/test/compattests.cpp \ qt/test/rpcnestedtests.cpp \ qt/test/test_main.cpp \ diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 8ce7562434..12112375ea 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -3,7 +3,33 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. bin_PROGRAMS += test/test_bitcoin -noinst_PROGRAMS += test/test_bitcoin_fuzzy + +FUZZ_TARGETS = \ + test/fuzz/address_deserialize \ + test/fuzz/addrman_deserialize \ + test/fuzz/banentry_deserialize \ + test/fuzz/block_deserialize \ + test/fuzz/blockheader_deserialize \ + test/fuzz/blocklocator_deserialize \ + test/fuzz/blockmerkleroot \ + test/fuzz/blocktransactions_deserialize \ + test/fuzz/blocktransactionsrequest_deserialize \ + test/fuzz/blockundo_deserialize \ + test/fuzz/bloomfilter_deserialize \ + test/fuzz/coins_deserialize \ + test/fuzz/diskblockindex_deserialize \ + test/fuzz/inv_deserialize \ + test/fuzz/messageheader_deserialize \ + test/fuzz/netaddr_deserialize \ + test/fuzz/service_deserialize \ + test/fuzz/transaction_deserialize \ + test/fuzz/txoutcompressor_deserialize \ + test/fuzz/txundo_deserialize + +if ENABLE_FUZZ +noinst_PROGRAMS += $(FUZZ_TARGETS:=) +endif + TEST_SRCDIR = test TEST_BINARY=test/test_bitcoin$(EXEEXT) @@ -27,6 +53,10 @@ BITCOIN_TEST_SUITE = \ test/test_bitcoin.h \ test/test_bitcoin.cpp +FUZZ_SUITE = \ + test/fuzz/fuzz.cpp \ + test/fuzz/fuzz.h + # test_bitcoin binary # BITCOIN_TESTS =\ test/arith_uint256_tests.cpp \ @@ -108,6 +138,7 @@ endif if ENABLE_WALLET BITCOIN_TESTS += \ + wallet/test/db_tests.cpp \ wallet/test/psbt_wallet_tests.cpp \ wallet/test/wallet_tests.cpp \ wallet/test/wallet_crypto_tests.cpp \ @@ -138,28 +169,348 @@ test_test_bitcoin_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) -s if ENABLE_ZMQ test_test_bitcoin_LDADD += $(ZMQ_LIBS) endif -# - -# test_bitcoin_fuzzy binary # -test_test_bitcoin_fuzzy_SOURCES = test/test_bitcoin_fuzzy.cpp -test_test_bitcoin_fuzzy_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_test_bitcoin_fuzzy_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_test_bitcoin_fuzzy_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) - -test_test_bitcoin_fuzzy_LDADD = \ - $(LIBUNIVALUE) \ - $(LIBBITCOIN_SERVER) \ - $(LIBBITCOIN_COMMON) \ - $(LIBBITCOIN_UTIL) \ - $(LIBBITCOIN_CONSENSUS) \ - $(LIBBITCOIN_CRYPTO) \ - $(LIBBITCOIN_CRYPTO_SSE41) \ - $(LIBBITCOIN_CRYPTO_AVX2) \ - $(LIBBITCOIN_CRYPTO_SHANI) \ - $(LIBSECP256K1) - -test_test_bitcoin_fuzzy_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS) -# + +if ENABLE_FUZZ +test_fuzz_block_deserialize_SOURCES = $(FUZZ_SUITE) test/test_bitcoin_fuzzy.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) +test_fuzz_block_deserialize_LDADD = \ + $(LIBUNIVALUE) \ + $(LIBBITCOIN_SERVER) \ + $(LIBBITCOIN_COMMON) \ + $(LIBBITCOIN_UTIL) \ + $(LIBBITCOIN_CONSENSUS) \ + $(LIBBITCOIN_CRYPTO) \ + $(LIBBITCOIN_CRYPTO_SSE41) \ + $(LIBBITCOIN_CRYPTO_AVX2) \ + $(LIBBITCOIN_CRYPTO_SHANI) \ + $(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_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) +test_fuzz_transaction_deserialize_LDADD = \ + $(LIBUNIVALUE) \ + $(LIBBITCOIN_SERVER) \ + $(LIBBITCOIN_COMMON) \ + $(LIBBITCOIN_UTIL) \ + $(LIBBITCOIN_CONSENSUS) \ + $(LIBBITCOIN_CRYPTO) \ + $(LIBBITCOIN_CRYPTO_SSE41) \ + $(LIBBITCOIN_CRYPTO_AVX2) \ + $(LIBBITCOIN_CRYPTO_SHANI) \ + $(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_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) +test_fuzz_blocklocator_deserialize_LDADD = \ + $(LIBUNIVALUE) \ + $(LIBBITCOIN_SERVER) \ + $(LIBBITCOIN_COMMON) \ + $(LIBBITCOIN_UTIL) \ + $(LIBBITCOIN_CONSENSUS) \ + $(LIBBITCOIN_CRYPTO) \ + $(LIBBITCOIN_CRYPTO_SSE41) \ + $(LIBBITCOIN_CRYPTO_AVX2) \ + $(LIBBITCOIN_CRYPTO_SHANI) \ + $(LIBSECP256K1) +test_fuzz_blocklocator_deserialize_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS) + +test_fuzz_blockmerkleroot_SOURCES = $(FUZZ_SUITE) test/test_bitcoin_fuzzy.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) +test_fuzz_blockmerkleroot_LDADD = \ + $(LIBUNIVALUE) \ + $(LIBBITCOIN_SERVER) \ + $(LIBBITCOIN_COMMON) \ + $(LIBBITCOIN_UTIL) \ + $(LIBBITCOIN_CONSENSUS) \ + $(LIBBITCOIN_CRYPTO) \ + $(LIBBITCOIN_CRYPTO_SSE41) \ + $(LIBBITCOIN_CRYPTO_AVX2) \ + $(LIBBITCOIN_CRYPTO_SHANI) \ + $(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_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) +test_fuzz_addrman_deserialize_LDADD = \ + $(LIBUNIVALUE) \ + $(LIBBITCOIN_SERVER) \ + $(LIBBITCOIN_COMMON) \ + $(LIBBITCOIN_UTIL) \ + $(LIBBITCOIN_CONSENSUS) \ + $(LIBBITCOIN_CRYPTO) \ + $(LIBBITCOIN_CRYPTO_SSE41) \ + $(LIBBITCOIN_CRYPTO_AVX2) \ + $(LIBBITCOIN_CRYPTO_SHANI) \ + $(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_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) +test_fuzz_blockheader_deserialize_LDADD = \ + $(LIBUNIVALUE) \ + $(LIBBITCOIN_SERVER) \ + $(LIBBITCOIN_COMMON) \ + $(LIBBITCOIN_UTIL) \ + $(LIBBITCOIN_CONSENSUS) \ + $(LIBBITCOIN_CRYPTO) \ + $(LIBBITCOIN_CRYPTO_SSE41) \ + $(LIBBITCOIN_CRYPTO_AVX2) \ + $(LIBBITCOIN_CRYPTO_SHANI) \ + $(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_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) +test_fuzz_banentry_deserialize_LDADD = \ + $(LIBUNIVALUE) \ + $(LIBBITCOIN_SERVER) \ + $(LIBBITCOIN_COMMON) \ + $(LIBBITCOIN_UTIL) \ + $(LIBBITCOIN_CONSENSUS) \ + $(LIBBITCOIN_CRYPTO) \ + $(LIBBITCOIN_CRYPTO_SSE41) \ + $(LIBBITCOIN_CRYPTO_AVX2) \ + $(LIBBITCOIN_CRYPTO_SHANI) \ + $(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_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) +test_fuzz_txundo_deserialize_LDADD = \ + $(LIBUNIVALUE) \ + $(LIBBITCOIN_SERVER) \ + $(LIBBITCOIN_COMMON) \ + $(LIBBITCOIN_UTIL) \ + $(LIBBITCOIN_CONSENSUS) \ + $(LIBBITCOIN_CRYPTO) \ + $(LIBBITCOIN_CRYPTO_SSE41) \ + $(LIBBITCOIN_CRYPTO_AVX2) \ + $(LIBBITCOIN_CRYPTO_SHANI) \ + $(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_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) +test_fuzz_blockundo_deserialize_LDADD = \ + $(LIBUNIVALUE) \ + $(LIBBITCOIN_SERVER) \ + $(LIBBITCOIN_COMMON) \ + $(LIBBITCOIN_UTIL) \ + $(LIBBITCOIN_CONSENSUS) \ + $(LIBBITCOIN_CRYPTO) \ + $(LIBBITCOIN_CRYPTO_SSE41) \ + $(LIBBITCOIN_CRYPTO_AVX2) \ + $(LIBBITCOIN_CRYPTO_SHANI) \ + $(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_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) +test_fuzz_coins_deserialize_LDADD = \ + $(LIBUNIVALUE) \ + $(LIBBITCOIN_SERVER) \ + $(LIBBITCOIN_COMMON) \ + $(LIBBITCOIN_UTIL) \ + $(LIBBITCOIN_CONSENSUS) \ + $(LIBBITCOIN_CRYPTO) \ + $(LIBBITCOIN_CRYPTO_SSE41) \ + $(LIBBITCOIN_CRYPTO_AVX2) \ + $(LIBBITCOIN_CRYPTO_SHANI) \ + $(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_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) +test_fuzz_netaddr_deserialize_LDADD = \ + $(LIBUNIVALUE) \ + $(LIBBITCOIN_SERVER) \ + $(LIBBITCOIN_COMMON) \ + $(LIBBITCOIN_UTIL) \ + $(LIBBITCOIN_CONSENSUS) \ + $(LIBBITCOIN_CRYPTO) \ + $(LIBBITCOIN_CRYPTO_SSE41) \ + $(LIBBITCOIN_CRYPTO_AVX2) \ + $(LIBBITCOIN_CRYPTO_SHANI) \ + $(LIBSECP256K1) +test_fuzz_netaddr_deserialize_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS) + +test_fuzz_service_deserialize_SOURCES = $(FUZZ_SUITE) test/test_bitcoin_fuzzy.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) +test_fuzz_service_deserialize_LDADD = \ + $(LIBUNIVALUE) \ + $(LIBBITCOIN_SERVER) \ + $(LIBBITCOIN_COMMON) \ + $(LIBBITCOIN_UTIL) \ + $(LIBBITCOIN_CONSENSUS) \ + $(LIBBITCOIN_CRYPTO) \ + $(LIBBITCOIN_CRYPTO_SSE41) \ + $(LIBBITCOIN_CRYPTO_AVX2) \ + $(LIBBITCOIN_CRYPTO_SHANI) \ + $(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_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) +test_fuzz_messageheader_deserialize_LDADD = \ + $(LIBUNIVALUE) \ + $(LIBBITCOIN_SERVER) \ + $(LIBBITCOIN_COMMON) \ + $(LIBBITCOIN_UTIL) \ + $(LIBBITCOIN_CONSENSUS) \ + $(LIBBITCOIN_CRYPTO) \ + $(LIBBITCOIN_CRYPTO_SSE41) \ + $(LIBBITCOIN_CRYPTO_AVX2) \ + $(LIBBITCOIN_CRYPTO_SHANI) \ + $(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_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) +test_fuzz_address_deserialize_LDADD = \ + $(LIBUNIVALUE) \ + $(LIBBITCOIN_SERVER) \ + $(LIBBITCOIN_COMMON) \ + $(LIBBITCOIN_UTIL) \ + $(LIBBITCOIN_CONSENSUS) \ + $(LIBBITCOIN_CRYPTO) \ + $(LIBBITCOIN_CRYPTO_SSE41) \ + $(LIBBITCOIN_CRYPTO_AVX2) \ + $(LIBBITCOIN_CRYPTO_SHANI) \ + $(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_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) +test_fuzz_inv_deserialize_LDADD = \ + $(LIBUNIVALUE) \ + $(LIBBITCOIN_SERVER) \ + $(LIBBITCOIN_COMMON) \ + $(LIBBITCOIN_UTIL) \ + $(LIBBITCOIN_CONSENSUS) \ + $(LIBBITCOIN_CRYPTO) \ + $(LIBBITCOIN_CRYPTO_SSE41) \ + $(LIBBITCOIN_CRYPTO_AVX2) \ + $(LIBBITCOIN_CRYPTO_SHANI) \ + $(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_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) +test_fuzz_bloomfilter_deserialize_LDADD = \ + $(LIBUNIVALUE) \ + $(LIBBITCOIN_SERVER) \ + $(LIBBITCOIN_COMMON) \ + $(LIBBITCOIN_UTIL) \ + $(LIBBITCOIN_CONSENSUS) \ + $(LIBBITCOIN_CRYPTO) \ + $(LIBBITCOIN_CRYPTO_SSE41) \ + $(LIBBITCOIN_CRYPTO_AVX2) \ + $(LIBBITCOIN_CRYPTO_SHANI) \ + $(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_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) +test_fuzz_diskblockindex_deserialize_LDADD = \ + $(LIBUNIVALUE) \ + $(LIBBITCOIN_SERVER) \ + $(LIBBITCOIN_COMMON) \ + $(LIBBITCOIN_UTIL) \ + $(LIBBITCOIN_CONSENSUS) \ + $(LIBBITCOIN_CRYPTO) \ + $(LIBBITCOIN_CRYPTO_SSE41) \ + $(LIBBITCOIN_CRYPTO_AVX2) \ + $(LIBBITCOIN_CRYPTO_SHANI) \ + $(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_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) +test_fuzz_txoutcompressor_deserialize_LDADD = \ + $(LIBUNIVALUE) \ + $(LIBBITCOIN_SERVER) \ + $(LIBBITCOIN_COMMON) \ + $(LIBBITCOIN_UTIL) \ + $(LIBBITCOIN_CONSENSUS) \ + $(LIBBITCOIN_CRYPTO) \ + $(LIBBITCOIN_CRYPTO_SSE41) \ + $(LIBBITCOIN_CRYPTO_AVX2) \ + $(LIBBITCOIN_CRYPTO_SHANI) \ + $(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_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) +test_fuzz_blocktransactions_deserialize_LDADD = \ + $(LIBUNIVALUE) \ + $(LIBBITCOIN_SERVER) \ + $(LIBBITCOIN_COMMON) \ + $(LIBBITCOIN_UTIL) \ + $(LIBBITCOIN_CONSENSUS) \ + $(LIBBITCOIN_CRYPTO) \ + $(LIBBITCOIN_CRYPTO_SSE41) \ + $(LIBBITCOIN_CRYPTO_AVX2) \ + $(LIBBITCOIN_CRYPTO_SHANI) \ + $(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_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) +test_fuzz_blocktransactionsrequest_deserialize_LDADD = \ + $(LIBUNIVALUE) \ + $(LIBBITCOIN_SERVER) \ + $(LIBBITCOIN_COMMON) \ + $(LIBBITCOIN_UTIL) \ + $(LIBBITCOIN_CONSENSUS) \ + $(LIBBITCOIN_CRYPTO) \ + $(LIBBITCOIN_CRYPTO_SSE41) \ + $(LIBBITCOIN_CRYPTO_AVX2) \ + $(LIBBITCOIN_CRYPTO_SHANI) \ + $(LIBSECP256K1) +test_fuzz_blocktransactionsrequest_deserialize_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS) +endif # ENABLE_FUZZ nodist_test_test_bitcoin_SOURCES = $(GENERATED_TEST_FILES) diff --git a/src/addrdb.cpp b/src/addrdb.cpp index 1590bce074..c6083f5554 100644 --- a/src/addrdb.cpp +++ b/src/addrdb.cpp @@ -105,19 +105,18 @@ bool DeserializeFileDB(const fs::path& path, Data& data) } -CBanDB::CBanDB() +CBanDB::CBanDB(fs::path ban_list_path) : m_ban_list_path(std::move(ban_list_path)) { - pathBanlist = GetDataDir() / "banlist.dat"; } bool CBanDB::Write(const banmap_t& banSet) { - return SerializeFileDB("banlist", pathBanlist, banSet); + return SerializeFileDB("banlist", m_ban_list_path, banSet); } bool CBanDB::Read(banmap_t& banSet) { - return DeserializeFileDB(pathBanlist, banSet); + return DeserializeFileDB(m_ban_list_path, banSet); } CAddrDB::CAddrDB() diff --git a/src/addrdb.h b/src/addrdb.h index 90eca44bdb..290b63dd12 100644 --- a/src/addrdb.h +++ b/src/addrdb.h @@ -43,6 +43,11 @@ public: nCreateTime = nCreateTimeIn; } + explicit CBanEntry(int64_t n_create_time_in, BanReason ban_reason_in) : CBanEntry(n_create_time_in) + { + banReason = ban_reason_in; + } + ADD_SERIALIZE_METHODS; template <typename Stream, typename Operation> @@ -92,9 +97,9 @@ public: class CBanDB { private: - fs::path pathBanlist; + const fs::path m_ban_list_path; public: - CBanDB(); + explicit CBanDB(fs::path ban_list_path); bool Write(const banmap_t& banSet); bool Read(banmap_t& banSet); }; diff --git a/src/addrman.h b/src/addrman.h index af5a1d3b23..003bd059f8 100644 --- a/src/addrman.h +++ b/src/addrman.h @@ -23,33 +23,31 @@ */ class CAddrInfo : public CAddress { - - public: //! last try whatsoever by us (memory only) - int64_t nLastTry; + int64_t nLastTry{0}; //! last counted attempt (memory only) - int64_t nLastCountAttempt; + int64_t nLastCountAttempt{0}; private: //! where knowledge about this address first came from CNetAddr source; //! last successful connection by us - int64_t nLastSuccess; + int64_t nLastSuccess{0}; //! connection attempts since last successful attempt - int nAttempts; + int nAttempts{0}; //! reference count in new sets (memory only) - int nRefCount; + int nRefCount{0}; //! in tried set? (memory only) - bool fInTried; + bool fInTried{false}; //! position in vRandom - int nRandomPos; + int nRandomPos{-1}; friend class CAddrMan; @@ -65,25 +63,12 @@ public: READWRITE(nAttempts); } - void Init() - { - nLastSuccess = 0; - nLastTry = 0; - nLastCountAttempt = 0; - nAttempts = 0; - nRefCount = 0; - fInTried = false; - nRandomPos = -1; - } - CAddrInfo(const CAddress &addrIn, const CNetAddr &addrSource) : CAddress(addrIn), source(addrSource) { - Init(); } CAddrInfo() : CAddress(), source() { - Init(); } //! Calculate in which "tried" bucket this entry belongs @@ -106,7 +91,6 @@ public: //! Calculate the relative chance this entry should be given when selecting nodes to connect to double GetChance(int64_t nNow = GetAdjustedTime()) const; - }; /** Stochastic address manager diff --git a/src/banman.cpp b/src/banman.cpp new file mode 100644 index 0000000000..47d64a8f31 --- /dev/null +++ b/src/banman.cpp @@ -0,0 +1,220 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2017 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 <banman.h> + +#include <netaddress.h> +#include <ui_interface.h> +#include <util/system.h> +#include <util/time.h> + + +BanMan::BanMan(fs::path ban_file, CClientUIInterface* client_interface, int64_t default_ban_time) + : m_client_interface(client_interface), m_ban_db(std::move(ban_file)), m_default_ban_time(default_ban_time) +{ + if (m_client_interface) m_client_interface->InitMessage(_("Loading banlist...")); + + int64_t n_start = GetTimeMillis(); + m_is_dirty = false; + banmap_t banmap; + if (m_ban_db.Read(banmap)) { + SetBanned(banmap); // thread save setter + SetBannedSetDirty(false); // no need to write down, just read data + SweepBanned(); // sweep out unused entries + + LogPrint(BCLog::NET, "Loaded %d banned node ips/subnets from banlist.dat %dms\n", + banmap.size(), GetTimeMillis() - n_start); + } else { + LogPrintf("Invalid or missing banlist.dat; recreating\n"); + SetBannedSetDirty(true); // force write + DumpBanlist(); + } +} + +BanMan::~BanMan() +{ + DumpBanlist(); +} + +void BanMan::DumpBanlist() +{ + SweepBanned(); // clean unused entries (if bantime has expired) + + if (!BannedSetIsDirty()) return; + + int64_t n_start = GetTimeMillis(); + + banmap_t banmap; + GetBanned(banmap); + if (m_ban_db.Write(banmap)) { + SetBannedSetDirty(false); + } + + LogPrint(BCLog::NET, "Flushed %d banned node ips/subnets to banlist.dat %dms\n", + banmap.size(), GetTimeMillis() - n_start); +} + +void BanMan::ClearBanned() +{ + { + LOCK(m_cs_banned); + m_banned.clear(); + m_is_dirty = true; + } + DumpBanlist(); //store banlist to disk + if (m_client_interface) m_client_interface->BannedListChanged(); +} + +int BanMan::IsBannedLevel(CNetAddr net_addr) +{ + // Returns the most severe level of banning that applies to this address. + // 0 - Not banned + // 1 - Automatic misbehavior ban + // 2 - Any other ban + int level = 0; + auto current_time = GetTime(); + LOCK(m_cs_banned); + for (const auto& it : m_banned) { + CSubNet sub_net = it.first; + CBanEntry ban_entry = it.second; + + if (current_time < ban_entry.nBanUntil && sub_net.Match(net_addr)) { + if (ban_entry.banReason != BanReasonNodeMisbehaving) return 2; + level = 1; + } + } + return level; +} + +bool BanMan::IsBanned(CNetAddr net_addr) +{ + auto current_time = GetTime(); + LOCK(m_cs_banned); + for (const auto& it : m_banned) { + CSubNet sub_net = it.first; + CBanEntry ban_entry = it.second; + + if (current_time < ban_entry.nBanUntil && sub_net.Match(net_addr)) { + return true; + } + } + return false; +} + +bool BanMan::IsBanned(CSubNet sub_net) +{ + auto current_time = GetTime(); + LOCK(m_cs_banned); + banmap_t::iterator i = m_banned.find(sub_net); + if (i != m_banned.end()) { + CBanEntry ban_entry = (*i).second; + if (current_time < ban_entry.nBanUntil) { + return true; + } + } + return false; +} + +void BanMan::Ban(const CNetAddr& net_addr, const BanReason& ban_reason, int64_t ban_time_offset, bool since_unix_epoch) +{ + CSubNet sub_net(net_addr); + Ban(sub_net, ban_reason, ban_time_offset, since_unix_epoch); +} + +void BanMan::Ban(const CSubNet& sub_net, const BanReason& ban_reason, int64_t ban_time_offset, bool since_unix_epoch) +{ + CBanEntry ban_entry(GetTime(), ban_reason); + + int64_t normalized_ban_time_offset = ban_time_offset; + bool normalized_since_unix_epoch = since_unix_epoch; + if (ban_time_offset <= 0) { + normalized_ban_time_offset = m_default_ban_time; + normalized_since_unix_epoch = false; + } + ban_entry.nBanUntil = (normalized_since_unix_epoch ? 0 : GetTime()) + normalized_ban_time_offset; + + { + LOCK(m_cs_banned); + if (m_banned[sub_net].nBanUntil < ban_entry.nBanUntil) { + m_banned[sub_net] = ban_entry; + m_is_dirty = true; + } else + return; + } + if (m_client_interface) m_client_interface->BannedListChanged(); + + //store banlist to disk immediately if user requested ban + if (ban_reason == BanReasonManuallyAdded) DumpBanlist(); +} + +bool BanMan::Unban(const CNetAddr& net_addr) +{ + CSubNet sub_net(net_addr); + return Unban(sub_net); +} + +bool BanMan::Unban(const CSubNet& sub_net) +{ + { + LOCK(m_cs_banned); + if (m_banned.erase(sub_net) == 0) return false; + m_is_dirty = true; + } + if (m_client_interface) m_client_interface->BannedListChanged(); + DumpBanlist(); //store banlist to disk immediately + return true; +} + +void BanMan::GetBanned(banmap_t& banmap) +{ + LOCK(m_cs_banned); + // Sweep the banlist so expired bans are not returned + SweepBanned(); + banmap = m_banned; //create a thread safe copy +} + +void BanMan::SetBanned(const banmap_t& banmap) +{ + LOCK(m_cs_banned); + m_banned = banmap; + m_is_dirty = true; +} + +void BanMan::SweepBanned() +{ + int64_t now = GetTime(); + bool notify_ui = false; + { + LOCK(m_cs_banned); + banmap_t::iterator it = m_banned.begin(); + while (it != m_banned.end()) { + CSubNet sub_net = (*it).first; + CBanEntry ban_entry = (*it).second; + if (now > ban_entry.nBanUntil) { + m_banned.erase(it++); + m_is_dirty = true; + notify_ui = true; + LogPrint(BCLog::NET, "%s: Removed banned node ip/subnet from banlist.dat: %s\n", __func__, sub_net.ToString()); + } else + ++it; + } + } + // update UI + if (notify_ui && m_client_interface) { + m_client_interface->BannedListChanged(); + } +} + +bool BanMan::BannedSetIsDirty() +{ + LOCK(m_cs_banned); + return m_is_dirty; +} + +void BanMan::SetBannedSetDirty(bool dirty) +{ + LOCK(m_cs_banned); //reuse m_banned lock for the m_is_dirty flag + m_is_dirty = dirty; +} diff --git a/src/banman.h b/src/banman.h new file mode 100644 index 0000000000..a1a00309dd --- /dev/null +++ b/src/banman.h @@ -0,0 +1,70 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2017 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +#ifndef BITCOIN_BANMAN_H +#define BITCOIN_BANMAN_H + +#include <cstdint> +#include <memory> + +#include <addrdb.h> +#include <fs.h> +#include <sync.h> + +// NOTE: When adjusting this, update rpcnet:setban's help ("24h") +static constexpr unsigned int DEFAULT_MISBEHAVING_BANTIME = 60 * 60 * 24; // Default 24-hour ban + +class CClientUIInterface; +class CNetAddr; +class CSubNet; + +// Denial-of-service detection/prevention +// The idea is to detect peers that are behaving +// badly and disconnect/ban them, but do it in a +// one-coding-mistake-won't-shatter-the-entire-network +// way. +// IMPORTANT: There should be nothing I can give a +// node that it will forward on that will make that +// node's peers drop it. If there is, an attacker +// can isolate a node and/or try to split the network. +// Dropping a node for sending stuff that is invalid +// now but might be valid in a later version is also +// dangerous, because it can cause a network split +// between nodes running old code and nodes running +// new code. + +class BanMan +{ +public: + ~BanMan(); + BanMan(fs::path ban_file, CClientUIInterface* client_interface, int64_t default_ban_time); + void Ban(const CNetAddr& net_addr, const BanReason& ban_reason, int64_t ban_time_offset = 0, bool since_unix_epoch = false); + void Ban(const CSubNet& sub_net, const BanReason& ban_reason, int64_t ban_time_offset = 0, bool since_unix_epoch = false); + void ClearBanned(); + int IsBannedLevel(CNetAddr net_addr); + bool IsBanned(CNetAddr net_addr); + bool IsBanned(CSubNet sub_net); + bool Unban(const CNetAddr& net_addr); + bool Unban(const CSubNet& sub_net); + void GetBanned(banmap_t& banmap); + void DumpBanlist(); + +private: + void SetBanned(const banmap_t& banmap); + bool BannedSetIsDirty(); + //!set the "dirty" flag for the banlist + void SetBannedSetDirty(bool dirty = true); + //!clean unused entries (if bantime has expired) + void SweepBanned(); + + CCriticalSection m_cs_banned; + banmap_t m_banned GUARDED_BY(m_cs_banned); + bool m_is_dirty GUARDED_BY(m_cs_banned); + CClientUIInterface* m_client_interface = nullptr; + CBanDB m_ban_db; + const int64_t m_default_ban_time; +}; + +extern std::unique_ptr<BanMan> g_banman; +#endif diff --git a/src/bench/bench_bitcoin.cpp b/src/bench/bench_bitcoin.cpp index 32faba86b4..b804a84478 100644 --- a/src/bench/bench_bitcoin.cpp +++ b/src/bench/bench_bitcoin.cpp @@ -6,7 +6,6 @@ #include <crypto/sha256.h> #include <key.h> -#include <random.h> #include <util/system.h> #include <util/strencodings.h> #include <validation.h> @@ -67,7 +66,6 @@ int main(int argc, char** argv) const fs::path bench_datadir{SetDataDir()}; SHA256AutoDetect(); - RandomInit(); ECC_Start(); SetupEnvironment(); diff --git a/src/bench/mempool_eviction.cpp b/src/bench/mempool_eviction.cpp index 49ea6e88b5..ac8a182358 100644 --- a/src/bench/mempool_eviction.cpp +++ b/src/bench/mempool_eviction.cpp @@ -9,7 +9,7 @@ #include <list> #include <vector> -static void AddTx(const CTransactionRef& tx, const CAmount& nFee, CTxMemPool& pool) EXCLUSIVE_LOCKS_REQUIRED(pool.cs) +static void AddTx(const CTransactionRef& tx, const CAmount& nFee, CTxMemPool& pool) EXCLUSIVE_LOCKS_REQUIRED(cs_main, pool.cs) { int64_t nTime = 0; unsigned int nHeight = 1; @@ -108,7 +108,7 @@ static void MempoolEviction(benchmark::State& state) tx7.vout[1].nValue = 10 * COIN; CTxMemPool pool; - LOCK(pool.cs); + LOCK2(cs_main, pool.cs); // Create transaction references outside the "hot loop" const CTransactionRef tx1_r{MakeTransactionRef(tx1)}; const CTransactionRef tx2_r{MakeTransactionRef(tx2)}; diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp index 2e41adc276..9d1309cde3 100644 --- a/src/bitcoin-tx.cpp +++ b/src/bitcoin-tx.cpp @@ -62,7 +62,7 @@ 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); @@ -818,7 +818,7 @@ static int CommandLineRawTx(int argc, char* argv[]) MutateTx(tx, key, value); } - OutputTx(tx); + OutputTx(CTransaction(tx)); } catch (const std::exception& e) { strPrint = std::string("error: ") + e.what(); diff --git a/src/bitcoin-wallet-res.rc b/src/bitcoin-wallet-res.rc new file mode 100644 index 0000000000..e9fa2dbb40 --- /dev/null +++ b/src/bitcoin-wallet-res.rc @@ -0,0 +1,35 @@ +#include <windows.h> // needed for VERSIONINFO +#include "clientversion.h" // holds the needed client version information + +#define VER_PRODUCTVERSION CLIENT_VERSION_MAJOR,CLIENT_VERSION_MINOR,CLIENT_VERSION_REVISION,CLIENT_VERSION_BUILD +#define VER_PRODUCTVERSION_STR STRINGIZE(CLIENT_VERSION_MAJOR) "." STRINGIZE(CLIENT_VERSION_MINOR) "." STRINGIZE(CLIENT_VERSION_REVISION) "." STRINGIZE(CLIENT_VERSION_BUILD) +#define VER_FILEVERSION VER_PRODUCTVERSION +#define VER_FILEVERSION_STR VER_PRODUCTVERSION_STR + +VS_VERSION_INFO VERSIONINFO +FILEVERSION VER_FILEVERSION +PRODUCTVERSION VER_PRODUCTVERSION +FILEOS VOS_NT_WINDOWS32 +FILETYPE VFT_APP +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904E4" // U.S. English - multilingual (hex) + BEGIN + VALUE "CompanyName", "Bitcoin" + VALUE "FileDescription", "bitcoin-wallet (CLI tool for " PACKAGE_NAME " wallets)" + VALUE "FileVersion", VER_FILEVERSION_STR + VALUE "InternalName", "bitcoin-wallet" + VALUE "LegalCopyright", COPYRIGHT_STR + VALUE "LegalTrademarks1", "Distributed under the MIT software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php." + VALUE "OriginalFilename", "bitcoin-wallet.exe" + VALUE "ProductName", "bitcoin-wallet" + VALUE "ProductVersion", VER_PRODUCTVERSION_STR + END + END + + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1252 // language neutral - multilingual (decimal) + END +END diff --git a/src/bitcoin-wallet.cpp b/src/bitcoin-wallet.cpp new file mode 100644 index 0000000000..11caa0dc6c --- /dev/null +++ b/src/bitcoin-wallet.cpp @@ -0,0 +1,121 @@ +// Copyright (c) 2016-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. + +#if defined(HAVE_CONFIG_H) +#include <config/bitcoin-config.h> +#endif + +#include <chainparams.h> +#include <chainparamsbase.h> +#include <consensus/consensus.h> +#include <logging.h> +#include <util/system.h> +#include <util/strencodings.h> +#include <wallet/wallettool.h> + +#include <stdio.h> + +const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr; + +static void SetupWalletToolArgs() +{ + 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); + gArgs.AddArg("-printtoconsole", "Send trace/debug info to console (default: 1 when no -debug is true, 0 otherwise.", false, OptionsCategory::DEBUG_TEST); + + 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[]) +{ + SetupWalletToolArgs(); + std::string error_message; + if (!gArgs.ParseParameters(argc, argv, error_message)) { + fprintf(stderr, "Error parsing command line arguments: %s\n", error_message.c_str()); + return false; + } + if (argc < 2 || HelpRequested(gArgs)) { + std::string usage = strprintf("%s bitcoin-wallet version", PACKAGE_NAME) + " " + FormatFullVersion() + "\n\n" + + "wallet-tool is an offline tool for creating and interacting with Bitcoin Core wallet files.\n" + + "By default wallet-tool will act on wallets in the default mainnet wallet directory in the datadir.\n" + + "To change the target wallet, use the -datadir, -wallet and -testnet/-regtest arguments.\n\n" + + "Usage:\n" + + " bitcoin-wallet [options] <command>\n\n" + + gArgs.GetHelpMessage(); + + fprintf(stdout, "%s", usage.c_str()); + return false; + } + + // check for printtoconsole, allow -debug + 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()); + return false; + } + // Check for -testnet or -regtest parameter (Params() calls are only valid after this clause) + SelectParams(gArgs.GetChainName()); + + return true; +} + +int main(int argc, char* argv[]) +{ +#ifdef WIN32 + util::WinCmdLineArgs winArgs; + std::tie(argc, argv) = winArgs.get(); +#endif + SetupEnvironment(); + RandomInit(); + try { + if (!WalletAppInit(argc, argv)) return EXIT_FAILURE; + } catch (const std::exception& e) { + PrintExceptionContinue(&e, "WalletAppInit()"); + return EXIT_FAILURE; + } catch (...) { + PrintExceptionContinue(nullptr, "WalletAppInit()"); + return EXIT_FAILURE; + } + + std::string method {}; + for(int i = 1; i < argc; ++i) { + if (!IsSwitchChar(argv[i][0])) { + if (!method.empty()) { + fprintf(stderr, "Error: two methods provided (%s and %s). Only one method should be provided.\n", method.c_str(), argv[i]); + return EXIT_FAILURE; + } + method = argv[i]; + } + } + + if (method.empty()) { + fprintf(stderr, "No method provided. Run `bitcoin-wallet -help` for valid methods.\n"); + return EXIT_FAILURE; + } + + // A name must be provided when creating a file + if (method == "create" && !gArgs.IsArgSet("-wallet")) { + fprintf(stderr, "Wallet name must be provided when creating a new wallet.\n"); + return EXIT_FAILURE; + } + + std::string name = gArgs.GetArg("-wallet", ""); + + ECCVerifyHandle globalVerifyHandle; + ECC_Start(); + if (!WalletTool::ExecuteWalletToolFunc(method, name)) + return EXIT_FAILURE; + ECC_Stop(); + return EXIT_SUCCESS; +} diff --git a/src/chain.h b/src/chain.h index 3b786664af..5a6f10b84f 100644 --- a/src/chain.h +++ b/src/chain.h @@ -18,7 +18,7 @@ * Maximum amount of time that a block timestamp is allowed to exceed the * current network-adjusted time before the block will be accepted. */ -static const int64_t MAX_FUTURE_BLOCK_TIME = 2 * 60 * 60; +static constexpr int64_t MAX_FUTURE_BLOCK_TIME = 2 * 60 * 60; /** * Timestamp window used as a grace period by code that compares external @@ -26,7 +26,15 @@ static const int64_t MAX_FUTURE_BLOCK_TIME = 2 * 60 * 60; * to block timestamps. This should be set at least as high as * MAX_FUTURE_BLOCK_TIME. */ -static const int64_t TIMESTAMP_WINDOW = MAX_FUTURE_BLOCK_TIME; +static constexpr int64_t TIMESTAMP_WINDOW = MAX_FUTURE_BLOCK_TIME; + +/** + * Maximum gap between node time and block time used + * for the "Catching up..." mode in GUI. + * + * Ref: https://github.com/bitcoin/bitcoin/pull/1026 + */ +static constexpr int64_t MAX_BLOCK_TIME_GAP = 90 * 60; class CBlockFileInfo { diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 4ce1b53880..d3972fdb89 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -107,6 +107,8 @@ public: pchMessageStart[3] = 0xd9; nDefaultPort = 8333; nPruneAfterHeight = 100000; + m_assumed_blockchain_size = 200; + m_assumed_chain_state_size = 3; genesis = CreateGenesisBlock(1231006505, 2083236893, 0x1d00ffff, 1, 50 * COIN); consensus.hashGenesisBlock = genesis.GetHash(); @@ -125,6 +127,7 @@ public: vSeeds.emplace_back("seed.bitcoin.jonasschnelli.ch"); // Jonas Schnelli, only supports x1, x5, x9, and xd vSeeds.emplace_back("seed.btc.petertodd.org"); // Peter Todd, only supports x1, x5, x9, and xd vSeeds.emplace_back("seed.bitcoin.sprovoost.nl"); // Sjors Provoost + vSeeds.emplace_back("dnsseed.emzy.de"); // Stephan Oeste base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,0); base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,5); @@ -216,6 +219,8 @@ public: pchMessageStart[3] = 0x07; nDefaultPort = 18333; nPruneAfterHeight = 1000; + m_assumed_blockchain_size = 20; + m_assumed_chain_state_size = 2; genesis = CreateGenesisBlock(1296688602, 414098458, 0x1d00ffff, 1, 50 * COIN); consensus.hashGenesisBlock = genesis.GetHash(); @@ -272,10 +277,10 @@ public: strNetworkID = "regtest"; consensus.nSubsidyHalvingInterval = 150; consensus.BIP16Exception = uint256(); - consensus.BIP34Height = 100000000; // BIP34 has not activated on regtest (far in the future so block v1 are not rejected in tests) + consensus.BIP34Height = 500; // BIP34 activated on regtest (Used in functional tests) consensus.BIP34Hash = uint256(); - consensus.BIP65Height = 1351; // BIP65 activated on regtest (Used in rpc activation tests) - consensus.BIP66Height = 1251; // BIP66 activated on regtest (Used in rpc activation tests) + consensus.BIP65Height = 1351; // BIP65 activated on regtest (Used in functional tests) + consensus.BIP66Height = 1251; // BIP66 activated on regtest (Used in functional tests) consensus.powLimit = uint256S("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks consensus.nPowTargetSpacing = 10 * 60; @@ -305,6 +310,8 @@ public: pchMessageStart[3] = 0xda; nDefaultPort = 18444; nPruneAfterHeight = 1000; + m_assumed_blockchain_size = 0; + m_assumed_chain_state_size = 0; UpdateVersionBitsParametersFromArgs(args); diff --git a/src/chainparams.h b/src/chainparams.h index 19818b40af..6ff3dbb7e5 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -67,6 +67,10 @@ public: /** Policy: Filter transactions that do not match well-defined patterns */ bool RequireStandard() const { return fRequireStandard; } uint64_t PruneAfterHeight() const { return nPruneAfterHeight; } + /** Minimum free space (in GB) needed for data directory */ + uint64_t AssumedBlockchainSize() const { return m_assumed_blockchain_size; } + /** Minimum free space (in GB) needed for data directory when pruned; Does not include prune target*/ + uint64_t AssumedChainStateSize() const { return m_assumed_chain_state_size; } /** Make miner stop after a block is found. In RPC, don't return until nGenProcLimit blocks are generated */ bool MineBlocksOnDemand() const { return fMineBlocksOnDemand; } /** Return the BIP70 network string (main, test or regtest) */ @@ -87,6 +91,8 @@ protected: CMessageHeader::MessageStartChars pchMessageStart; int nDefaultPort; uint64_t nPruneAfterHeight; + uint64_t m_assumed_blockchain_size; + uint64_t m_assumed_chain_state_size; std::vector<std::string> vSeeds; std::vector<unsigned char> base58Prefixes[MAX_BASE58_TYPES]; std::string bech32_hrp; diff --git a/src/coins.h b/src/coins.h index 94493453f0..d39ebf9062 100644 --- a/src/coins.h +++ b/src/coins.h @@ -298,17 +298,17 @@ private: }; //! Utility function to add all of a transaction's outputs to a cache. -// When check is false, this assumes that overwrites are only possible for coinbase transactions. -// When check is true, the underlying view may be queried to determine whether an addition is -// an overwrite. +//! When check is false, this assumes that overwrites are only possible for coinbase transactions. +//! When check is true, the underlying view may be queried to determine whether an addition is +//! an overwrite. // TODO: pass in a boolean to limit these possible overwrites to known // (pre-BIP34) cases. void AddCoins(CCoinsViewCache& cache, const CTransaction& tx, int nHeight, bool check = false); //! Utility function to find any unspent output with a given txid. -// This function can be quite expensive because in the event of a transaction -// which is not found in the cache, it can cause up to MAX_OUTPUTS_PER_BLOCK -// lookups to database, so it should be used with care. +//! This function can be quite expensive because in the event of a transaction +//! which is not found in the cache, it can cause up to MAX_OUTPUTS_PER_BLOCK +//! lookups to database, so it should be used with care. const Coin& AccessByTxid(const CCoinsViewCache& cache, const uint256& txid); #endif // BITCOIN_COINS_H 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/crypto/sha512.h b/src/crypto/sha512.h index cd1023bc85..4118ac1b18 100644 --- a/src/crypto/sha512.h +++ b/src/crypto/sha512.h @@ -17,7 +17,7 @@ private: uint64_t bytes; public: - static const size_t OUTPUT_SIZE = 64; + static constexpr size_t OUTPUT_SIZE = 64; CSHA512(); CSHA512& Write(const unsigned char* data, size_t len); diff --git a/src/httpserver.cpp b/src/httpserver.cpp index cb8578927a..b9ca037c9d 100644 --- a/src/httpserver.cpp +++ b/src/httpserver.cpp @@ -124,7 +124,6 @@ public: struct HTTPPathHandler { - HTTPPathHandler() {} HTTPPathHandler(std::string _prefix, bool _exactMatch, HTTPRequestHandler _handler): prefix(_prefix), exactMatch(_exactMatch), handler(_handler) { @@ -365,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/index/base.cpp b/src/index/base.cpp index 4d4a7e1502..f6f59572ce 100644 --- a/src/index/base.cpp +++ b/src/index/base.cpp @@ -60,7 +60,11 @@ bool BaseIndex::Init() } LOCK(cs_main); - m_best_block_index = FindForkInGlobalIndex(chainActive, locator); + if (locator.IsNull()) { + m_best_block_index = nullptr; + } else { + m_best_block_index = FindForkInGlobalIndex(chainActive, locator); + } m_synced = m_best_block_index.load() == chainActive.Tip(); return true; } diff --git a/src/index/txindex.cpp b/src/index/txindex.cpp index ba1c44765f..10bc8419dd 100644 --- a/src/index/txindex.cpp +++ b/src/index/txindex.cpp @@ -245,6 +245,9 @@ bool TxIndex::Init() bool TxIndex::WriteBlock(const CBlock& block, const CBlockIndex* pindex) { + // Exclude genesis block transaction because outputs are not spendable. + if (pindex->nHeight == 0) return true; + CDiskTxPos pos(pindex->GetBlockPos(), GetSizeOfCompactSize(block.vtx.size())); std::vector<std::pair<uint256, CDiskTxPos>> vPos; vPos.reserve(block.vtx.size()); diff --git a/src/init.cpp b/src/init.cpp index 18c145a023..8fcf94b49b 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -11,6 +11,7 @@ #include <addrman.h> #include <amount.h> +#include <banman.h> #include <chain.h> #include <chainparams.h> #include <checkpoints.h> @@ -73,8 +74,12 @@ static const bool DEFAULT_PROXYRANDOMIZE = true; static const bool DEFAULT_REST_ENABLE = false; static const bool DEFAULT_STOPAFTERBLOCKIMPORT = false; +// Dump addresses to banlist.dat every 15 minutes (900s) +static constexpr int DUMP_BANS_INTERVAL = 60 * 15; + std::unique_ptr<CConnman> g_connman; std::unique_ptr<PeerLogicValidation> peerLogic; +std::unique_ptr<BanMan> g_banman; #ifdef WIN32 // Win32 LevelDB doesn't use filedescriptors, and the ones used for @@ -199,6 +204,7 @@ void Shutdown(InitInterfaces& interfaces) // destruct and reset all to nullptr. peerLogic.reset(); g_connman.reset(); + g_banman.reset(); g_txindex.reset(); if (g_is_mempool_loaded && gArgs.GetArg("-persistmempool", DEFAULT_PERSIST_MEMPOOL)) { @@ -261,10 +267,10 @@ void Shutdown(InitInterfaces& interfaces) LogPrintf("%s: Unable to remove pidfile: %s\n", __func__, e.what()); } #endif + interfaces.chain_clients.clear(); UnregisterAllValidationInterfaces(); GetMainSignals().UnregisterBackgroundSignalScheduler(); GetMainSignals().UnregisterWithMempoolSignals(mempool); - interfaces.chain_clients.clear(); globalVerifyHandle.reset(); ECC_Stop(); LogPrintf("%s: done\n", __func__); @@ -283,7 +289,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) @@ -346,7 +352,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 megabytes (%d to %d, default: %d)", nMinDbCache, nMaxDbCache, nDefaultDbCache), false, 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("-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); @@ -827,17 +833,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); @@ -885,16 +891,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()) @@ -930,7 +927,7 @@ bool AppInitParameterInteraction() // also see: InitParameterInteraction() - if (!fs::is_directory(GetBlocksDir(false))) { + if (!fs::is_directory(GetBlocksDir())) { return InitError(strprintf(_("Specified blocks directory \"%s\" does not exist."), gArgs.GetArg("-blocksdir", "").c_str())); } @@ -975,7 +972,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)); } } @@ -984,7 +981,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)); } } @@ -1055,7 +1052,7 @@ bool AppInitParameterInteraction() if (nPruneTarget < MIN_DISK_SPACE_FOR_BLOCK_FILES) { return InitError(strprintf(_("Prune configured below the minimum of %d MiB. Please use a higher number."), MIN_DISK_SPACE_FOR_BLOCK_FILES / 1024 / 1024)); } - LogPrintf("Prune configured to target %uMiB on disk for block and undo files.\n", nPruneTarget / 1024 / 1024); + LogPrintf("Prune configured to target %u MiB on disk for block and undo files.\n", nPruneTarget / 1024 / 1024); fPruneMode = true; } @@ -1191,19 +1188,19 @@ bool AppInitMain(InitInterfaces& interfaces) #ifndef WIN32 CreatePidFile(GetPidFile(), getpid()); #endif - if (g_logger->m_print_to_file) { - if (gArgs.GetBoolArg("-shrinkdebugfile", g_logger->DefaultShrinkDebugFile())) { + 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()); @@ -1290,11 +1287,12 @@ bool AppInitMain(InitInterfaces& interfaces) // is not yet setup and may end up being set up twice if we // need to reindex later. + assert(!g_banman); + g_banman = MakeUnique<BanMan>(GetDataDir() / "banlist.dat", &uiInterface, gArgs.GetArg("-bantime", DEFAULT_MISBEHAVING_BANTIME)); assert(!g_connman); g_connman = std::unique_ptr<CConnman>(new CConnman(GetRand(std::numeric_limits<uint64_t>::max()), GetRand(std::numeric_limits<uint64_t>::max()))); - CConnman& connman = *g_connman; - peerLogic.reset(new PeerLogicValidation(&connman, scheduler, gArgs.GetBoolArg("-enablebip61", DEFAULT_ENABLE_BIP61))); + peerLogic.reset(new PeerLogicValidation(g_connman.get(), g_banman.get(), scheduler, gArgs.GetBoolArg("-enablebip61", DEFAULT_ENABLE_BIP61))); RegisterValidationInterface(peerLogic.get()); // sanitize comments per BIP-0014, format user agent and check total size @@ -1321,7 +1319,7 @@ bool AppInitMain(InitInterfaces& interfaces) for (int n = 0; n < NET_MAX; n++) { enum Network net = (enum Network)n; if (!nets.count(net)) - SetLimited(net); + SetReachable(net, false); } } @@ -1332,7 +1330,7 @@ bool AppInitMain(InitInterfaces& interfaces) // -proxy sets a proxy for all outgoing network traffic // -noproxy (or -proxy=0) as well as the empty string can be used to not set a proxy, this is the default std::string proxyArg = gArgs.GetArg("-proxy", ""); - SetLimited(NET_ONION); + SetReachable(NET_ONION, false); if (proxyArg != "" && proxyArg != "0") { CService proxyAddr; if (!Lookup(proxyArg.c_str(), proxyAddr, 9050, fNameLookup)) { @@ -1347,7 +1345,7 @@ bool AppInitMain(InitInterfaces& interfaces) SetProxy(NET_IPV6, addrProxy); SetProxy(NET_ONION, addrProxy); SetNameProxy(addrProxy); - SetLimited(NET_ONION, false); // by default, -proxy sets onion as reachable, unless -noonion later + SetReachable(NET_ONION, true); // by default, -proxy sets onion as reachable, unless -noonion later } // -onion can be used to set only a proxy for .onion, or override normal proxy for .onion addresses @@ -1356,7 +1354,7 @@ bool AppInitMain(InitInterfaces& interfaces) std::string onionArg = gArgs.GetArg("-onion", ""); if (onionArg != "") { if (onionArg == "0") { // Handle -noonion/-onion=0 - SetLimited(NET_ONION); // set onions as unreachable + SetReachable(NET_ONION, false); } else { CService onionProxy; if (!Lookup(onionArg.c_str(), onionProxy, 9050, fNameLookup)) { @@ -1366,7 +1364,7 @@ bool AppInitMain(InitInterfaces& interfaces) if (!addrOnion.IsValid()) return InitError(strprintf(_("Invalid -onion address or hostname: '%s'"), onionArg)); SetProxy(NET_ONION, addrOnion); - SetLimited(NET_ONION, false); + SetReachable(NET_ONION, true); } } @@ -1416,12 +1414,12 @@ bool AppInitMain(InitInterfaces& interfaces) nCoinCacheUsage = nTotalCache; // the rest goes to in-memory cache int64_t nMempoolSizeMax = gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000; LogPrintf("Cache configuration:\n"); - LogPrintf("* Using %.1fMiB for block index database\n", nBlockTreeDBCache * (1.0 / 1024 / 1024)); + LogPrintf("* Using %.1f MiB for block index database\n", nBlockTreeDBCache * (1.0 / 1024 / 1024)); if (gArgs.GetBoolArg("-txindex", DEFAULT_TXINDEX)) { - LogPrintf("* Using %.1fMiB for transaction index database\n", nTxIndexCache * (1.0 / 1024 / 1024)); + LogPrintf("* Using %.1f MiB for transaction index database\n", nTxIndexCache * (1.0 / 1024 / 1024)); } - LogPrintf("* Using %.1fMiB for chain state database\n", nCoinDBCache * (1.0 / 1024 / 1024)); - LogPrintf("* Using %.1fMiB for in-memory UTXO set (plus up to %.1fMiB of unused mempool space)\n", nCoinCacheUsage * (1.0 / 1024 / 1024), nMempoolSizeMax * (1.0 / 1024 / 1024)); + LogPrintf("* Using %.1f MiB for chain state database\n", nCoinDBCache * (1.0 / 1024 / 1024)); + LogPrintf("* Using %.1f MiB for in-memory UTXO set (plus up to %.1f MiB of unused mempool space)\n", nCoinCacheUsage * (1.0 / 1024 / 1024), nMempoolSizeMax * (1.0 / 1024 / 1024)); bool fLoaded = false; while (!fLoaded && !ShutdownRequested()) { @@ -1631,8 +1629,14 @@ bool AppInitMain(InitInterfaces& interfaces) // ********************************************************* Step 11: import blocks - if (!CheckDiskSpace() && !CheckDiskSpace(0, true)) + if (!CheckDiskSpace(/* additional_bytes */ 0, /* blocks_dir */ false)) { + InitError(strprintf(_("Error: Disk space is low for %s"), GetDataDir())); return false; + } + if (!CheckDiskSpace(/* additional_bytes */ 0, /* blocks_dir */ true)) { + InitError(strprintf(_("Error: Disk space is low for %s"), GetBlocksDir())); + return false; + } // Either install a handler to notify us when genesis activates, or set fHaveGenesis directly. // No locking, as this happens before any background thread is started. @@ -1698,6 +1702,7 @@ bool AppInitMain(InitInterfaces& interfaces) connOptions.nMaxFeeler = 1; connOptions.nBestHeight = chain_active_height; connOptions.uiInterface = &uiInterface; + connOptions.m_banman = g_banman.get(); connOptions.m_msgproc = peerLogic.get(); connOptions.nSendBufferMaxSize = 1000*gArgs.GetArg("-maxsendbuffer", DEFAULT_MAXSENDBUFFER); connOptions.nReceiveFloodSize = 1000*gArgs.GetArg("-maxreceivebuffer", DEFAULT_MAXRECEIVEBUFFER); @@ -1743,7 +1748,7 @@ bool AppInitMain(InitInterfaces& interfaces) connOptions.m_specified_outgoing = connect; } } - if (!connman.Start(scheduler, connOptions)) { + if (!g_connman->Start(scheduler, connOptions)) { return false; } @@ -1756,5 +1761,9 @@ bool AppInitMain(InitInterfaces& interfaces) client->start(scheduler); } + scheduler.scheduleEvery([]{ + g_banman->DumpBanlist(); + }, DUMP_BANS_INTERVAL * 1000); + return true; } diff --git a/src/interfaces/chain.cpp b/src/interfaces/chain.cpp index 2571a91031..da810bc5e6 100644 --- a/src/interfaces/chain.cpp +++ b/src/interfaces/chain.cpp @@ -4,7 +4,11 @@ #include <interfaces/chain.h> +#include <chain.h> +#include <chainparams.h> +#include <primitives/block.h> #include <sync.h> +#include <uint256.h> #include <util/system.h> #include <validation.h> @@ -16,6 +20,118 @@ namespace { class LockImpl : public Chain::Lock { + Optional<int> getHeight() override + { + int height = ::chainActive.Height(); + if (height >= 0) { + return height; + } + return nullopt; + } + Optional<int> getBlockHeight(const uint256& hash) override + { + CBlockIndex* block = LookupBlockIndex(hash); + if (block && ::chainActive.Contains(block)) { + return block->nHeight; + } + return nullopt; + } + int getBlockDepth(const uint256& hash) override + { + const Optional<int> tip_height = getHeight(); + const Optional<int> height = getBlockHeight(hash); + return tip_height && height ? *tip_height - *height + 1 : 0; + } + uint256 getBlockHash(int height) override + { + CBlockIndex* block = ::chainActive[height]; + assert(block != nullptr); + return block->GetBlockHash(); + } + int64_t getBlockTime(int height) override + { + CBlockIndex* block = ::chainActive[height]; + assert(block != nullptr); + return block->GetBlockTime(); + } + int64_t getBlockMedianTimePast(int height) override + { + CBlockIndex* block = ::chainActive[height]; + assert(block != nullptr); + return block->GetMedianTimePast(); + } + bool haveBlockOnDisk(int height) override + { + CBlockIndex* block = ::chainActive[height]; + return block && ((block->nStatus & BLOCK_HAVE_DATA) != 0) && block->nTx > 0; + } + Optional<int> findFirstBlockWithTime(int64_t time, uint256* hash) override + { + CBlockIndex* block = ::chainActive.FindEarliestAtLeast(time); + if (block) { + if (hash) *hash = block->GetBlockHash(); + return block->nHeight; + } + return nullopt; + } + Optional<int> findFirstBlockWithTimeAndHeight(int64_t time, int height) override + { + // TODO: Could update CChain::FindEarliestAtLeast() to take a height + // parameter and use it with std::lower_bound() to make this + // implementation more efficient and allow combining + // findFirstBlockWithTime and findFirstBlockWithTimeAndHeight into one + // method. + for (CBlockIndex* block = ::chainActive[height]; block; block = ::chainActive.Next(block)) { + if (block->GetBlockTime() >= time) { + return block->nHeight; + } + } + return nullopt; + } + Optional<int> findPruned(int start_height, Optional<int> stop_height) override + { + if (::fPruneMode) { + CBlockIndex* block = stop_height ? ::chainActive[*stop_height] : ::chainActive.Tip(); + while (block && block->nHeight >= start_height) { + if ((block->nStatus & BLOCK_HAVE_DATA) == 0) { + return block->nHeight; + } + block = block->pprev; + } + } + return nullopt; + } + Optional<int> findFork(const uint256& hash, Optional<int>* height) override + { + const CBlockIndex* block = LookupBlockIndex(hash); + const CBlockIndex* fork = block ? ::chainActive.FindFork(block) : nullptr; + if (height) { + if (block) { + *height = block->nHeight; + } else { + height->reset(); + } + } + if (fork) { + return fork->nHeight; + } + return nullopt; + } + bool isPotentialTip(const uint256& hash) override + { + if (::chainActive.Tip()->GetBlockHash() == hash) return true; + CBlockIndex* block = LookupBlockIndex(hash); + return block && block->GetAncestor(::chainActive.Height()) == ::chainActive.Tip(); + } + CBlockLocator getTipLocator() override { return ::chainActive.GetLocator(); } + Optional<int> findLocatorFork(const CBlockLocator& locator) override + { + LockAnnotation lock(::cs_main); + if (CBlockIndex* fork = FindForkInGlobalIndex(::chainActive, locator)) { + return fork->nHeight; + } + return nullopt; + } }; class LockingStateImpl : public LockImpl, public UniqueLock<CCriticalSection> @@ -35,6 +151,32 @@ public: return std::move(result); } std::unique_ptr<Chain::Lock> assumeLocked() override { return MakeUnique<LockImpl>(); } + bool findBlock(const uint256& hash, CBlock* block, int64_t* time, int64_t* time_max) override + { + CBlockIndex* index; + { + LOCK(cs_main); + index = LookupBlockIndex(hash); + if (!index) { + return false; + } + if (time) { + *time = index->GetBlockTime(); + } + if (time_max) { + *time_max = index->GetBlockTimeMax(); + } + } + if (block && !ReadBlockFromDisk(*block, index, Params().GetConsensus())) { + block->SetNull(); + } + return true; + } + double guessVerificationProgress(const uint256& block_hash) override + { + LOCK(cs_main); + return GuessVerificationProgress(Params().TxData(), LookupBlockIndex(block_hash)); + } }; } // namespace diff --git a/src/interfaces/chain.h b/src/interfaces/chain.h index fe5658de4b..3a54b9164e 100644 --- a/src/interfaces/chain.h +++ b/src/interfaces/chain.h @@ -5,11 +5,17 @@ #ifndef BITCOIN_INTERFACES_CHAIN_H #define BITCOIN_INTERFACES_CHAIN_H +#include <optional.h> + #include <memory> +#include <stdint.h> #include <string> #include <vector> +class CBlock; class CScheduler; +class uint256; +struct CBlockLocator; namespace interfaces { @@ -28,6 +34,74 @@ public: { public: virtual ~Lock() {} + + //! Get current chain height, not including genesis block (returns 0 if + //! chain only contains genesis block, nullopt if chain does not contain + //! any blocks). + virtual Optional<int> getHeight() = 0; + + //! Get block height above genesis block. Returns 0 for genesis block, + //! 1 for following block, and so on. Returns nullopt for a block not + //! included in the current chain. + virtual Optional<int> getBlockHeight(const uint256& hash) = 0; + + //! Get block depth. Returns 1 for chain tip, 2 for preceding block, and + //! so on. Returns 0 for a block not included in the current chain. + virtual int getBlockDepth(const uint256& hash) = 0; + + //! Get block hash. Height must be valid or this function will abort. + virtual uint256 getBlockHash(int height) = 0; + + //! Get block time. Height must be valid or this function will abort. + virtual int64_t getBlockTime(int height) = 0; + + //! Get block median time past. Height must be valid or this function + //! will abort. + virtual int64_t getBlockMedianTimePast(int height) = 0; + + //! Check that the block is available on disk (i.e. has not been + //! pruned), and contains transactions. + virtual bool haveBlockOnDisk(int height) = 0; + + //! Return height of the first block in the chain with timestamp equal + //! or greater than the given time, or nullopt if there is no block with + //! a high enough timestamp. Also return the block hash as an optional + //! output parameter (to avoid the cost of a second lookup in case this + //! information is needed.) + virtual Optional<int> findFirstBlockWithTime(int64_t time, uint256* hash) = 0; + + //! Return height of the first block in the chain with timestamp equal + //! or greater than the given time and height equal or greater than the + //! given height, or nullopt if there is no such block. + //! + //! Calling this with height 0 is equivalent to calling + //! findFirstBlockWithTime, but less efficient because it requires a + //! linear instead of a binary search. + virtual Optional<int> findFirstBlockWithTimeAndHeight(int64_t time, int height) = 0; + + //! Return height of last block in the specified range which is pruned, or + //! nullopt if no block in the range is pruned. Range is inclusive. + virtual Optional<int> findPruned(int start_height = 0, Optional<int> stop_height = nullopt) = 0; + + //! Return height of the highest block on the chain that is an ancestor + //! of the specified block, or nullopt if no common ancestor is found. + //! Also return the height of the specified block as an optional output + //! parameter (to avoid the cost of a second hash lookup in case this + //! information is desired). + virtual Optional<int> findFork(const uint256& hash, Optional<int>* height) = 0; + + //! Return true if block hash points to the current chain tip, or to a + //! possible descendant of the current chain tip that isn't currently + //! connected. + virtual bool isPotentialTip(const uint256& hash) = 0; + + //! Get locator for the current chain tip. + 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 + //! locator. + virtual Optional<int> findLocatorFork(const CBlockLocator& locator) = 0; }; //! Return Lock interface. Chain is locked when this is called, and @@ -38,6 +112,21 @@ public: //! method is temporary and is only used in a few places to avoid changing //! behavior while code is transitioned to use the Chain::Lock interface. virtual std::unique_ptr<Lock> assumeLocked() = 0; + + //! Return whether node has the block and optionally return block metadata + //! or contents. + //! + //! If a block pointer is provided to retrieve the block contents, and the + //! block exists but doesn't have data (for example due to pruning), the + //! block will be empty and all fields set to null. + virtual bool findBlock(const uint256& hash, + CBlock* block = nullptr, + int64_t* time = nullptr, + int64_t* max_time = nullptr) = 0; + + //! Estimate fraction of total transactions verified if blocks up to + //! the specified block hash are verified. + virtual double guessVerificationProgress(const uint256& block_hash) = 0; }; //! Interface to let node manage chain clients (wallets, or maybe tools for diff --git a/src/interfaces/node.cpp b/src/interfaces/node.cpp index bd7e414ff3..a2b89c3f90 100644 --- a/src/interfaces/node.cpp +++ b/src/interfaces/node.cpp @@ -6,6 +6,7 @@ #include <addrdb.h> #include <amount.h> +#include <banman.h> #include <chain.h> #include <chainparams.h> #include <init.h> @@ -60,11 +61,13 @@ public: bool softSetArg(const std::string& arg, const std::string& value) override { return gArgs.SoftSetArg(arg, value); } bool softSetBoolArg(const std::string& arg, bool value) override { return gArgs.SoftSetBoolArg(arg, value); } void selectParams(const std::string& network) override { SelectParams(network); } + uint64_t getAssumedBlockchainSize() override { return Params().AssumedBlockchainSize(); } + uint64_t getAssumedChainStateSize() override { return Params().AssumedChainStateSize(); } std::string getNetwork() override { return Params().NetworkIDString(); } 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() && @@ -120,28 +123,35 @@ public: } bool getBanned(banmap_t& banmap) override { - if (g_connman) { - g_connman->GetBanned(banmap); + if (g_banman) { + g_banman->GetBanned(banmap); return true; } return false; } bool ban(const CNetAddr& net_addr, BanReason reason, int64_t ban_time_offset) override { - if (g_connman) { - g_connman->Ban(net_addr, reason, ban_time_offset); + if (g_banman) { + g_banman->Ban(net_addr, reason, ban_time_offset); return true; } return false; } bool unban(const CSubNet& ip) override { - if (g_connman) { - g_connman->Unban(ip); + if (g_banman) { + g_banman->Unban(ip); return true; } return false; } + bool disconnect(const CNetAddr& net_addr) override + { + if (g_connman) { + return g_connman->DisconnectNode(net_addr); + } + return false; + } bool disconnect(NodeId id) override { if (g_connman) { diff --git a/src/interfaces/node.h b/src/interfaces/node.h index 1f8bbbff7a..54c2d78338 100644 --- a/src/interfaces/node.h +++ b/src/interfaces/node.h @@ -18,6 +18,7 @@ #include <tuple> #include <vector> +class BanMan; class CCoinControl; class CFeeRate; class CNodeStats; @@ -52,6 +53,12 @@ public: //! Choose network parameters. virtual void selectParams(const std::string& network) = 0; + //! Get the (assumed) blockchain size. + virtual uint64_t getAssumedBlockchainSize() = 0; + + //! Get the (assumed) chain state size. + virtual uint64_t getAssumedChainStateSize() = 0; + //! Get network name. virtual std::string getNetwork() = 0; @@ -107,7 +114,10 @@ public: //! Unban node. virtual bool unban(const CSubNet& ip) = 0; - //! Disconnect node. + //! Disconnect node by address. + virtual bool disconnect(const CNetAddr& net_addr) = 0; + + //! Disconnect node by id. virtual bool disconnect(NodeId id) = 0; //! Get total bytes recv. diff --git a/src/interfaces/wallet.cpp b/src/interfaces/wallet.cpp index 672a557d41..a2cae2a7a7 100644 --- a/src/interfaces/wallet.cpp +++ b/src/interfaces/wallet.cpp @@ -318,7 +318,8 @@ public: } bool tryGetTxStatus(const uint256& txid, interfaces::WalletTxStatus& tx_status, - int& num_blocks) override + int& num_blocks, + int64_t& block_time) override { auto locked_chain = m_wallet.chain().lock(true /* try_lock */); if (!locked_chain) { @@ -332,7 +333,13 @@ public: if (mi == m_wallet.mapWallet.end()) { return false; } - num_blocks = ::chainActive.Height(); + if (Optional<int> height = locked_chain->getHeight()) { + num_blocks = *height; + block_time = locked_chain->getBlockTime(*height); + } else { + num_blocks = -1; + block_time = -1; + } tx_status = MakeWalletTxStatus(*locked_chain, mi->second); return true; } @@ -346,7 +353,7 @@ public: LOCK(m_wallet.cs_wallet); auto mi = m_wallet.mapWallet.find(txid); if (mi != m_wallet.mapWallet.end()) { - num_blocks = ::chainActive.Height(); + 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); @@ -377,7 +384,7 @@ public: return false; } balances = getBalances(); - num_blocks = ::chainActive.Height(); + num_blocks = locked_chain->getHeight().get_value_or(-1); return true; } CAmount getBalance() override { return m_wallet.GetBalance(); } @@ -486,6 +493,10 @@ public: { return MakeHandler(m_wallet.NotifyWatchonlyChanged.connect(fn)); } + std::unique_ptr<Handler> handleCanGetAddressesChanged(CanGetAddressesChangedFn fn) override + { + return MakeHandler(m_wallet.NotifyCanGetAddressesChanged.connect(fn)); + } std::shared_ptr<CWallet> m_shared_wallet; CWallet& m_wallet; diff --git a/src/interfaces/wallet.h b/src/interfaces/wallet.h index c79b9afce3..72c64ded01 100644 --- a/src/interfaces/wallet.h +++ b/src/interfaces/wallet.h @@ -178,7 +178,8 @@ public: //! Try to get updated status for a particular transaction, if possible without blocking. virtual bool tryGetTxStatus(const uint256& txid, WalletTxStatus& tx_status, - int& num_blocks) = 0; + int& num_blocks, + int64_t& block_time) = 0; //! Get transaction details. virtual WalletTx getWalletTxDetails(const uint256& txid, @@ -270,6 +271,10 @@ public: //! Register handler for watchonly changed messages. using WatchOnlyChangedFn = std::function<void(bool have_watch_only)>; virtual std::unique_ptr<Handler> handleWatchOnlyChanged(WatchOnlyChangedFn fn) = 0; + + //! Register handler for keypool changed messages. + using CanGetAddressesChangedFn = std::function<void()>; + virtual std::unique_ptr<Handler> handleCanGetAddressesChanged(CanGetAddressesChangedFn fn) = 0; }; //! Tracking object returned by CreateTransaction and passed to CommitTransaction. diff --git a/src/key.cpp b/src/key.cpp index 80d6589a3c..9d982fc44f 100644 --- a/src/key.cpp +++ b/src/key.cpp @@ -246,7 +246,7 @@ bool CKey::SignCompact(const uint256 &hash, std::vector<unsigned char>& vchSig) secp256k1_ecdsa_recoverable_signature sig; int ret = secp256k1_ecdsa_sign_recoverable(secp256k1_context_sign, &sig, hash.begin(), begin(), secp256k1_nonce_function_rfc6979, nullptr); assert(ret); - secp256k1_ecdsa_recoverable_signature_serialize_compact(secp256k1_context_sign, &vchSig[1], &rec, &sig); + ret = secp256k1_ecdsa_recoverable_signature_serialize_compact(secp256k1_context_sign, &vchSig[1], &rec, &sig); assert(ret); assert(rec != -1); vchSig[0] = 27 + rec + (fCompressed ? 4 : 0); diff --git a/src/leveldb/db/c.cc b/src/leveldb/db/c.cc index 08ff0ad90a..b23e3dcc9d 100644 --- a/src/leveldb/db/c.cc +++ b/src/leveldb/db/c.cc @@ -5,7 +5,9 @@ #include "leveldb/c.h" #include <stdlib.h> +#ifndef WIN32 #include <unistd.h> +#endif #include "leveldb/cache.h" #include "leveldb/comparator.h" #include "leveldb/db.h" diff --git a/src/leveldb/port/port_win.h b/src/leveldb/port/port_win.h index e8bf46ef27..989c15cd91 100644 --- a/src/leveldb/port/port_win.h +++ b/src/leveldb/port/port_win.h @@ -32,9 +32,16 @@ #define STORAGE_LEVELDB_PORT_PORT_WIN_H_ #ifdef _MSC_VER +#if !(_MSC_VER >= 1900) #define snprintf _snprintf +#endif #define close _close #define fread_unlocked _fread_nolock +#ifdef _WIN64 +#define ssize_t int64_t +#else +#define ssize_t int32_t +#endif #endif #include <string> diff --git a/src/leveldb/util/env_win.cc b/src/leveldb/util/env_win.cc index 81380216bb..830332abe9 100644 --- a/src/leveldb/util/env_win.cc +++ b/src/leveldb/util/env_win.cc @@ -203,24 +203,16 @@ public: void ToWidePath(const std::string& value, std::wstring& target) { wchar_t buffer[MAX_PATH]; - MultiByteToWideChar(CP_ACP, 0, value.c_str(), -1, buffer, MAX_PATH); + MultiByteToWideChar(CP_UTF8, 0, value.c_str(), -1, buffer, MAX_PATH); target = buffer; } void ToNarrowPath(const std::wstring& value, std::string& target) { char buffer[MAX_PATH]; - WideCharToMultiByte(CP_ACP, 0, value.c_str(), -1, buffer, MAX_PATH, NULL, NULL); + WideCharToMultiByte(CP_UTF8, 0, value.c_str(), -1, buffer, MAX_PATH, NULL, NULL); target = buffer; } -std::string GetCurrentDir() -{ - CHAR path[MAX_PATH]; - ::GetModuleFileNameA(::GetModuleHandleA(NULL),path,MAX_PATH); - *strrchr(path,'\\') = 0; - return std::string(path); -} - std::wstring GetCurrentDirW() { WCHAR path[MAX_PATH]; @@ -229,6 +221,13 @@ std::wstring GetCurrentDirW() return std::wstring(path); } +std::string GetCurrentDir() +{ + std::string path; + ToNarrowPath(GetCurrentDirW(), path); + return path; +} + std::string& ModifyPath(std::string& path) { if(path[0] == '/' || path[0] == '\\'){ @@ -764,14 +763,16 @@ uint64_t Win32Env::NowMicros() static Status CreateDirInner( const std::string& dirname ) { Status sRet; - DWORD attr = ::GetFileAttributes(dirname.c_str()); + std::wstring dirnameW; + ToWidePath(dirname, dirnameW); + DWORD attr = ::GetFileAttributesW(dirnameW.c_str()); if (attr == INVALID_FILE_ATTRIBUTES) { // doesn't exist: std::size_t slash = dirname.find_last_of("\\"); if (slash != std::string::npos){ sRet = CreateDirInner(dirname.substr(0, slash)); if (!sRet.ok()) return sRet; } - BOOL result = ::CreateDirectory(dirname.c_str(), NULL); + BOOL result = ::CreateDirectoryW(dirnameW.c_str(), NULL); if (result == FALSE) { sRet = Status::IOError(dirname, "Could not create directory."); return sRet; 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/merkleblock.cpp b/src/merkleblock.cpp index 0c37bab1f8..a54268d655 100644 --- a/src/merkleblock.cpp +++ b/src/merkleblock.cpp @@ -53,7 +53,7 @@ uint256 CPartialMerkleTree::CalcHash(int height, unsigned int pos, const std::ve else right = left; // combine subhashes - return Hash(BEGIN(left), END(left), BEGIN(right), END(right)); + return Hash(left.begin(), left.end(), right.begin(), right.end()); } } @@ -109,7 +109,7 @@ uint256 CPartialMerkleTree::TraverseAndExtract(int height, unsigned int pos, uns right = left; } // and combine them before returning - return Hash(BEGIN(left), END(left), BEGIN(right), END(right)); + return Hash(left.begin(), left.end(), right.begin(), right.end()); } } diff --git a/src/net.cpp b/src/net.cpp index a288c6e81e..d52d5b7cf5 100644 --- a/src/net.cpp +++ b/src/net.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. @@ -9,6 +9,7 @@ #include <net.h> +#include <banman.h> #include <chainparams.h> #include <clientversion.h> #include <consensus/consensus.h> @@ -41,8 +42,8 @@ #include <math.h> -// Dump addresses to peers.dat and banlist.dat every 15 minutes (900s) -#define DUMP_ADDRESSES_INTERVAL 900 +// Dump addresses to peers.dat every 15 minutes (900s) +static constexpr int DUMP_PEERS_INTERVAL = 15 * 60; // We add a random period time (0 to 1 seconds) to feeler connections to prevent synchronization. #define FEELER_SLEEP_WINDOW 1 @@ -57,17 +58,6 @@ #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, @@ -80,7 +70,7 @@ enum BindFlags { // The sleep time needs to be small to avoid new sockets stalling static const uint64_t SELECT_TIMEOUT_MILLISECONDS = 50; -const static std::string NET_MESSAGE_COMMAND_OTHER = "*other*"; +const std::string NET_MESSAGE_COMMAND_OTHER = "*other*"; static const uint64_t RANDOMIZER_ID_NETGROUP = 0x6c0edd8036ef4036ULL; // SHA256("netgroup")[0:8] static const uint64_t RANDOMIZER_ID_LOCALHOSTNONCE = 0xd93e69e2bbfa5735ULL; // SHA256("localhostnonce")[0:8] @@ -173,8 +163,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; } @@ -183,7 +172,7 @@ bool IsPeerAddrLocalGood(CNode *pnode) { CService addrLocal = pnode->GetAddrLocal(); return fDiscover && pnode->addr.IsRoutable() && addrLocal.IsRoutable() && - !IsLimited(addrLocal.GetNetwork()); + IsReachable(addrLocal.GetNetwork()); } // pushes our own address to a peer @@ -222,7 +211,7 @@ bool AddLocal(const CService& addr, int nScore) if (!fDiscover && nScore < LOCAL_MANUAL) return false; - if (IsLimited(addr)) + if (!IsReachable(addr)) return false; LogPrintf("AddLocal(%s,%i)\n", addr.ToString(), nScore); @@ -252,24 +241,23 @@ void RemoveLocal(const CService& addr) mapLocalHost.erase(addr); } -/** Make a particular network entirely off-limits (no automatic connects to it) */ -void SetLimited(enum Network net, bool fLimited) +void SetReachable(enum Network net, bool reachable) { if (net == NET_UNROUTABLE || net == NET_INTERNAL) return; LOCK(cs_mapLocalHost); - vfLimited[net] = fLimited; + vfLimited[net] = !reachable; } -bool IsLimited(enum Network net) +bool IsReachable(enum Network net) { LOCK(cs_mapLocalHost); - return vfLimited[net]; + return !vfLimited[net]; } -bool IsLimited(const CNetAddr &addr) +bool IsReachable(const CNetAddr &addr) { - return IsLimited(addr.GetNetwork()); + return IsReachable(addr.GetNetwork()); } /** vote for a local address */ @@ -292,21 +280,6 @@ bool IsLocal(const CService& addr) return mapLocalHost.count(addr) > 0; } -/** check whether a given network is one we can probably connect to */ -bool IsReachable(enum Network net) -{ - LOCK(cs_mapLocalHost); - return !vfLimited[net]; -} - -/** check whether a given address is in a network we can probably connect to */ -bool IsReachable(const CNetAddr& addr) -{ - enum Network net = addr.GetNetwork(); - return IsReachable(net); -} - - CNode* CConnman::FindNode(const CNetAddr& ip) { LOCK(cs_vNodes); @@ -473,26 +446,6 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo return pnode; } -void CConnman::DumpBanlist() -{ - SweepBanned(); // clean unused entries (if bantime has expired) - - if (!BannedSetIsDirty()) - return; - - int64_t nStart = GetTimeMillis(); - - CBanDB bandb; - banmap_t banmap; - GetBanned(banmap); - if (bandb.Write(banmap)) { - SetBannedSetDirty(false); - } - - LogPrint(BCLog::NET, "Flushed %d banned node ips/subnets to banlist.dat %dms\n", - banmap.size(), GetTimeMillis() - nStart); -} - void CNode::CloseSocketDisconnect() { fDisconnect = true; @@ -504,157 +457,6 @@ void CNode::CloseSocketDisconnect() } } -void CConnman::ClearBanned() -{ - { - LOCK(cs_setBanned); - setBanned.clear(); - setBannedIsDirty = true; - } - DumpBanlist(); //store banlist to disk - if(clientInterface) - clientInterface->BannedListChanged(); -} - -bool CConnman::IsBanned(CNetAddr ip) -{ - LOCK(cs_setBanned); - for (const auto& it : setBanned) { - CSubNet subNet = it.first; - CBanEntry banEntry = it.second; - - if (subNet.Match(ip) && GetTime() < banEntry.nBanUntil) { - return true; - } - } - return false; -} - -bool CConnman::IsBanned(CSubNet subnet) -{ - LOCK(cs_setBanned); - banmap_t::iterator i = setBanned.find(subnet); - if (i != setBanned.end()) - { - CBanEntry banEntry = (*i).second; - if (GetTime() < banEntry.nBanUntil) { - return true; - } - } - return false; -} - -void CConnman::Ban(const CNetAddr& addr, const BanReason &banReason, int64_t bantimeoffset, bool sinceUnixEpoch) { - CSubNet subNet(addr); - Ban(subNet, banReason, bantimeoffset, sinceUnixEpoch); -} - -void CConnman::Ban(const CSubNet& subNet, const BanReason &banReason, int64_t bantimeoffset, bool sinceUnixEpoch) { - CBanEntry banEntry(GetTime()); - banEntry.banReason = banReason; - if (bantimeoffset <= 0) - { - bantimeoffset = gArgs.GetArg("-bantime", DEFAULT_MISBEHAVING_BANTIME); - sinceUnixEpoch = false; - } - banEntry.nBanUntil = (sinceUnixEpoch ? 0 : GetTime() )+bantimeoffset; - - { - LOCK(cs_setBanned); - if (setBanned[subNet].nBanUntil < banEntry.nBanUntil) { - setBanned[subNet] = banEntry; - setBannedIsDirty = true; - } - else - return; - } - if(clientInterface) - clientInterface->BannedListChanged(); - { - LOCK(cs_vNodes); - for (CNode* pnode : vNodes) { - if (subNet.Match(static_cast<CNetAddr>(pnode->addr))) - pnode->fDisconnect = true; - } - } - if(banReason == BanReasonManuallyAdded) - DumpBanlist(); //store banlist to disk immediately if user requested ban -} - -bool CConnman::Unban(const CNetAddr &addr) { - CSubNet subNet(addr); - return Unban(subNet); -} - -bool CConnman::Unban(const CSubNet &subNet) { - { - LOCK(cs_setBanned); - if (!setBanned.erase(subNet)) - return false; - setBannedIsDirty = true; - } - if(clientInterface) - clientInterface->BannedListChanged(); - DumpBanlist(); //store banlist to disk immediately - return true; -} - -void CConnman::GetBanned(banmap_t &banMap) -{ - LOCK(cs_setBanned); - // Sweep the banlist so expired bans are not returned - SweepBanned(); - banMap = setBanned; //create a thread safe copy -} - -void CConnman::SetBanned(const banmap_t &banMap) -{ - LOCK(cs_setBanned); - setBanned = banMap; - setBannedIsDirty = true; -} - -void CConnman::SweepBanned() -{ - int64_t now = GetTime(); - bool notifyUI = false; - { - LOCK(cs_setBanned); - banmap_t::iterator it = setBanned.begin(); - while(it != setBanned.end()) - { - CSubNet subNet = (*it).first; - CBanEntry banEntry = (*it).second; - if(now > banEntry.nBanUntil) - { - setBanned.erase(it++); - setBannedIsDirty = true; - notifyUI = true; - LogPrint(BCLog::NET, "%s: Removed banned node ip/subnet from banlist.dat: %s\n", __func__, subNet.ToString()); - } - else - ++it; - } - } - // update UI - if(notifyUI && clientInterface) { - clientInterface->BannedListChanged(); - } -} - -bool CConnman::BannedSetIsDirty() -{ - LOCK(cs_setBanned); - return setBannedIsDirty; -} - -void CConnman::SetBannedSetDirty(bool dirty) -{ - LOCK(cs_setBanned); //reuse setBanned lock for the isDirty flag - setBannedIsDirty = dirty; -} - - bool CConnman::IsWhitelistedRange(const CNetAddr &addr) { for (const CSubNet& subnet : vWhitelistedRange) { if (subnet.Match(addr)) @@ -787,7 +589,6 @@ bool CNode::ReceiveMsgBytes(const char *pch, unsigned int nBytes, bool& complete nBytes -= handled; if (msg.complete()) { - //store received bytes per message command //to prevent a memory DOS, only allow valid commands mapMsgCmdSize::iterator i = mapRecvBytesPerMsgCmd.find(msg.hdr.pchCommand); @@ -951,6 +752,7 @@ struct NodeEvictionCandidate bool fBloomFilter; CAddress addr; uint64_t nKeyedNetGroup; + bool prefer_evict; }; static bool ReverseCompareNodeMinPingTime(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b) @@ -1019,7 +821,8 @@ bool CConnman::AttemptToEvictConnection() NodeEvictionCandidate candidate = {node->GetId(), node->nTimeConnected, node->nMinPingUsecTime, node->nLastBlockTime, node->nLastTXTime, HasAllDesirableServiceFlags(node->nServices), - node->fRelayTxes, node->pfilter != nullptr, node->addr, node->nKeyedNetGroup}; + node->fRelayTxes, node->pfilter != nullptr, node->addr, node->nKeyedNetGroup, + node->m_prefer_evict}; vEvictionCandidates.push_back(candidate); } } @@ -1044,6 +847,14 @@ bool CConnman::AttemptToEvictConnection() if (vEvictionCandidates.empty()) return false; + // If any remaining peers are preferred for eviction consider only them. + // This happens after the other preferences since if a peer is really the best by other criteria (esp relaying blocks) + // then we probably don't want to evict it no matter what. + if (std::any_of(vEvictionCandidates.begin(),vEvictionCandidates.end(),[](NodeEvictionCandidate const &n){return n.prefer_evict;})) { + vEvictionCandidates.erase(std::remove_if(vEvictionCandidates.begin(),vEvictionCandidates.end(), + [](NodeEvictionCandidate const &n){return !n.prefer_evict;}),vEvictionCandidates.end()); + } + // Identify the network group with the most connections and youngest member. // (vEvictionCandidates is already sorted by reverse connect time) uint64_t naMostConnections; @@ -1124,7 +935,11 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) { // on all platforms. Set it again here just to be sure. SetSocketNoDelay(hSocket); - if (IsBanned(addr) && !whitelisted) + int bannedlevel = m_banman ? m_banman->IsBannedLevel(addr) : 0; + + // Don't accept connections from banned peers, but if our inbound slots aren't almost full, accept + // if the only banning reason was an automatic misbehavior ban. + if (!whitelisted && bannedlevel > ((nInbound + 1 < nMaxInbound) ? 1 : 0)) { LogPrint(BCLog::NET, "connection from %s dropped (banned)\n", addr.ToString()); CloseSocket(hSocket); @@ -1148,6 +963,7 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) { CNode* pnode = new CNode(id, nLocalServices, GetBestHeight(), hSocket, addr, CalculateKeyedNetGroup(addr), nonce, addr_bind, "", true); pnode->AddRef(); pnode->fWhitelisted = whitelisted; + pnode->m_prefer_evict = bannedlevel > 0; m_msgproc->InitializeNode(pnode); LogPrint(BCLog::NET, "connection from %s accepted\n", addr.ToString()); @@ -1792,12 +1608,6 @@ void CConnman::DumpAddresses() addrman.size(), GetTimeMillis() - nStart); } -void CConnman::DumpData() -{ - DumpAddresses(); - DumpBanlist(); -} - void CConnman::ProcessOneShot() { std::string strDest; @@ -1968,7 +1778,7 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect) if (nTries > 100) break; - if (IsLimited(addr)) + if (!IsReachable(addr)) continue; // only consider very recently tried nodes after 30 failed attempts @@ -2102,7 +1912,7 @@ void CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFai } if (!pszDest) { if (IsLocal(addrConnect) || - FindNode(static_cast<CNetAddr>(addrConnect)) || IsBanned(addrConnect) || + FindNode(static_cast<CNetAddr>(addrConnect)) || (m_banman && m_banman->IsBanned(addrConnect)) || FindNode(addrConnect.ToStringIPPort())) return; } else if (FindNode(std::string(pszDest))) @@ -2317,14 +2127,6 @@ void CConnman::SetNetworkActive(bool active) CConnman::CConnman(uint64_t nSeed0In, uint64_t nSeed1In) : nSeed0(nSeed0In), nSeed1(nSeed1In) { - fNetworkActive = true; - setBannedIsDirty = false; - fAddressesInitialized = false; - nLastNodeId = 0; - nPrevNodeCount = 0; - nSendBufferMaxSize = 0; - nReceiveFloodSize = 0; - flagInterruptMsgProc = false; SetTryNewOutboundPeer(false); Options connOptions; @@ -2338,7 +2140,7 @@ NodeId CConnman::GetNewNodeId() bool CConnman::Bind(const CService &addr, unsigned int flags) { - if (!(flags & BF_EXPLICIT) && IsLimited(addr)) + if (!(flags & BF_EXPLICIT) && !IsReachable(addr)) return false; std::string strError; if (!BindListenPort(addr, strError, (flags & BF_WHITELIST) != 0)) { @@ -2411,24 +2213,6 @@ bool CConnman::Start(CScheduler& scheduler, const Options& connOptions) DumpAddresses(); } } - if (clientInterface) - clientInterface->InitMessage(_("Loading banlist...")); - // Load addresses from banlist.dat - nStart = GetTimeMillis(); - CBanDB bandb; - banmap_t banmap; - if (bandb.Read(banmap)) { - SetBanned(banmap); // thread save setter - SetBannedSetDirty(false); // no need to write down, just read data - SweepBanned(); // sweep out unused entries - - LogPrint(BCLog::NET, "Loaded %d banned node ips/subnets from banlist.dat %dms\n", - banmap.size(), GetTimeMillis() - nStart); - } else { - LogPrintf("Invalid or missing banlist.dat; recreating\n"); - SetBannedSetDirty(true); // force write - DumpBanlist(); - } uiInterface.InitMessage(_("Starting network threads...")); @@ -2482,7 +2266,7 @@ bool CConnman::Start(CScheduler& scheduler, const Options& connOptions) threadMessageHandler = std::thread(&TraceThread<std::function<void()> >, "msghand", std::function<void()>(std::bind(&CConnman::ThreadMessageHandler, this))); // Dump network addresses - scheduler.scheduleEvery(std::bind(&CConnman::DumpData, this), DUMP_ADDRESSES_INTERVAL * 1000); + scheduler.scheduleEvery(std::bind(&CConnman::DumpAddresses, this), DUMP_PEERS_INTERVAL * 1000); return true; } @@ -2541,7 +2325,7 @@ void CConnman::Stop() if (fAddressesInitialized) { - DumpData(); + DumpAddresses(); fAddressesInitialized = false; } @@ -2668,6 +2452,25 @@ bool CConnman::DisconnectNode(const std::string& strNode) } return false; } + +bool CConnman::DisconnectNode(const CSubNet& subnet) +{ + bool disconnected = false; + LOCK(cs_vNodes); + for (CNode* pnode : vNodes) { + if (subnet.Match(pnode->addr)) { + pnode->fDisconnect = true; + disconnected = true; + } + } + return disconnected; +} + +bool CConnman::DisconnectNode(const CNetAddr& addr) +{ + return DisconnectNode(CSubNet(addr)); +} + bool CConnman::DisconnectNode(NodeId id) { LOCK(cs_vNodes); @@ -2805,8 +2608,8 @@ int CConnman::GetBestHeight() const unsigned int CConnman::GetReceiveFloodSize() const { return nReceiveFloodSize; } -CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn, SOCKET hSocketIn, const CAddress& addrIn, uint64_t nKeyedNetGroupIn, uint64_t nLocalHostNonceIn, const CAddress &addrBindIn, const std::string& addrNameIn, bool fInboundIn) : - nTimeConnected(GetSystemTimeInSeconds()), +CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn, SOCKET hSocketIn, const CAddress& addrIn, uint64_t nKeyedNetGroupIn, uint64_t nLocalHostNonceIn, const CAddress& addrBindIn, const std::string& addrNameIn, bool fInboundIn) + : nTimeConnected(GetSystemTimeInSeconds()), addr(addrIn), addrBind(addrBindIn), fInbound(fInboundIn), @@ -2816,56 +2619,14 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn id(idIn), nLocalHostNonce(nLocalHostNonceIn), nLocalServices(nLocalServicesIn), - nMyStartingHeight(nMyStartingHeightIn), - nSendVersion(0) + nMyStartingHeight(nMyStartingHeightIn) { - nServices = NODE_NONE; hSocket = hSocketIn; - nRecvVersion = INIT_PROTO_VERSION; - nLastSend = 0; - nLastRecv = 0; - nSendBytes = 0; - nRecvBytes = 0; - nTimeOffset = 0; addrName = addrNameIn == "" ? addr.ToStringIPPort() : addrNameIn; - nVersion = 0; strSubVer = ""; - fWhitelisted = false; - fOneShot = false; - m_manual_connection = false; - fClient = false; // set by version message - m_limited_node = false; // set by version message - fFeeler = false; - fSuccessfullyConnected = false; - fDisconnect = false; - nRefCount = 0; - nSendSize = 0; - nSendOffset = 0; hashContinue = uint256(); - nStartingHeight = -1; filterInventoryKnown.reset(); - fSendMempool = false; - fGetAddr = false; - nNextLocalAddrSend = 0; - nNextAddrSend = 0; - nNextInvSend = 0; - fRelayTxes = false; - fSentAddr = false; pfilter = MakeUnique<CBloomFilter>(); - timeLastMempoolReq = 0; - nLastBlockTime = 0; - nLastTXTime = 0; - nPingNonceSent = 0; - nPingUsecStart = 0; - nPingUsecTime = 0; - fPingQueued = false; - nMinPingUsecTime = std::numeric_limits<int64_t>::max(); - minFeeFilter = 0; - lastSentFeeFilter = 0; - nextSendTimeFeeFilter = 0; - fPauseRecv = false; - fPauseSend = false; - nProcessQueueSize = 0; for (const std::string &msg : getAllNetMessageTypes()) mapRecvBytesPerMsgCmd[msg] = 0; @@ -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. @@ -37,6 +37,7 @@ class CScheduler; class CNode; +class BanMan; /** Time between pings automatically sent out for latency probing and keepalive (in seconds). */ static const int PING_INTERVAL = 2 * 60; @@ -85,9 +86,6 @@ static const bool DEFAULT_FORCEDNSSEED = false; static const size_t DEFAULT_MAXRECEIVEBUFFER = 5 * 1000; static const size_t DEFAULT_MAXSENDBUFFER = 1 * 1000; -// NOTE: When adjusting this, update rpcnet:setban's help ("24h") -static const unsigned int DEFAULT_MISBEHAVING_BANTIME = 60 * 60 * 24; // Default 24-hour ban - typedef int64_t NodeId; struct AddedNodeInfo @@ -114,6 +112,7 @@ struct CSerializedNetMsg std::string command; }; + class NetEventsInterface; class CConnman { @@ -136,6 +135,7 @@ public: int nBestHeight = 0; CClientUIInterface* uiInterface = nullptr; NetEventsInterface* m_msgproc = nullptr; + BanMan* m_banman = nullptr; unsigned int nSendBufferMaxSize = 0; unsigned int nReceiveFloodSize = 0; uint64_t nMaxOutboundTimeframe = 0; @@ -158,6 +158,7 @@ public: nMaxFeeler = connOptions.nMaxFeeler; nBestHeight = connOptions.nBestHeight; clientInterface = connOptions.uiInterface; + m_banman = connOptions.m_banman; m_msgproc = connOptions.m_msgproc; nSendBufferMaxSize = connOptions.nSendBufferMaxSize; nReceiveFloodSize = connOptions.nReceiveFloodSize; @@ -238,30 +239,6 @@ public: void AddNewAddresses(const std::vector<CAddress>& vAddr, const CAddress& addrFrom, int64_t nTimePenalty = 0); std::vector<CAddress> GetAddresses(); - // Denial-of-service detection/prevention - // The idea is to detect peers that are behaving - // badly and disconnect/ban them, but do it in a - // one-coding-mistake-won't-shatter-the-entire-network - // way. - // IMPORTANT: There should be nothing I can give a - // node that it will forward on that will make that - // node's peers drop it. If there is, an attacker - // can isolate a node and/or try to split the network. - // Dropping a node for sending stuff that is invalid - // now but might be valid in a later version is also - // dangerous, because it can cause a network split - // between nodes running old code and nodes running - // new code. - void Ban(const CNetAddr& netAddr, const BanReason& reason, int64_t bantimeoffset = 0, bool sinceUnixEpoch = false); - void Ban(const CSubNet& subNet, const BanReason& reason, int64_t bantimeoffset = 0, bool sinceUnixEpoch = false); - void ClearBanned(); // needed for unit testing - bool IsBanned(CNetAddr ip); - bool IsBanned(CSubNet subnet); - bool Unban(const CNetAddr &ip); - bool Unban(const CSubNet &ip); - void GetBanned(banmap_t &banmap); - void SetBanned(const banmap_t &banmap); - // This allows temporarily exceeding nMaxOutbound, with the goal of finding // a peer that is better than all our current peers. void SetTryNewOutboundPeer(bool flag); @@ -282,6 +259,8 @@ public: size_t GetNodeCount(NumConnections num); void GetNodeStats(std::vector<CNodeStats>& vstats); bool DisconnectNode(const std::string& node); + bool DisconnectNode(const CSubNet& subnet); + bool DisconnectNode(const CNetAddr& addr); bool DisconnectNode(NodeId id); ServiceFlags GetLocalServices() const; @@ -294,17 +273,17 @@ public: void SetMaxOutboundTimeframe(uint64_t timeframe); uint64_t GetMaxOutboundTimeframe(); - //!check if the outbound target is reached - // if param historicalBlockServingLimit is set true, the function will - // response true if the limit for serving historical blocks has been reached + //! check if the outbound target is reached + //! if param historicalBlockServingLimit is set true, the function will + //! response true if the limit for serving historical blocks has been reached bool OutboundTargetReached(bool historicalBlockServingLimit); - //!response the bytes left in the current max outbound cycle - // in case of no limit, it will always response 0 + //! response the bytes left in the current max outbound cycle + //! in case of no limit, it will always response 0 uint64_t GetOutboundTargetBytesLeft(); - //!response the time in second left in the current max outbound cycle - // in case of no limit, it will always response 0 + //! response the time in second left in the current max outbound cycle + //! in case of no limit, it will always response 0 uint64_t GetMaxOutboundTimeLeftInCycle(); uint64_t GetTotalBytesRecv(); @@ -368,15 +347,7 @@ private: NodeId GetNewNodeId(); size_t SocketSendData(CNode *pnode) const; - //!check is the banlist has unwritten changes - bool BannedSetIsDirty(); - //!set the "dirty" flag for the banlist - void SetBannedSetDirty(bool dirty=true); - //!clean unused entries (if bantime has expired) - void SweepBanned(); void DumpAddresses(); - void DumpData(); - void DumpBanlist(); // Network stats void RecordBytesRecv(uint64_t bytes); @@ -404,15 +375,12 @@ private: // whitelisted (as well as those connecting to whitelisted binds). std::vector<CSubNet> vWhitelistedRange; - unsigned int nSendBufferMaxSize; - unsigned int nReceiveFloodSize; + unsigned int nSendBufferMaxSize{0}; + unsigned int nReceiveFloodSize{0}; std::vector<ListenSocket> vhListenSocket; - std::atomic<bool> fNetworkActive; - banmap_t setBanned GUARDED_BY(cs_setBanned); - CCriticalSection cs_setBanned; - bool setBannedIsDirty GUARDED_BY(cs_setBanned); - bool fAddressesInitialized; + std::atomic<bool> fNetworkActive{true}; + bool fAddressesInitialized{false}; CAddrMan addrman; std::deque<std::string> vOneShots GUARDED_BY(cs_vOneShots); CCriticalSection cs_vOneShots; @@ -421,8 +389,8 @@ private: std::vector<CNode*> vNodes; std::list<CNode*> vNodesDisconnected; mutable CCriticalSection cs_vNodes; - std::atomic<NodeId> nLastNodeId; - unsigned int nPrevNodeCount; + std::atomic<NodeId> nLastNodeId{0}; + unsigned int nPrevNodeCount{0}; /** Services this instance offers */ ServiceFlags nLocalServices; @@ -437,6 +405,7 @@ private: std::atomic<int> nBestHeight; CClientUIInterface* clientInterface; NetEventsInterface* m_msgproc; + BanMan* m_banman; /** SipHasher seeds for deterministic randomness */ const uint64_t nSeed0, nSeed1; @@ -446,7 +415,7 @@ private: std::condition_variable condMsgProc; Mutex mutexMsgProc; - std::atomic<bool> flagInterruptMsgProc; + std::atomic<bool> flagInterruptMsgProc{false}; CThreadInterrupt interruptNet; @@ -466,6 +435,7 @@ private: friend struct CConnmanTest; }; extern std::unique_ptr<CConnman> g_connman; +extern std::unique_ptr<BanMan> g_banman; void Discover(); void StartMapPort(); void InterruptMapPort(); @@ -520,17 +490,23 @@ enum bool IsPeerAddrLocalGood(CNode *pnode); void AdvertiseLocal(CNode *pnode); -void SetLimited(enum Network net, bool fLimited = true); -bool IsLimited(enum Network net); -bool IsLimited(const CNetAddr& addr); + +/** + * Mark a network as reachable or unreachable (no automatic connects to it) + * @note Networks are reachable by default + */ +void SetReachable(enum Network net, bool reachable); +/** @returns true if the network is reachable, false otherwise */ +bool IsReachable(enum Network net); +/** @returns true if the address is in a reachable network, false otherwise */ +bool IsReachable(const CNetAddr& addr); + bool AddLocal(const CService& addr, int nScore = LOCAL_NONE); bool AddLocal(const CNetAddr& addr, int nScore = LOCAL_NONE); void RemoveLocal(const CService& addr); bool SeenLocal(const CService& addr); bool IsLocal(const CService& addr); bool GetLocal(CService &addr, const CNetAddr *paddrPeer = nullptr); -bool IsReachable(enum Network net); -bool IsReachable(const CNetAddr &addr); CAddress GetLocalAddress(const CNetAddr *paddrPeer, ServiceFlags nLocalServices); @@ -550,6 +526,8 @@ struct LocalServiceInfo { extern CCriticalSection cs_mapLocalHost; extern std::map<CNetAddr, LocalServiceInfo> mapLocalHost GUARDED_BY(cs_mapLocalHost); + +extern const std::string NET_MESSAGE_COMMAND_OTHER; typedef std::map<std::string, uint64_t> mapMsgCmdSize; //command, total bytes class CNodeStats @@ -638,11 +616,11 @@ class CNode friend class CConnman; public: // socket - std::atomic<ServiceFlags> nServices; + std::atomic<ServiceFlags> nServices{NODE_NONE}; SOCKET hSocket GUARDED_BY(cs_hSocket); - size_t nSendSize; // total size of all vSendMsg entries - size_t nSendOffset; // offset inside the first vSendMsg already sent - uint64_t nSendBytes GUARDED_BY(cs_vSend); + size_t nSendSize{0}; // total size of all vSendMsg entries + size_t nSendOffset{0}; // offset inside the first vSendMsg already sent + uint64_t nSendBytes GUARDED_BY(cs_vSend){0}; std::deque<std::vector<unsigned char>> vSendMsg GUARDED_BY(cs_vSend); CCriticalSection cs_vSend; CCriticalSection cs_hSocket; @@ -650,68 +628,71 @@ public: CCriticalSection cs_vProcessMsg; std::list<CNetMessage> vProcessMsg GUARDED_BY(cs_vProcessMsg); - size_t nProcessQueueSize; + size_t nProcessQueueSize{0}; CCriticalSection cs_sendProcessing; std::deque<CInv> vRecvGetData; - uint64_t nRecvBytes GUARDED_BY(cs_vRecv); - std::atomic<int> nRecvVersion; + uint64_t nRecvBytes GUARDED_BY(cs_vRecv){0}; + std::atomic<int> nRecvVersion{INIT_PROTO_VERSION}; - std::atomic<int64_t> nLastSend; - std::atomic<int64_t> nLastRecv; + std::atomic<int64_t> nLastSend{0}; + std::atomic<int64_t> nLastRecv{0}; const int64_t nTimeConnected; - std::atomic<int64_t> nTimeOffset; + std::atomic<int64_t> nTimeOffset{0}; // Address of this peer const CAddress addr; // Bind address of our side of the connection const CAddress addrBind; - std::atomic<int> nVersion; + std::atomic<int> nVersion{0}; // strSubVer is whatever byte array we read from the wire. However, this field is intended // to be printed out, displayed to humans in various forms and so on. So we sanitize it and // store the sanitized version in cleanSubVer. The original should be used when dealing with // the network or wire types and the cleaned string used when displayed or logged. std::string strSubVer GUARDED_BY(cs_SubVer), cleanSubVer GUARDED_BY(cs_SubVer); CCriticalSection cs_SubVer; // used for both cleanSubVer and strSubVer - bool fWhitelisted; // This peer can bypass DoS banning. - bool fFeeler; // If true this node is being used as a short lived feeler. - bool fOneShot; - bool m_manual_connection; - bool fClient; - bool m_limited_node; //after BIP159 + bool m_prefer_evict{false}; // This peer is preferred for eviction. + bool fWhitelisted{false}; // This peer can bypass DoS banning. + bool fFeeler{false}; // If true this node is being used as a short lived feeler. + bool fOneShot{false}; + bool m_manual_connection{false}; + bool fClient{false}; // set by version message + bool m_limited_node{false}; //after BIP159, set by version message const bool fInbound; - std::atomic_bool fSuccessfullyConnected; - std::atomic_bool fDisconnect; + std::atomic_bool fSuccessfullyConnected{false}; + // Setting fDisconnect to true will cause the node to be disconnected the + // next time DisconnectNodes() runs + std::atomic_bool fDisconnect{false}; // We use fRelayTxes for two purposes - // a) it allows us to not relay tx invs before receiving the peer's version message // b) the peer may tell us in its version message that we should not relay tx invs // unless it loads a bloom filter. - bool fRelayTxes GUARDED_BY(cs_filter); - bool fSentAddr; + bool fRelayTxes GUARDED_BY(cs_filter){false}; + bool fSentAddr{false}; CSemaphoreGrant grantOutbound; mutable CCriticalSection cs_filter; std::unique_ptr<CBloomFilter> pfilter PT_GUARDED_BY(cs_filter); - std::atomic<int> nRefCount; + std::atomic<int> nRefCount{0}; const uint64_t nKeyedNetGroup; - std::atomic_bool fPauseRecv; - std::atomic_bool fPauseSend; -protected: + std::atomic_bool fPauseRecv{false}; + std::atomic_bool fPauseSend{false}; +protected: mapMsgCmdSize mapSendBytesPerMsgCmd; mapMsgCmdSize mapRecvBytesPerMsgCmd GUARDED_BY(cs_vRecv); public: uint256 hashContinue; - std::atomic<int> nStartingHeight; + std::atomic<int> nStartingHeight{-1}; // flood relay std::vector<CAddress> vAddrToSend; CRollingBloomFilter addrKnown; - bool fGetAddr; + bool fGetAddr{false}; std::set<uint256> setKnown; - int64_t nNextAddrSend GUARDED_BY(cs_sendProcessing); - int64_t nNextLocalAddrSend GUARDED_BY(cs_sendProcessing); + int64_t nNextAddrSend GUARDED_BY(cs_sendProcessing){0}; + int64_t nNextLocalAddrSend GUARDED_BY(cs_sendProcessing){0}; // inventory based relay CRollingBloomFilter filterInventoryKnown GUARDED_BY(cs_inventory); @@ -725,35 +706,35 @@ public: CCriticalSection cs_inventory; std::set<uint256> setAskFor; std::multimap<int64_t, CInv> mapAskFor; - int64_t nNextInvSend; + int64_t nNextInvSend{0}; // Used for headers announcements - unfiltered blocks to relay std::vector<uint256> vBlockHashesToAnnounce GUARDED_BY(cs_inventory); // Used for BIP35 mempool sending - bool fSendMempool GUARDED_BY(cs_inventory); + bool fSendMempool GUARDED_BY(cs_inventory){false}; // Last time a "MEMPOOL" request was serviced. - std::atomic<int64_t> timeLastMempoolReq; + std::atomic<int64_t> timeLastMempoolReq{0}; // Block and TXN accept times - std::atomic<int64_t> nLastBlockTime; - std::atomic<int64_t> nLastTXTime; + std::atomic<int64_t> nLastBlockTime{0}; + std::atomic<int64_t> nLastTXTime{0}; // Ping time measurement: // The pong reply we're expecting, or 0 if no pong expected. - std::atomic<uint64_t> nPingNonceSent; + std::atomic<uint64_t> nPingNonceSent{0}; // Time (in usec) the last ping was sent, or 0 if no ping was ever sent. - std::atomic<int64_t> nPingUsecStart; + std::atomic<int64_t> nPingUsecStart{0}; // Last measured round-trip time. - std::atomic<int64_t> nPingUsecTime; + std::atomic<int64_t> nPingUsecTime{0}; // Best measured round-trip time. - std::atomic<int64_t> nMinPingUsecTime; + std::atomic<int64_t> nMinPingUsecTime{std::numeric_limits<int64_t>::max()}; // Whether a ping is requested. - std::atomic<bool> fPingQueued; + std::atomic<bool> fPingQueued{false}; // Minimum fee rate with which to filter inv's to this node - CAmount minFeeFilter GUARDED_BY(cs_feeFilter); + CAmount minFeeFilter GUARDED_BY(cs_feeFilter){0}; CCriticalSection cs_feeFilter; - CAmount lastSentFeeFilter; - int64_t nextSendTimeFeeFilter; + CAmount lastSentFeeFilter{0}; + int64_t nextSendTimeFeeFilter{0}; CNode(NodeId id, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn, SOCKET hSocketIn, const CAddress &addrIn, uint64_t nKeyedNetGroupIn, uint64_t nLocalHostNonceIn, const CAddress &addrBindIn, const std::string &addrNameIn = "", bool fInboundIn = false); ~CNode(); @@ -766,7 +747,7 @@ private: // Services offered to this peer const ServiceFlags nLocalServices; const int nMyStartingHeight; - int nSendVersion; + int nSendVersion{0}; std::list<CNetMessage> vRecvMsg; // Used only by SocketHandler thread mutable CCriticalSection cs_addrName; diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 0e222bdfa4..62b7d4e966 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -6,6 +6,7 @@ #include <net_processing.h> #include <addrman.h> +#include <banman.h> #include <arith_uint256.h> #include <blockencodings.h> #include <chainparams.h> @@ -841,9 +842,8 @@ static bool BlockRequestAllowed(const CBlockIndex* pindex, const Consensus::Para (GetBlockProofEquivalentTime(*pindexBestHeader, *pindex, *pindexBestHeader, consensusParams) < STALE_RELAY_AGE_LIMIT); } -PeerLogicValidation::PeerLogicValidation(CConnman* connmanIn, CScheduler &scheduler, bool enable_bip61) - : connman(connmanIn), m_stale_tip_check_time(0), m_enable_bip61(enable_bip61) { - +PeerLogicValidation::PeerLogicValidation(CConnman* connmanIn, BanMan* banman, CScheduler &scheduler, bool enable_bip61) + : connman(connmanIn), m_banman(banman), m_stale_tip_check_time(0), m_enable_bip61(enable_bip61) { // Initialize global variables that cannot be constructed at startup. recentRejects.reset(new CRollingBloomFilter(120000, 0.000001)); @@ -2943,7 +2943,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr return true; } -static bool SendRejectsAndCheckIfBanned(CNode* pnode, CConnman* connman, bool enable_bip61) EXCLUSIVE_LOCKS_REQUIRED(cs_main) +bool PeerLogicValidation::SendRejectsAndCheckIfBanned(CNode* pnode, bool enable_bip61) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { AssertLockHeld(cs_main); CNodeState &state = *State(pnode->GetId()); @@ -2961,14 +2961,16 @@ static bool SendRejectsAndCheckIfBanned(CNode* pnode, CConnman* connman, bool en LogPrintf("Warning: not punishing whitelisted peer %s!\n", pnode->addr.ToString()); else if (pnode->m_manual_connection) LogPrintf("Warning: not punishing manually-connected peer %s!\n", pnode->addr.ToString()); - else { + else if (pnode->addr.IsLocal()) { + // Disconnect but don't ban _this_ local node + LogPrintf("Warning: disconnecting but not banning local peer %s!\n", pnode->addr.ToString()); pnode->fDisconnect = true; - if (pnode->addr.IsLocal()) - LogPrintf("Warning: not banning local peer %s!\n", pnode->addr.ToString()); - else - { - connman->Ban(pnode->addr, BanReasonNodeMisbehaving); + } else { + // Disconnect and ban all nodes sharing the address + if (m_banman) { + m_banman->Ban(pnode->addr, BanReasonNodeMisbehaving); } + connman->DisconnectNode(pnode->addr); } return true; } @@ -3092,7 +3094,7 @@ bool PeerLogicValidation::ProcessMessages(CNode* pfrom, std::atomic<bool>& inter } LOCK(cs_main); - SendRejectsAndCheckIfBanned(pfrom, connman, m_enable_bip61); + SendRejectsAndCheckIfBanned(pfrom, m_enable_bip61); return fMoreWork; } @@ -3293,8 +3295,7 @@ bool PeerLogicValidation::SendMessages(CNode* pto) if (!lockMain) return true; - if (SendRejectsAndCheckIfBanned(pto, connman, m_enable_bip61)) - return true; + if (SendRejectsAndCheckIfBanned(pto, m_enable_bip61)) return true; CNodeState &state = *State(pto->GetId()); // Address refresh broadcast diff --git a/src/net_processing.h b/src/net_processing.h index 0113e25f7e..39c22d7118 100644 --- a/src/net_processing.h +++ b/src/net_processing.h @@ -23,9 +23,11 @@ static constexpr bool DEFAULT_ENABLE_BIP61{false}; class PeerLogicValidation final : public CValidationInterface, public NetEventsInterface { private: CConnman* const connman; + BanMan* const m_banman; + bool SendRejectsAndCheckIfBanned(CNode* pnode, bool enable_bip61) EXCLUSIVE_LOCKS_REQUIRED(cs_main); public: - explicit PeerLogicValidation(CConnman* connman, CScheduler &scheduler, bool enable_bip61); + PeerLogicValidation(CConnman* connman, BanMan* banman, CScheduler &scheduler, bool enable_bip61); /** * Overridden from CValidationInterface. 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/optional.h b/src/optional.h new file mode 100644 index 0000000000..95a3b24d0a --- /dev/null +++ b/src/optional.h @@ -0,0 +1,26 @@ +// Copyright (c) 2017 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_OPTIONAL_H +#define BITCOIN_OPTIONAL_H + +#include <utility> + +#include <boost/optional.hpp> + +//! Substitute for C++17 std::optional +template <typename T> +using Optional = boost::optional<T>; + +//! Substitute for C++17 std::make_optional +template <typename T> +Optional<T> MakeOptional(bool condition, T&& value) +{ + return boost::make_optional(condition, std::forward<T>(value)); +} + +//! Substitute for C++17 std::nullopt +static auto& nullopt = boost::none; + +#endif // BITCOIN_OPTIONAL_H diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h index c88d5b1ad3..f6f8e31363 100644 --- a/src/primitives/transaction.h +++ b/src/primitives/transaction.h @@ -298,7 +298,7 @@ public: CTransaction(); /** Convert a CMutableTransaction into a CTransaction. */ - CTransaction(const CMutableTransaction &tx); + explicit CTransaction(const CMutableTransaction &tx); CTransaction(CMutableTransaction &&tx); template <typename Stream> diff --git a/src/protocol.h b/src/protocol.h index 50d197415b..a790a06906 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -402,7 +402,6 @@ public: std::string GetCommand() const; std::string ToString() const; - // TODO: make private (improves encapsulation) public: int type; uint256 hash; diff --git a/src/qt/addressbookpage.cpp b/src/qt/addressbookpage.cpp index 26bdf60d4a..726dafccb0 100644 --- a/src/qt/addressbookpage.cpp +++ b/src/qt/addressbookpage.cpp @@ -59,7 +59,7 @@ protected: AddressBookPage::AddressBookPage(const PlatformStyle *platformStyle, Mode _mode, Tabs _tab, QWidget *parent) : QDialog(parent), ui(new Ui::AddressBookPage), - model(0), + model(nullptr), mode(_mode), tab(_tab) { diff --git a/src/qt/addressbookpage.h b/src/qt/addressbookpage.h index 32ab2dfeb5..6394d26801 100644 --- a/src/qt/addressbookpage.h +++ b/src/qt/addressbookpage.h @@ -38,7 +38,7 @@ public: ForEditing /**< Open address book for editing */ }; - explicit AddressBookPage(const PlatformStyle *platformStyle, Mode mode, Tabs tab, QWidget *parent = 0); + explicit AddressBookPage(const PlatformStyle *platformStyle, Mode mode, Tabs tab, QWidget *parent = nullptr); ~AddressBookPage(); void setModel(AddressTableModel *model); diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp index 2f88e15d21..c3143e948a 100644 --- a/src/qt/addresstablemodel.cpp +++ b/src/qt/addresstablemodel.cpp @@ -153,7 +153,7 @@ public: } else { - return 0; + return nullptr; } } }; @@ -300,8 +300,8 @@ QVariant AddressTableModel::headerData(int section, Qt::Orientation orientation, Qt::ItemFlags AddressTableModel::flags(const QModelIndex &index) const { - if(!index.isValid()) - return 0; + if (!index.isValid()) return Qt::NoItemFlags; + AddressTableEntry *rec = static_cast<AddressTableEntry*>(index.internalPointer()); Qt::ItemFlags retval = Qt::ItemIsSelectable | Qt::ItemIsEnabled; diff --git a/src/qt/addresstablemodel.h b/src/qt/addresstablemodel.h index 41bed4e290..035f3e0571 100644 --- a/src/qt/addresstablemodel.h +++ b/src/qt/addresstablemodel.h @@ -25,7 +25,7 @@ class AddressTableModel : public QAbstractTableModel Q_OBJECT public: - explicit AddressTableModel(WalletModel *parent = 0); + explicit AddressTableModel(WalletModel *parent = nullptr); ~AddressTableModel(); enum ColumnIndex { diff --git a/src/qt/askpassphrasedialog.cpp b/src/qt/askpassphrasedialog.cpp index 821c23c467..a89a15bc9d 100644 --- a/src/qt/askpassphrasedialog.cpp +++ b/src/qt/askpassphrasedialog.cpp @@ -22,7 +22,7 @@ AskPassphraseDialog::AskPassphraseDialog(Mode _mode, QWidget *parent) : QDialog(parent), ui(new Ui::AskPassphraseDialog), mode(_mode), - model(0), + model(nullptr), fCapsLock(false) { ui->setupUi(this); diff --git a/src/qt/bantablemodel.cpp b/src/qt/bantablemodel.cpp index dcfe3dcc57..00c446cc63 100644 --- a/src/qt/bantablemodel.cpp +++ b/src/qt/bantablemodel.cpp @@ -40,8 +40,8 @@ class BanTablePriv public: /** Local cache of peer information */ QList<CCombinedBan> cachedBanlist; - /** Column to sort nodes by */ - int sortColumn; + /** Column to sort nodes by (default to unsorted) */ + int sortColumn{-1}; /** Order (ascending or descending) to sort nodes by */ Qt::SortOrder sortOrder; @@ -76,7 +76,7 @@ public: if (idx >= 0 && idx < cachedBanlist.size()) return &cachedBanlist[idx]; - return 0; + return nullptr; } }; @@ -87,8 +87,6 @@ BanTableModel::BanTableModel(interfaces::Node& node, ClientModel *parent) : { columns << tr("IP/Netmask") << tr("Banned Until"); priv.reset(new BanTablePriv()); - // default to unsorted - priv->sortColumn = -1; // load initial data refresh(); @@ -147,8 +145,7 @@ QVariant BanTableModel::headerData(int section, Qt::Orientation orientation, int Qt::ItemFlags BanTableModel::flags(const QModelIndex &index) const { - if(!index.isValid()) - return 0; + if (!index.isValid()) return Qt::NoItemFlags; Qt::ItemFlags retval = Qt::ItemIsSelectable | Qt::ItemIsEnabled; return retval; diff --git a/src/qt/bantablemodel.h b/src/qt/bantablemodel.h index b8505b599f..9dec5fa6a9 100644 --- a/src/qt/bantablemodel.h +++ b/src/qt/bantablemodel.h @@ -45,7 +45,7 @@ class BanTableModel : public QAbstractTableModel Q_OBJECT public: - explicit BanTableModel(interfaces::Node& node, ClientModel *parent = 0); + explicit BanTableModel(interfaces::Node& node, ClientModel *parent = nullptr); ~BanTableModel(); void startAutoRefresh(); void stopAutoRefresh(); diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index eaeb93a652..85d79ee26c 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2018 The Bitcoin Core developers +// Copyright (c) 2011-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. @@ -6,6 +6,7 @@ #include <config/bitcoin-config.h> #endif +#include <qt/bitcoin.h> #include <qt/bitcoingui.h> #include <chainparams.h> @@ -23,7 +24,7 @@ #ifdef ENABLE_WALLET #include <qt/paymentserver.h> -#include <qt/walletmodel.h> +#include <qt/walletcontroller.h> #endif #include <interfaces/handler.h> @@ -71,11 +72,6 @@ Q_DECLARE_METATYPE(bool*) Q_DECLARE_METATYPE(CAmount) Q_DECLARE_METATYPE(uint256) -/** Translate string to current locale using Qt. */ -const std::function<std::string(const char*)> G_TRANSLATION_FUN = [](const char* psz) { - return QCoreApplication::translate("bitcoin-core", psz).toStdString(); -}; - static QString GetLangTerritory() { QSettings settings; @@ -140,101 +136,6 @@ void DebugMessageHandler(QtMsgType type, const QMessageLogContext& context, cons } } -/** Class encapsulating Bitcoin Core startup and shutdown. - * Allows running startup and shutdown in a different thread from the UI thread. - */ -class BitcoinCore: public QObject -{ - Q_OBJECT -public: - explicit BitcoinCore(interfaces::Node& node); - -public Q_SLOTS: - void initialize(); - void shutdown(); - -Q_SIGNALS: - void initializeResult(bool success); - void shutdownResult(); - void runawayException(const QString &message); - -private: - /// Pass fatal exception message to UI thread - void handleRunawayException(const std::exception *e); - - interfaces::Node& m_node; -}; - -/** Main Bitcoin application object */ -class BitcoinApplication: public QApplication -{ - Q_OBJECT -public: - explicit BitcoinApplication(interfaces::Node& node, int &argc, char **argv); - ~BitcoinApplication(); - -#ifdef ENABLE_WALLET - /// Create payment server - void createPaymentServer(); -#endif - /// parameter interaction/setup based on rules - void parameterSetup(); - /// Create options model - void createOptionsModel(bool resetSettings); - /// Create main window - void createWindow(const NetworkStyle *networkStyle); - /// Create splash screen - void createSplashScreen(const NetworkStyle *networkStyle); - - /// Request core initialization - void requestInitialize(); - /// Request core shutdown - void requestShutdown(); - - /// Get process return value - int getReturnValue() const { return returnValue; } - - /// Get window identifier of QMainWindow (BitcoinGUI) - WId getMainWinId() const; - - /// Setup platform style - void setupPlatformStyle(); - -public Q_SLOTS: - void initializeResult(bool success); - void shutdownResult(); - /// Handle runaway exceptions. Shows a message box with the problem and quits the program. - void handleRunawayException(const QString &message); - void addWallet(WalletModel* walletModel); - void removeWallet(); - -Q_SIGNALS: - void requestedInitialize(); - void requestedShutdown(); - void stopThread(); - void splashFinished(); - -private: - QThread *coreThread; - interfaces::Node& m_node; - OptionsModel *optionsModel; - ClientModel *clientModel; - BitcoinGUI *window; - QTimer *pollShutdownTimer; -#ifdef ENABLE_WALLET - PaymentServer* paymentServer; - std::vector<WalletModel*> m_wallet_models; - std::unique_ptr<interfaces::Handler> m_handler_load_wallet; -#endif - int returnValue; - const PlatformStyle *platformStyle; - std::unique_ptr<QWidget> shutdownWindow; - - void startThread(); -}; - -#include <qt/bitcoin.moc> - BitcoinCore::BitcoinCore(interfaces::Node& node) : QObject(), m_node(node) { @@ -277,18 +178,14 @@ void BitcoinCore::shutdown() BitcoinApplication::BitcoinApplication(interfaces::Node& node, int &argc, char **argv): QApplication(argc, argv), - coreThread(0), + coreThread(nullptr), m_node(node), - optionsModel(0), - clientModel(0), - window(0), - pollShutdownTimer(0), -#ifdef ENABLE_WALLET - paymentServer(0), - m_wallet_models(), -#endif + optionsModel(nullptr), + clientModel(nullptr), + window(nullptr), + pollShutdownTimer(nullptr), returnValue(0), - platformStyle(0) + platformStyle(nullptr) { setQuitOnLastWindowClosed(false); } @@ -311,21 +208,23 @@ BitcoinApplication::~BitcoinApplication() if(coreThread) { qDebug() << __func__ << ": Stopping thread"; - Q_EMIT stopThread(); + coreThread->quit(); coreThread->wait(); qDebug() << __func__ << ": Stopped thread"; } delete window; - window = 0; + window = nullptr; #ifdef ENABLE_WALLET delete paymentServer; - paymentServer = 0; + paymentServer = nullptr; + delete m_wallet_controller; + m_wallet_controller = nullptr; #endif delete optionsModel; - optionsModel = 0; + optionsModel = nullptr; delete platformStyle; - platformStyle = 0; + platformStyle = nullptr; } #ifdef ENABLE_WALLET @@ -342,7 +241,7 @@ void BitcoinApplication::createOptionsModel(bool resetSettings) void BitcoinApplication::createWindow(const NetworkStyle *networkStyle) { - window = new BitcoinGUI(m_node, platformStyle, networkStyle, 0); + window = new BitcoinGUI(m_node, platformStyle, networkStyle, nullptr); pollShutdownTimer = new QTimer(window); connect(pollShutdownTimer, &QTimer::timeout, window, &BitcoinGUI::detectShutdown); @@ -350,7 +249,7 @@ void BitcoinApplication::createWindow(const NetworkStyle *networkStyle) void BitcoinApplication::createSplashScreen(const NetworkStyle *networkStyle) { - SplashScreen *splash = new SplashScreen(m_node, 0, networkStyle); + SplashScreen *splash = new SplashScreen(m_node, nullptr, networkStyle); // We don't hold a direct pointer to the splash screen after creation, but the splash // screen will take care of deleting itself when finish() happens. splash->show(); @@ -358,6 +257,11 @@ void BitcoinApplication::createSplashScreen(const NetworkStyle *networkStyle) connect(this, &BitcoinApplication::requestedShutdown, splash, &QWidget::close); } +bool BitcoinApplication::baseInitialize() +{ + return m_node.baseInitialize(); +} + void BitcoinApplication::startThread() { if(coreThread) @@ -373,8 +277,7 @@ void BitcoinApplication::startThread() connect(this, &BitcoinApplication::requestedInitialize, executor, &BitcoinCore::initialize); connect(this, &BitcoinApplication::requestedShutdown, executor, &BitcoinCore::shutdown); /* make sure executor object is deleted in its own thread */ - connect(this, &BitcoinApplication::stopThread, executor, &QObject::deleteLater); - connect(this, &BitcoinApplication::stopThread, coreThread, &QThread::quit); + connect(coreThread, &QThread::finished, executor, &QObject::deleteLater); coreThread->start(); } @@ -406,54 +309,24 @@ void BitcoinApplication::requestShutdown() qDebug() << __func__ << ": Requesting shutdown"; startThread(); window->hide(); - window->setClientModel(0); + // 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 - window->removeAllWallets(); - for (const WalletModel* walletModel : m_wallet_models) { - delete walletModel; - } - m_wallet_models.clear(); -#endif delete clientModel; - clientModel = 0; - - m_node.startShutdown(); + clientModel = nullptr; // Request shutdown from core thread Q_EMIT requestedShutdown(); } -void BitcoinApplication::addWallet(WalletModel* walletModel) -{ -#ifdef ENABLE_WALLET - window->addWallet(walletModel); - - if (m_wallet_models.empty()) { - window->setCurrentWallet(walletModel->getWalletName()); - } - -#ifdef ENABLE_BIP70 - connect(walletModel, &WalletModel::coinsSent, - paymentServer, &PaymentServer::fetchPaymentACK); -#endif - connect(walletModel, &WalletModel::unload, this, &BitcoinApplication::removeWallet); - - m_wallet_models.push_back(walletModel); -#endif -} - -void BitcoinApplication::removeWallet() -{ -#ifdef ENABLE_WALLET - WalletModel* walletModel = static_cast<WalletModel*>(sender()); - m_wallet_models.erase(std::find(m_wallet_models.begin(), m_wallet_models.end(), walletModel)); - window->removeWallet(walletModel); - walletModel->deleteLater(); -#endif -} - void BitcoinApplication::initializeResult(bool success) { qDebug() << __func__ << ": Initialization result: " << success; @@ -464,48 +337,46 @@ void BitcoinApplication::initializeResult(bool success) // Log this only after AppInitMain finishes, as then logging setup is guaranteed complete qWarning() << "Platform customization:" << platformStyle->getName(); #ifdef ENABLE_WALLET + m_wallet_controller = new WalletController(m_node, platformStyle, optionsModel, this); #ifdef ENABLE_BIP70 PaymentServer::LoadRootCAs(); #endif - paymentServer->setOptionsModel(optionsModel); + if (paymentServer) { + paymentServer->setOptionsModel(optionsModel); +#ifdef ENABLE_BIP70 + connect(m_wallet_controller, &WalletController::coinsSent, paymentServer, &PaymentServer::fetchPaymentACK); +#endif + } #endif clientModel = new ClientModel(m_node, optionsModel); window->setClientModel(clientModel); - #ifdef ENABLE_WALLET - m_handler_load_wallet = m_node.handleLoadWallet([this](std::unique_ptr<interfaces::Wallet> wallet) { - WalletModel* wallet_model = new WalletModel(std::move(wallet), m_node, platformStyle, optionsModel, nullptr); - // Fix wallet model thread affinity. - wallet_model->moveToThread(thread()); - QMetaObject::invokeMethod(this, "addWallet", Qt::QueuedConnection, Q_ARG(WalletModel*, wallet_model)); - }); - - for (auto& wallet : m_node.getWallets()) { - addWallet(new WalletModel(std::move(wallet), m_node, platformStyle, optionsModel)); - } + window->setWalletController(m_wallet_controller); #endif - // If -min option passed, start window minimized. - if(gArgs.GetBoolArg("-min", false)) - { - window->showMinimized(); - } - else - { + // If -min option passed, start window minimized (iconified) or minimized to tray + if (!gArgs.GetBoolArg("-min", false)) { window->show(); + } else if (clientModel->getOptionsModel()->getMinimizeToTray() && window->hasTrayIcon()) { + // do nothing as the window is managed by the tray icon + } else { + window->showMinimized(); } Q_EMIT splashFinished(); + Q_EMIT windowShown(window); #ifdef ENABLE_WALLET // Now that initialization/startup is done, process any command-line // bitcoin: URIs or payment requests: - connect(paymentServer, &PaymentServer::receivedPaymentRequest, window, &BitcoinGUI::handlePaymentRequest); - connect(window, &BitcoinGUI::receivedURI, paymentServer, &PaymentServer::handleURIOrFile); - connect(paymentServer, &PaymentServer::message, [this](const QString& title, const QString& message, unsigned int style) { - window->message(title, message, style); - }); - QTimer::singleShot(100, paymentServer, &PaymentServer::uiReady); + if (paymentServer) { + connect(paymentServer, &PaymentServer::receivedPaymentRequest, window, &BitcoinGUI::handlePaymentRequest); + connect(window, &BitcoinGUI::receivedURI, paymentServer, &PaymentServer::handleURIOrFile); + connect(paymentServer, &PaymentServer::message, [this](const QString& title, const QString& message, unsigned int style) { + window->message(title, message, style); + }); + QTimer::singleShot(100, paymentServer, &PaymentServer::uiReady); + } #endif pollShutdownTimer->start(200); } else { @@ -521,7 +392,7 @@ void BitcoinApplication::shutdownResult() void BitcoinApplication::handleRunawayException(const QString &message) { - QMessageBox::critical(0, "Runaway exception", BitcoinGUI::tr("A fatal error occurred. Bitcoin can no longer continue safely and will quit.") + QString("\n\n") + message); + QMessageBox::critical(nullptr, "Runaway exception", BitcoinGUI::tr("A fatal error occurred. Bitcoin can no longer continue safely and will quit.") + QString("\n\n") + message); ::exit(EXIT_FAILURE); } @@ -548,7 +419,7 @@ static void SetupUIArgs() } #ifndef BITCOIN_QT_TEST -int main(int argc, char *argv[]) +int GuiMain(int argc, char* argv[]) { #ifdef WIN32 util::WinCmdLineArgs winArgs; @@ -585,9 +456,6 @@ int main(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()>"); -#ifdef ENABLE_WALLET - qRegisterMetaType<WalletModel*>("WalletModel*"); -#endif /// 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: @@ -595,7 +463,7 @@ int main(int argc, char *argv[]) SetupUIArgs(); std::string error; if (!node->parseParameters(argc, argv, error)) { - QMessageBox::critical(0, QObject::tr(PACKAGE_NAME), + QMessageBox::critical(nullptr, QObject::tr(PACKAGE_NAME), QObject::tr("Error parsing command line arguments: %1.").arg(QString::fromStdString(error))); return EXIT_FAILURE; } @@ -632,12 +500,12 @@ int main(int argc, char *argv[]) /// - Do not call GetDataDir(true) before this step finishes if (!fs::is_directory(GetDataDir(false))) { - QMessageBox::critical(0, QObject::tr(PACKAGE_NAME), - QObject::tr("Error: Specified data directory \"%1\" does not exist.").arg(QString::fromStdString(gArgs.GetArg("-datadir", "")))); + QMessageBox::critical(nullptr, QObject::tr(PACKAGE_NAME), + QObject::tr("Error: Specified data directory \"%1\" does not exist.").arg(QString::fromStdString(gArgs.GetArg("-datadir", "")))); return EXIT_FAILURE; } if (!node->readConfigFiles(error)) { - QMessageBox::critical(0, QObject::tr(PACKAGE_NAME), + QMessageBox::critical(nullptr, QObject::tr(PACKAGE_NAME), QObject::tr("Error: Cannot parse configuration file: %1.").arg(QString::fromStdString(error))); return EXIT_FAILURE; } @@ -652,7 +520,7 @@ int main(int argc, char *argv[]) try { node->selectParams(gArgs.GetChainName()); } catch(std::exception &e) { - QMessageBox::critical(0, QObject::tr(PACKAGE_NAME), QObject::tr("Error: %1").arg(e.what())); + QMessageBox::critical(nullptr, QObject::tr(PACKAGE_NAME), QObject::tr("Error: %1").arg(e.what())); return EXIT_FAILURE; } #ifdef ENABLE_WALLET @@ -706,7 +574,7 @@ int main(int argc, char *argv[]) // Perform base initialization before spinning up initialization/shutdown thread // This is acceptable because this function only contains steps that are quick to execute, // so the GUI thread won't be held up. - if (node->baseInitialize()) { + if (app.baseInitialize()) { app.requestInitialize(); #if defined(Q_OS_WIN) WinShutdownMonitor::registerShutdownBlockReason(QObject::tr("%1 didn't yet exit safely...").arg(QObject::tr(PACKAGE_NAME)), (HWND)app.getMainWinId()); diff --git a/src/qt/bitcoin.h b/src/qt/bitcoin.h new file mode 100644 index 0000000000..370712d953 --- /dev/null +++ b/src/qt/bitcoin.h @@ -0,0 +1,124 @@ +// Copyright (c) 2011-2016 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_QT_BITCOIN_H +#define BITCOIN_QT_BITCOIN_H + +#if defined(HAVE_CONFIG_H) +#include <config/bitcoin-config.h> +#endif + +#include <QApplication> +#include <memory> +#include <vector> + +class BitcoinGUI; +class ClientModel; +class NetworkStyle; +class OptionsModel; +class PaymentServer; +class PlatformStyle; +class WalletController; +class WalletModel; + +namespace interfaces { +class Handler; +class Node; +} // namespace interfaces + +/** Class encapsulating Bitcoin Core startup and shutdown. + * Allows running startup and shutdown in a different thread from the UI thread. + */ +class BitcoinCore: public QObject +{ + Q_OBJECT +public: + explicit BitcoinCore(interfaces::Node& node); + +public Q_SLOTS: + void initialize(); + void shutdown(); + +Q_SIGNALS: + void initializeResult(bool success); + void shutdownResult(); + void runawayException(const QString &message); + +private: + /// Pass fatal exception message to UI thread + void handleRunawayException(const std::exception *e); + + interfaces::Node& m_node; +}; + +/** Main Bitcoin application object */ +class BitcoinApplication: public QApplication +{ + Q_OBJECT +public: + explicit BitcoinApplication(interfaces::Node& node, int &argc, char **argv); + ~BitcoinApplication(); + +#ifdef ENABLE_WALLET + /// Create payment server + void createPaymentServer(); +#endif + /// parameter interaction/setup based on rules + void parameterSetup(); + /// Create options model + void createOptionsModel(bool resetSettings); + /// Create main window + void createWindow(const NetworkStyle *networkStyle); + /// Create splash screen + void createSplashScreen(const NetworkStyle *networkStyle); + /// Basic initialization, before starting initialization/shutdown thread. Return true on success. + bool baseInitialize(); + + /// Request core initialization + void requestInitialize(); + /// Request core shutdown + void requestShutdown(); + + /// Get process return value + int getReturnValue() const { return returnValue; } + + /// Get window identifier of QMainWindow (BitcoinGUI) + WId getMainWinId() const; + + /// Setup platform style + void setupPlatformStyle(); + +public Q_SLOTS: + void initializeResult(bool success); + void shutdownResult(); + /// Handle runaway exceptions. Shows a message box with the problem and quits the program. + void handleRunawayException(const QString &message); + +Q_SIGNALS: + void requestedInitialize(); + void requestedShutdown(); + void splashFinished(); + void windowShown(BitcoinGUI* window); + +private: + QThread *coreThread; + interfaces::Node& m_node; + OptionsModel *optionsModel; + ClientModel *clientModel; + BitcoinGUI *window; + QTimer *pollShutdownTimer; +#ifdef ENABLE_WALLET + PaymentServer* paymentServer{nullptr}; + WalletController* m_wallet_controller{nullptr}; +#endif + int returnValue; + const PlatformStyle *platformStyle; + std::unique_ptr<QWidget> shutdownWindow; + + void startThread(); +}; + +int GuiMain(int argc, char* argv[]); + +#endif // BITCOIN_QT_BITCOIN_H diff --git a/src/qt/bitcoinamountfield.cpp b/src/qt/bitcoinamountfield.cpp index 558fcf50ba..5854ade655 100644 --- a/src/qt/bitcoinamountfield.cpp +++ b/src/qt/bitcoinamountfield.cpp @@ -60,7 +60,7 @@ public: } } - CAmount value(bool *valid_out=0) const + CAmount value(bool *valid_out=nullptr) const { return parse(text(), valid_out); } @@ -159,7 +159,7 @@ private: * return validity. * @note Must return 0 if !valid. */ - CAmount parse(const QString &text, bool *valid_out=0) const + CAmount parse(const QString &text, bool *valid_out=nullptr) const { CAmount val = 0; bool valid = BitcoinUnits::parse(currentUnit, text, &val); @@ -196,7 +196,7 @@ protected: if (text().isEmpty()) // Allow step-up with empty field return StepUpEnabled; - StepEnabled rv = 0; + StepEnabled rv = StepNone; bool valid = false; CAmount val = value(&valid); if (valid) { @@ -216,7 +216,7 @@ Q_SIGNALS: BitcoinAmountField::BitcoinAmountField(QWidget *parent) : QWidget(parent), - amount(0) + amount(nullptr) { amount = new AmountSpinBox(this); amount->setLocale(QLocale::c()); diff --git a/src/qt/bitcoinamountfield.h b/src/qt/bitcoinamountfield.h index 650481e30d..2db6b65f2c 100644 --- a/src/qt/bitcoinamountfield.h +++ b/src/qt/bitcoinamountfield.h @@ -26,9 +26,9 @@ class BitcoinAmountField: public QWidget Q_PROPERTY(qint64 value READ value WRITE setValue NOTIFY valueChanged USER true) public: - explicit BitcoinAmountField(QWidget *parent = 0); + explicit BitcoinAmountField(QWidget *parent = nullptr); - CAmount value(bool *value=0) const; + CAmount value(bool *value=nullptr) const; void setValue(const CAmount& value); /** If allow empty is set to false the field will be set to the minimum allowed value if left empty. **/ diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 15e1b98fb4..ba7e8c7daf 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2018 The Bitcoin Core developers +// Copyright (c) 2011-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. @@ -19,6 +19,7 @@ #include <qt/utilitydialog.h> #ifdef ENABLE_WALLET +#include <qt/walletcontroller.h> #include <qt/walletframe.h> #include <qt/walletmodel.h> #include <qt/walletview.h> @@ -28,6 +29,7 @@ #include <qt/macdockiconhandler.h> #endif +#include <chain.h> #include <chainparams.h> #include <interfaces/handler.h> #include <interfaces/node.h> @@ -35,6 +37,7 @@ #include <util/system.h> #include <iostream> +#include <memory> #include <QAction> #include <QApplication> @@ -43,6 +46,7 @@ #include <QDesktopWidget> #include <QDragEnterEvent> #include <QListWidget> +#include <QMenu> #include <QMenuBar> #include <QMessageBox> #include <QMimeData> @@ -52,6 +56,7 @@ #include <QStackedWidget> #include <QStatusBar> #include <QStyle> +#include <QSystemTrayIcon> #include <QTimer> #include <QToolBar> #include <QUrlQuery> @@ -72,7 +77,9 @@ const std::string BitcoinGUI::DEFAULT_UIPLATFORM = BitcoinGUI::BitcoinGUI(interfaces::Node& node, const PlatformStyle *_platformStyle, const NetworkStyle *networkStyle, QWidget *parent) : QMainWindow(parent), m_node(node), - platformStyle(_platformStyle) + trayIconMenu{new QMenu()}, + platformStyle(_platformStyle), + m_network_style(networkStyle) { QSettings settings; if (!restoreGeometry(settings.value("MainWindowGeometry").toByteArray())) { @@ -80,22 +87,14 @@ BitcoinGUI::BitcoinGUI(interfaces::Node& node, const PlatformStyle *_platformSty move(QApplication::desktop()->availableGeometry().center() - frameGeometry().center()); } - QString windowTitle = tr(PACKAGE_NAME) + " - "; #ifdef ENABLE_WALLET enableWallet = WalletModel::isWalletEnabled(); #endif // ENABLE_WALLET - if(enableWallet) - { - windowTitle += tr("Wallet"); - } else { - windowTitle += tr("Node"); - } - windowTitle += " " + networkStyle->getTitleAddText(); - QApplication::setWindowIcon(networkStyle->getTrayAndWindowIcon()); - setWindowIcon(networkStyle->getTrayAndWindowIcon()); - setWindowTitle(windowTitle); + QApplication::setWindowIcon(m_network_style->getTrayAndWindowIcon()); + setWindowIcon(m_network_style->getTrayAndWindowIcon()); + updateWindowTitle(); - rpcConsole = new RPCConsole(node, _platformStyle, 0); + rpcConsole = new RPCConsole(node, _platformStyle, nullptr); helpMessageDialog = new HelpMessageDialog(node, this, false); #ifdef ENABLE_WALLET if(enableWallet) @@ -110,6 +109,7 @@ BitcoinGUI::BitcoinGUI(interfaces::Node& node, const PlatformStyle *_platformSty * the central widget is the rpc console. */ setCentralWidget(rpcConsole); + Q_EMIT consoleShown(rpcConsole); } // Accept D&D of URIs @@ -127,8 +127,9 @@ BitcoinGUI::BitcoinGUI(interfaces::Node& node, const PlatformStyle *_platformSty // Create system tray icon and notification if (QSystemTrayIcon::isSystemTrayAvailable()) { - createTrayIcon(networkStyle); + createTrayIcon(); } + notificator = new Notificator(QApplication::applicationName(), trayIcon, this); // Create status bar statusBar(); @@ -323,6 +324,7 @@ void BitcoinGUI::createActions() openRPCConsoleAction->setStatusTip(tr("Open debugging and diagnostic console")); // initially disable the debug window menu item openRPCConsoleAction->setEnabled(false); + openRPCConsoleAction->setObjectName("openRPCConsoleAction"); usedSendingAddressesAction = new QAction(platformStyle->TextColorIcon(":/icons/address-book"), tr("&Sending addresses"), this); usedSendingAddressesAction->setStatusTip(tr("Show the list of used sending addresses and labels")); @@ -482,6 +484,7 @@ void BitcoinGUI::createToolBars() toolbar->addWidget(spacer); m_wallet_selector = new QComboBox(); + m_wallet_selector->setSizeAdjustPolicy(QComboBox::AdjustToContents); connect(m_wallet_selector, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &BitcoinGUI::setCurrentWalletBySelectorIndex); m_wallet_selector_label = new QLabel(); @@ -536,8 +539,7 @@ void BitcoinGUI::setClientModel(ClientModel *_clientModel) unitDisplayControl->setOptionsModel(_clientModel->getOptionsModel()); OptionsModel* optionsModel = _clientModel->getOptionsModel(); - if(optionsModel) - { + if (optionsModel && trayIcon) { // be aware of the tray icon disable state change reported by the OptionsModel object. connect(optionsModel, &OptionsModel::hideTrayIconChanged, this, &BitcoinGUI::setTrayIconVisible); @@ -565,27 +567,39 @@ void BitcoinGUI::setClientModel(ClientModel *_clientModel) } #ifdef ENABLE_WALLET -bool BitcoinGUI::addWallet(WalletModel *walletModel) +void BitcoinGUI::setWalletController(WalletController* wallet_controller) { - if(!walletFrame) - return false; - const QString name = walletModel->getWalletName(); - QString display_name = name.isEmpty() ? "["+tr("default wallet")+"]" : name; + assert(!m_wallet_controller); + assert(wallet_controller); + + m_wallet_controller = wallet_controller; + + connect(wallet_controller, &WalletController::walletAdded, this, &BitcoinGUI::addWallet); + connect(wallet_controller, &WalletController::walletRemoved, this, &BitcoinGUI::removeWallet); + + for (WalletModel* wallet_model : m_wallet_controller->getWallets()) { + addWallet(wallet_model); + } +} + +void BitcoinGUI::addWallet(WalletModel* walletModel) +{ + if (!walletFrame) return; + const QString display_name = walletModel->getDisplayName(); setWalletActionsEnabled(true); - m_wallet_selector->addItem(display_name, name); + rpcConsole->addWallet(walletModel); + walletFrame->addWallet(walletModel); + m_wallet_selector->addItem(display_name, QVariant::fromValue(walletModel)); if (m_wallet_selector->count() == 2) { m_wallet_selector_label_action->setVisible(true); m_wallet_selector_action->setVisible(true); } - rpcConsole->addWallet(walletModel); - return walletFrame->addWallet(walletModel); } -bool BitcoinGUI::removeWallet(WalletModel* walletModel) +void BitcoinGUI::removeWallet(WalletModel* walletModel) { - if (!walletFrame) return false; - QString name = walletModel->getWalletName(); - int index = m_wallet_selector->findData(name); + if (!walletFrame) return; + int index = m_wallet_selector->findData(QVariant::fromValue(walletModel)); m_wallet_selector->removeItem(index); if (m_wallet_selector->count() == 0) { setWalletActionsEnabled(false); @@ -594,20 +608,27 @@ bool BitcoinGUI::removeWallet(WalletModel* walletModel) m_wallet_selector_action->setVisible(false); } rpcConsole->removeWallet(walletModel); - return walletFrame->removeWallet(name); + walletFrame->removeWallet(walletModel); + updateWindowTitle(); } -bool BitcoinGUI::setCurrentWallet(const QString& name) +void BitcoinGUI::setCurrentWallet(WalletModel* wallet_model) { - if(!walletFrame) - return false; - return walletFrame->setCurrentWallet(name); + if (!walletFrame) return; + walletFrame->setCurrentWallet(wallet_model); + for (int index = 0; index < m_wallet_selector->count(); ++index) { + if (m_wallet_selector->itemData(index).value<WalletModel*>() == wallet_model) { + m_wallet_selector->setCurrentIndex(index); + break; + } + } + updateWindowTitle(); } -bool BitcoinGUI::setCurrentWalletBySelectorIndex(int index) +void BitcoinGUI::setCurrentWalletBySelectorIndex(int index) { - QString internal_name = m_wallet_selector->itemData(index).toString(); - return setCurrentWallet(internal_name); + WalletModel* wallet_model = m_wallet_selector->itemData(index).value<WalletModel*>(); + if (wallet_model) setCurrentWallet(wallet_model); } void BitcoinGUI::removeAllWallets() @@ -637,19 +658,17 @@ void BitcoinGUI::setWalletActionsEnabled(bool enabled) openAction->setEnabled(enabled); } -void BitcoinGUI::createTrayIcon(const NetworkStyle *networkStyle) +void BitcoinGUI::createTrayIcon() { assert(QSystemTrayIcon::isSystemTrayAvailable()); #ifndef Q_OS_MAC - trayIcon = new QSystemTrayIcon(this); - QString toolTip = tr("%1 client").arg(tr(PACKAGE_NAME)) + " " + networkStyle->getTitleAddText(); - trayIcon->setToolTip(toolTip); - trayIcon->setIcon(networkStyle->getTrayAndWindowIcon()); - trayIcon->hide(); + if (QSystemTrayIcon::isSystemTrayAvailable()) { + trayIcon = new QSystemTrayIcon(m_network_style->getTrayAndWindowIcon(), this); + QString toolTip = tr("%1 client").arg(tr(PACKAGE_NAME)) + " " + m_network_style->getTitleAddText(); + trayIcon->setToolTip(toolTip); + } #endif - - notificator = new Notificator(QApplication::applicationName(), trayIcon, this); } void BitcoinGUI::createTrayIconMenu() @@ -659,16 +678,12 @@ void BitcoinGUI::createTrayIconMenu() if (!trayIcon) return; - trayIconMenu = new QMenu(this); - trayIcon->setContextMenu(trayIconMenu); - + trayIcon->setContextMenu(trayIconMenu.get()); connect(trayIcon, &QSystemTrayIcon::activated, this, &BitcoinGUI::trayIconActivated); #else // Note: On macOS, the Dock icon is used to provide the tray's functionality. MacDockIconHandler *dockIconHandler = MacDockIconHandler::instance(); connect(dockIconHandler, &MacDockIconHandler::dockIconClicked, this, &BitcoinGUI::macosDockIconActivated); - - trayIconMenu = new QMenu(this); trayIconMenu->setAsDockMenu(); #endif @@ -728,6 +743,7 @@ void BitcoinGUI::aboutClicked() void BitcoinGUI::showDebugWindow() { GUIUtil::bringToFront(rpcConsole); + Q_EMIT consoleShown(rpcConsole); } void BitcoinGUI::showDebugWindowActivateConsole() @@ -902,8 +918,7 @@ void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVer tooltip = tr("Processed %n block(s) of transaction history.", "", count); // Set icon state: spinning if catching up, tick otherwise - if(secs < 90*60) - { + if (secs < MAX_BLOCK_TIME_GAP) { tooltip = tr("Up to date") + QString(".<br>") + tooltip; labelBlocksIcon->setPixmap(platformStyle->SingleColorIcon(":/icons/synced").pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE)); @@ -1197,7 +1212,7 @@ void BitcoinGUI::updateProxyIcon() bool proxy_enabled = clientModel->getProxyInfo(ip_port); if (proxy_enabled) { - if (labelProxyIcon->pixmap() == 0) { + if (labelProxyIcon->pixmap() == nullptr) { QString ip_port_q = QString::fromStdString(ip_port); labelProxyIcon->setPixmap(platformStyle->SingleColorIcon(":/icons/proxy").pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE)); labelProxyIcon->setToolTip(tr("Proxy is <b>enabled</b>: %1").arg(ip_port_q)); @@ -1209,6 +1224,23 @@ void BitcoinGUI::updateProxyIcon() } } +void BitcoinGUI::updateWindowTitle() +{ + QString window_title = tr(PACKAGE_NAME); +#ifdef ENABLE_WALLET + if (walletFrame) { + WalletModel* const wallet_model = walletFrame->currentWalletModel(); + if (wallet_model && !wallet_model->getWalletName().isEmpty()) { + window_title += " - " + wallet_model->getDisplayName(); + } + } +#endif + if (!m_network_style->getTitleAddText().isEmpty()) { + window_title += " - " + m_network_style->getTitleAddText(); + } + setWindowTitle(window_title); +} + void BitcoinGUI::showNormalIfMinimized(bool fToggleHidden) { if(!clientModel) @@ -1238,25 +1270,21 @@ void BitcoinGUI::detectShutdown() void BitcoinGUI::showProgress(const QString &title, int nProgress) { - if (nProgress == 0) - { - progressDialog = new QProgressDialog(title, "", 0, 100); + if (nProgress == 0) { + progressDialog = new QProgressDialog(title, QString(), 0, 100); + GUIUtil::PolishProgressDialog(progressDialog); progressDialog->setWindowModality(Qt::ApplicationModal); progressDialog->setMinimumDuration(0); - progressDialog->setCancelButton(0); progressDialog->setAutoClose(false); progressDialog->setValue(0); - } - else if (nProgress == 100) - { - if (progressDialog) - { + } else if (nProgress == 100) { + if (progressDialog) { progressDialog->close(); progressDialog->deleteLater(); } - } - else if (progressDialog) + } else if (progressDialog) { progressDialog->setValue(nProgress); + } } void BitcoinGUI::setTrayIconVisible(bool fHideTrayIcon) @@ -1305,8 +1333,8 @@ void BitcoinGUI::unsubscribeFromCoreSignals() } UnitDisplayStatusBarControl::UnitDisplayStatusBarControl(const PlatformStyle *platformStyle) : - optionsModel(0), - menu(0) + optionsModel(nullptr), + menu(nullptr) { createContextMenu(); setToolTip(tr("Unit to show amounts in. Click to select another unit.")); diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index aeff5dae30..c31cefe603 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2018 The Bitcoin Core developers +// Copyright (c) 2011-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. @@ -16,7 +16,6 @@ #include <QLabel> #include <QMainWindow> #include <QMap> -#include <QMenu> #include <QPoint> #include <QSystemTrayIcon> @@ -34,6 +33,7 @@ class PlatformStyle; class RPCConsole; class SendCoinsRecipient; class UnitDisplayStatusBarControl; +class WalletController; class WalletFrame; class WalletModel; class HelpMessageDialog; @@ -47,6 +47,7 @@ class Node; QT_BEGIN_NAMESPACE class QAction; class QComboBox; +class QMenu; class QProgressBar; class QProgressDialog; QT_END_NAMESPACE @@ -67,25 +68,36 @@ class BitcoinGUI : public QMainWindow public: static const std::string DEFAULT_UIPLATFORM; - explicit BitcoinGUI(interfaces::Node& node, const PlatformStyle *platformStyle, const NetworkStyle *networkStyle, QWidget *parent = 0); + explicit BitcoinGUI(interfaces::Node& node, const PlatformStyle *platformStyle, const NetworkStyle *networkStyle, QWidget *parent = nullptr); ~BitcoinGUI(); /** Set the client model. The client model represents the part of the core that communicates with the P2P network, and is wallet-agnostic. */ void setClientModel(ClientModel *clientModel); +#ifdef ENABLE_WALLET + void setWalletController(WalletController* wallet_controller); +#endif #ifdef ENABLE_WALLET /** Set the wallet model. The wallet model represents a bitcoin wallet, and offers access to the list of transactions, address book and sending functionality. */ - bool addWallet(WalletModel *walletModel); - bool removeWallet(WalletModel* walletModel); + void addWallet(WalletModel* walletModel); + void removeWallet(WalletModel* walletModel); void removeAllWallets(); #endif // ENABLE_WALLET bool enableWallet = false; + /** Get the tray icon status. + Some systems have not "system tray" or "notification area" available. + */ + bool hasTrayIcon() const { return trayIcon; } + + /** Disconnect core signals from GUI client */ + void unsubscribeFromCoreSignals(); + protected: void changeEvent(QEvent *e); void closeEvent(QCloseEvent *event); @@ -96,6 +108,7 @@ protected: private: interfaces::Node& m_node; + WalletController* m_wallet_controller{nullptr}; std::unique_ptr<interfaces::Handler> m_handler_message_box; std::unique_ptr<interfaces::Handler> m_handler_question; ClientModel* clientModel = nullptr; @@ -141,7 +154,7 @@ private: QComboBox* m_wallet_selector = nullptr; QSystemTrayIcon* trayIcon = nullptr; - QMenu* trayIconMenu = nullptr; + const std::unique_ptr<QMenu> trayIconMenu; Notificator* notificator = nullptr; RPCConsole* rpcConsole = nullptr; HelpMessageDialog* helpMessageDialog = nullptr; @@ -156,6 +169,7 @@ private: int spinnerFrame = 0; const PlatformStyle *platformStyle; + const NetworkStyle* const m_network_style; /** Create the main UI actions. */ void createActions(); @@ -164,7 +178,7 @@ private: /** Create the toolbars */ void createToolBars(); /** Create system tray icon and notification */ - void createTrayIcon(const NetworkStyle *networkStyle); + void createTrayIcon(); /** Create system tray menu (or setup the dock menu) */ void createTrayIconMenu(); @@ -173,8 +187,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(); @@ -187,6 +199,8 @@ private: Q_SIGNALS: /** Signal raised when a URI was entered or dragged to the GUI */ void receivedURI(const QString &uri); + /** Signal raised when RPC console shown */ + void consoleShown(RPCConsole* console); public Q_SLOTS: /** Set number of connections shown in the UI */ @@ -206,8 +220,8 @@ public Q_SLOTS: void message(const QString &title, const QString &message, unsigned int style, bool *ret = nullptr); #ifdef ENABLE_WALLET - bool setCurrentWallet(const QString& name); - bool setCurrentWalletBySelectorIndex(int index); + void setCurrentWallet(WalletModel* wallet_model); + void setCurrentWalletBySelectorIndex(int index); /** Set the UI status indicators based on the currently selected wallet. */ void updateWalletStatus(); @@ -235,6 +249,7 @@ public Q_SLOTS: private: /** Set the proxy-enabled icon as shown in the UI. */ void updateProxyIcon(); + void updateWindowTitle(); public Q_SLOTS: #ifdef ENABLE_WALLET 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 217326f818..30d9e977b8 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -35,9 +35,9 @@ ClientModel::ClientModel(interfaces::Node& node, OptionsModel *_optionsModel, QO QObject(parent), m_node(node), optionsModel(_optionsModel), - peerTableModel(0), - banTableModel(0), - pollTimer(0) + peerTableModel(nullptr), + banTableModel(nullptr), + pollTimer(nullptr) { cachedBestHeaderHeight = -1; cachedBestHeaderTime = -1; diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h index 79e7074cca..95f4521f06 100644 --- a/src/qt/clientmodel.h +++ b/src/qt/clientmodel.h @@ -46,7 +46,7 @@ class ClientModel : public QObject Q_OBJECT public: - explicit ClientModel(interfaces::Node& node, OptionsModel *optionsModel, QObject *parent = 0); + explicit ClientModel(interfaces::Node& node, OptionsModel *optionsModel, QObject *parent = nullptr); ~ClientModel(); interfaces::Node& node() const { return m_node; } diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index 77f8bcf901..0d9f1adcd2 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -49,7 +49,7 @@ bool CCoinControlWidgetItem::operator<(const QTreeWidgetItem &other) const { CoinControlDialog::CoinControlDialog(const PlatformStyle *_platformStyle, QWidget *parent) : QDialog(parent), ui(new Ui::CoinControlDialog), - model(0), + model(nullptr), platformStyle(_platformStyle) { ui->setupUi(this); diff --git a/src/qt/coincontroldialog.h b/src/qt/coincontroldialog.h index 8f15ae4b20..efc06a7656 100644 --- a/src/qt/coincontroldialog.h +++ b/src/qt/coincontroldialog.h @@ -43,7 +43,7 @@ class CoinControlDialog : public QDialog Q_OBJECT public: - explicit CoinControlDialog(const PlatformStyle *platformStyle, QWidget *parent = 0); + explicit CoinControlDialog(const PlatformStyle *platformStyle, QWidget *parent = nullptr); ~CoinControlDialog(); void setModel(WalletModel *model); diff --git a/src/qt/coincontroltreewidget.h b/src/qt/coincontroltreewidget.h index 62645fcdb0..88fc8b704f 100644 --- a/src/qt/coincontroltreewidget.h +++ b/src/qt/coincontroltreewidget.h @@ -13,7 +13,7 @@ class CoinControlTreeWidget : public QTreeWidget Q_OBJECT public: - explicit CoinControlTreeWidget(QWidget *parent = 0); + explicit CoinControlTreeWidget(QWidget *parent = nullptr); protected: virtual void keyPressEvent(QKeyEvent *event); diff --git a/src/qt/csvmodelwriter.cpp b/src/qt/csvmodelwriter.cpp index fe63fed52c..656afb6e87 100644 --- a/src/qt/csvmodelwriter.cpp +++ b/src/qt/csvmodelwriter.cpp @@ -10,7 +10,7 @@ CSVModelWriter::CSVModelWriter(const QString &_filename, QObject *parent) : QObject(parent), - filename(_filename), model(0) + filename(_filename), model(nullptr) { } diff --git a/src/qt/csvmodelwriter.h b/src/qt/csvmodelwriter.h index edea369ad1..e8611bea35 100644 --- a/src/qt/csvmodelwriter.h +++ b/src/qt/csvmodelwriter.h @@ -20,7 +20,7 @@ class CSVModelWriter : public QObject Q_OBJECT public: - explicit CSVModelWriter(const QString &filename, QObject *parent = 0); + explicit CSVModelWriter(const QString &filename, QObject *parent = nullptr); void setModel(const QAbstractItemModel *model); void addColumn(const QString &title, int column, int role=Qt::EditRole); diff --git a/src/qt/editaddressdialog.cpp b/src/qt/editaddressdialog.cpp index 0b0b96b30c..4711412ac4 100644 --- a/src/qt/editaddressdialog.cpp +++ b/src/qt/editaddressdialog.cpp @@ -15,9 +15,9 @@ EditAddressDialog::EditAddressDialog(Mode _mode, QWidget *parent) : QDialog(parent), ui(new Ui::EditAddressDialog), - mapper(0), + mapper(nullptr), mode(_mode), - model(0) + model(nullptr) { ui->setupUi(this); diff --git a/src/qt/editaddressdialog.h b/src/qt/editaddressdialog.h index fd88b45793..4d0e0709be 100644 --- a/src/qt/editaddressdialog.h +++ b/src/qt/editaddressdialog.h @@ -30,7 +30,7 @@ public: EditSendingAddress }; - explicit EditAddressDialog(Mode mode, QWidget *parent = 0); + explicit EditAddressDialog(Mode mode, QWidget *parent = nullptr); ~EditAddressDialog(); void setModel(AddressTableModel *model); diff --git a/src/qt/forms/debugwindow.ui b/src/qt/forms/debugwindow.ui index dca16d6f78..f0b976001e 100644 --- a/src/qt/forms/debugwindow.ui +++ b/src/qt/forms/debugwindow.ui @@ -453,6 +453,9 @@ </item> <item> <widget class="QComboBox" name="WalletSelector"> + <property name="sizeAdjustPolicy"> + <enum>QComboBox::AdjustToContents</enum> + </property> <item> <property name="text"> <string>(none)</string> @@ -896,570 +899,593 @@ <attribute name="title"> <string>&Peers</string> </attribute> - <layout class="QGridLayout" name="gridLayout_2"> - <item row="0" column="0" rowspan="2"> - <layout class="QVBoxLayout" name="verticalLayout_101"> - <property name="spacing"> - <number>0</number> - </property> - <item> - <widget class="QTableView" name="peerWidget"> - <property name="horizontalScrollBarPolicy"> - <enum>Qt::ScrollBarAsNeeded</enum> - </property> - <property name="tabKeyNavigation"> - <bool>false</bool> - </property> - <property name="sortingEnabled"> - <bool>true</bool> - </property> - <attribute name="horizontalHeaderHighlightSections"> - <bool>false</bool> - </attribute> - </widget> - </item> - <item> - <widget class="QLabel" name="banHeading"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Minimum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="minimumSize"> - <size> - <width>300</width> - <height>32</height> - </size> - </property> - <property name="maximumSize"> - <size> - <width>16777215</width> - <height>32</height> - </size> - </property> - <property name="font"> - <font> - <pointsize>12</pointsize> - </font> - </property> - <property name="cursor"> - <cursorShape>IBeamCursor</cursorShape> - </property> - <property name="text"> - <string>Banned peers</string> - </property> - <property name="alignment"> - <set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set> - </property> - <property name="wordWrap"> - <bool>true</bool> - </property> - <property name="textInteractionFlags"> - <set>Qt::NoTextInteraction</set> - </property> - </widget> - </item> - <item> - <widget class="QTableView" name="banlistWidget"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="horizontalScrollBarPolicy"> - <enum>Qt::ScrollBarAsNeeded</enum> - </property> - <property name="tabKeyNavigation"> - <bool>false</bool> - </property> - <property name="sortingEnabled"> - <bool>true</bool> - </property> - <attribute name="horizontalHeaderHighlightSections"> - <bool>false</bool> - </attribute> - </widget> - </item> - </layout> - </item> - <item row="0" column="1"> - <widget class="QLabel" name="peerHeading"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Minimum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="minimumSize"> - <size> - <width>300</width> - <height>32</height> - </size> - </property> - <property name="font"> - <font> - <pointsize>10</pointsize> - </font> - </property> - <property name="cursor"> - <cursorShape>IBeamCursor</cursorShape> - </property> - <property name="text"> - <string>Select a peer to view detailed information.</string> - </property> - <property name="alignment"> - <set>Qt::AlignHCenter|Qt::AlignTop</set> - </property> - <property name="wordWrap"> - <bool>true</bool> - </property> - <property name="textInteractionFlags"> - <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> + <layout class="QVBoxLayout" name="verticalLayout_6"> + <item> + <widget class="QSplitter" name="splitter"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> </property> - </widget> - </item> - <item row="1" column="1"> - <widget class="QWidget" name="detailWidget" native="true"> - <property name="minimumSize"> - <size> - <width>300</width> - <height>0</height> - </size> + <property name="childrenCollapsible"> + <bool>false</bool> </property> - <layout class="QGridLayout" name="gridLayout_3"> - <item row="0" column="0"> - <widget class="QLabel" name="label_30"> - <property name="text"> - <string>Whitelisted</string> - </property> - </widget> - </item> - <item row="0" column="2"> - <widget class="QLabel" name="peerWhitelisted"> - <property name="cursor"> - <cursorShape>IBeamCursor</cursorShape> - </property> - <property name="text"> - <string>N/A</string> - </property> - <property name="textFormat"> - <enum>Qt::PlainText</enum> - </property> - <property name="textInteractionFlags"> - <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> - </property> - </widget> - </item> - <item row="1" column="0"> - <widget class="QLabel" name="label_23"> - <property name="text"> - <string>Direction</string> - </property> - </widget> - </item> - <item row="1" column="2"> - <widget class="QLabel" name="peerDirection"> - <property name="cursor"> - <cursorShape>IBeamCursor</cursorShape> - </property> - <property name="text"> - <string>N/A</string> - </property> - <property name="textFormat"> - <enum>Qt::PlainText</enum> - </property> - <property name="textInteractionFlags"> - <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> - </property> - </widget> - </item> - <item row="2" column="0"> - <widget class="QLabel" name="label_21"> - <property name="text"> - <string>Version</string> - </property> - </widget> - </item> - <item row="2" column="2"> - <widget class="QLabel" name="peerVersion"> - <property name="cursor"> - <cursorShape>IBeamCursor</cursorShape> - </property> - <property name="text"> - <string>N/A</string> - </property> - <property name="textFormat"> - <enum>Qt::PlainText</enum> - </property> - <property name="textInteractionFlags"> - <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> - </property> - </widget> - </item> - <item row="3" column="0"> - <widget class="QLabel" name="label_28"> - <property name="text"> - <string>User Agent</string> - </property> - </widget> - </item> - <item row="3" column="2"> - <widget class="QLabel" name="peerSubversion"> - <property name="cursor"> - <cursorShape>IBeamCursor</cursorShape> - </property> - <property name="text"> - <string>N/A</string> - </property> - <property name="textFormat"> - <enum>Qt::PlainText</enum> - </property> - <property name="textInteractionFlags"> - <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> - </property> - </widget> - </item> - <item row="4" column="0"> - <widget class="QLabel" name="label_4"> - <property name="text"> - <string>Services</string> - </property> - </widget> - </item> - <item row="4" column="2"> - <widget class="QLabel" name="peerServices"> - <property name="cursor"> - <cursorShape>IBeamCursor</cursorShape> - </property> - <property name="text"> - <string>N/A</string> - </property> - <property name="textFormat"> - <enum>Qt::PlainText</enum> - </property> - <property name="textInteractionFlags"> - <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> - </property> - </widget> - </item> - <item row="5" column="0"> - <widget class="QLabel" name="label_29"> - <property name="text"> - <string>Starting Block</string> - </property> - </widget> - </item> - <item row="5" column="2"> - <widget class="QLabel" name="peerHeight"> - <property name="cursor"> - <cursorShape>IBeamCursor</cursorShape> - </property> - <property name="text"> - <string>N/A</string> - </property> - <property name="textFormat"> - <enum>Qt::PlainText</enum> - </property> - <property name="textInteractionFlags"> - <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> - </property> - </widget> - </item> - <item row="6" column="0"> - <widget class="QLabel" name="label_27"> - <property name="text"> - <string>Synced Headers</string> - </property> - </widget> - </item> - <item row="6" column="2"> - <widget class="QLabel" name="peerSyncHeight"> - <property name="cursor"> - <cursorShape>IBeamCursor</cursorShape> - </property> - <property name="text"> - <string>N/A</string> - </property> - <property name="textFormat"> - <enum>Qt::PlainText</enum> - </property> - <property name="textInteractionFlags"> - <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> - </property> - </widget> - </item> - <item row="7" column="0"> - <widget class="QLabel" name="label_25"> - <property name="text"> - <string>Synced Blocks</string> - </property> - </widget> - </item> - <item row="7" column="2"> - <widget class="QLabel" name="peerCommonHeight"> - <property name="cursor"> - <cursorShape>IBeamCursor</cursorShape> - </property> - <property name="text"> - <string>N/A</string> - </property> - <property name="textFormat"> - <enum>Qt::PlainText</enum> - </property> - <property name="textInteractionFlags"> - <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> - </property> - </widget> - </item> - <item row="8" column="0"> - <widget class="QLabel" name="label_24"> - <property name="text"> - <string>Ban Score</string> - </property> - </widget> - </item> - <item row="8" column="2"> - <widget class="QLabel" name="peerBanScore"> - <property name="cursor"> - <cursorShape>IBeamCursor</cursorShape> - </property> - <property name="text"> - <string>N/A</string> - </property> - <property name="textFormat"> - <enum>Qt::PlainText</enum> - </property> - <property name="textInteractionFlags"> - <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> - </property> - </widget> - </item> - <item row="9" column="0"> - <widget class="QLabel" name="label_22"> - <property name="text"> - <string>Connection Time</string> - </property> - </widget> - </item> - <item row="9" column="2"> - <widget class="QLabel" name="peerConnTime"> - <property name="cursor"> - <cursorShape>IBeamCursor</cursorShape> - </property> - <property name="text"> - <string>N/A</string> - </property> - <property name="textFormat"> - <enum>Qt::PlainText</enum> - </property> - <property name="textInteractionFlags"> - <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> - </property> - </widget> - </item> - <item row="10" column="0"> - <widget class="QLabel" name="label_15"> - <property name="text"> - <string>Last Send</string> - </property> - </widget> - </item> - <item row="10" column="2"> - <widget class="QLabel" name="peerLastSend"> - <property name="cursor"> - <cursorShape>IBeamCursor</cursorShape> - </property> - <property name="text"> - <string>N/A</string> - </property> - <property name="textFormat"> - <enum>Qt::PlainText</enum> - </property> - <property name="textInteractionFlags"> - <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> - </property> - </widget> - </item> - <item row="11" column="0"> - <widget class="QLabel" name="label_19"> - <property name="text"> - <string>Last Receive</string> - </property> - </widget> - </item> - <item row="11" column="2"> - <widget class="QLabel" name="peerLastRecv"> - <property name="cursor"> - <cursorShape>IBeamCursor</cursorShape> - </property> - <property name="text"> - <string>N/A</string> - </property> - <property name="textFormat"> - <enum>Qt::PlainText</enum> - </property> - <property name="textInteractionFlags"> - <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> - </property> - </widget> - </item> - <item row="12" column="0"> - <widget class="QLabel" name="label_18"> - <property name="text"> - <string>Sent</string> - </property> - </widget> - </item> - <item row="12" column="2"> - <widget class="QLabel" name="peerBytesSent"> - <property name="cursor"> - <cursorShape>IBeamCursor</cursorShape> - </property> - <property name="text"> - <string>N/A</string> - </property> - <property name="textFormat"> - <enum>Qt::PlainText</enum> - </property> - <property name="textInteractionFlags"> - <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> - </property> - </widget> - </item> - <item row="13" column="0"> - <widget class="QLabel" name="label_20"> - <property name="text"> - <string>Received</string> - </property> - </widget> - </item> - <item row="13" column="2"> - <widget class="QLabel" name="peerBytesRecv"> - <property name="cursor"> - <cursorShape>IBeamCursor</cursorShape> - </property> - <property name="text"> - <string>N/A</string> - </property> - <property name="textFormat"> - <enum>Qt::PlainText</enum> - </property> - <property name="textInteractionFlags"> - <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> - </property> - </widget> - </item> - <item row="14" column="0"> - <widget class="QLabel" name="label_26"> - <property name="text"> - <string>Ping Time</string> - </property> - </widget> - </item> - <item row="14" column="2"> - <widget class="QLabel" name="peerPingTime"> - <property name="cursor"> - <cursorShape>IBeamCursor</cursorShape> - </property> - <property name="text"> - <string>N/A</string> - </property> - <property name="textFormat"> - <enum>Qt::PlainText</enum> - </property> - <property name="textInteractionFlags"> - <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> - </property> - </widget> - </item> - <item row="15" column="0"> - <widget class="QLabel" name="peerPingWaitLabel"> - <property name="toolTip"> - <string>The duration of a currently outstanding ping.</string> - </property> - <property name="text"> - <string>Ping Wait</string> - </property> - </widget> - </item> - <item row="15" column="2"> - <widget class="QLabel" name="peerPingWait"> - <property name="cursor"> - <cursorShape>IBeamCursor</cursorShape> - </property> - <property name="text"> - <string>N/A</string> - </property> - <property name="textFormat"> - <enum>Qt::PlainText</enum> - </property> - <property name="textInteractionFlags"> - <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> - </property> - </widget> - </item> - <item row="16" column="0"> - <widget class="QLabel" name="peerMinPingLabel"> - <property name="text"> - <string>Min Ping</string> - </property> - </widget> - </item> - <item row="16" column="2"> - <widget class="QLabel" name="peerMinPing"> - <property name="cursor"> - <cursorShape>IBeamCursor</cursorShape> - </property> - <property name="text"> - <string>N/A</string> - </property> - <property name="textFormat"> - <enum>Qt::PlainText</enum> - </property> - <property name="textInteractionFlags"> - <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> - </property> - </widget> - </item> - <item row="17" column="0"> - <widget class="QLabel" name="label_timeoffset"> - <property name="text"> - <string>Time Offset</string> - </property> - </widget> - </item> - <item row="17" column="2"> - <widget class="QLabel" name="timeoffset"> - <property name="cursor"> - <cursorShape>IBeamCursor</cursorShape> - </property> - <property name="text"> - <string>N/A</string> - </property> - <property name="textFormat"> - <enum>Qt::PlainText</enum> - </property> - <property name="textInteractionFlags"> - <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> - </property> - </widget> - </item> - <item row="18" column="1"> - <spacer name="verticalSpacer_3"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>40</height> - </size> - </property> - </spacer> - </item> - </layout> + <widget class="QWidget" name="widget_1" native="true"> + <property name="sizePolicy"> + <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred"> + <horstretch>1</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>400</width> + <height>0</height> + </size> + </property> + <layout class="QVBoxLayout" name="verticalLayout_7"> + <item> + <widget class="QTableView" name="peerWidget"> + <property name="tabKeyNavigation"> + <bool>false</bool> + </property> + <property name="sortingEnabled"> + <bool>true</bool> + </property> + <attribute name="horizontalHeaderHighlightSections"> + <bool>false</bool> + </attribute> + </widget> + </item> + <item> + <widget class="QLabel" name="banHeading"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>32</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>16777215</width> + <height>32</height> + </size> + </property> + <property name="font"> + <font> + <pointsize>12</pointsize> + </font> + </property> + <property name="cursor"> + <cursorShape>IBeamCursor</cursorShape> + </property> + <property name="text"> + <string>Banned peers</string> + </property> + <property name="alignment"> + <set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + <property name="textInteractionFlags"> + <set>Qt::NoTextInteraction</set> + </property> + </widget> + </item> + <item> + <widget class="QTableView" name="banlistWidget"> + <property name="tabKeyNavigation"> + <bool>false</bool> + </property> + <property name="sortingEnabled"> + <bool>true</bool> + </property> + <attribute name="horizontalHeaderHighlightSections"> + <bool>false</bool> + </attribute> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" name="widget_2" native="true"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>300</width> + <height>0</height> + </size> + </property> + <layout class="QVBoxLayout" name="verticalLayout_8"> + <item> + <widget class="QLabel" name="peerHeading"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>32</height> + </size> + </property> + <property name="font"> + <font> + <pointsize>10</pointsize> + </font> + </property> + <property name="cursor"> + <cursorShape>IBeamCursor</cursorShape> + </property> + <property name="text"> + <string>Select a peer to view detailed information.</string> + </property> + <property name="alignment"> + <set>Qt::AlignHCenter|Qt::AlignTop</set> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + <property name="textInteractionFlags"> + <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> + </property> + </widget> + </item> + <item> + <widget class="QScrollArea" name="scrollArea"> + <property name="widgetResizable"> + <bool>true</bool> + </property> + <widget class="QWidget" name="detailWidget"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>300</width> + <height>426</height> + </rect> + </property> + <property name="minimumSize"> + <size> + <width>300</width> + <height>0</height> + </size> + </property> + <layout class="QGridLayout" name="gridLayout_2" columnstretch="0,1"> + <item row="0" column="0"> + <widget class="QLabel" name="label_30"> + <property name="text"> + <string>Whitelisted</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QLabel" name="peerWhitelisted"> + <property name="cursor"> + <cursorShape>IBeamCursor</cursorShape> + </property> + <property name="text"> + <string>N/A</string> + </property> + <property name="textFormat"> + <enum>Qt::PlainText</enum> + </property> + <property name="textInteractionFlags"> + <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_23"> + <property name="text"> + <string>Direction</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QLabel" name="peerDirection"> + <property name="cursor"> + <cursorShape>IBeamCursor</cursorShape> + </property> + <property name="text"> + <string>N/A</string> + </property> + <property name="textFormat"> + <enum>Qt::PlainText</enum> + </property> + <property name="textInteractionFlags"> + <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="label_21"> + <property name="text"> + <string>Version</string> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QLabel" name="peerVersion"> + <property name="cursor"> + <cursorShape>IBeamCursor</cursorShape> + </property> + <property name="text"> + <string>N/A</string> + </property> + <property name="textFormat"> + <enum>Qt::PlainText</enum> + </property> + <property name="textInteractionFlags"> + <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> + </property> + </widget> + </item> + <item row="3" column="0"> + <widget class="QLabel" name="label_28"> + <property name="text"> + <string>User Agent</string> + </property> + </widget> + </item> + <item row="3" column="1"> + <widget class="QLabel" name="peerSubversion"> + <property name="cursor"> + <cursorShape>IBeamCursor</cursorShape> + </property> + <property name="text"> + <string>N/A</string> + </property> + <property name="textFormat"> + <enum>Qt::PlainText</enum> + </property> + <property name="textInteractionFlags"> + <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> + </property> + </widget> + </item> + <item row="4" column="0"> + <widget class="QLabel" name="label_4"> + <property name="text"> + <string>Services</string> + </property> + </widget> + </item> + <item row="4" column="1"> + <widget class="QLabel" name="peerServices"> + <property name="cursor"> + <cursorShape>IBeamCursor</cursorShape> + </property> + <property name="text"> + <string>N/A</string> + </property> + <property name="textFormat"> + <enum>Qt::PlainText</enum> + </property> + <property name="textInteractionFlags"> + <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> + </property> + </widget> + </item> + <item row="5" column="0"> + <widget class="QLabel" name="label_29"> + <property name="text"> + <string>Starting Block</string> + </property> + </widget> + </item> + <item row="5" column="1"> + <widget class="QLabel" name="peerHeight"> + <property name="cursor"> + <cursorShape>IBeamCursor</cursorShape> + </property> + <property name="text"> + <string>N/A</string> + </property> + <property name="textFormat"> + <enum>Qt::PlainText</enum> + </property> + <property name="textInteractionFlags"> + <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> + </property> + </widget> + </item> + <item row="6" column="0"> + <widget class="QLabel" name="label_27"> + <property name="text"> + <string>Synced Headers</string> + </property> + </widget> + </item> + <item row="6" column="1"> + <widget class="QLabel" name="peerSyncHeight"> + <property name="cursor"> + <cursorShape>IBeamCursor</cursorShape> + </property> + <property name="text"> + <string>N/A</string> + </property> + <property name="textFormat"> + <enum>Qt::PlainText</enum> + </property> + <property name="textInteractionFlags"> + <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> + </property> + </widget> + </item> + <item row="7" column="0"> + <widget class="QLabel" name="label_25"> + <property name="text"> + <string>Synced Blocks</string> + </property> + </widget> + </item> + <item row="7" column="1"> + <widget class="QLabel" name="peerCommonHeight"> + <property name="cursor"> + <cursorShape>IBeamCursor</cursorShape> + </property> + <property name="text"> + <string>N/A</string> + </property> + <property name="textFormat"> + <enum>Qt::PlainText</enum> + </property> + <property name="textInteractionFlags"> + <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> + </property> + </widget> + </item> + <item row="8" column="0"> + <widget class="QLabel" name="label_24"> + <property name="text"> + <string>Ban Score</string> + </property> + </widget> + </item> + <item row="8" column="1"> + <widget class="QLabel" name="peerBanScore"> + <property name="cursor"> + <cursorShape>IBeamCursor</cursorShape> + </property> + <property name="text"> + <string>N/A</string> + </property> + <property name="textFormat"> + <enum>Qt::PlainText</enum> + </property> + <property name="textInteractionFlags"> + <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> + </property> + </widget> + </item> + <item row="9" column="0"> + <widget class="QLabel" name="label_22"> + <property name="text"> + <string>Connection Time</string> + </property> + </widget> + </item> + <item row="9" column="1"> + <widget class="QLabel" name="peerConnTime"> + <property name="cursor"> + <cursorShape>IBeamCursor</cursorShape> + </property> + <property name="text"> + <string>N/A</string> + </property> + <property name="textFormat"> + <enum>Qt::PlainText</enum> + </property> + <property name="textInteractionFlags"> + <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> + </property> + </widget> + </item> + <item row="10" column="0"> + <widget class="QLabel" name="label_15"> + <property name="text"> + <string>Last Send</string> + </property> + </widget> + </item> + <item row="10" column="1"> + <widget class="QLabel" name="peerLastSend"> + <property name="cursor"> + <cursorShape>IBeamCursor</cursorShape> + </property> + <property name="text"> + <string>N/A</string> + </property> + <property name="textFormat"> + <enum>Qt::PlainText</enum> + </property> + <property name="textInteractionFlags"> + <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> + </property> + </widget> + </item> + <item row="11" column="0"> + <widget class="QLabel" name="label_19"> + <property name="text"> + <string>Last Receive</string> + </property> + </widget> + </item> + <item row="11" column="1"> + <widget class="QLabel" name="peerLastRecv"> + <property name="cursor"> + <cursorShape>IBeamCursor</cursorShape> + </property> + <property name="text"> + <string>N/A</string> + </property> + <property name="textFormat"> + <enum>Qt::PlainText</enum> + </property> + <property name="textInteractionFlags"> + <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> + </property> + </widget> + </item> + <item row="12" column="0"> + <widget class="QLabel" name="label_18"> + <property name="text"> + <string>Sent</string> + </property> + </widget> + </item> + <item row="12" column="1"> + <widget class="QLabel" name="peerBytesSent"> + <property name="cursor"> + <cursorShape>IBeamCursor</cursorShape> + </property> + <property name="text"> + <string>N/A</string> + </property> + <property name="textFormat"> + <enum>Qt::PlainText</enum> + </property> + <property name="textInteractionFlags"> + <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> + </property> + </widget> + </item> + <item row="13" column="0"> + <widget class="QLabel" name="label_20"> + <property name="text"> + <string>Received</string> + </property> + </widget> + </item> + <item row="13" column="1"> + <widget class="QLabel" name="peerBytesRecv"> + <property name="cursor"> + <cursorShape>IBeamCursor</cursorShape> + </property> + <property name="text"> + <string>N/A</string> + </property> + <property name="textFormat"> + <enum>Qt::PlainText</enum> + </property> + <property name="textInteractionFlags"> + <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> + </property> + </widget> + </item> + <item row="14" column="0"> + <widget class="QLabel" name="label_26"> + <property name="text"> + <string>Ping Time</string> + </property> + </widget> + </item> + <item row="14" column="1"> + <widget class="QLabel" name="peerPingTime"> + <property name="cursor"> + <cursorShape>IBeamCursor</cursorShape> + </property> + <property name="text"> + <string>N/A</string> + </property> + <property name="textFormat"> + <enum>Qt::PlainText</enum> + </property> + <property name="textInteractionFlags"> + <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> + </property> + </widget> + </item> + <item row="15" column="0"> + <widget class="QLabel" name="peerPingWaitLabel"> + <property name="toolTip"> + <string>The duration of a currently outstanding ping.</string> + </property> + <property name="text"> + <string>Ping Wait</string> + </property> + </widget> + </item> + <item row="15" column="1"> + <widget class="QLabel" name="peerPingWait"> + <property name="cursor"> + <cursorShape>IBeamCursor</cursorShape> + </property> + <property name="text"> + <string>N/A</string> + </property> + <property name="textFormat"> + <enum>Qt::PlainText</enum> + </property> + <property name="textInteractionFlags"> + <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> + </property> + </widget> + </item> + <item row="16" column="0"> + <widget class="QLabel" name="peerMinPingLabel"> + <property name="text"> + <string>Min Ping</string> + </property> + </widget> + </item> + <item row="16" column="1"> + <widget class="QLabel" name="peerMinPing"> + <property name="cursor"> + <cursorShape>IBeamCursor</cursorShape> + </property> + <property name="text"> + <string>N/A</string> + </property> + <property name="textFormat"> + <enum>Qt::PlainText</enum> + </property> + <property name="textInteractionFlags"> + <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> + </property> + </widget> + </item> + <item row="17" column="0"> + <widget class="QLabel" name="label_timeoffset"> + <property name="text"> + <string>Time Offset</string> + </property> + </widget> + </item> + <item row="17" column="1"> + <widget class="QLabel" name="timeoffset"> + <property name="cursor"> + <cursorShape>IBeamCursor</cursorShape> + </property> + <property name="text"> + <string>N/A</string> + </property> + <property name="textFormat"> + <enum>Qt::PlainText</enum> + </property> + <property name="textInteractionFlags"> + <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> + </property> + </widget> + </item> + </layout> + </widget> + </widget> + </item> + </layout> + </widget> </widget> </item> </layout> diff --git a/src/qt/forms/optionsdialog.ui b/src/qt/forms/optionsdialog.ui index 8f34e6bc82..240a7a7e92 100644 --- a/src/qt/forms/optionsdialog.ui +++ b/src/qt/forms/optionsdialog.ui @@ -121,7 +121,7 @@ <item> <widget class="QLabel" name="databaseCacheUnitLabel"> <property name="text"> - <string>MB</string> + <string>MiB</string> </property> <property name="textFormat"> <enum>Qt::PlainText</enum> @@ -714,7 +714,7 @@ <item> <widget class="QLabel" name="overriddenByCommandLineInfoLabel"> <property name="text"> - <string>Active command-line options that override above options:</string> + <string>Options set in this dialog are overridden by the command line or in the configuration file:</string> </property> <property name="textFormat"> <enum>Qt::PlainText</enum> diff --git a/src/qt/guiconstants.h b/src/qt/guiconstants.h index 04b03a5435..736ff13a4a 100644 --- a/src/qt/guiconstants.h +++ b/src/qt/guiconstants.h @@ -50,5 +50,9 @@ static const int MAX_URI_LENGTH = 255; #define QAPP_ORG_DOMAIN "bitcoin.org" #define QAPP_APP_NAME_DEFAULT "Bitcoin-Qt" #define QAPP_APP_NAME_TESTNET "Bitcoin-Qt-testnet" +#define QAPP_APP_NAME_REGTEST "Bitcoin-Qt-regtest" + +/* One gigabyte (GB) in bytes */ +static constexpr uint64_t GB_BYTES{1000000000}; #endif // BITCOIN_QT_GUICONSTANTS_H diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index 2fc166b0c5..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 @@ -48,13 +44,15 @@ #include <QFileDialog> #include <QFont> #include <QFontDatabase> +#include <QFontMetrics> #include <QKeyEvent> #include <QLineEdit> +#include <QMouseEvent> +#include <QProgressDialog> #include <QSettings> #include <QTextDocument> // for Qt::mightBeRichText #include <QThread> #include <QUrlQuery> -#include <QMouseEvent> #if defined(Q_OS_MAC) #pragma GCC diagnostic push @@ -681,13 +679,11 @@ bool SetStartOnSystemStartup(bool fAutoStart) } -#elif defined(Q_OS_MAC) +#elif defined(Q_OS_MAC) && defined(MAC_OS_X_VERSION_MIN_REQUIRED) && MAC_OS_X_VERSION_MIN_REQUIRED <= 101100 // based on: https://github.com/Mozketo/LaunchAtLoginController/blob/master/LaunchAtLoginController.m -LSSharedFileListItemRef findStartupItemInList(LSSharedFileListRef list, CFURLRef findUrl); -LSSharedFileListItemRef findStartupItemInList(LSSharedFileListRef list, CFURLRef findUrl) +LSSharedFileListItemRef findStartupItemInList(CFArrayRef listSnapshot, LSSharedFileListRef list, CFURLRef findUrl) { - CFArrayRef listSnapshot = LSSharedFileListCopySnapshot(list, nullptr); if (listSnapshot == nullptr) { return nullptr; } @@ -712,15 +708,12 @@ LSSharedFileListItemRef findStartupItemInList(LSSharedFileListRef list, CFURLRef if(currentItemURL) { if (CFEqual(currentItemURL, findUrl)) { // found - CFRelease(listSnapshot); CFRelease(currentItemURL); return item; } CFRelease(currentItemURL); } } - - CFRelease(listSnapshot); return nullptr; } @@ -732,10 +725,12 @@ bool GetStartOnSystemStartup() } LSSharedFileListRef loginItems = LSSharedFileListCreate(nullptr, kLSSharedFileListSessionLoginItems, nullptr); - LSSharedFileListItemRef foundItem = findStartupItemInList(loginItems, bitcoinAppUrl); - + CFArrayRef listSnapshot = LSSharedFileListCopySnapshot(loginItems, nullptr); + bool res = (findStartupItemInList(listSnapshot, loginItems, bitcoinAppUrl) != nullptr); CFRelease(bitcoinAppUrl); - return !!foundItem; // return boolified object + CFRelease(loginItems); + CFRelease(listSnapshot); + return res; } bool SetStartOnSystemStartup(bool fAutoStart) @@ -746,7 +741,8 @@ bool SetStartOnSystemStartup(bool fAutoStart) } LSSharedFileListRef loginItems = LSSharedFileListCreate(nullptr, kLSSharedFileListSessionLoginItems, nullptr); - LSSharedFileListItemRef foundItem = findStartupItemInList(loginItems, bitcoinAppUrl); + CFArrayRef listSnapshot = LSSharedFileListCopySnapshot(loginItems, nullptr); + LSSharedFileListItemRef foundItem = findStartupItemInList(listSnapshot, loginItems, bitcoinAppUrl); if(fAutoStart && !foundItem) { // add bitcoin app to startup item list @@ -758,6 +754,8 @@ bool SetStartOnSystemStartup(bool fAutoStart) } CFRelease(bitcoinAppUrl); + CFRelease(loginItems); + CFRelease(listSnapshot); return true; } #pragma GCC diagnostic pop @@ -933,4 +931,16 @@ bool ItemDelegate::eventFilter(QObject *object, QEvent *event) return QItemDelegate::eventFilter(object, event); } +void PolishProgressDialog(QProgressDialog* dialog) +{ +#ifdef Q_OS_MAC + // Workaround for macOS-only Qt bug; see: QTBUG-65750, QTBUG-70357. + const int margin = dialog->fontMetrics().width("X"); + dialog->resize(dialog->width() + 2 * margin, dialog->height()); + dialog->show(); +#else + Q_UNUSED(dialog); +#endif +} + } // namespace GUIUtil diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h index f1d0aa48ef..cbec73a882 100644 --- a/src/qt/guiutil.h +++ b/src/qt/guiutil.h @@ -31,6 +31,7 @@ class QAbstractItemView; class QDateTime; class QFont; class QLineEdit; +class QProgressDialog; class QUrl; class QWidget; QT_END_NAMESPACE @@ -133,7 +134,7 @@ namespace GUIUtil Q_OBJECT public: - explicit ToolTipToRichTextFilter(int size_threshold, QObject *parent = 0); + explicit ToolTipToRichTextFilter(int size_threshold, QObject *parent = nullptr); protected: bool eventFilter(QObject *obj, QEvent *evt); @@ -248,6 +249,9 @@ namespace GUIUtil private: bool eventFilter(QObject *object, QEvent *event); }; + + // Fix known bugs in QProgressDialog class. + void PolishProgressDialog(QProgressDialog* dialog); } // namespace GUIUtil #endif // BITCOIN_QT_GUIUTIL_H diff --git a/src/qt/intro.cpp b/src/qt/intro.cpp index 0b61b05318..499af9fa07 100644 --- a/src/qt/intro.cpp +++ b/src/qt/intro.cpp @@ -10,6 +10,7 @@ #include <qt/intro.h> #include <qt/forms/ui_intro.h> +#include <qt/guiconstants.h> #include <qt/guiutil.h> #include <interfaces/node.h> @@ -21,11 +22,6 @@ #include <cmath> -static const uint64_t GB_BYTES = 1000000000LL; -/* Minimum free space (in GB) needed for data directory */ -constexpr uint64_t BLOCK_CHAIN_SIZE = 220; -/* Minimum free space (in GB) needed for data directory when pruned; Does not include prune target */ -static const uint64_t CHAIN_STATE_SIZE = 3; /* Total required space (in GB) depending on user choice (prune, not prune) */ static uint64_t requiredSpace; @@ -114,11 +110,13 @@ void FreespaceChecker::check() } -Intro::Intro(QWidget *parent) : +Intro::Intro(QWidget *parent, uint64_t blockchain_size, uint64_t chain_state_size) : QDialog(parent), ui(new Ui::Intro), - thread(0), - signalled(false) + thread(nullptr), + signalled(false), + m_blockchain_size(blockchain_size), + m_chain_state_size(chain_state_size) { ui->setupUi(this); ui->welcomeLabel->setText(ui->welcomeLabel->text().arg(tr(PACKAGE_NAME))); @@ -126,14 +124,14 @@ Intro::Intro(QWidget *parent) : ui->lblExplanation1->setText(ui->lblExplanation1->text() .arg(tr(PACKAGE_NAME)) - .arg(BLOCK_CHAIN_SIZE) + .arg(m_blockchain_size) .arg(2009) .arg(tr("Bitcoin")) ); ui->lblExplanation2->setText(ui->lblExplanation2->text().arg(tr(PACKAGE_NAME))); uint64_t pruneTarget = std::max<int64_t>(0, gArgs.GetArg("-prune", 0)); - requiredSpace = BLOCK_CHAIN_SIZE; + requiredSpace = m_blockchain_size; QString storageRequiresMsg = tr("At least %1 GB of data will be stored in this directory, and it will grow over time."); if (pruneTarget) { uint64_t prunedGBs = std::ceil(pruneTarget * 1024 * 1024.0 / GB_BYTES); @@ -145,7 +143,7 @@ Intro::Intro(QWidget *parent) : } else { ui->lblExplanation3->setVisible(false); } - requiredSpace += CHAIN_STATE_SIZE; + requiredSpace += m_chain_state_size; ui->sizeWarningLabel->setText( tr("%1 will download and store a copy of the Bitcoin block chain.").arg(tr(PACKAGE_NAME)) + " " + storageRequiresMsg.arg(requiredSpace) + " " + @@ -158,7 +156,7 @@ Intro::~Intro() { delete ui; /* Ensure thread is finished before it is deleted */ - Q_EMIT stopThread(); + thread->quit(); thread->wait(); } @@ -201,8 +199,15 @@ bool Intro::pickDataDirectory(interfaces::Node& node) if(!fs::exists(GUIUtil::qstringToBoostPath(dataDir)) || gArgs.GetBoolArg("-choosedatadir", DEFAULT_CHOOSE_DATADIR) || settings.value("fReset", false).toBool() || gArgs.GetBoolArg("-resetguisettings", false)) { + /* Use selectParams here to guarantee Params() can be used by node interface */ + try { + node.selectParams(gArgs.GetChainName()); + } catch (const std::exception&) { + return false; + } + /* If current default data directory does not exist, let the user choose one */ - Intro intro; + Intro intro(0, node.getAssumedBlockchainSize(), node.getAssumedChainStateSize()); intro.setDataDirectory(dataDir); intro.setWindowIcon(QIcon(":icons/bitcoin")); @@ -221,7 +226,7 @@ bool Intro::pickDataDirectory(interfaces::Node& node) } break; } catch (const fs::filesystem_error&) { - QMessageBox::critical(0, tr(PACKAGE_NAME), + QMessageBox::critical(nullptr, tr(PACKAGE_NAME), tr("Error: Specified data directory \"%1\" cannot be created.").arg(dataDir)); /* fall through, back to choosing screen */ } @@ -281,7 +286,7 @@ void Intro::on_dataDirectory_textChanged(const QString &dataDirStr) void Intro::on_ellipsisButton_clicked() { - QString dir = QDir::toNativeSeparators(QFileDialog::getExistingDirectory(0, "Choose data directory", ui->dataDirectory->text())); + QString dir = QDir::toNativeSeparators(QFileDialog::getExistingDirectory(nullptr, "Choose data directory", ui->dataDirectory->text())); if(!dir.isEmpty()) ui->dataDirectory->setText(dir); } @@ -306,8 +311,7 @@ void Intro::startThread() connect(executor, &FreespaceChecker::reply, this, &Intro::setStatus); connect(this, &Intro::requestCheck, executor, &FreespaceChecker::check); /* make sure executor object is deleted in its own thread */ - connect(this, &Intro::stopThread, executor, &QObject::deleteLater); - connect(this, &Intro::stopThread, thread, &QThread::quit); + connect(thread, &QThread::finished, executor, &QObject::deleteLater); thread->start(); } diff --git a/src/qt/intro.h b/src/qt/intro.h index 2b3da963e2..b537c94f7d 100644 --- a/src/qt/intro.h +++ b/src/qt/intro.h @@ -30,7 +30,8 @@ class Intro : public QDialog Q_OBJECT public: - explicit Intro(QWidget *parent = 0); + explicit Intro(QWidget *parent = nullptr, + uint64_t blockchain_size = 0, uint64_t chain_state_size = 0); ~Intro(); QString getDataDirectory(); @@ -54,7 +55,6 @@ public: Q_SIGNALS: void requestCheck(); - void stopThread(); public Q_SLOTS: void setStatus(int status, const QString &message, quint64 bytesAvailable); @@ -71,6 +71,8 @@ private: QMutex mutex; bool signalled; QString pathToCheck; + uint64_t m_blockchain_size; + uint64_t m_chain_state_size; void startThread(); void checkPath(const QString &dataDir); 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/main.cpp b/src/qt/main.cpp new file mode 100644 index 0000000000..6a3c2249d1 --- /dev/null +++ b/src/qt/main.cpp @@ -0,0 +1,17 @@ +// 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. + +#include <qt/bitcoin.h> + +#include <QCoreApplication> + +#include <functional> +#include <string> + +/** Translate string to current locale using Qt. */ +extern const std::function<std::string(const char*)> G_TRANSLATION_FUN = [](const char* psz) { + return QCoreApplication::translate("bitcoin-core", psz).toStdString(); +}; + +int main(int argc, char* argv[]) { return GuiMain(argc, argv); } diff --git a/src/qt/networkstyle.cpp b/src/qt/networkstyle.cpp index b134a139b0..f0c860e669 100644 --- a/src/qt/networkstyle.cpp +++ b/src/qt/networkstyle.cpp @@ -17,7 +17,7 @@ static const struct { } network_styles[] = { {"main", QAPP_APP_NAME_DEFAULT, 0, 0, ""}, {"test", QAPP_APP_NAME_TESTNET, 70, 30, QT_TRANSLATE_NOOP("SplashScreen", "[testnet]")}, - {"regtest", QAPP_APP_NAME_TESTNET, 160, 30, "[regtest]"} + {"regtest", QAPP_APP_NAME_REGTEST, 160, 30, "[regtest]"} }; static const unsigned network_styles_count = sizeof(network_styles)/sizeof(*network_styles); @@ -88,5 +88,5 @@ const NetworkStyle *NetworkStyle::instantiate(const QString &networkId) network_styles[x].titleAddText); } } - return 0; + return nullptr; } diff --git a/src/qt/notificator.cpp b/src/qt/notificator.cpp index 94505043dc..4b91c19761 100644 --- a/src/qt/notificator.cpp +++ b/src/qt/notificator.cpp @@ -39,7 +39,7 @@ Notificator::Notificator(const QString &_programName, QSystemTrayIcon *_trayIcon mode(None), trayIcon(_trayIcon) #ifdef USE_DBUS - ,interface(0) + ,interface(nullptr) #endif { if(_trayIcon && _trayIcon->supportsMessages()) @@ -154,14 +154,14 @@ QVariant FreedesktopImage::toVariant(const QImage &img) void Notificator::notifyDBus(Class cls, const QString &title, const QString &text, const QIcon &icon, int millisTimeout) { - Q_UNUSED(cls); - // Arguments for DBus call: + // https://developer.gnome.org/notification-spec/ + // Arguments for DBus "Notify" call: QList<QVariant> args; // Program Name: args.append(programName); - // Unique ID of this notification type: + // Replaces ID; A value of 0 means that this notification won't replace any existing notifications: args.append(0U); // Application Icon, empty string @@ -209,9 +209,8 @@ void Notificator::notifyDBus(Class cls, const QString &title, const QString &tex } #endif -void Notificator::notifySystray(Class cls, const QString &title, const QString &text, const QIcon &icon, int millisTimeout) +void Notificator::notifySystray(Class cls, const QString &title, const QString &text, int millisTimeout) { - Q_UNUSED(icon); QSystemTrayIcon::MessageIcon sicon = QSystemTrayIcon::NoIcon; switch(cls) // Set icon based on class { @@ -222,13 +221,12 @@ void Notificator::notifySystray(Class cls, const QString &title, const QString & trayIcon->showMessage(title, text, sicon, millisTimeout); } -// Based on Qt's tray icon implementation #ifdef Q_OS_MAC -void Notificator::notifyMacUserNotificationCenter(Class cls, const QString &title, const QString &text, const QIcon &icon) { +void Notificator::notifyMacUserNotificationCenter(const QString &title, const QString &text) +{ // icon is not supported by the user notification center yet. OSX will use the app icon. MacNotificationHandler::instance()->showNotification(title, text); } - #endif void Notificator::notify(Class cls, const QString &title, const QString &text, const QIcon &icon, int millisTimeout) @@ -241,11 +239,11 @@ void Notificator::notify(Class cls, const QString &title, const QString &text, c break; #endif case QSystemTray: - notifySystray(cls, title, text, icon, millisTimeout); + notifySystray(cls, title, text, millisTimeout); break; #ifdef Q_OS_MAC case UserNotificationCenter: - notifyMacUserNotificationCenter(cls, title, text, icon); + notifyMacUserNotificationCenter(title, text); break; #endif default: diff --git a/src/qt/notificator.h b/src/qt/notificator.h index 10b7b6c50a..7d80b43e43 100644 --- a/src/qt/notificator.h +++ b/src/qt/notificator.h @@ -57,7 +57,7 @@ private: enum Mode { None, /**< Ignore informational notifications, and show a modal pop-up dialog for Critical notifications. */ Freedesktop, /**< Use DBus org.freedesktop.Notifications */ - QSystemTray, /**< Use QSystemTray::showMessage */ + QSystemTray, /**< Use QSystemTrayIcon::showMessage() */ UserNotificationCenter /**< Use the 10.8+ User Notification Center (Mac only) */ }; QString programName; @@ -68,9 +68,9 @@ private: void notifyDBus(Class cls, const QString &title, const QString &text, const QIcon &icon, int millisTimeout); #endif - void notifySystray(Class cls, const QString &title, const QString &text, const QIcon &icon, int millisTimeout); + void notifySystray(Class cls, const QString &title, const QString &text, int millisTimeout); #ifdef Q_OS_MAC - void notifyMacUserNotificationCenter(Class cls, const QString &title, const QString &text, const QIcon &icon); + void notifyMacUserNotificationCenter(const QString &title, const QString &text); #endif }; diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index c9871f6c66..9094aeff56 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -10,6 +10,7 @@ #include <qt/forms/ui_optionsdialog.h> #include <qt/bitcoinunits.h> +#include <qt/guiconstants.h> #include <qt/guiutil.h> #include <qt/optionsmodel.h> @@ -29,18 +30,14 @@ OptionsDialog::OptionsDialog(QWidget *parent, bool enableWallet) : QDialog(parent), ui(new Ui::OptionsDialog), - model(0), - mapper(0) + model(nullptr), + mapper(nullptr) { ui->setupUi(this); /* Main elements init */ ui->databaseCache->setMinimum(nMinDbCache); ui->databaseCache->setMaximum(nMaxDbCache); - static const uint64_t GiB = 1024 * 1024 * 1024; - static const uint64_t nMinDiskSpace = MIN_DISK_SPACE_FOR_BLOCK_FILES / GiB + - (MIN_DISK_SPACE_FOR_BLOCK_FILES % GiB) ? 1 : 0; - ui->pruneSize->setMinimum(nMinDiskSpace); ui->threadsScriptVerif->setMinimum(-GetNumCores()); ui->threadsScriptVerif->setMaximum(MAX_SCRIPTCHECK_THREADS); ui->pruneWarning->setVisible(false); @@ -74,6 +71,12 @@ OptionsDialog::OptionsDialog(QWidget *parent, bool enableWallet) : #ifdef Q_OS_MAC /* remove Window tab on Mac */ ui->tabWidget->removeTab(ui->tabWidget->indexOf(ui->tabWindow)); +#if defined(MAC_OS_X_VERSION_MIN_REQUIRED) && MAC_OS_X_VERSION_MIN_REQUIRED > 101100 + /* hide launch at startup option if compiled against macOS > 10.11 (removed API) */ + ui->bitcoinAtStartup->setVisible(false); + ui->verticalLayout_Main->removeWidget(ui->bitcoinAtStartup); + ui->verticalLayout_Main->removeItem(ui->horizontalSpacer_0_Main); +#endif #endif /* remove Wallet tab in case of -disablewallet */ @@ -161,6 +164,10 @@ void OptionsDialog::setModel(OptionsModel *_model) mapper->toFirst(); updateDefaultProxyNets(); + + // Prune values are in GB to be consistent with intro.cpp + static constexpr uint64_t nMinDiskSpace = (MIN_DISK_SPACE_FOR_BLOCK_FILES / GB_BYTES) + (MIN_DISK_SPACE_FOR_BLOCK_FILES % GB_BYTES) ? 1 : 0; + ui->pruneSize->setRange(nMinDiskSpace, _model->node().getAssumedBlockchainSize()); } /* warn when one of the following settings changes by user action (placed here so init via mapper doesn't trigger them) */ diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index d04a2cf862..62496a57f4 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -9,6 +9,7 @@ #include <qt/optionsmodel.h> #include <qt/bitcoinunits.h> +#include <qt/guiconstants.h> #include <qt/guiutil.h> #include <interfaces/node.h> @@ -92,10 +93,10 @@ void OptionsModel::Init(bool resetSettings) settings.setValue("bPrune", false); if (!settings.contains("nPruneSize")) settings.setValue("nPruneSize", 2); - // Convert prune size to MB: - const uint64_t nPruneSizeMB = settings.value("nPruneSize").toInt() * 1000; - if (!m_node.softSetArg("-prune", settings.value("bPrune").toBool() ? std::to_string(nPruneSizeMB) : "0")) { - addOverriddenOption("-prune"); + // Convert prune size from GB to MiB: + const uint64_t nPruneSizeMiB = (settings.value("nPruneSize").toInt() * GB_BYTES) >> 20; + if (!m_node.softSetArg("-prune", settings.value("bPrune").toBool() ? std::to_string(nPruneSizeMiB) : "0")) { + addOverriddenOption("-prune"); } if (!settings.contains("nDatabaseCache")) diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h index 2421734527..1af3a72b92 100644 --- a/src/qt/optionsmodel.h +++ b/src/qt/optionsmodel.h @@ -31,7 +31,7 @@ class OptionsModel : public QAbstractListModel Q_OBJECT public: - explicit OptionsModel(interfaces::Node& node, QObject *parent = 0, bool resetSettings = false); + explicit OptionsModel(interfaces::Node& node, QObject *parent = nullptr, bool resetSettings = false); enum OptionID { StartAtStartup, // bool diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index bec79335e7..d8e48f350a 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -113,8 +113,8 @@ public: OverviewPage::OverviewPage(const PlatformStyle *platformStyle, QWidget *parent) : QWidget(parent), ui(new Ui::OverviewPage), - clientModel(0), - walletModel(0), + clientModel(nullptr), + walletModel(nullptr), txdelegate(new TxViewDelegate(platformStyle, this)) { ui->setupUi(this); diff --git a/src/qt/overviewpage.h b/src/qt/overviewpage.h index 75100ae6f7..00ba7ad4ce 100644 --- a/src/qt/overviewpage.h +++ b/src/qt/overviewpage.h @@ -30,7 +30,7 @@ class OverviewPage : public QWidget Q_OBJECT public: - explicit OverviewPage(const PlatformStyle *platformStyle, QWidget *parent = 0); + explicit OverviewPage(const PlatformStyle *platformStyle, QWidget *parent = nullptr); ~OverviewPage(); void setClientModel(ClientModel *clientModel); diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp index 8148986b51..b1ec90ad36 100644 --- a/src/qt/paymentserver.cpp +++ b/src/qt/paymentserver.cpp @@ -194,10 +194,10 @@ bool PaymentServer::ipcSendCommandLine() PaymentServer::PaymentServer(QObject* parent, bool startLocalServer) : QObject(parent), saveURIs(true), - uriServer(0), - optionsModel(0) + uriServer(nullptr), + optionsModel(nullptr) #ifdef ENABLE_BIP70 - ,netManager(0) + ,netManager(nullptr) #endif { #ifdef ENABLE_BIP70 @@ -223,7 +223,7 @@ PaymentServer::PaymentServer(QObject* parent, bool startLocalServer) : if (!uriServer->listen(name)) { // constructor is called early in init, so don't use "Q_EMIT message()" here - QMessageBox::critical(0, tr("Payment request error"), + QMessageBox::critical(nullptr, tr("Payment request error"), tr("Cannot start bitcoin: click-to-pay handler")); } else { diff --git a/src/qt/peertablemodel.cpp b/src/qt/peertablemodel.cpp index 8cfedca57f..496aeebf7d 100644 --- a/src/qt/peertablemodel.cpp +++ b/src/qt/peertablemodel.cpp @@ -49,8 +49,8 @@ class PeerTablePriv public: /** Local cache of peer information */ QList<CNodeCombinedStats> cachedNodeStats; - /** Column to sort nodes by */ - int sortColumn; + /** Column to sort nodes by (default to unsorted) */ + int sortColumn{-1}; /** Order (ascending or descending) to sort nodes by */ Qt::SortOrder sortOrder; /** Index of rows by node ID */ @@ -96,7 +96,7 @@ public: if (idx >= 0 && idx < cachedNodeStats.size()) return &cachedNodeStats[idx]; - return 0; + return nullptr; } }; @@ -104,12 +104,10 @@ PeerTableModel::PeerTableModel(interfaces::Node& node, ClientModel *parent) : QAbstractTableModel(parent), m_node(node), clientModel(parent), - timer(0) + timer(nullptr) { columns << tr("NodeId") << tr("Node/Service") << tr("Ping") << tr("Sent") << tr("Received") << tr("User Agent"); priv.reset(new PeerTablePriv()); - // default to unsorted - priv->sortColumn = -1; // set up timer for auto refresh timer = new QTimer(this); @@ -199,8 +197,7 @@ QVariant PeerTableModel::headerData(int section, Qt::Orientation orientation, in Qt::ItemFlags PeerTableModel::flags(const QModelIndex &index) const { - if(!index.isValid()) - return 0; + if (!index.isValid()) return Qt::NoItemFlags; Qt::ItemFlags retval = Qt::ItemIsSelectable | Qt::ItemIsEnabled; return retval; diff --git a/src/qt/peertablemodel.h b/src/qt/peertablemodel.h index 738a06496f..b3f5dd7dbe 100644 --- a/src/qt/peertablemodel.h +++ b/src/qt/peertablemodel.h @@ -51,7 +51,7 @@ class PeerTableModel : public QAbstractTableModel Q_OBJECT public: - explicit PeerTableModel(interfaces::Node& node, ClientModel *parent = 0); + explicit PeerTableModel(interfaces::Node& node, ClientModel *parent = nullptr); ~PeerTableModel(); const CNodeCombinedStats *getNodeStats(int idx); int getRowByNodeId(NodeId nodeid); diff --git a/src/qt/platformstyle.cpp b/src/qt/platformstyle.cpp index 56e0830cdc..d537d759de 100644 --- a/src/qt/platformstyle.cpp +++ b/src/qt/platformstyle.cpp @@ -139,6 +139,6 @@ const PlatformStyle *PlatformStyle::instantiate(const QString &platformId) platform_styles[x].useExtraSpacing); } } - return 0; + return nullptr; } diff --git a/src/qt/qvalidatedlineedit.cpp b/src/qt/qvalidatedlineedit.cpp index 85c5a58a84..aa936d6b7c 100644 --- a/src/qt/qvalidatedlineedit.cpp +++ b/src/qt/qvalidatedlineedit.cpp @@ -10,7 +10,7 @@ QValidatedLineEdit::QValidatedLineEdit(QWidget *parent) : QLineEdit(parent), valid(true), - checkValidator(0) + checkValidator(nullptr) { connect(this, &QValidatedLineEdit::textChanged, this, &QValidatedLineEdit::markValid); } diff --git a/src/qt/qvaluecombobox.h b/src/qt/qvaluecombobox.h index f266302310..8892071fba 100644 --- a/src/qt/qvaluecombobox.h +++ b/src/qt/qvaluecombobox.h @@ -16,7 +16,7 @@ class QValueComboBox : public QComboBox Q_PROPERTY(QVariant value READ value WRITE setValue NOTIFY valueChanged USER true) public: - explicit QValueComboBox(QWidget *parent = 0); + explicit QValueComboBox(QWidget *parent = nullptr); QVariant value() const; void setValue(const QVariant &value); diff --git a/src/qt/receivecoinsdialog.cpp b/src/qt/receivecoinsdialog.cpp index a7cc5da19e..22a79a12bb 100644 --- a/src/qt/receivecoinsdialog.cpp +++ b/src/qt/receivecoinsdialog.cpp @@ -25,8 +25,8 @@ ReceiveCoinsDialog::ReceiveCoinsDialog(const PlatformStyle *_platformStyle, QWidget *parent) : QDialog(parent), ui(new Ui::ReceiveCoinsDialog), - columnResizingFixer(0), - model(0), + columnResizingFixer(nullptr), + model(nullptr), platformStyle(_platformStyle) { ui->setupUi(this); @@ -100,8 +100,13 @@ void ReceiveCoinsDialog::setModel(WalletModel *_model) ui->useBech32->setCheckState(Qt::Unchecked); } - // eventually disable the main receive button if private key operations are disabled - ui->receiveButton->setEnabled(!model->privateKeysDisabled()); + // Set the button to be enabled or disabled based on whether the wallet can give out new addresses. + ui->receiveButton->setEnabled(model->canGetAddresses()); + + // Enable/disable the receive button if the wallet is now able/unable to give out new addresses. + connect(model, &WalletModel::canGetAddressesChanged, [this] { + ui->receiveButton->setEnabled(model->canGetAddresses()); + }); } } diff --git a/src/qt/receivecoinsdialog.h b/src/qt/receivecoinsdialog.h index bc0f6248f0..5bca2f46e2 100644 --- a/src/qt/receivecoinsdialog.h +++ b/src/qt/receivecoinsdialog.h @@ -39,7 +39,7 @@ public: MINIMUM_COLUMN_WIDTH = 130 }; - explicit ReceiveCoinsDialog(const PlatformStyle *platformStyle, QWidget *parent = 0); + explicit ReceiveCoinsDialog(const PlatformStyle *platformStyle, QWidget *parent = nullptr); ~ReceiveCoinsDialog(); void setModel(WalletModel *model); diff --git a/src/qt/receiverequestdialog.cpp b/src/qt/receiverequestdialog.cpp index c561d948be..f5b30cf6d2 100644 --- a/src/qt/receiverequestdialog.cpp +++ b/src/qt/receiverequestdialog.cpp @@ -26,7 +26,7 @@ #endif QRImageWidget::QRImageWidget(QWidget *parent): - QLabel(parent), contextMenu(0) + QLabel(parent), contextMenu(nullptr) { contextMenu = new QMenu(this); QAction *saveImageAction = new QAction(tr("&Save Image..."), this); @@ -88,7 +88,7 @@ void QRImageWidget::contextMenuEvent(QContextMenuEvent *event) ReceiveRequestDialog::ReceiveRequestDialog(QWidget *parent) : QDialog(parent), ui(new Ui::ReceiveRequestDialog), - model(0) + model(nullptr) { ui->setupUi(this); diff --git a/src/qt/receiverequestdialog.h b/src/qt/receiverequestdialog.h index 5662af18b7..dd28fd73c8 100644 --- a/src/qt/receiverequestdialog.h +++ b/src/qt/receiverequestdialog.h @@ -28,7 +28,7 @@ class QRImageWidget : public QLabel Q_OBJECT public: - explicit QRImageWidget(QWidget *parent = 0); + explicit QRImageWidget(QWidget *parent = nullptr); QImage exportImage(); public Q_SLOTS: @@ -48,7 +48,7 @@ class ReceiveRequestDialog : public QDialog Q_OBJECT public: - explicit ReceiveRequestDialog(QWidget *parent = 0); + explicit ReceiveRequestDialog(QWidget *parent = nullptr); ~ReceiveRequestDialog(); void setModel(WalletModel *model); diff --git a/src/qt/recentrequeststablemodel.cpp b/src/qt/recentrequeststablemodel.cpp index 82ab48ac20..aa746017f3 100644 --- a/src/qt/recentrequeststablemodel.cpp +++ b/src/qt/recentrequeststablemodel.cpp @@ -15,8 +15,6 @@ RecentRequestsTableModel::RecentRequestsTableModel(WalletModel *parent) : QAbstractTableModel(parent), walletModel(parent) { - nReceiveRequestsMaxId = 0; - // Load entries from wallet std::vector<std::string> vReceiveRequests; parent->loadReceiveRequests(vReceiveRequests); diff --git a/src/qt/recentrequeststablemodel.h b/src/qt/recentrequeststablemodel.h index ff2c0c8098..8a1140e952 100644 --- a/src/qt/recentrequeststablemodel.h +++ b/src/qt/recentrequeststablemodel.h @@ -94,7 +94,7 @@ private: WalletModel *walletModel; QStringList columns; QList<RecentRequestEntry> list; - int64_t nReceiveRequestsMaxId; + int64_t nReceiveRequestsMaxId{0}; /** Updates the column title to "Amount (DisplayUnit)" and emits headerDataChanged() signal for table headers to react. */ void updateAmountColumnTitle(); diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index 774a0d78e7..fc1e14b031 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2018 The Bitcoin Core developers +// Copyright (c) 2011-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. @@ -18,6 +18,7 @@ #include <netbase.h> #include <rpc/server.h> #include <rpc/client.h> +#include <util/strencodings.h> #include <util/system.h> #include <openssl/crypto.h> @@ -85,7 +86,7 @@ public: explicit RPCExecutor(interfaces::Node& node) : m_node(node) {} public Q_SLOTS: - void request(const QString &command, const QString &walletID); + void request(const QString &command, const WalletModel* wallet_model); Q_SIGNALS: void reply(int category, const QString &command); @@ -148,7 +149,7 @@ public: * @param[out] pstrFilteredOut Command line, filtered to remove any sensitive data */ -bool RPCConsole::RPCParseCommandLine(interfaces::Node* node, std::string &strResult, const std::string &strCommand, const bool fExecute, std::string * const pstrFilteredOut, const std::string *walletID) +bool RPCConsole::RPCParseCommandLine(interfaces::Node* node, std::string &strResult, const std::string &strCommand, const bool fExecute, std::string * const pstrFilteredOut, const WalletModel* wallet_model) { std::vector< std::vector<std::string> > stack; stack.push_back(std::vector<std::string>()); @@ -226,7 +227,7 @@ bool RPCConsole::RPCParseCommandLine(interfaces::Node* node, std::string &strRes if (lastResult.isArray()) { for(char argch: curarg) - if (!std::isdigit(argch)) + if (!IsDigit(argch)) throw std::runtime_error("Invalid result query"); subelement = lastResult[atoi(curarg.c_str())]; } @@ -306,8 +307,8 @@ bool RPCConsole::RPCParseCommandLine(interfaces::Node* node, std::string &strRes std::string method = stack.back()[0]; std::string uri; #ifdef ENABLE_WALLET - if (walletID) { - QByteArray encodedName = QUrl::toPercentEncoding(QString::fromStdString(*walletID)); + if (wallet_model) { + QByteArray encodedName = QUrl::toPercentEncoding(wallet_model->getWalletName()); uri = "/wallet/"+std::string(encodedName.constData(), encodedName.length()); } #endif @@ -387,7 +388,7 @@ bool RPCConsole::RPCParseCommandLine(interfaces::Node* node, std::string &strRes } } -void RPCExecutor::request(const QString &command, const QString &walletID) +void RPCExecutor::request(const QString &command, const WalletModel* wallet_model) { try { @@ -395,13 +396,12 @@ void RPCExecutor::request(const QString &command, const QString &walletID) std::string executableCommand = command.toStdString() + "\n"; // Catch the console-only-help command before RPC call is executed and reply with help text as-if a RPC reply. - if(executableCommand == "help-console\n") - { + if(executableCommand == "help-console\n") { Q_EMIT reply(RPCConsole::CMD_REPLY, QString(("\n" "This console accepts RPC commands using the standard syntax.\n" " example: getblockhash 0\n\n" - "This console can also accept RPC commands using parenthesized syntax.\n" + "This console can also accept RPC commands using the parenthesized syntax.\n" " example: getblockhash(0)\n\n" "Commands may be nested when specified with the parenthesized syntax.\n" @@ -411,16 +411,14 @@ void RPCExecutor::request(const QString &command, const QString &walletID) " example: getblockhash 0\n" " getblockhash,0\n\n" - "Named results can be queried with a non-quoted key string in brackets.\n" - " example: getblock(getblockhash(0) true)[tx]\n\n" + "Named results can be queried with a non-quoted key string in brackets using the parenthesized syntax.\n" + " example: getblock(getblockhash(0) 1)[tx]\n\n" - "Results without keys can be queried using an integer in brackets.\n" - " example: getblock(getblockhash(0),true)[tx][0]\n\n"))); + "Results without keys can be queried with an integer in brackets using the parenthesized syntax.\n" + " example: getblock(getblockhash(0),1)[tx][0]\n\n"))); return; } - std::string wallet_id = walletID.toStdString(); - if (!RPCConsole::RPCExecuteCommandLine(m_node, result, executableCommand, nullptr, walletID.isNull() ? nullptr : &wallet_id)) - { + if (!RPCConsole::RPCExecuteCommandLine(m_node, result, executableCommand, nullptr, wallet_model)) { Q_EMIT reply(RPCConsole::CMD_ERROR, QString("Parse error: unbalanced ' or \"")); return; } @@ -486,7 +484,7 @@ RPCConsole::RPCConsole(interfaces::Node& node, const PlatformStyle *_platformSty // set library version labels #ifdef ENABLE_WALLET - ui->berkeleyDBVersion->setText(DbEnv::version(0, 0, 0)); + ui->berkeleyDBVersion->setText(DbEnv::version(nullptr, nullptr, nullptr)); #else ui->label_berkeleyDBVersion->hide(); ui->berkeleyDBVersion->hide(); @@ -689,8 +687,7 @@ void RPCConsole::setClientModel(ClientModel *model) } if (!model) { // Client model is being set to 0, this means shutdown() is about to be called. - // Make sure we clean up the executor thread - Q_EMIT stopExecutor(); + thread.quit(); thread.wait(); } } @@ -698,10 +695,8 @@ void RPCConsole::setClientModel(ClientModel *model) #ifdef ENABLE_WALLET void RPCConsole::addWallet(WalletModel * const walletModel) { - const QString name = walletModel->getWalletName(); - // use name for text and internal data object (to allow to move to a wallet id later) - QString display_name = name.isEmpty() ? "["+tr("default wallet")+"]" : name; - ui->WalletSelector->addItem(display_name, name); + // use name for text and wallet model for internal data object (to allow to move to a wallet id later) + ui->WalletSelector->addItem(walletModel->getDisplayName(), QVariant::fromValue(walletModel)); if (ui->WalletSelector->count() == 2 && !isVisible()) { // First wallet added, set to default so long as the window isn't presently visible (and potentially in use) ui->WalletSelector->setCurrentIndex(1); @@ -714,8 +709,7 @@ void RPCConsole::addWallet(WalletModel * const walletModel) void RPCConsole::removeWallet(WalletModel * const walletModel) { - const QString name = walletModel->getWalletName(); - ui->WalletSelector->removeItem(ui->WalletSelector->findData(name)); + ui->WalletSelector->removeItem(ui->WalletSelector->findData(QVariant::fromValue(walletModel))); if (ui->WalletSelector->count() == 2) { ui->WalletSelector->setVisible(false); ui->WalletSelectorLabel->setVisible(false); @@ -910,25 +904,25 @@ void RPCConsole::on_lineEdit_returnPressed() cmdBeforeBrowsing = QString(); - QString walletID; + WalletModel* wallet_model{nullptr}; #ifdef ENABLE_WALLET const int wallet_index = ui->WalletSelector->currentIndex(); if (wallet_index > 0) { - walletID = (QString)ui->WalletSelector->itemData(wallet_index).value<QString>(); + wallet_model = ui->WalletSelector->itemData(wallet_index).value<WalletModel*>(); } - if (m_last_wallet_id != walletID) { - if (walletID.isNull()) { - message(CMD_REQUEST, tr("Executing command without any wallet")); + if (m_last_wallet_model != wallet_model) { + if (wallet_model) { + message(CMD_REQUEST, tr("Executing command using \"%1\" wallet").arg(wallet_model->getWalletName())); } else { - message(CMD_REQUEST, tr("Executing command using \"%1\" wallet").arg(walletID)); + message(CMD_REQUEST, tr("Executing command without any wallet")); } - m_last_wallet_id = walletID; + m_last_wallet_model = wallet_model; } #endif message(CMD_REQUEST, QString::fromStdString(strFilteredCmd)); - Q_EMIT cmdRequest(cmd, walletID); + Q_EMIT cmdRequest(cmd, m_last_wallet_model); cmd = QString::fromStdString(strFilteredCmd); @@ -979,11 +973,8 @@ void RPCConsole::startExecutor() // Requests from this object must go to executor connect(this, &RPCConsole::cmdRequest, executor, &RPCExecutor::request); - // On stopExecutor signal - // - quit the Qt event loop in the execution thread - connect(this, &RPCConsole::stopExecutor, &thread, &QThread::quit); - // - queue executor for deletion (in execution thread) - connect(&thread, &QThread::finished, executor, &RPCExecutor::deleteLater, Qt::DirectConnection); + // Make sure executor object is deleted in its own thread + connect(&thread, &QThread::finished, executor, &RPCExecutor::deleteLater); // Default implementation of QThread::run() simply spins up an event loop in the thread, // which is what we want. @@ -992,10 +983,9 @@ void RPCConsole::startExecutor() void RPCConsole::on_tabWidget_currentChanged(int index) { - if (ui->tabWidget->widget(index) == ui->tab_console) + if (ui->tabWidget->widget(index) == ui->tab_console) { ui->lineEdit->setFocus(); - else if (ui->tabWidget->widget(index) != ui->tab_peers) - clearSelectedNode(); + } } void RPCConsole::on_openDebugLogfileButton_clicked() @@ -1221,16 +1211,16 @@ void RPCConsole::banSelectedNode(int bantime) // Get currently selected peer address NodeId id = nodes.at(i).data().toLongLong(); - // Get currently selected peer address - int detailNodeRow = clientModel->getPeerTableModel()->getRowByNodeId(id); - if(detailNodeRow < 0) - return; + // Get currently selected peer address + int detailNodeRow = clientModel->getPeerTableModel()->getRowByNodeId(id); + if (detailNodeRow < 0) return; - // Find possible nodes, ban it and clear the selected node - const CNodeCombinedStats *stats = clientModel->getPeerTableModel()->getNodeStats(detailNodeRow); - if(stats) { + // Find possible nodes, ban it and clear the selected node + const CNodeCombinedStats *stats = clientModel->getPeerTableModel()->getNodeStats(detailNodeRow); + if (stats) { m_node.ban(stats->nodeStats.addr, BanReasonManuallyAdded, bantime); - } + m_node.disconnect(stats->nodeStats.addr); + } } clearSelectedNode(); clientModel->getBanTableModel()->refresh(); diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h index 20dbf5ec95..79b0f3b19c 100644 --- a/src/qt/rpcconsole.h +++ b/src/qt/rpcconsole.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2018 The Bitcoin Core developers +// Copyright (c) 2011-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. @@ -41,9 +41,9 @@ public: explicit RPCConsole(interfaces::Node& node, const PlatformStyle *platformStyle, QWidget *parent); ~RPCConsole(); - static bool RPCParseCommandLine(interfaces::Node* node, std::string &strResult, const std::string &strCommand, bool fExecute, std::string * const pstrFilteredOut = nullptr, const std::string *walletID = nullptr); - static bool RPCExecuteCommandLine(interfaces::Node& node, std::string &strResult, const std::string &strCommand, std::string * const pstrFilteredOut = nullptr, const std::string *walletID = nullptr) { - return RPCParseCommandLine(&node, strResult, strCommand, true, pstrFilteredOut, walletID); + static bool RPCParseCommandLine(interfaces::Node* node, std::string &strResult, const std::string &strCommand, bool fExecute, std::string * const pstrFilteredOut = nullptr, const WalletModel* wallet_model = nullptr); + static bool RPCExecuteCommandLine(interfaces::Node& node, std::string &strResult, const std::string &strCommand, std::string * const pstrFilteredOut = nullptr, const WalletModel* wallet_model = nullptr) { + return RPCParseCommandLine(&node, strResult, strCommand, true, pstrFilteredOut, wallet_model); } void setClientModel(ClientModel *model); @@ -132,8 +132,7 @@ public Q_SLOTS: Q_SIGNALS: // For RPC command executor - void stopExecutor(); - void cmdRequest(const QString &command, const QString &walletID); + void cmdRequest(const QString &command, const WalletModel* wallet_model); private: void startExecutor(); @@ -165,7 +164,7 @@ private: int consoleFontSize = 0; QCompleter *autoCompleter = nullptr; QThread thread; - QString m_last_wallet_id; + WalletModel* m_last_wallet_model{nullptr}; /** Update UI with latest network info from model. */ void updateNetworkState(); diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index 65db0280b7..6e00ab755c 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -54,8 +54,8 @@ int getIndexForConfTarget(int target) { SendCoinsDialog::SendCoinsDialog(const PlatformStyle *_platformStyle, QWidget *parent) : QDialog(parent), ui(new Ui::SendCoinsDialog), - clientModel(0), - model(0), + clientModel(nullptr), + model(nullptr), fNewRecipientAllowed(true), fFeeMinimized(true), platformStyle(_platformStyle) @@ -443,7 +443,7 @@ SendCoinsEntry *SendCoinsDialog::addEntry() void SendCoinsDialog::updateTabsAndLabels() { - setupTabChain(0); + setupTabChain(nullptr); coinControlUpdateLabels(); } @@ -478,7 +478,7 @@ QWidget *SendCoinsDialog::setupTabChain(QWidget *prev) void SendCoinsDialog::setAddress(const QString &address) { - SendCoinsEntry *entry = 0; + SendCoinsEntry *entry = nullptr; // Replace the first entry if it is still unused if(ui->entries->count() == 1) { @@ -501,7 +501,7 @@ void SendCoinsDialog::pasteEntry(const SendCoinsRecipient &rv) if(!fNewRecipientAllowed) return; - SendCoinsEntry *entry = 0; + SendCoinsEntry *entry = nullptr; // Replace the first entry if it is still unused if(ui->entries->count() == 1) { diff --git a/src/qt/sendcoinsdialog.h b/src/qt/sendcoinsdialog.h index e1ebc77d59..337a72b878 100644 --- a/src/qt/sendcoinsdialog.h +++ b/src/qt/sendcoinsdialog.h @@ -31,7 +31,7 @@ class SendCoinsDialog : public QDialog Q_OBJECT public: - explicit SendCoinsDialog(const PlatformStyle *platformStyle, QWidget *parent = 0); + explicit SendCoinsDialog(const PlatformStyle *platformStyle, QWidget *parent = nullptr); ~SendCoinsDialog(); void setClientModel(ClientModel *clientModel); @@ -108,7 +108,7 @@ class SendConfirmationDialog : public QMessageBox Q_OBJECT public: - SendConfirmationDialog(const QString &title, const QString &text, int secDelay = SEND_CONFIRM_DELAY, QWidget *parent = 0); + SendConfirmationDialog(const QString &title, const QString &text, int secDelay = SEND_CONFIRM_DELAY, QWidget *parent = nullptr); int exec(); private Q_SLOTS: diff --git a/src/qt/sendcoinsentry.cpp b/src/qt/sendcoinsentry.cpp index 76c942c8b9..7324d759fb 100644 --- a/src/qt/sendcoinsentry.cpp +++ b/src/qt/sendcoinsentry.cpp @@ -21,7 +21,7 @@ SendCoinsEntry::SendCoinsEntry(const PlatformStyle *_platformStyle, QWidget *parent) : QStackedWidget(parent), ui(new Ui::SendCoinsEntry), - model(0), + model(nullptr), platformStyle(_platformStyle) { ui->setupUi(this); @@ -155,7 +155,7 @@ bool SendCoinsEntry::validate(interfaces::Node& node) } // Sending a zero amount is invalid - if (ui->payAmount->value(0) <= 0) + if (ui->payAmount->value(nullptr) <= 0) { ui->payAmount->setValid(false); retval = false; diff --git a/src/qt/sendcoinsentry.h b/src/qt/sendcoinsentry.h index 48ecd598d6..42e2217130 100644 --- a/src/qt/sendcoinsentry.h +++ b/src/qt/sendcoinsentry.h @@ -26,7 +26,7 @@ class SendCoinsEntry : public QStackedWidget Q_OBJECT public: - explicit SendCoinsEntry(const PlatformStyle *platformStyle, QWidget *parent = 0); + explicit SendCoinsEntry(const PlatformStyle *platformStyle, QWidget *parent = nullptr); ~SendCoinsEntry(); void setModel(WalletModel *model); diff --git a/src/qt/signverifymessagedialog.cpp b/src/qt/signverifymessagedialog.cpp index 487fc9ee1e..d37a78fa8c 100644 --- a/src/qt/signverifymessagedialog.cpp +++ b/src/qt/signverifymessagedialog.cpp @@ -22,7 +22,7 @@ SignVerifyMessageDialog::SignVerifyMessageDialog(const PlatformStyle *_platformStyle, QWidget *parent) : QDialog(parent), ui(new Ui::SignVerifyMessageDialog), - model(0), + model(nullptr), platformStyle(_platformStyle) { ui->setupUi(this); diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp index b109a08b1c..0126a2920e 100644 --- a/src/qt/splashscreen.cpp +++ b/src/qt/splashscreen.cpp @@ -26,7 +26,7 @@ SplashScreen::SplashScreen(interfaces::Node& node, Qt::WindowFlags f, const NetworkStyle *networkStyle) : - QWidget(0, f), curAlignment(0), m_node(node) + QWidget(nullptr, f), curAlignment(0), m_node(node) { // set reference point, paddings int paddingRight = 50; diff --git a/src/qt/test/apptests.cpp b/src/qt/test/apptests.cpp new file mode 100644 index 0000000000..2c477a2e98 --- /dev/null +++ b/src/qt/test/apptests.cpp @@ -0,0 +1,117 @@ +// 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. + +#include <qt/test/apptests.h> + +#include <chainparams.h> +#include <init.h> +#include <qt/bitcoin.h> +#include <qt/bitcoingui.h> +#include <qt/networkstyle.h> +#include <qt/rpcconsole.h> +#include <shutdown.h> +#include <validation.h> + +#if defined(HAVE_CONFIG_H) +#include <config/bitcoin-config.h> +#endif +#ifdef ENABLE_WALLET +#include <wallet/db.h> +#endif + +#include <QAction> +#include <QEventLoop> +#include <QLineEdit> +#include <QScopedPointer> +#include <QTest> +#include <QTextEdit> +#include <QtGlobal> +#if QT_VERSION >= 0x050000 +#include <QtTest/QtTestWidgets> +#endif +#include <QtTest/QtTestGui> +#include <new> +#include <string> +#include <univalue.h> + +namespace { +//! Call getblockchaininfo RPC and check first field of JSON output. +void TestRpcCommand(RPCConsole* console) +{ + QEventLoop loop; + QTextEdit* messagesWidget = console->findChild<QTextEdit*>("messagesWidget"); + QObject::connect(messagesWidget, &QTextEdit::textChanged, &loop, &QEventLoop::quit); + QLineEdit* lineEdit = console->findChild<QLineEdit*>("lineEdit"); + QTest::keyClicks(lineEdit, "getblockchaininfo"); + QTest::keyClick(lineEdit, Qt::Key_Return); + loop.exec(); + QString output = messagesWidget->toPlainText(); + UniValue value; + value.read(output.right(output.size() - output.lastIndexOf(QChar::ObjectReplacementCharacter) - 1).toStdString()); + QCOMPARE(value["chain"].get_str(), std::string("regtest")); +} +} // namespace + +//! Entry point for BitcoinApplication tests. +void AppTests::appTests() +{ +#ifdef Q_OS_MAC + if (QApplication::platformName() == "minimal") { + // Disable for mac on "minimal" platform to avoid crashes inside the Qt + // framework when it tries to look up unimplemented cocoa functions, + // and fails to handle returned nulls + // (https://bugreports.qt.io/browse/QTBUG-49686). + QWARN("Skipping AppTests on mac build with 'minimal' platform set due to Qt bugs. To run AppTests, invoke " + "with 'test_bitcoin-qt -platform cocoa' on mac, or else use a linux or windows build."); + return; + } +#endif + + m_app.parameterSetup(); + m_app.createOptionsModel(true /* reset settings */); + QScopedPointer<const NetworkStyle> style( + NetworkStyle::instantiate(QString::fromStdString(Params().NetworkIDString()))); + m_app.setupPlatformStyle(); + m_app.createWindow(style.data()); + connect(&m_app, &BitcoinApplication::windowShown, this, &AppTests::guiTests); + expectCallback("guiTests"); + m_app.baseInitialize(); + m_app.requestInitialize(); + m_app.exec(); + m_app.requestShutdown(); + m_app.exec(); + + // Reset global state to avoid interfering with later tests. + AbortShutdown(); + UnloadBlockIndex(); +} + +//! Entry point for BitcoinGUI tests. +void AppTests::guiTests(BitcoinGUI* window) +{ + HandleCallback callback{"guiTests", *this}; + connect(window, &BitcoinGUI::consoleShown, this, &AppTests::consoleTests); + expectCallback("consoleTests"); + QAction* action = window->findChild<QAction*>("openRPCConsoleAction"); + action->activate(QAction::Trigger); +} + +//! Entry point for RPCConsole tests. +void AppTests::consoleTests(RPCConsole* console) +{ + HandleCallback callback{"consoleTests", *this}; + TestRpcCommand(console); +} + +//! Destructor to shut down after the last expected callback completes. +AppTests::HandleCallback::~HandleCallback() +{ + auto& callbacks = m_app_tests.m_callbacks; + auto it = callbacks.find(m_callback); + assert(it != callbacks.end()); + callbacks.erase(it); + if (callbacks.empty()) { + m_app_tests.m_app.quit(); + } +} diff --git a/src/qt/test/apptests.h b/src/qt/test/apptests.h new file mode 100644 index 0000000000..83bf56f1e4 --- /dev/null +++ b/src/qt/test/apptests.h @@ -0,0 +1,50 @@ +// 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. + +#ifndef BITCOIN_QT_TEST_APPTESTS_H +#define BITCOIN_QT_TEST_APPTESTS_H + +#include <QObject> +#include <set> +#include <string> +#include <utility> + +class BitcoinApplication; +class BitcoinGUI; +class RPCConsole; + +class AppTests : public QObject +{ + Q_OBJECT +public: + explicit AppTests(BitcoinApplication& app) : m_app(app) {} + +private Q_SLOTS: + void appTests(); + void guiTests(BitcoinGUI* window); + void consoleTests(RPCConsole* console); + +private: + //! Add expected callback name to list of pending callbacks. + void expectCallback(std::string callback) { m_callbacks.emplace(std::move(callback)); } + + //! RAII helper to remove no-longer-pending callback. + struct HandleCallback + { + std::string m_callback; + AppTests& m_app_tests; + ~HandleCallback(); + }; + + //! Bitcoin application. + BitcoinApplication& m_app; + + //! Set of pending callback names. Used to track expected callbacks and shut + //! down the app after the last callback has been handled and all tests have + //! either run or thrown exceptions. This could be a simple int counter + //! instead of a set of names, but the names might be useful for debugging. + std::multiset<std::string> m_callbacks; +}; + +#endif // BITCOIN_QT_TEST_APPTESTS_H diff --git a/src/qt/test/paymentservertests.cpp b/src/qt/test/paymentservertests.cpp index 94907595f5..f0eca899fc 100644 --- a/src/qt/test/paymentservertests.cpp +++ b/src/qt/test/paymentservertests.cpp @@ -181,12 +181,12 @@ void PaymentServerTests::paymentServerTests() QCOMPARE(PaymentServer::verifyExpired(r.paymentRequest.getDetails()), true); // Test BIP70 DoS protection: - unsigned char randData[BIP70_MAX_PAYMENTREQUEST_SIZE + 1]; - GetRandBytes(randData, sizeof(randData)); + auto randdata = FastRandomContext().randbytes(BIP70_MAX_PAYMENTREQUEST_SIZE + 1); + // Write data to a temp file: QTemporaryFile tempFile; tempFile.open(); - tempFile.write((const char*)randData, sizeof(randData)); + tempFile.write((const char*)randdata.data(), randdata.size()); tempFile.close(); // compares 50001 <= BIP70_MAX_PAYMENTREQUEST_SIZE == false QCOMPARE(PaymentServer::verifySize(tempFile.size()), false); diff --git a/src/qt/test/rpcnestedtests.cpp b/src/qt/test/rpcnestedtests.cpp index ed453336da..173c814f1e 100644 --- a/src/qt/test/rpcnestedtests.cpp +++ b/src/qt/test/rpcnestedtests.cpp @@ -41,7 +41,7 @@ void RPCNestedTests::rpcNestedTests() TestingSetup test; - SetRPCWarmupFinished(); + if (RPCIsInWarmup(nullptr)) SetRPCWarmupFinished(); std::string result; std::string result2; diff --git a/src/qt/test/test_main.cpp b/src/qt/test/test_main.cpp index b6523604fd..a2bf53973b 100644 --- a/src/qt/test/test_main.cpp +++ b/src/qt/test/test_main.cpp @@ -7,6 +7,9 @@ #endif #include <chainparams.h> +#include <interfaces/node.h> +#include <qt/bitcoin.h> +#include <qt/test/apptests.h> #include <qt/test/rpcnestedtests.h> #include <util/system.h> #include <qt/test/uritests.h> @@ -47,12 +50,13 @@ int main(int argc, char *argv[]) { SetupEnvironment(); SetupNetworking(); - SelectParams(CBaseChainParams::MAIN); + SelectParams(CBaseChainParams::REGTEST); noui_connect(); ClearDatadirCache(); fs::path pathTemp = fs::temp_directory_path() / strprintf("test_bitcoin-qt_%lu_%i", (unsigned long)GetTime(), (int)GetRand(100000)); fs::create_directories(pathTemp); gArgs.ForceSetArg("-datadir", pathTemp.string()); + auto node = interfaces::MakeNode(); bool fInvalid = false; @@ -67,11 +71,15 @@ int main(int argc, char *argv[]) // Don't remove this, it's needed to access // QApplication:: and QCoreApplication:: in the tests - QApplication app(argc, argv); + BitcoinApplication app(*node, argc, argv); app.setApplicationName("Bitcoin-Qt-test"); SSL_library_init(); + AppTests app_tests(app); + if (QTest::qExec(&app_tests) != 0) { + fInvalid = true; + } URITests test1; if (QTest::qExec(&test1) != 0) { fInvalid = true; diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp index 610d83acb6..2b50a2ba81 100644 --- a/src/qt/test/wallettests.cpp +++ b/src/qt/test/wallettests.cpp @@ -1,6 +1,7 @@ #include <qt/test/wallettests.h> #include <qt/test/util.h> +#include <init.h> #include <interfaces/chain.h> #include <interfaces/node.h> #include <base58.h> @@ -146,13 +147,10 @@ void TestGUI() auto locked_chain = wallet->chain().lock(); WalletRescanReserver reserver(wallet.get()); reserver.reserve(); - const CBlockIndex* const null_block = nullptr; - const CBlockIndex *stop_block, *failed_block; - QCOMPARE( - wallet->ScanForWalletTransactions(chainActive.Genesis(), nullptr, reserver, failed_block, stop_block, true /* fUpdate */), - CWallet::ScanResult::SUCCESS); - QCOMPARE(stop_block, chainActive.Tip()); - QCOMPARE(failed_block, null_block); + CWallet::ScanResult result = wallet->ScanForWalletTransactions(locked_chain->getBlockHash(0), {} /* stop_block */, reserver, true /* fUpdate */); + QCOMPARE(result.status, CWallet::ScanResult::SUCCESS); + QCOMPARE(result.last_scanned_block, chainActive.Tip()->GetBlockHash()); + QVERIFY(result.last_failed_block.IsNull()); } wallet->SetBroadcastTransactions(true); diff --git a/src/qt/trafficgraphwidget.cpp b/src/qt/trafficgraphwidget.cpp index 3aed3f2b97..1588be8da3 100644 --- a/src/qt/trafficgraphwidget.cpp +++ b/src/qt/trafficgraphwidget.cpp @@ -19,14 +19,14 @@ TrafficGraphWidget::TrafficGraphWidget(QWidget *parent) : QWidget(parent), - timer(0), + timer(nullptr), fMax(0.0f), nMins(0), vSamplesIn(), vSamplesOut(), nLastBytesIn(0), nLastBytesOut(0), - clientModel(0) + clientModel(nullptr) { timer = new QTimer(this); connect(timer, &QTimer::timeout, this, &TrafficGraphWidget::updateRates); diff --git a/src/qt/trafficgraphwidget.h b/src/qt/trafficgraphwidget.h index 00660574af..48bd246b34 100644 --- a/src/qt/trafficgraphwidget.h +++ b/src/qt/trafficgraphwidget.h @@ -20,7 +20,7 @@ class TrafficGraphWidget : public QWidget Q_OBJECT public: - explicit TrafficGraphWidget(QWidget *parent = 0); + explicit TrafficGraphWidget(QWidget *parent = nullptr); void setClientModel(ClientModel *model); int getGraphRangeMins() const; diff --git a/src/qt/transactiondescdialog.h b/src/qt/transactiondescdialog.h index f1371b3856..8fd3f3166a 100644 --- a/src/qt/transactiondescdialog.h +++ b/src/qt/transactiondescdialog.h @@ -21,7 +21,7 @@ class TransactionDescDialog : public QDialog Q_OBJECT public: - explicit TransactionDescDialog(const QModelIndex &idx, QWidget *parent = 0); + explicit TransactionDescDialog(const QModelIndex &idx, QWidget *parent = nullptr); ~TransactionDescDialog(); private: diff --git a/src/qt/transactionfilterproxy.h b/src/qt/transactionfilterproxy.h index 9febd59820..685f8d3a26 100644 --- a/src/qt/transactionfilterproxy.h +++ b/src/qt/transactionfilterproxy.h @@ -16,7 +16,7 @@ class TransactionFilterProxy : public QSortFilterProxyModel Q_OBJECT public: - explicit TransactionFilterProxy(QObject *parent = 0); + explicit TransactionFilterProxy(QObject *parent = nullptr); /** Earliest date that can be represented (far in the past) */ static const QDateTime MIN_DATE; diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp index d88cfe52ed..aa785553c8 100644 --- a/src/qt/transactionrecord.cpp +++ b/src/qt/transactionrecord.cpp @@ -4,6 +4,7 @@ #include <qt/transactionrecord.h> +#include <chain.h> #include <consensus/consensus.h> #include <interfaces/wallet.h> #include <key_io.h> @@ -12,6 +13,7 @@ #include <stdint.h> +#include <QDateTime> /* Return positive answer if transaction should be shown in list. */ @@ -158,7 +160,7 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const interface return parts; } -void TransactionRecord::updateStatus(const interfaces::WalletTxStatus& wtx, int numBlocks) +void TransactionRecord::updateStatus(const interfaces::WalletTxStatus& wtx, int numBlocks, int64_t block_time) { // Determine transaction status @@ -172,10 +174,9 @@ void TransactionRecord::updateStatus(const interfaces::WalletTxStatus& wtx, int status.depth = wtx.depth_in_main_chain; status.cur_num_blocks = numBlocks; - if (!wtx.is_final) - { - if (wtx.lock_time < LOCKTIME_THRESHOLD) - { + const bool up_to_date = ((int64_t)QDateTime::currentMSecsSinceEpoch() / 1000 - block_time < MAX_BLOCK_TIME_GAP); + if (up_to_date && !wtx.is_final) { + if (wtx.lock_time < LOCKTIME_THRESHOLD) { status.status = TransactionStatus::OpenUntilBlock; status.open_for = wtx.lock_time - numBlocks; } diff --git a/src/qt/transactionrecord.h b/src/qt/transactionrecord.h index 470f70e2ab..3f64cefd09 100644 --- a/src/qt/transactionrecord.h +++ b/src/qt/transactionrecord.h @@ -138,7 +138,7 @@ public: /** Update status from core wallet tx. */ - void updateStatus(const interfaces::WalletTxStatus& wtx, int numBlocks); + void updateStatus(const interfaces::WalletTxStatus& wtx, int numBlocks, int64_t block_time); /** Return whether a status update is needed. */ diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp index 01722146c5..631a9b891d 100644 --- a/src/qt/transactiontablemodel.cpp +++ b/src/qt/transactiontablemodel.cpp @@ -192,12 +192,13 @@ public: // simply re-use the cached status. interfaces::WalletTxStatus wtx; int numBlocks; - if (wallet.tryGetTxStatus(rec->hash, wtx, numBlocks) && rec->statusUpdateNeeded(numBlocks)) { - rec->updateStatus(wtx, numBlocks); + int64_t block_time; + if (wallet.tryGetTxStatus(rec->hash, wtx, numBlocks, block_time) && rec->statusUpdateNeeded(numBlocks)) { + rec->updateStatus(wtx, numBlocks, block_time); } return rec; } - return 0; + return nullptr; } QString describe(interfaces::Node& node, interfaces::Wallet& wallet, TransactionRecord *rec, int unit) diff --git a/src/qt/transactiontablemodel.h b/src/qt/transactiontablemodel.h index 8be3a7ab2e..7a7d98962b 100644 --- a/src/qt/transactiontablemodel.h +++ b/src/qt/transactiontablemodel.h @@ -28,7 +28,7 @@ class TransactionTableModel : public QAbstractTableModel Q_OBJECT public: - explicit TransactionTableModel(const PlatformStyle *platformStyle, WalletModel *parent = 0); + explicit TransactionTableModel(const PlatformStyle *platformStyle, WalletModel *parent = nullptr); ~TransactionTableModel(); enum ColumnIndex { diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp index 68410c8bd6..762ec434a1 100644 --- a/src/qt/transactionview.cpp +++ b/src/qt/transactionview.cpp @@ -38,8 +38,8 @@ #include <QVBoxLayout> TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *parent) : - QWidget(parent), model(0), transactionProxyModel(0), - transactionView(0), abandonAction(0), bumpFeeAction(0), columnResizingFixer(0) + QWidget(parent), model(nullptr), transactionProxyModel(nullptr), + transactionView(nullptr), abandonAction(nullptr), bumpFeeAction(nullptr), columnResizingFixer(nullptr) { // Build filter row setContentsMargins(0,0,0,0); @@ -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/transactionview.h b/src/qt/transactionview.h index fdd8b069c7..e07181d1c8 100644 --- a/src/qt/transactionview.h +++ b/src/qt/transactionview.h @@ -35,7 +35,7 @@ class TransactionView : public QWidget Q_OBJECT public: - explicit TransactionView(const PlatformStyle *platformStyle, QWidget *parent = 0); + explicit TransactionView(const PlatformStyle *platformStyle, QWidget *parent = nullptr); void setModel(WalletModel *model); diff --git a/src/qt/utilitydialog.h b/src/qt/utilitydialog.h index ad1fda4573..f1cedff282 100644 --- a/src/qt/utilitydialog.h +++ b/src/qt/utilitydialog.h @@ -45,7 +45,7 @@ class ShutdownWindow : public QWidget Q_OBJECT public: - explicit ShutdownWindow(QWidget *parent=0, Qt::WindowFlags f=0); + explicit ShutdownWindow(QWidget *parent=nullptr, Qt::WindowFlags f=Qt::Widget); static QWidget *showShutdownWindow(BitcoinGUI *window); protected: diff --git a/src/qt/walletcontroller.cpp b/src/qt/walletcontroller.cpp new file mode 100644 index 0000000000..df2b7a3f9b --- /dev/null +++ b/src/qt/walletcontroller.cpp @@ -0,0 +1,95 @@ +// 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 <qt/walletcontroller.h> + +#include <interfaces/handler.h> +#include <interfaces/node.h> + +#include <algorithm> + +#include <QMutexLocker> +#include <QThread> + +WalletController::WalletController(interfaces::Node& node, const PlatformStyle* platform_style, OptionsModel* options_model, QObject* parent) + : QObject(parent) + , m_node(node) + , m_platform_style(platform_style) + , m_options_model(options_model) +{ + m_handler_load_wallet = m_node.handleLoadWallet([this](std::unique_ptr<interfaces::Wallet> wallet) { + getOrCreateWallet(std::move(wallet)); + }); + + for (std::unique_ptr<interfaces::Wallet>& wallet : m_node.getWallets()) { + getOrCreateWallet(std::move(wallet)); + } +} + +// Not using the default destructor because not all member types definitions are +// available in the header, just forward declared. +WalletController::~WalletController() {} + +std::vector<WalletModel*> WalletController::getWallets() const +{ + QMutexLocker locker(&m_mutex); + return m_wallets; +} + +WalletModel* WalletController::getOrCreateWallet(std::unique_ptr<interfaces::Wallet> wallet) +{ + QMutexLocker locker(&m_mutex); + + // Return model instance if exists. + if (!m_wallets.empty()) { + std::string name = wallet->getWalletName(); + for (WalletModel* wallet_model : m_wallets) { + if (wallet_model->wallet().getWalletName() == name) { + return wallet_model; + } + } + } + + // Instantiate model and register it. + WalletModel* wallet_model = new WalletModel(std::move(wallet), m_node, m_platform_style, m_options_model, nullptr); + m_wallets.push_back(wallet_model); + + connect(wallet_model, &WalletModel::unload, [this, wallet_model] { + removeAndDeleteWallet(wallet_model); + }); + + // Re-emit coinsSent signal from wallet model. + connect(wallet_model, &WalletModel::coinsSent, this, &WalletController::coinsSent); + + // Notify walletAdded signal on the GUI thread. + if (QThread::currentThread() == thread()) { + addWallet(wallet_model); + } else { + // Handler callback runs in a different thread so fix wallet model thread affinity. + wallet_model->moveToThread(thread()); + QMetaObject::invokeMethod(this, "addWallet", Qt::QueuedConnection, Q_ARG(WalletModel*, wallet_model)); + } + + return wallet_model; +} + +void WalletController::addWallet(WalletModel* wallet_model) +{ + // Take ownership of the wallet model and register it. + wallet_model->setParent(this); + Q_EMIT walletAdded(wallet_model); +} + +void WalletController::removeAndDeleteWallet(WalletModel* wallet_model) +{ + // Unregister wallet model. + { + QMutexLocker locker(&m_mutex); + m_wallets.erase(std::remove(m_wallets.begin(), m_wallets.end(), wallet_model)); + } + Q_EMIT walletRemoved(wallet_model); + // Currently this can trigger the unload since the model can hold the last + // CWallet shared pointer. + delete wallet_model; +} diff --git a/src/qt/walletcontroller.h b/src/qt/walletcontroller.h new file mode 100644 index 0000000000..22b71b07ff --- /dev/null +++ b/src/qt/walletcontroller.h @@ -0,0 +1,59 @@ +// 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_QT_WALLETCONTROLLER_H +#define BITCOIN_QT_WALLETCONTROLLER_H + +#include <qt/walletmodel.h> +#include <sync.h> + +#include <list> +#include <memory> +#include <vector> + +#include <QMutex> + +class OptionsModel; +class PlatformStyle; + +namespace interfaces { +class Handler; +class Node; +} // namespace interfaces + +/** + * Controller between interfaces::Node, WalletModel instances and the GUI. + */ +class WalletController : public QObject +{ + Q_OBJECT + + WalletModel* getOrCreateWallet(std::unique_ptr<interfaces::Wallet> wallet); + void removeAndDeleteWallet(WalletModel* wallet_model); + +public: + WalletController(interfaces::Node& node, const PlatformStyle* platform_style, OptionsModel* options_model, QObject* parent); + ~WalletController(); + + std::vector<WalletModel*> getWallets() const; + +private Q_SLOTS: + void addWallet(WalletModel* wallet_model); + +Q_SIGNALS: + void walletAdded(WalletModel* wallet_model); + void walletRemoved(WalletModel* wallet_model); + + void coinsSent(WalletModel* wallet_model, SendCoinsRecipient recipient, QByteArray transaction); + +private: + 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; +}; + +#endif // BITCOIN_QT_WALLETCONTROLLER_H diff --git a/src/qt/walletframe.cpp b/src/qt/walletframe.cpp index d15bd95b8e..466f2278eb 100644 --- a/src/qt/walletframe.cpp +++ b/src/qt/walletframe.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2018 The Bitcoin Core developers +// Copyright (c) 2011-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. @@ -46,8 +46,7 @@ bool WalletFrame::addWallet(WalletModel *walletModel) return false; } - const QString name = walletModel->getWalletName(); - if (mapWalletViews.count(name) > 0) { + if (mapWalletViews.count(walletModel) > 0) { return false; } @@ -65,7 +64,7 @@ bool WalletFrame::addWallet(WalletModel *walletModel) } walletStack->addWidget(walletView); - mapWalletViews[name] = walletView; + mapWalletViews[walletModel] = walletView; // Ensure a walletView is able to show the main window connect(walletView, &WalletView::showNormalIfMinimized, [this]{ @@ -77,24 +76,24 @@ bool WalletFrame::addWallet(WalletModel *walletModel) return true; } -bool WalletFrame::setCurrentWallet(const QString& name) +bool WalletFrame::setCurrentWallet(WalletModel* wallet_model) { - if (mapWalletViews.count(name) == 0) + if (mapWalletViews.count(wallet_model) == 0) return false; - WalletView *walletView = mapWalletViews.value(name); + WalletView *walletView = mapWalletViews.value(wallet_model); walletStack->setCurrentWidget(walletView); assert(walletView); walletView->updateEncryptionStatus(); return true; } -bool WalletFrame::removeWallet(const QString &name) +bool WalletFrame::removeWallet(WalletModel* wallet_model) { - if (mapWalletViews.count(name) == 0) + if (mapWalletViews.count(wallet_model) == 0) return false; - WalletView *walletView = mapWalletViews.take(name); + WalletView *walletView = mapWalletViews.take(wallet_model); walletStack->removeWidget(walletView); delete walletView; return true; @@ -102,7 +101,7 @@ bool WalletFrame::removeWallet(const QString &name) void WalletFrame::removeAllWallets() { - QMap<QString, WalletView*>::const_iterator i; + QMap<WalletModel*, WalletView*>::const_iterator i; for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i) walletStack->removeWidget(i.value()); mapWalletViews.clear(); @@ -120,35 +119,35 @@ bool WalletFrame::handlePaymentRequest(const SendCoinsRecipient &recipient) void WalletFrame::showOutOfSyncWarning(bool fShow) { bOutOfSync = fShow; - QMap<QString, WalletView*>::const_iterator i; + QMap<WalletModel*, WalletView*>::const_iterator i; for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i) i.value()->showOutOfSyncWarning(fShow); } void WalletFrame::gotoOverviewPage() { - QMap<QString, WalletView*>::const_iterator i; + QMap<WalletModel*, WalletView*>::const_iterator i; for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i) i.value()->gotoOverviewPage(); } void WalletFrame::gotoHistoryPage() { - QMap<QString, WalletView*>::const_iterator i; + QMap<WalletModel*, WalletView*>::const_iterator i; for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i) i.value()->gotoHistoryPage(); } void WalletFrame::gotoReceiveCoinsPage() { - QMap<QString, WalletView*>::const_iterator i; + QMap<WalletModel*, WalletView*>::const_iterator i; for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i) i.value()->gotoReceiveCoinsPage(); } void WalletFrame::gotoSendCoinsPage(QString addr) { - QMap<QString, WalletView*>::const_iterator i; + QMap<WalletModel*, WalletView*>::const_iterator i; for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i) i.value()->gotoSendCoinsPage(addr); } @@ -209,11 +208,17 @@ void WalletFrame::usedReceivingAddresses() walletView->usedReceivingAddresses(); } -WalletView *WalletFrame::currentWalletView() +WalletView* WalletFrame::currentWalletView() const { return qobject_cast<WalletView*>(walletStack->currentWidget()); } +WalletModel* WalletFrame::currentWalletModel() const +{ + WalletView* wallet_view = currentWalletView(); + return wallet_view ? wallet_view->getWalletModel() : nullptr; +} + void WalletFrame::outOfSyncWarningClicked() { Q_EMIT requestedSyncWarningInfo(); diff --git a/src/qt/walletframe.h b/src/qt/walletframe.h index 1963e89b24..6a74fde9fd 100644 --- a/src/qt/walletframe.h +++ b/src/qt/walletframe.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2018 The Bitcoin Core developers +// Copyright (c) 2011-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. @@ -31,14 +31,14 @@ class WalletFrame : public QFrame Q_OBJECT public: - explicit WalletFrame(const PlatformStyle *platformStyle, BitcoinGUI *_gui = 0); + explicit WalletFrame(const PlatformStyle *platformStyle, BitcoinGUI *_gui = nullptr); ~WalletFrame(); void setClientModel(ClientModel *clientModel); bool addWallet(WalletModel *walletModel); - bool setCurrentWallet(const QString& name); - bool removeWallet(const QString &name); + bool setCurrentWallet(WalletModel* wallet_model); + bool removeWallet(WalletModel* wallet_model); void removeAllWallets(); bool handlePaymentRequest(const SendCoinsRecipient& recipient); @@ -53,14 +53,15 @@ private: QStackedWidget *walletStack; BitcoinGUI *gui; ClientModel *clientModel; - QMap<QString, WalletView*> mapWalletViews; + QMap<WalletModel*, WalletView*> mapWalletViews; bool bOutOfSync; const PlatformStyle *platformStyle; public: - WalletView *currentWalletView(); + WalletView* currentWalletView() const; + WalletModel* currentWalletModel() const; public Q_SLOTS: /** Switch to overview (home) page */ diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index ba16fdd5e1..2a9144bec9 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2018 The Bitcoin Core developers +// Copyright (c) 2011-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. @@ -33,15 +33,13 @@ WalletModel::WalletModel(std::unique_ptr<interfaces::Wallet> wallet, interfaces::Node& node, const PlatformStyle *platformStyle, OptionsModel *_optionsModel, QObject *parent) : - QObject(parent), m_wallet(std::move(wallet)), m_node(node), optionsModel(_optionsModel), addressTableModel(0), - transactionTableModel(0), - recentRequestsTableModel(0), + QObject(parent), m_wallet(std::move(wallet)), m_node(node), optionsModel(_optionsModel), addressTableModel(nullptr), + transactionTableModel(nullptr), + recentRequestsTableModel(nullptr), cachedEncryptionStatus(Unencrypted), cachedNumBlocks(0) { fHaveWatchOnly = m_wallet->haveWatchOnly(); - fForceCheckBalanceChanged = false; - addressTableModel = new AddressTableModel(this); transactionTableModel = new TransactionTableModel(platformStyle, this); recentRequestsTableModel = new RecentRequestsTableModel(this); @@ -378,7 +376,7 @@ bool WalletModel::changePassphrase(const SecureString &oldPass, const SecureStri static void NotifyUnload(WalletModel* walletModel) { qDebug() << "NotifyUnload"; - QMetaObject::invokeMethod(walletModel, "unload", Qt::QueuedConnection); + QMetaObject::invokeMethod(walletModel, "unload"); } static void NotifyKeyStoreStatusChanged(WalletModel *walletmodel) @@ -425,6 +423,11 @@ static void NotifyWatchonlyChanged(WalletModel *walletmodel, bool fHaveWatchonly Q_ARG(bool, fHaveWatchonly)); } +static void NotifyCanGetAddressesChanged(WalletModel* walletmodel) +{ + QMetaObject::invokeMethod(walletmodel, "canGetAddressesChanged"); +} + void WalletModel::subscribeToCoreSignals() { // Connect signals to wallet @@ -434,6 +437,7 @@ void WalletModel::subscribeToCoreSignals() m_handler_transaction_changed = m_wallet->handleTransactionChanged(std::bind(NotifyTransactionChanged, this, std::placeholders::_1, std::placeholders::_2)); m_handler_show_progress = m_wallet->handleShowProgress(std::bind(ShowProgress, this, std::placeholders::_1, std::placeholders::_2)); m_handler_watch_only_changed = m_wallet->handleWatchOnlyChanged(std::bind(NotifyWatchonlyChanged, this, std::placeholders::_1)); + m_handler_can_get_addrs_changed = m_wallet->handleCanGetAddressesChanged(boost::bind(NotifyCanGetAddressesChanged, this)); } void WalletModel::unsubscribeFromCoreSignals() @@ -445,6 +449,7 @@ void WalletModel::unsubscribeFromCoreSignals() m_handler_transaction_changed->disconnect(); m_handler_show_progress->disconnect(); m_handler_watch_only_changed->disconnect(); + m_handler_can_get_addrs_changed->disconnect(); } // WalletModel::UnlockContext implementation @@ -512,7 +517,7 @@ bool WalletModel::bumpFee(uint256 hash, uint256& new_hash) CAmount new_fee; CMutableTransaction mtx; if (!m_wallet->createBumpTransaction(hash, coin_control, 0 /* totalFee */, errors, old_fee, new_fee, mtx)) { - QMessageBox::critical(0, tr("Fee bump error"), tr("Increasing transaction fee failed") + "<br />(" + + QMessageBox::critical(nullptr, tr("Fee bump error"), tr("Increasing transaction fee failed") + "<br />(" + (errors.size() ? QString::fromStdString(errors[0]) : "") +")"); return false; } @@ -551,12 +556,12 @@ bool WalletModel::bumpFee(uint256 hash, uint256& new_hash) // sign bumped transaction if (!m_wallet->signBumpTransaction(mtx)) { - QMessageBox::critical(0, tr("Fee bump error"), tr("Can't sign transaction.")); + QMessageBox::critical(nullptr, tr("Fee bump error"), tr("Can't sign transaction.")); return false; } // commit the bumped transaction if(!m_wallet->commitBumpTransaction(hash, std::move(mtx), errors, new_hash)) { - QMessageBox::critical(0, tr("Fee bump error"), tr("Could not commit transaction") + "<br />(" + + QMessageBox::critical(nullptr, tr("Fee bump error"), tr("Could not commit transaction") + "<br />(" + QString::fromStdString(errors[0])+")"); return false; } @@ -573,11 +578,27 @@ bool WalletModel::privateKeysDisabled() const return m_wallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS); } +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)); +} + QString WalletModel::getWalletName() const { return QString::fromStdString(m_wallet->getWalletName()); } +QString WalletModel::getDisplayName() const +{ + const QString name = getWalletName(); + return name.isEmpty() ? "["+tr("default wallet")+"]" : name; +} + bool WalletModel::isMultiwallet() { return m_node.getWallets().size() > 1; diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index ec4c5a2a6c..b123befbb4 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2018 The Bitcoin Core developers +// Copyright (c) 2011-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. @@ -127,7 +127,7 @@ class WalletModel : public QObject Q_OBJECT public: - explicit WalletModel(std::unique_ptr<interfaces::Wallet> wallet, interfaces::Node& node, const PlatformStyle *platformStyle, OptionsModel *optionsModel, QObject *parent = 0); + explicit WalletModel(std::unique_ptr<interfaces::Wallet> wallet, interfaces::Node& node, const PlatformStyle *platformStyle, OptionsModel *optionsModel, QObject *parent = nullptr); ~WalletModel(); enum StatusCode // Returned by sendCoins @@ -214,11 +214,13 @@ public: static bool isWalletEnabled(); bool privateKeysDisabled() const; + bool canGetAddresses() const; interfaces::Node& node() const { return m_node; } interfaces::Wallet& wallet() const { return *m_wallet; } QString getWalletName() const; + QString getDisplayName() const; bool isMultiwallet(); @@ -231,10 +233,11 @@ private: std::unique_ptr<interfaces::Handler> m_handler_transaction_changed; std::unique_ptr<interfaces::Handler> m_handler_show_progress; std::unique_ptr<interfaces::Handler> m_handler_watch_only_changed; + std::unique_ptr<interfaces::Handler> m_handler_can_get_addrs_changed; interfaces::Node& m_node; bool fHaveWatchOnly; - bool fForceCheckBalanceChanged; + bool fForceCheckBalanceChanged{false}; // Wallet has an options model for wallet-specific options // (transaction fee, for example) @@ -282,6 +285,9 @@ Q_SIGNALS: // Signal that wallet is about to be removed void unload(); + // Notify that there are now keys in the keypool + void canGetAddressesChanged(); + public Q_SLOTS: /* Wallet status might have changed */ void updateStatus(); diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp index a619992344..5f6f93d948 100644 --- a/src/qt/walletview.cpp +++ b/src/qt/walletview.cpp @@ -32,8 +32,8 @@ WalletView::WalletView(const PlatformStyle *_platformStyle, QWidget *parent): QStackedWidget(parent), - clientModel(0), - walletModel(0), + clientModel(nullptr), + walletModel(nullptr), platformStyle(_platformStyle) { // Create tabs @@ -305,24 +305,19 @@ void WalletView::usedReceivingAddresses() void WalletView::showProgress(const QString &title, int nProgress) { - if (nProgress == 0) - { - progressDialog = new QProgressDialog(title, "", 0, 100); + if (nProgress == 0) { + progressDialog = new QProgressDialog(title, tr("Cancel"), 0, 100); + GUIUtil::PolishProgressDialog(progressDialog); progressDialog->setWindowModality(Qt::ApplicationModal); progressDialog->setMinimumDuration(0); progressDialog->setAutoClose(false); progressDialog->setValue(0); - progressDialog->setCancelButtonText(tr("Cancel")); - } - else if (nProgress == 100) - { - if (progressDialog) - { + } else if (nProgress == 100) { + if (progressDialog) { progressDialog->close(); progressDialog->deleteLater(); } - } - else if (progressDialog) { + } else if (progressDialog) { if (progressDialog->wasCanceled()) { getWalletModel()->wallet().abortRescan(); } else { diff --git a/src/random.cpp b/src/random.cpp index f8ffda136d..3277c34d3f 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -19,6 +19,8 @@ #include <chrono> #include <thread> +#include <support/allocators/secure.h> + #ifndef WIN32 #include <fcntl.h> #include <sys/time.h> @@ -47,6 +49,7 @@ #include <openssl/err.h> #include <openssl/rand.h> +#include <openssl/conf.h> [[noreturn]] static void RandFailure() { @@ -54,7 +57,7 @@ std::abort(); } -static inline int64_t GetPerformanceCounter() +static inline int64_t GetPerformanceCounter() noexcept { // Read the hardware time stamp counter when available. // See https://en.wikipedia.org/wiki/Time_Stamp_Counter for more information. @@ -74,27 +77,38 @@ static inline int64_t GetPerformanceCounter() #endif } - #if defined(__x86_64__) || defined(__amd64__) || defined(__i386__) -static std::atomic<bool> hwrand_initialized{false}; static bool rdrand_supported = false; static constexpr uint32_t CPUID_F1_ECX_RDRAND = 0x40000000; -static void RDRandInit() +static void InitHardwareRand() { uint32_t eax, ebx, ecx, edx; if (__get_cpuid(1, &eax, &ebx, &ecx, &edx) && (ecx & CPUID_F1_ECX_RDRAND)) { - LogPrintf("Using RdRand as an additional entropy source\n"); rdrand_supported = true; } - hwrand_initialized.store(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. + LogPrintf("Using RdRand as an additional entropy source\n"); + } +} + #else -static void RDRandInit() {} +/* 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). + * Slower sources should probably be invoked separately, and/or only from + * RandAddSeedSleep (which is called during idle background operation). + */ +static void InitHardwareRand() {} +static void ReportHardwareRand() {} #endif -static bool GetHWRand(unsigned char* ent32) { +static bool GetHardwareRand(unsigned char* ent32) noexcept { #if defined(__x86_64__) || defined(__amd64__) || defined(__i386__) - assert(hwrand_initialized.load(std::memory_order_relaxed)); if (rdrand_supported) { uint8_t ok; // Not all assemblers support the rdrand instruction, write it in hex. @@ -129,18 +143,8 @@ static bool GetHWRand(unsigned char* ent32) { return false; } -void RandAddSeed() +static void RandAddSeedPerfmon(CSHA512& hasher) { - // Seed with CPU performance counter - int64_t nCounter = GetPerformanceCounter(); - RAND_add(&nCounter, sizeof(nCounter), 1.5); - memory_cleanse((void*)&nCounter, sizeof(nCounter)); -} - -static void RandAddSeedPerfmon() -{ - RandAddSeed(); - #ifdef WIN32 // Don't need this on Linux, OpenSSL automatically uses /dev/urandom // Seed with the entire set of perfmon data @@ -164,15 +168,15 @@ static void RandAddSeedPerfmon() } RegCloseKey(HKEY_PERFORMANCE_DATA); if (ret == ERROR_SUCCESS) { - RAND_add(vData.data(), nSize, nSize / 100.0); + hasher.Write(vData.data(), nSize); memory_cleanse(vData.data(), nSize); - LogPrint(BCLog::RAND, "%s: %lu bytes\n", __func__, nSize); } else { - static bool warned = false; // Warn only once - if (!warned) { - LogPrintf("%s: Warning: RegQueryValueExA(HKEY_PERFORMANCE_DATA) failed with code %i\n", __func__, ret); - warned = true; - } + // Performance data is only a best-effort attempt at improving the + // situation when the OS randomness (and other sources) aren't + // adequate. As a result, failure to read it is isn't considered critical, + // so we don't call RandFailure(). + // TODO: Add logging when the logger is made functional before global + // constructors have been invoked. } #endif } @@ -272,106 +276,257 @@ void GetOSRand(unsigned char *ent32) #endif } -void GetRandBytes(unsigned char* buf, int num) +void LockingCallbackOpenSSL(int mode, int i, const char* file, int line); + +namespace { + +class RNGState { + Mutex m_mutex; + /* The RNG state consists of 256 bits of entropy, taken from the output of + * one operation's SHA512 output, and fed as input to the next one. + * Carrying 256 bits of entropy should be sufficient to guarantee + * unpredictability as long as any entropy source was ever unpredictable + * to an attacker. To protect against situations where an attacker might + * observe the RNG's state, fresh entropy is always mixed when + * GetStrongRandBytes is called. + */ + unsigned char m_state[32] GUARDED_BY(m_mutex) = {0}; + uint64_t m_counter GUARDED_BY(m_mutex) = 0; + bool m_strongly_seeded GUARDED_BY(m_mutex) = false; + std::unique_ptr<Mutex[]> m_mutex_openssl; + +public: + RNGState() noexcept + { + InitHardwareRand(); + + // Init OpenSSL library multithreading support + m_mutex_openssl.reset(new Mutex[CRYPTO_num_locks()]); + CRYPTO_set_locking_callback(LockingCallbackOpenSSL); + + // OpenSSL can optionally load a config file which lists optional loadable modules and engines. + // We don't use them so we don't require the config. However some of our libs may call functions + // which attempt to load the config file, possibly resulting in an exit() or crash if it is missing + // or corrupt. Explicitly tell OpenSSL not to try to load the file. The result for our libs will be + // that the config appears to have been loaded and there are no modules/engines available. + OPENSSL_no_config(); + } + + ~RNGState() + { + // Securely erase the memory used by the OpenSSL PRNG + RAND_cleanup(); + // Shutdown OpenSSL library multithreading support + CRYPTO_set_locking_callback(nullptr); + } + + /** Extract up to 32 bytes of entropy from the RNG state, mixing in new entropy from hasher. + * + * If this function has never been called with strong_seed = true, false is returned. + */ + bool MixExtract(unsigned char* out, size_t num, CSHA512&& hasher, bool strong_seed) noexcept + { + assert(num <= 32); + unsigned char buf[64]; + static_assert(sizeof(buf) == CSHA512::OUTPUT_SIZE, "Buffer needs to have hasher's output size"); + bool ret; + { + LOCK(m_mutex); + ret = (m_strongly_seeded |= strong_seed); + // Write the current state of the RNG into the hasher + hasher.Write(m_state, 32); + // Write a new counter number into the state + hasher.Write((const unsigned char*)&m_counter, sizeof(m_counter)); + ++m_counter; + // Finalize the hasher + hasher.Finalize(buf); + // Store the last 32 bytes of the hash output as new RNG state. + memcpy(m_state, buf + 32, 32); + } + // If desired, copy (up to) the first 32 bytes of the hash output as output. + if (num) { + assert(out != nullptr); + memcpy(out, buf, num); + } + // Best effort cleanup of internal state + hasher.Reset(); + memory_cleanse(buf, 64); + return ret; + } + + Mutex& GetOpenSSLMutex(int i) { return m_mutex_openssl[i]; } +}; + +RNGState& GetRNGState() noexcept { - if (RAND_bytes(buf, num) != 1) { - RandFailure(); + // This C++11 idiom relies on the guarantee that static variable are initialized + // on first call, even when multiple parallel calls are permitted. + static std::vector<RNGState, secure_allocator<RNGState>> g_rng(1); + return g_rng[0]; +} +} + +void LockingCallbackOpenSSL(int mode, int i, const char* file, int line) NO_THREAD_SAFETY_ANALYSIS +{ + RNGState& rng = GetRNGState(); + + if (mode & CRYPTO_LOCK) { + rng.GetOpenSSLMutex(i).lock(); + } else { + rng.GetOpenSSLMutex(i).unlock(); } } -static void AddDataToRng(void* data, size_t len); +/* A note on the use of noexcept in the seeding functions below: + * + * None of the RNG code should ever throw any exception, with the sole exception + * of MilliSleep in SeedSleep, which can (and does) support interruptions which + * cause a boost::thread_interrupted to be thrown. + * + * This means that SeedSleep, and all functions that invoke it are throwing. + * However, we know that GetRandBytes() and GetStrongRandBytes() never trigger + * this sleeping logic, so they are noexcept. The same is true for all the + * GetRand*() functions that use GetRandBytes() indirectly. + * + * TODO: After moving away from interruptible boost-based thread management, + * everything can become noexcept here. + */ -void RandAddSeedSleep() +static void SeedTimestamp(CSHA512& hasher) noexcept { - int64_t nPerfCounter1 = GetPerformanceCounter(); - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - int64_t nPerfCounter2 = GetPerformanceCounter(); + int64_t perfcounter = GetPerformanceCounter(); + hasher.Write((const unsigned char*)&perfcounter, sizeof(perfcounter)); +} - // Combine with and update state - AddDataToRng(&nPerfCounter1, sizeof(nPerfCounter1)); - AddDataToRng(&nPerfCounter2, sizeof(nPerfCounter2)); +static void SeedFast(CSHA512& hasher) noexcept +{ + unsigned char buffer[32]; + + // Stack pointer to indirectly commit to thread/callstack + const unsigned char* ptr = buffer; + 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)); - memory_cleanse(&nPerfCounter1, sizeof(nPerfCounter1)); - memory_cleanse(&nPerfCounter2, sizeof(nPerfCounter2)); + // High-precision timestamp + SeedTimestamp(hasher); } +static void SeedSlow(CSHA512& hasher) noexcept +{ + unsigned char buffer[32]; -static Mutex cs_rng_state; -static unsigned char rng_state[32] = {0}; -static uint64_t rng_counter = 0; + // Everything that the 'fast' seeder includes + SeedFast(hasher); -static void AddDataToRng(void* data, size_t len) { - CSHA512 hasher; - hasher.Write((const unsigned char*)&len, sizeof(len)); - hasher.Write((const unsigned char*)data, len); - unsigned char buf[64]; - { - WAIT_LOCK(cs_rng_state, lock); - hasher.Write(rng_state, sizeof(rng_state)); - hasher.Write((const unsigned char*)&rng_counter, sizeof(rng_counter)); - ++rng_counter; - hasher.Finalize(buf); - memcpy(rng_state, buf + 32, 32); - } - memory_cleanse(buf, 64); + // OS randomness + GetOSRand(buffer); + hasher.Write(buffer, sizeof(buffer)); + + // OpenSSL RNG (for now) + RAND_bytes(buffer, sizeof(buffer)); + hasher.Write(buffer, sizeof(buffer)); + + // High-precision timestamp. + // + // Note that we also commit to a timestamp in the Fast seeder, so we indirectly commit to a + // benchmark of all the entropy gathering sources in this function). + SeedTimestamp(hasher); } -void GetStrongRandBytes(unsigned char* out, int num) +static void SeedSleep(CSHA512& hasher) { - assert(num <= 32); - CSHA512 hasher; - unsigned char buf[64]; + // Everything that the 'fast' seeder includes + SeedFast(hasher); + + // High-precision timestamp + SeedTimestamp(hasher); - // First source: OpenSSL's RNG - RandAddSeedPerfmon(); - GetRandBytes(buf, 32); - hasher.Write(buf, 32); + // Sleep for 1ms + MilliSleep(1); - // Second source: OS RNG - GetOSRand(buf); - hasher.Write(buf, 32); + // High-precision timestamp after sleeping (as we commit to both the time before and after, this measures the delay) + SeedTimestamp(hasher); - // Third source: HW RNG, if available. - if (GetHWRand(buf)) { - hasher.Write(buf, 32); + // Windows performance monitor data (once every 10 minutes) + RandAddSeedPerfmon(hasher); +} + +static void SeedStartup(CSHA512& hasher) noexcept +{ +#ifdef WIN32 + RAND_screen(); +#endif + + // Everything that the 'slow' seeder includes. + SeedSlow(hasher); + + // Windows performance monitor data. + RandAddSeedPerfmon(hasher); +} + +enum class RNGLevel { + FAST, //!< Automatically called by GetRandBytes + SLOW, //!< Automatically called by GetStrongRandBytes + SLEEP, //!< Called by RandAddSeedSleep() +}; + +static void ProcRand(unsigned char* out, int num, RNGLevel level) +{ + // Make sure the RNG is initialized first (as all Seed* function possibly need hwrand to be available). + RNGState& rng = GetRNGState(); + + assert(num <= 32); + + CSHA512 hasher; + switch (level) { + case RNGLevel::FAST: + SeedFast(hasher); + break; + case RNGLevel::SLOW: + SeedSlow(hasher); + break; + case RNGLevel::SLEEP: + SeedSleep(hasher); + break; } // Combine with and update state - { - WAIT_LOCK(cs_rng_state, lock); - hasher.Write(rng_state, sizeof(rng_state)); - hasher.Write((const unsigned char*)&rng_counter, sizeof(rng_counter)); - ++rng_counter; - hasher.Finalize(buf); - memcpy(rng_state, buf + 32, 32); + if (!rng.MixExtract(out, num, std::move(hasher), false)) { + // On the first invocation, also seed with SeedStartup(). + CSHA512 startup_hasher; + SeedStartup(startup_hasher); + rng.MixExtract(out, num, std::move(startup_hasher), true); } - // Produce output - memcpy(out, buf, num); - memory_cleanse(buf, 64); + // For anything but the 'fast' level, feed the resulting RNG output (after an additional hashing step) back into OpenSSL. + if (level != RNGLevel::FAST) { + unsigned char buf[64]; + CSHA512().Write(out, num).Finalize(buf); + RAND_add(buf, sizeof(buf), num); + memory_cleanse(buf, 64); + } } -uint64_t GetRand(uint64_t nMax) -{ - if (nMax == 0) - return 0; +void GetRandBytes(unsigned char* buf, int num) noexcept { ProcRand(buf, num, RNGLevel::FAST); } +void GetStrongRandBytes(unsigned char* buf, int num) noexcept { ProcRand(buf, num, RNGLevel::SLOW); } +void RandAddSeedSleep() { ProcRand(nullptr, 0, RNGLevel::SLEEP); } - // The range of the random source must be a multiple of the modulus - // to give every possible output value an equal possibility - uint64_t nRange = (std::numeric_limits<uint64_t>::max() / nMax) * nMax; - uint64_t nRand = 0; - do { - GetRandBytes((unsigned char*)&nRand, sizeof(nRand)); - } while (nRand >= nRange); - return (nRand % nMax); +bool g_mock_deterministic_tests{false}; + +uint64_t GetRand(uint64_t nMax) noexcept +{ + return FastRandomContext(g_mock_deterministic_tests).randrange(nMax); } -int GetRandInt(int nMax) +int GetRandInt(int nMax) noexcept { return GetRand(nMax); } -uint256 GetRandHash() +uint256 GetRandHash() noexcept { uint256 hash; GetRandBytes((unsigned char*)&hash, sizeof(hash)); @@ -385,7 +540,7 @@ void FastRandomContext::RandomSeed() requires_seed = false; } -uint256 FastRandomContext::rand256() +uint256 FastRandomContext::rand256() noexcept { if (bytebuf_size < 32) { FillByteBuffer(); @@ -406,7 +561,7 @@ std::vector<unsigned char> FastRandomContext::randbytes(size_t len) return ret; } -FastRandomContext::FastRandomContext(const uint256& seed) : requires_seed(false), bytebuf_size(0), bitbuf_size(0) +FastRandomContext::FastRandomContext(const uint256& seed) noexcept : requires_seed(false), bytebuf_size(0), bitbuf_size(0) { rng.SetKey(seed.begin(), 32); } @@ -449,13 +604,15 @@ bool Random_SanityCheck() if (stop == start) return false; // We called GetPerformanceCounter. Use it as entropy. - RAND_add((const unsigned char*)&start, sizeof(start), 1); - RAND_add((const unsigned char*)&stop, sizeof(stop), 1); + CSHA512 to_add; + to_add.Write((const unsigned char*)&start, sizeof(start)); + to_add.Write((const unsigned char*)&stop, sizeof(stop)); + GetRNGState().MixExtract(nullptr, 0, std::move(to_add), false); return true; } -FastRandomContext::FastRandomContext(bool fDeterministic) : requires_seed(!fDeterministic), bytebuf_size(0), bitbuf_size(0) +FastRandomContext::FastRandomContext(bool fDeterministic) noexcept : requires_seed(!fDeterministic), bytebuf_size(0), bitbuf_size(0) { if (!fDeterministic) { return; @@ -480,5 +637,8 @@ FastRandomContext& FastRandomContext::operator=(FastRandomContext&& from) noexce void RandomInit() { - RDRandInit(); + // Invoke RNG code to trigger initialization (if not already performed) + ProcRand(nullptr, 0, RNGLevel::FAST); + + ReportHardwareRand(); } diff --git a/src/random.h b/src/random.h index 00e90abbc5..4c73f3822a 100644 --- a/src/random.h +++ b/src/random.h @@ -13,33 +13,83 @@ #include <stdint.h> #include <limits> -/* Seed OpenSSL PRNG with additional entropy data */ -void RandAddSeed(); +/** + * Overall design of the RNG and entropy sources. + * + * We maintain a single global 256-bit RNG state for all high-quality randomness. + * The following (classes of) functions interact with that state by mixing in new + * entropy, and optionally extracting random output from it: + * + * - The GetRand*() class of functions, as well as construction of FastRandomContext objects, + * perform 'fast' seeding, consisting of mixing in: + * - 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. + * 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 + * is even faster (and acceptable to use inside tight loops). + * + * - The GetStrongRand*() class of function perform 'slow' seeding, including everything + * that fast seeding includes, but additionally: + * - OS entropy (/dev/urandom, getrandom(), ...). The application will terminate if + * this entropy source fails. + * - Bytes from OpenSSL's RNG (which itself may be seeded from various sources) + * - Another high-precision timestamp (indirectly committing to a benchmark of all the + * previous sources). + * These entropy sources are slower, but designed to make sure the RNG state contains + * fresh data that is unpredictable to attackers. + * + * - RandAddSeedSleep() seeds everything that fast seeding includes, but additionally: + * - A high-precision timestamp before and after sleeping 1ms. + * - (On Windows) Once every 10 minutes, performance monitoring data from the OS. + * These just exploit the fact the system is idle to improve the quality of the RNG + * slightly. + * + * 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: + * - (On Windows) Performance monitoring data from the OS. + * - (On Windows) Through OpenSSL, the screen contents. + * + * When mixing in new entropy, H = SHA512(entropy || old_rng_state) is computed, and + * (up to) the first 32 bytes of H are produced as output, while the last 32 bytes + * become the new RNG state. +*/ /** - * Functions to gather random data via the OpenSSL PRNG + * Generate random data via the internal PRNG. + * + * These functions are designed to be fast (sub microsecond), but do not necessarily + * meaningfully add entropy to the PRNG state. + * + * Thread-safe. */ -void GetRandBytes(unsigned char* buf, int num); -uint64_t GetRand(uint64_t nMax); -int GetRandInt(int nMax); -uint256 GetRandHash(); +void GetRandBytes(unsigned char* buf, int num) noexcept; +uint64_t GetRand(uint64_t nMax) noexcept; +int GetRandInt(int nMax) noexcept; +uint256 GetRandHash() noexcept; /** - * Add a little bit of randomness to the output of GetStrongRangBytes. - * This sleeps for a millisecond, so should only be called when there is - * no other work to be done. + * Gather entropy from various sources, feed it into the internal PRNG, and + * generate random data using it. + * + * This function will cause failure whenever the OS RNG fails. + * + * Thread-safe. */ -void RandAddSeedSleep(); +void GetStrongRandBytes(unsigned char* buf, int num) noexcept; /** - * Function to gather random data from multiple sources, failing whenever any - * of those sources fail to provide a result. + * Sleep for 1ms, gather entropy from various sources, and feed them to the PRNG state. + * + * Thread-safe. */ -void GetStrongRandBytes(unsigned char* buf, int num); +void RandAddSeedSleep(); /** * Fast randomness source. This is seeded once with secure random data, but - * is completely deterministic and insecure after that. + * is completely deterministic and does not gather more entropy after that. + * * This class is not thread-safe. */ class FastRandomContext { @@ -71,10 +121,10 @@ private: } public: - explicit FastRandomContext(bool fDeterministic = false); + explicit FastRandomContext(bool fDeterministic = false) noexcept; /** Initialize with explicit seed (only for testing) */ - explicit FastRandomContext(const uint256& seed); + explicit FastRandomContext(const uint256& seed) noexcept; // Do not permit copying a FastRandomContext (move it, or create a new one to get reseeded). FastRandomContext(const FastRandomContext&) = delete; @@ -85,7 +135,7 @@ public: FastRandomContext& operator=(FastRandomContext&& from) noexcept; /** Generate a random 64-bit integer. */ - uint64_t rand64() + uint64_t rand64() noexcept { if (bytebuf_size < 8) FillByteBuffer(); uint64_t ret = ReadLE64(bytebuf + 64 - bytebuf_size); @@ -94,7 +144,7 @@ public: } /** Generate a random (bits)-bit integer. */ - uint64_t randbits(int bits) { + uint64_t randbits(int bits) noexcept { if (bits == 0) { return 0; } else if (bits > 32) { @@ -109,7 +159,7 @@ public: } /** Generate a random integer in the range [0..range). */ - uint64_t randrange(uint64_t range) + uint64_t randrange(uint64_t range) noexcept { --range; int bits = CountBits(range); @@ -123,19 +173,19 @@ public: std::vector<unsigned char> randbytes(size_t len); /** Generate a random 32-bit integer. */ - uint32_t rand32() { return randbits(32); } + uint32_t rand32() noexcept { return randbits(32); } /** generate a random uint256. */ - uint256 rand256(); + uint256 rand256() noexcept; /** Generate a random boolean. */ - bool randbool() { return randbits(1); } + bool randbool() noexcept { return randbits(1); } // Compatibility with the C++11 UniformRandomBitGenerator concept typedef uint64_t result_type; static constexpr uint64_t min() { return 0; } static constexpr uint64_t max() { return std::numeric_limits<uint64_t>::max(); } - inline uint64_t operator()() { return rand64(); } + inline uint64_t operator()() noexcept { return rand64(); } }; /** More efficient than using std::shuffle on a FastRandomContext. @@ -178,7 +228,12 @@ void GetOSRand(unsigned char *ent32); */ bool Random_SanityCheck(); -/** Initialize the RNG. */ +/** + * Initialize global RNG state and log any CPU features that are used. + * + * Calling this function is optional. RNG state will be initialized when first + * needed if it is not called. + */ void RandomInit(); #endif // BITCOIN_RANDOM_H diff --git a/src/rest.cpp b/src/rest.cpp index 4988e6ed26..326f7ae1d2 100644 --- a/src/rest.cpp +++ b/src/rest.cpp @@ -136,10 +136,12 @@ static bool rest_headers(HTTPRequest* req, if (!ParseHashStr(hashStr, hash)) return RESTERR(req, HTTP_BAD_REQUEST, "Invalid hash: " + hashStr); + const CBlockIndex* tip = nullptr; std::vector<const CBlockIndex *> headers; headers.reserve(count); { LOCK(cs_main); + tip = chainActive.Tip(); const CBlockIndex* pindex = LookupBlockIndex(hash); while (pindex != nullptr && chainActive.Contains(pindex)) { headers.push_back(pindex); @@ -175,11 +177,8 @@ static bool rest_headers(HTTPRequest* req, } case RetFormat::JSON: { UniValue jsonHeaders(UniValue::VARR); - { - LOCK(cs_main); - for (const CBlockIndex *pindex : headers) { - jsonHeaders.push_back(blockheaderToJSON(pindex)); - } + for (const CBlockIndex *pindex : headers) { + jsonHeaders.push_back(blockheaderToJSON(tip, pindex)); } std::string strJSON = jsonHeaders.write() + "\n"; req->WriteHeader("Content-Type", "application/json"); @@ -207,8 +206,10 @@ static bool rest_block(HTTPRequest* req, CBlock block; CBlockIndex* pblockindex = nullptr; + CBlockIndex* tip = nullptr; { LOCK(cs_main); + tip = chainActive.Tip(); pblockindex = LookupBlockIndex(hash); if (!pblockindex) { return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found"); @@ -241,11 +242,7 @@ static bool rest_block(HTTPRequest* req, } case RetFormat::JSON: { - UniValue objBlock; - { - LOCK(cs_main); - objBlock = blockToJSON(block, pblockindex, showTxDetails); - } + UniValue objBlock = blockToJSON(block, tip, pblockindex, showTxDetails); std::string strJSON = objBlock.write() + "\n"; req->WriteHeader("Content-Type", "application/json"); req->WriteReply(HTTP_OK, strJSON); @@ -355,7 +352,7 @@ static bool rest_tx(HTTPRequest* req, const std::string& strURIPart) CTransactionRef tx; uint256 hashBlock = uint256(); - if (!GetTransaction(hash, tx, Params().GetConsensus(), hashBlock, true)) + if (!GetTransaction(hash, tx, Params().GetConsensus(), hashBlock)) return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found"); switch (rf) { @@ -578,6 +575,52 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart) } } +static bool rest_blockhash_by_height(HTTPRequest* req, + const std::string& str_uri_part) +{ + if (!CheckWarmup(req)) return false; + std::string height_str; + const RetFormat rf = ParseDataFormat(height_str, str_uri_part); + + int32_t blockheight; + if (!ParseInt32(height_str, &blockheight) || blockheight < 0) { + return RESTERR(req, HTTP_BAD_REQUEST, "Invalid height: " + SanitizeString(height_str)); + } + + CBlockIndex* pblockindex = nullptr; + { + LOCK(cs_main); + if (blockheight > chainActive.Height()) { + return RESTERR(req, HTTP_NOT_FOUND, "Block height out of range"); + } + pblockindex = chainActive[blockheight]; + } + switch (rf) { + case RetFormat::BINARY: { + CDataStream ss_blockhash(SER_NETWORK, PROTOCOL_VERSION); + ss_blockhash << pblockindex->GetBlockHash(); + req->WriteHeader("Content-Type", "application/octet-stream"); + req->WriteReply(HTTP_OK, ss_blockhash.str()); + return true; + } + case RetFormat::HEX: { + req->WriteHeader("Content-Type", "text/plain"); + req->WriteReply(HTTP_OK, pblockindex->GetBlockHash().GetHex() + "\n"); + return true; + } + case RetFormat::JSON: { + req->WriteHeader("Content-Type", "application/json"); + UniValue resp = UniValue(UniValue::VOBJ); + resp.pushKV("blockhash", pblockindex->GetBlockHash().GetHex()); + req->WriteReply(HTTP_OK, resp.write() + "\n"); + return true; + } + default: { + return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: " + AvailableDataFormatsString() + ")"); + } + } +} + static const struct { const char* prefix; bool (*handler)(HTTPRequest* req, const std::string& strReq); @@ -590,6 +633,7 @@ static const struct { {"/rest/mempool/contents", rest_mempool_contents}, {"/rest/headers/", rest_headers}, {"/rest/getutxos", rest_getutxos}, + {"/rest/blockhashbyheight/", rest_blockhash_by_height}, }; void StartREST() diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index ec87f42c93..fa0b62ec48 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -59,10 +59,7 @@ static CUpdatedBlock latestblock; */ double GetDifficulty(const CBlockIndex* blockindex) { - if (blockindex == nullptr) - { - return 1.0; - } + assert(blockindex); int nShift = (blockindex->nBits >> 24) & 0xff; double dDiff = @@ -82,15 +79,22 @@ double GetDifficulty(const CBlockIndex* blockindex) return dDiff; } -UniValue blockheaderToJSON(const CBlockIndex* blockindex) +static int ComputeNextBlockAndDepth(const CBlockIndex* tip, const CBlockIndex* blockindex, const CBlockIndex*& next) +{ + next = tip->GetAncestor(blockindex->nHeight + 1); + if (next && next->pprev == blockindex) { + return tip->nHeight - blockindex->nHeight + 1; + } + next = nullptr; + return blockindex == tip ? 1 : -1; +} + +UniValue blockheaderToJSON(const CBlockIndex* tip, const CBlockIndex* blockindex) { - AssertLockHeld(cs_main); UniValue result(UniValue::VOBJ); result.pushKV("hash", blockindex->GetBlockHash().GetHex()); - int confirmations = -1; - // Only report confirmations if the block is on the main chain - if (chainActive.Contains(blockindex)) - confirmations = chainActive.Height() - blockindex->nHeight + 1; + const CBlockIndex* pnext; + int confirmations = ComputeNextBlockAndDepth(tip, blockindex, pnext); result.pushKV("confirmations", confirmations); result.pushKV("height", blockindex->nHeight); result.pushKV("version", blockindex->nVersion); @@ -106,21 +110,17 @@ UniValue blockheaderToJSON(const CBlockIndex* blockindex) if (blockindex->pprev) result.pushKV("previousblockhash", blockindex->pprev->GetBlockHash().GetHex()); - CBlockIndex *pnext = chainActive.Next(blockindex); if (pnext) result.pushKV("nextblockhash", pnext->GetBlockHash().GetHex()); return result; } -UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails) +UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIndex* blockindex, bool txDetails) { - AssertLockHeld(cs_main); UniValue result(UniValue::VOBJ); result.pushKV("hash", blockindex->GetBlockHash().GetHex()); - int confirmations = -1; - // Only report confirmations if the block is on the main chain - if (chainActive.Contains(blockindex)) - confirmations = chainActive.Height() - blockindex->nHeight + 1; + const CBlockIndex* pnext; + int confirmations = ComputeNextBlockAndDepth(tip, blockindex, pnext); result.pushKV("confirmations", confirmations); result.pushKV("strippedsize", (int)::GetSerializeSize(block, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS)); result.pushKV("size", (int)::GetSerializeSize(block, PROTOCOL_VERSION)); @@ -152,7 +152,6 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx if (blockindex->pprev) result.pushKV("previousblockhash", blockindex->pprev->GetBlockHash().GetHex()); - CBlockIndex *pnext = chainActive.Next(blockindex); if (pnext) result.pushKV("nextblockhash", pnext->GetBlockHash().GetHex()); return result; @@ -163,14 +162,16 @@ static UniValue getblockcount(const JSONRPCRequest& request) if (request.fHelp || request.params.size() != 0) throw std::runtime_error( RPCHelpMan{"getblockcount", - "\nReturns the number of blocks in the longest blockchain.\n", {}} - .ToString() + - "\nResult:\n" + "\nReturns the number of blocks in the longest blockchain.\n", + {}, + RPCResult{ "n (numeric) The current block count\n" - "\nExamples:\n" - + HelpExampleCli("getblockcount", "") + }, + RPCExamples{ + HelpExampleCli("getblockcount", "") + HelpExampleRpc("getblockcount", "") - ); + }, + }.ToString()); LOCK(cs_main); return chainActive.Height(); @@ -181,14 +182,16 @@ static UniValue getbestblockhash(const JSONRPCRequest& request) if (request.fHelp || request.params.size() != 0) throw std::runtime_error( RPCHelpMan{"getbestblockhash", - "\nReturns the hash of the best (tip) block in the longest blockchain.\n", {}} - .ToString() + - "\nResult:\n" + "\nReturns the hash of the best (tip) block in the longest blockchain.\n", + {}, + RPCResult{ "\"hex\" (string) the block hash, hex-encoded\n" - "\nExamples:\n" - + HelpExampleCli("getbestblockhash", "") + }, + RPCExamples{ + HelpExampleCli("getbestblockhash", "") + HelpExampleRpc("getbestblockhash", "") - ); + }, + }.ToString()); LOCK(cs_main); return chainActive.Tip()->GetBlockHash().GetHex(); @@ -213,17 +216,18 @@ static UniValue waitfornewblock(const JSONRPCRequest& request) "\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."}, - }} - .ToString() + - "\nResult:\n" + }, + RPCResult{ "{ (json object)\n" " \"hash\" : { (string) The blockhash\n" " \"height\" : { (int) Block height\n" "}\n" - "\nExamples:\n" - + HelpExampleCli("waitfornewblock", "1000") + }, + RPCExamples{ + HelpExampleCli("waitfornewblock", "1000") + HelpExampleRpc("waitfornewblock", "1000") - ); + }, + }.ToString()); int timeout = 0; if (!request.params[0].isNull()) timeout = request.params[0].get_int(); @@ -254,17 +258,18 @@ static UniValue waitforblock(const JSONRPCRequest& request) { {"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."}, - }} - .ToString() + - "\nResult:\n" + }, + RPCResult{ "{ (json object)\n" " \"hash\" : { (string) The blockhash\n" " \"height\" : { (int) Block height\n" "}\n" - "\nExamples:\n" - + HelpExampleCli("waitforblock", "\"0000000000079f8ef3d2c688c244eb7a4570b24c9ed7b4a8c619eb02596f8862\", 1000") + }, + RPCExamples{ + HelpExampleCli("waitforblock", "\"0000000000079f8ef3d2c688c244eb7a4570b24c9ed7b4a8c619eb02596f8862\", 1000") + HelpExampleRpc("waitforblock", "\"0000000000079f8ef3d2c688c244eb7a4570b24c9ed7b4a8c619eb02596f8862\", 1000") - ); + }, + }.ToString()); int timeout = 0; uint256 hash(ParseHashV(request.params[0], "blockhash")); @@ -299,17 +304,18 @@ static UniValue waitforblockheight(const JSONRPCRequest& request) { {"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."}, - }} - .ToString() + - "\nResult:\n" + }, + RPCResult{ "{ (json object)\n" " \"hash\" : { (string) The blockhash\n" " \"height\" : { (int) Block height\n" "}\n" - "\nExamples:\n" - + HelpExampleCli("waitforblockheight", "\"100\", 1000") + }, + RPCExamples{ + HelpExampleCli("waitforblockheight", "\"100\", 1000") + HelpExampleRpc("waitforblockheight", "\"100\", 1000") - ); + }, + }.ToString()); int timeout = 0; int height = request.params[0].get_int(); @@ -337,12 +343,14 @@ static UniValue syncwithvalidationinterfacequeue(const JSONRPCRequest& request) if (request.fHelp || request.params.size() > 0) { throw std::runtime_error( RPCHelpMan{"syncwithvalidationinterfacequeue", - "\nWaits for the validation interface queue to catch up on everything that was there when we entered this function.\n", {}} - .ToString() + - "\nExamples:\n" - + HelpExampleCli("syncwithvalidationinterfacequeue","") + "\nWaits for the validation interface queue to catch up on everything that was there when we entered this function.\n", + {}, + RPCResults{}, + RPCExamples{ + HelpExampleCli("syncwithvalidationinterfacequeue","") + HelpExampleRpc("syncwithvalidationinterfacequeue","") - ); + }, + }.ToString()); } SyncWithValidationInterfaceQueue(); return NullUniValue; @@ -353,14 +361,16 @@ static UniValue getdifficulty(const JSONRPCRequest& request) if (request.fHelp || request.params.size() != 0) throw std::runtime_error( RPCHelpMan{"getdifficulty", - "\nReturns the proof-of-work difficulty as a multiple of the minimum difficulty.\n", {}} - .ToString() + - "\nResult:\n" + "\nReturns the proof-of-work difficulty as a multiple of the minimum difficulty.\n", + {}, + RPCResult{ "n.nnn (numeric) the proof-of-work difficulty as a multiple of the minimum difficulty.\n" - "\nExamples:\n" - + HelpExampleCli("getdifficulty", "") + }, + RPCExamples{ + HelpExampleCli("getdifficulty", "") + HelpExampleRpc("getdifficulty", "") - ); + }, + }.ToString()); LOCK(cs_main); return GetDifficulty(chainActive.Tip()); @@ -492,9 +502,8 @@ static UniValue getrawmempool(const JSONRPCRequest& request) "\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"}, - }} - .ToString() + - "\nResult: (for verbose = false):\n" + }, + RPCResult{"for verbose = false", "[ (json array of string)\n" " \"transactionid\" (string) The transaction id\n" " ,...\n" @@ -505,10 +514,12 @@ static UniValue getrawmempool(const JSONRPCRequest& request) + EntryDescriptionString() + " }, ...\n" "}\n" - "\nExamples:\n" - + HelpExampleCli("getrawmempool", "true") + }, + RPCExamples{ + HelpExampleCli("getrawmempool", "true") + HelpExampleRpc("getrawmempool", "true") - ); + }, + }.ToString()); bool fVerbose = false; if (!request.params[0].isNull()) @@ -526,23 +537,27 @@ static UniValue getmempoolancestors(const JSONRPCRequest& request) { {"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"}, - }} - .ToString() + - "\nResult (for verbose = false):\n" + }, + { + RPCResult{"for verbose = false", "[ (json array of strings)\n" " \"transactionid\" (string) The transaction id of an in-mempool ancestor transaction\n" " ,...\n" "]\n" - "\nResult (for verbose = true):\n" + }, + RPCResult{"for verbose = true", "{ (json object)\n" " \"transactionid\" : { (json object)\n" + EntryDescriptionString() + " }, ...\n" "}\n" - "\nExamples:\n" - + HelpExampleCli("getmempoolancestors", "\"mytxid\"") + }, + }, + RPCExamples{ + HelpExampleCli("getmempoolancestors", "\"mytxid\"") + HelpExampleRpc("getmempoolancestors", "\"mytxid\"") - ); + }, + }.ToString()); } bool fVerbose = false; @@ -592,23 +607,27 @@ static UniValue getmempooldescendants(const JSONRPCRequest& request) { {"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"}, - }} - .ToString() + - "\nResult (for verbose = false):\n" + }, + { + RPCResult{"for verbose = false", "[ (json array of strings)\n" " \"transactionid\" (string) The transaction id of an in-mempool descendant transaction\n" " ,...\n" "]\n" - "\nResult (for verbose = true):\n" + }, + RPCResult{"for verbose = true", "{ (json object)\n" " \"transactionid\" : { (json object)\n" + EntryDescriptionString() + " }, ...\n" "}\n" - "\nExamples:\n" - + HelpExampleCli("getmempooldescendants", "\"mytxid\"") + }, + }, + RPCExamples{ + HelpExampleCli("getmempooldescendants", "\"mytxid\"") + HelpExampleRpc("getmempooldescendants", "\"mytxid\"") - ); + }, + }.ToString()); } bool fVerbose = false; @@ -657,16 +676,17 @@ static UniValue getmempoolentry(const JSONRPCRequest& request) "\nReturns mempool data for given transaction\n", { {"txid", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "The transaction id (must be in mempool)"}, - }} - .ToString() + - "\nResult:\n" + }, + RPCResult{ "{ (json object)\n" + EntryDescriptionString() + "}\n" - "\nExamples:\n" - + HelpExampleCli("getmempoolentry", "\"mytxid\"") + }, + RPCExamples{ + HelpExampleCli("getmempoolentry", "\"mytxid\"") + HelpExampleRpc("getmempoolentry", "\"mytxid\"") - ); + }, + }.ToString()); } uint256 hash = ParseHashV(request.params[0], "parameter 1"); @@ -692,14 +712,15 @@ static UniValue getblockhash(const JSONRPCRequest& request) "\nReturns hash of block in best-block-chain at height provided.\n", { {"height", RPCArg::Type::NUM, /* opt */ false, /* default_val */ "", "The height index"}, - }} - .ToString() + - "\nResult:\n" + }, + RPCResult{ "\"hash\" (string) The block hash\n" - "\nExamples:\n" - + HelpExampleCli("getblockhash", "1000") + }, + RPCExamples{ + HelpExampleCli("getblockhash", "1000") + HelpExampleRpc("getblockhash", "1000") - ); + }, + }.ToString()); LOCK(cs_main); @@ -721,9 +742,9 @@ static UniValue getblockheader(const JSONRPCRequest& request) { {"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"}, - }} - .ToString() + - "\nResult (for verbose = true):\n" + }, + { + RPCResult{"for verbose = true", "{\n" " \"hash\" : \"hash\", (string) the block hash (same as provided)\n" " \"confirmations\" : n, (numeric) The number of confirmations, or -1 if the block is not on the main chain\n" @@ -741,14 +762,16 @@ static UniValue getblockheader(const JSONRPCRequest& request) " \"previousblockhash\" : \"hash\", (string) The hash of the previous block\n" " \"nextblockhash\" : \"hash\", (string) The hash of the next block\n" "}\n" - "\nResult (for verbose=false):\n" + }, + RPCResult{"for verbose=false", "\"data\" (string) A string that is serialized, hex-encoded data for block 'hash'.\n" - "\nExamples:\n" - + HelpExampleCli("getblockheader", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"") + }, + }, + RPCExamples{ + HelpExampleCli("getblockheader", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"") + HelpExampleRpc("getblockheader", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"") - ); - - LOCK(cs_main); + }, + }.ToString()); uint256 hash(ParseHashV(request.params[0], "hash")); @@ -756,7 +779,14 @@ static UniValue getblockheader(const JSONRPCRequest& request) if (!request.params[1].isNull()) fVerbose = request.params[1].get_bool(); - const CBlockIndex* pblockindex = LookupBlockIndex(hash); + const CBlockIndex* pblockindex; + const CBlockIndex* tip; + { + LOCK(cs_main); + pblockindex = LookupBlockIndex(hash); + tip = chainActive.Tip(); + } + if (!pblockindex) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); } @@ -769,7 +799,7 @@ static UniValue getblockheader(const JSONRPCRequest& request) return strHex; } - return blockheaderToJSON(pblockindex); + return blockheaderToJSON(tip, pblockindex); } static CBlock GetBlockChecked(const CBlockIndex* pblockindex) @@ -802,11 +832,12 @@ static UniValue getblock(const JSONRPCRequest& request) { {"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"}, - }} - .ToString() + - "\nResult (for verbosity = 0):\n" + }, + { + RPCResult{"for verbosity = 0", "\"data\" (string) A string that is serialized, hex-encoded data for block 'hash'.\n" - "\nResult (for verbosity = 1):\n" + }, + RPCResult{"for verbosity = 1", "{\n" " \"hash\" : \"hash\", (string) the block hash (same as provided)\n" " \"confirmations\" : n, (numeric) The number of confirmations, or -1 if the block is not on the main chain\n" @@ -831,7 +862,8 @@ static UniValue getblock(const JSONRPCRequest& request) " \"previousblockhash\" : \"hash\", (string) The hash of the previous block\n" " \"nextblockhash\" : \"hash\" (string) The hash of the next block\n" "}\n" - "\nResult (for verbosity = 2):\n" + }, + RPCResult{"for verbosity = 2", "{\n" " ..., Same output as verbosity = 1.\n" " \"tx\" : [ (array of Objects) The transactions in the format of the getrawtransaction RPC. Different from verbosity = 1 \"tx\" result.\n" @@ -839,10 +871,13 @@ static UniValue getblock(const JSONRPCRequest& request) " ],\n" " ,... Same output as verbosity = 1.\n" "}\n" - "\nExamples:\n" - + HelpExampleCli("getblock", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"") + }, + }, + RPCExamples{ + HelpExampleCli("getblock", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"") + HelpExampleRpc("getblock", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"") - ); + }, + }.ToString()); LOCK(cs_main); @@ -871,7 +906,7 @@ static UniValue getblock(const JSONRPCRequest& request) return strHex; } - return blockToJSON(block, pblockindex, verbosity >= 2); + return blockToJSON(block, chainActive.Tip(), pblockindex, verbosity >= 2); } struct CCoinsStats @@ -953,13 +988,15 @@ static UniValue pruneblockchain(const JSONRPCRequest& request) { {"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" " to prune blocks whose block time is at least 2 hours older than the provided timestamp."}, - }} - .ToString() + - "\nResult:\n" + }, + RPCResult{ "n (numeric) Height of the last block pruned.\n" - "\nExamples:\n" - + HelpExampleCli("pruneblockchain", "1000") - + HelpExampleRpc("pruneblockchain", "1000")); + }, + RPCExamples{ + HelpExampleCli("pruneblockchain", "1000") + + HelpExampleRpc("pruneblockchain", "1000") + }, + }.ToString()); if (!fPruneMode) throw JSONRPCError(RPC_MISC_ERROR, "Cannot prune blocks because node is not in prune mode."); @@ -1003,9 +1040,8 @@ static UniValue gettxoutsetinfo(const JSONRPCRequest& request) RPCHelpMan{"gettxoutsetinfo", "\nReturns statistics about the unspent transaction output set.\n" "Note this call may take some time.\n", - {}} - .ToString() + - "\nResult:\n" + {}, + RPCResult{ "{\n" " \"height\":n, (numeric) The current block height (index)\n" " \"bestblock\": \"hex\", (string) The hash of the block at the tip of the chain\n" @@ -1016,10 +1052,12 @@ static UniValue gettxoutsetinfo(const JSONRPCRequest& request) " \"disk_size\": n, (numeric) The estimated size of the chainstate on disk\n" " \"total_amount\": x.xxx (numeric) The total amount\n" "}\n" - "\nExamples:\n" - + HelpExampleCli("gettxoutsetinfo", "") + }, + RPCExamples{ + HelpExampleCli("gettxoutsetinfo", "") + HelpExampleRpc("gettxoutsetinfo", "") - ); + }, + }.ToString()); UniValue ret(UniValue::VOBJ); @@ -1050,9 +1088,8 @@ UniValue gettxout(const JSONRPCRequest& request) {"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."}, - }} - .ToString() + - "\nResult:\n" + }, + RPCResult{ "{\n" " \"bestblock\": \"hash\", (string) The hash of the block at the tip of the chain\n" " \"confirmations\" : n, (numeric) The number of confirmations\n" @@ -1069,15 +1106,16 @@ UniValue gettxout(const JSONRPCRequest& request) " },\n" " \"coinbase\" : true|false (boolean) Coinbase or not\n" "}\n" - - "\nExamples:\n" + }, + RPCExamples{ "\nGet unspent transactions\n" + HelpExampleCli("listunspent", "") + "\nView the details\n" + HelpExampleCli("gettxout", "\"txid\" 1") + "\nAs a JSON-RPC call\n" + HelpExampleRpc("gettxout", "\"txid\", 1") - ); + }, + }.ToString()); LOCK(cs_main); @@ -1130,14 +1168,15 @@ static UniValue verifychain(const JSONRPCRequest& request) { {"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."}, - }} - .ToString() + - "\nResult:\n" + }, + RPCResult{ "true|false (boolean) Verified or not\n" - "\nExamples:\n" - + HelpExampleCli("verifychain", "") + }, + RPCExamples{ + HelpExampleCli("verifychain", "") + HelpExampleRpc("verifychain", "") - ); + }, + }.ToString()); LOCK(cs_main); @@ -1150,7 +1189,7 @@ static UniValue verifychain(const JSONRPCRequest& request) } /** Implementation of IsSuperMajority with better feedback */ -static UniValue SoftForkMajorityDesc(int version, CBlockIndex* pindex, const Consensus::Params& consensusParams) +static UniValue SoftForkMajorityDesc(int version, const CBlockIndex* pindex, const Consensus::Params& consensusParams) { UniValue rv(UniValue::VOBJ); bool activated = false; @@ -1170,7 +1209,7 @@ static UniValue SoftForkMajorityDesc(int version, CBlockIndex* pindex, const Con return rv; } -static UniValue SoftForkDesc(const std::string &name, int version, CBlockIndex* pindex, const Consensus::Params& consensusParams) +static UniValue SoftForkDesc(const std::string &name, int version, const CBlockIndex* pindex, const Consensus::Params& consensusParams) { UniValue rv(UniValue::VOBJ); rv.pushKV("id", name); @@ -1225,9 +1264,9 @@ UniValue getblockchaininfo(const JSONRPCRequest& request) if (request.fHelp || request.params.size() != 0) throw std::runtime_error( RPCHelpMan{"getblockchaininfo", - "Returns an object containing various state info regarding blockchain processing.\n", {}} - .ToString() + - "\nResult:\n" + "Returns an object containing various state info regarding blockchain processing.\n", + {}, + RPCResult{ "{\n" " \"chain\": \"xxxx\", (string) current network name as defined in BIP70 (main, test, regtest)\n" " \"blocks\": xxxxxx, (numeric) the current number of blocks processed in the server\n" @@ -1270,27 +1309,30 @@ UniValue getblockchaininfo(const JSONRPCRequest& request) " }\n" " \"warnings\" : \"...\", (string) any network and blockchain warnings.\n" "}\n" - "\nExamples:\n" - + HelpExampleCli("getblockchaininfo", "") + }, + RPCExamples{ + HelpExampleCli("getblockchaininfo", "") + HelpExampleRpc("getblockchaininfo", "") - ); + }, + }.ToString()); LOCK(cs_main); + const CBlockIndex* tip = chainActive.Tip(); UniValue obj(UniValue::VOBJ); obj.pushKV("chain", Params().NetworkIDString()); obj.pushKV("blocks", (int)chainActive.Height()); obj.pushKV("headers", pindexBestHeader ? pindexBestHeader->nHeight : -1); - obj.pushKV("bestblockhash", chainActive.Tip()->GetBlockHash().GetHex()); - obj.pushKV("difficulty", (double)GetDifficulty(chainActive.Tip())); - obj.pushKV("mediantime", (int64_t)chainActive.Tip()->GetMedianTimePast()); - obj.pushKV("verificationprogress", GuessVerificationProgress(Params().TxData(), chainActive.Tip())); + obj.pushKV("bestblockhash", tip->GetBlockHash().GetHex()); + obj.pushKV("difficulty", (double)GetDifficulty(tip)); + obj.pushKV("mediantime", (int64_t)tip->GetMedianTimePast()); + obj.pushKV("verificationprogress", GuessVerificationProgress(Params().TxData(), tip)); obj.pushKV("initialblockdownload", IsInitialBlockDownload()); - obj.pushKV("chainwork", chainActive.Tip()->nChainWork.GetHex()); + obj.pushKV("chainwork", tip->nChainWork.GetHex()); obj.pushKV("size_on_disk", CalculateCurrentUsage()); obj.pushKV("pruned", fPruneMode); if (fPruneMode) { - CBlockIndex* block = chainActive.Tip(); + const CBlockIndex* block = tip; assert(block); while (block->pprev && (block->pprev->nStatus & BLOCK_HAVE_DATA)) { block = block->pprev; @@ -1307,7 +1349,6 @@ UniValue getblockchaininfo(const JSONRPCRequest& request) } const Consensus::Params& consensusParams = Params().GetConsensus(); - CBlockIndex* tip = chainActive.Tip(); UniValue softforks(UniValue::VARR); UniValue bip9_softforks(UniValue::VOBJ); softforks.push_back(SoftForkDesc("bip34", 2, tip, consensusParams)); @@ -1345,9 +1386,8 @@ static UniValue getchaintips(const JSONRPCRequest& request) RPCHelpMan{"getchaintips", "Return information about all known tips in the block tree," " including the main chain as well as orphaned branches.\n", - {}} - .ToString() + - "\nResult:\n" + {}, + RPCResult{ "[\n" " {\n" " \"height\": xxxx, (numeric) height of the chain tip\n" @@ -1368,10 +1408,12 @@ static UniValue getchaintips(const JSONRPCRequest& request) "3. \"valid-headers\" All blocks are available for this branch, but they were never fully validated\n" "4. \"valid-fork\" This branch is not part of the active chain, but is fully validated\n" "5. \"active\" This is the tip of the active main chain, which is certainly valid\n" - "\nExamples:\n" - + HelpExampleCli("getchaintips", "") + }, + RPCExamples{ + HelpExampleCli("getchaintips", "") + HelpExampleRpc("getchaintips", "") - ); + }, + }.ToString()); LOCK(cs_main); @@ -1462,9 +1504,9 @@ static UniValue getmempoolinfo(const JSONRPCRequest& request) if (request.fHelp || request.params.size() != 0) throw std::runtime_error( RPCHelpMan{"getmempoolinfo", - "\nReturns details on the active state of the TX memory pool.\n", {}} - .ToString() + - "\nResult:\n" + "\nReturns details on the active state of the TX memory pool.\n", + {}, + RPCResult{ "{\n" " \"size\": xxxxx, (numeric) Current tx count\n" " \"bytes\": xxxxx, (numeric) Sum of all virtual transaction sizes as defined in BIP 141. Differs from actual serialized size because witness data is discounted\n" @@ -1473,10 +1515,12 @@ static UniValue getmempoolinfo(const JSONRPCRequest& request) " \"mempoolminfee\": xxxxx (numeric) Minimum fee rate in " + CURRENCY_UNIT + "/kB for tx to be accepted. Is the maximum of minrelaytxfee and minimum mempool fee\n" " \"minrelaytxfee\": xxxxx (numeric) Current minimum relay fee for transactions\n" "}\n" - "\nExamples:\n" - + HelpExampleCli("getmempoolinfo", "") + }, + RPCExamples{ + HelpExampleCli("getmempoolinfo", "") + HelpExampleRpc("getmempoolinfo", "") - ); + }, + }.ToString()); return mempoolInfoToJSON(); } @@ -1491,13 +1535,13 @@ static UniValue preciousblock(const JSONRPCRequest& request) "\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"}, - }} - .ToString() + - "\nResult:\n" - "\nExamples:\n" - + HelpExampleCli("preciousblock", "\"blockhash\"") + }, + RPCResults{}, + RPCExamples{ + HelpExampleCli("preciousblock", "\"blockhash\"") + HelpExampleRpc("preciousblock", "\"blockhash\"") - ); + }, + }.ToString()); uint256 hash(ParseHashV(request.params[0], "blockhash")); CBlockIndex* pblockindex; @@ -1528,13 +1572,13 @@ static UniValue invalidateblock(const JSONRPCRequest& request) "\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"}, - }} - .ToString() + - "\nResult:\n" - "\nExamples:\n" - + HelpExampleCli("invalidateblock", "\"blockhash\"") + }, + RPCResults{}, + RPCExamples{ + HelpExampleCli("invalidateblock", "\"blockhash\"") + HelpExampleRpc("invalidateblock", "\"blockhash\"") - ); + }, + }.ToString()); uint256 hash(ParseHashV(request.params[0], "blockhash")); CValidationState state; @@ -1565,17 +1609,17 @@ static UniValue reconsiderblock(const JSONRPCRequest& request) if (request.fHelp || request.params.size() != 1) throw std::runtime_error( RPCHelpMan{"reconsiderblock", - "\nRemoves invalidity status of a block and its descendants, reconsider them for activation.\n" + "\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"}, - }} - .ToString() + - "\nResult:\n" - "\nExamples:\n" - + HelpExampleCli("reconsiderblock", "\"blockhash\"") + }, + RPCResults{}, + RPCExamples{ + HelpExampleCli("reconsiderblock", "\"blockhash\"") + HelpExampleRpc("reconsiderblock", "\"blockhash\"") - ); + }, + }.ToString()); uint256 hash(ParseHashV(request.params[0], "blockhash")); @@ -1608,9 +1652,8 @@ static UniValue getchaintxstats(const JSONRPCRequest& request) { {"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."}, - }} - .ToString() + - "\nResult:\n" + }, + RPCResult{ "{\n" " \"time\": xxxxx, (numeric) The timestamp for the final block in the window in UNIX format.\n" " \"txcount\": xxxxx, (numeric) The total number of transactions in the chain up to that point.\n" @@ -1620,10 +1663,12 @@ static UniValue getchaintxstats(const JSONRPCRequest& request) " \"window_interval\": xxxxx, (numeric) The elapsed time in the window in seconds. Only returned if \"window_block_count\" is > 0.\n" " \"txrate\": x.xx, (numeric) The average rate of transactions per second in the window. Only returned if \"window_interval\" is > 0.\n" "}\n" - "\nExamples:\n" - + HelpExampleCli("getchaintxstats", "") + }, + RPCExamples{ + HelpExampleCli("getchaintxstats", "") + HelpExampleRpc("getchaintxstats", "2016") - ); + }, + }.ToString()); const CBlockIndex* pindex; int blockcount = 30 * 24 * 60 * 60 / Params().GetConsensus().nPowTargetSpacing; // By default: 1 month @@ -1747,9 +1792,8 @@ static UniValue getblockstats(const JSONRPCRequest& request) {"time", RPCArg::Type::STR, /* opt */ true, /* default_val */ "", "Selected statistic"}, }, "stats"}, - }} - .ToString() + - "\nResult:\n" + }, + RPCResult{ "{ (json object)\n" " \"avgfee\": xxxxx, (numeric) Average fee in the block\n" " \"avgfeerate\": xxxxx, (numeric) Average feerate (in satoshis per virtual byte)\n" @@ -1787,10 +1831,12 @@ static UniValue getblockstats(const JSONRPCRequest& request) " \"utxo_increase\": xxxxx, (numeric) The increase/decrease in the number of unspent outputs\n" " \"utxo_size_inc\": xxxxx, (numeric) The increase/decrease in size for the utxo index (not discounting op_return and similar)\n" "}\n" - "\nExamples:\n" - + HelpExampleCli("getblockstats", "1000 '[\"minfeerate\",\"avgfeerate\"]'") + }, + RPCExamples{ + HelpExampleCli("getblockstats", "1000 '[\"minfeerate\",\"avgfeerate\"]'") + HelpExampleRpc("getblockstats", "1000 '[\"minfeerate\",\"avgfeerate\"]'") - ); + }, + }.ToString()); } LOCK(cs_main); @@ -1914,7 +1960,7 @@ static UniValue getblockstats(const JSONRPCRequest& request) for (const CTxIn& in : tx->vin) { CTransactionRef tx_in; uint256 hashBlock; - if (!GetTransaction(in.prevout.hash, tx_in, Params().GetConsensus(), hashBlock, false)) { + if (!GetTransaction(in.prevout.hash, tx_in, Params().GetConsensus(), hashBlock)) { throw JSONRPCError(RPC_INTERNAL_ERROR, std::string("Unexpected internal error (tx index seems corrupt)")); } @@ -2002,12 +2048,14 @@ static UniValue savemempool(const JSONRPCRequest& request) if (request.fHelp || request.params.size() != 0) { throw std::runtime_error( RPCHelpMan{"savemempool", - "\nDumps the mempool to disk. It will fail until the previous dump is fully loaded.\n", {}} - .ToString() + - "\nExamples:\n" - + HelpExampleCli("savemempool", "") + "\nDumps the mempool to disk. It will fail until the previous dump is fully loaded.\n", + {}, + RPCResults{}, + RPCExamples{ + HelpExampleCli("savemempool", "") + HelpExampleRpc("savemempool", "") - ); + }, + }.ToString()); } if (!g_is_mempool_loaded) { @@ -2116,9 +2164,8 @@ UniValue scantxoutset(const JSONRPCRequest& request) }, }, "[scanobjects,...]"}, - }} - .ToString() + - "\nResult:\n" + }, + RPCResult{ "{\n" " \"unspents\": [\n" " {\n" @@ -2132,6 +2179,9 @@ UniValue scantxoutset(const JSONRPCRequest& request) " ,...], \n" " \"total_amount\" : x.xxx, (numeric) The total amount of all found unspent outputs in " + CURRENCY_UNIT + "\n" "]\n" + }, + RPCExamples{""}, + }.ToString() ); RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VARR}); diff --git a/src/rpc/blockchain.h b/src/rpc/blockchain.h index add335eb8a..529132d033 100644 --- a/src/rpc/blockchain.h +++ b/src/rpc/blockchain.h @@ -27,7 +27,7 @@ double GetDifficulty(const CBlockIndex* blockindex); void RPCNotifyBlockChange(bool ibd, const CBlockIndex *); /** Block description to JSON */ -UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails = false); +UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIndex* blockindex, bool txDetails = false); /** Mempool information to JSON */ UniValue mempoolInfoToJSON(); @@ -36,7 +36,7 @@ UniValue mempoolInfoToJSON(); UniValue mempoolToJSON(bool fVerbose = false); /** Block header to JSON */ -UniValue blockheaderToJSON(const CBlockIndex* blockindex); +UniValue blockheaderToJSON(const CBlockIndex* tip, const CBlockIndex* blockindex); /** Used by getblockstats to get feerates at different percentiles by weight */ void CalculatePercentilesByWeight(CAmount result[NUM_GETBLOCKSTATS_PERCENTILES], std::vector<std::pair<CAmount, int64_t>>& scores, int64_t total_weight); diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index 6f1bfb03d1..f95e22574c 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -89,8 +89,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" }, diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 2fd6f99be5..200dfa107b 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -94,14 +94,15 @@ static UniValue getnetworkhashps(const JSONRPCRequest& request) { {"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."}, - }} - .ToString() + - "\nResult:\n" + }, + RPCResult{ "x (numeric) Hashes per second estimated\n" - "\nExamples:\n" - + HelpExampleCli("getnetworkhashps", "") + }, + RPCExamples{ + HelpExampleCli("getnetworkhashps", "") + HelpExampleRpc("getnetworkhashps", "") - ); + }, + }.ToString()); LOCK(cs_main); return GetNetworkHashPS(!request.params[0].isNull() ? request.params[0].get_int() : 120, !request.params[1].isNull() ? request.params[1].get_int() : -1); @@ -165,16 +166,17 @@ static UniValue generatetoaddress(const JSONRPCRequest& request) {"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."}, - }} - .ToString() + - "\nResult:\n" + }, + RPCResult{ "[ blockhashes ] (array) hashes of blocks generated\n" - "\nExamples:\n" + }, + RPCExamples{ "\nGenerate 11 blocks to myaddress\n" + HelpExampleCli("generatetoaddress", "11 \"myaddress\"") + "If you are running the bitcoin core wallet, you can get a new address to send the newly generated bitcoin to with:\n" + HelpExampleCli("getnewaddress", "") - ); + }, + }.ToString()); int nGenerate = request.params[0].get_int(); uint64_t nMaxTries = 1000000; @@ -198,9 +200,9 @@ static UniValue getmininginfo(const JSONRPCRequest& request) if (request.fHelp || request.params.size() != 0) throw std::runtime_error( RPCHelpMan{"getmininginfo", - "\nReturns a json object containing mining-related information.", {}} - .ToString() + - "\nResult:\n" + "\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" @@ -211,10 +213,12 @@ static UniValue getmininginfo(const JSONRPCRequest& request) " \"chain\": \"xxxx\", (string) current network name as defined in BIP70 (main, test, regtest)\n" " \"warnings\": \"...\" (string) any network and blockchain warnings\n" "}\n" - "\nExamples:\n" - + HelpExampleCli("getmininginfo", "") + }, + RPCExamples{ + HelpExampleCli("getmininginfo", "") + HelpExampleRpc("getmininginfo", "") - ); + }, + }.ToString()); LOCK(cs_main); @@ -247,14 +251,15 @@ static UniValue prioritisetransaction(const JSONRPCRequest& request) " 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."}, - }} - .ToString() + - "\nResult:\n" + }, + RPCResult{ "true (boolean) Returns true\n" - "\nExamples:\n" - + HelpExampleCli("prioritisetransaction", "\"txid\" 0.0 10000") + }, + RPCExamples{ + HelpExampleCli("prioritisetransaction", "\"txid\" 0.0 10000") + HelpExampleRpc("prioritisetransaction", "\"txid\", 0.0, 10000") - ); + }, + }.ToString()); LOCK(cs_main); @@ -326,9 +331,8 @@ static UniValue getblocktemplate(const JSONRPCRequest& request) }, }, "\"template_request\""}, - }} - .ToString() + - "\nResult:\n" + }, + RPCResult{ "{\n" " \"version\" : n, (numeric) The preferred block version\n" " \"rules\" : [ \"rulename\", ... ], (array of strings) specific block rules that are to be enforced\n" @@ -372,11 +376,12 @@ static UniValue getblocktemplate(const JSONRPCRequest& request) " \"bits\" : \"xxxxxxxx\", (string) compressed target of next block\n" " \"height\" : n (numeric) The height of the next block\n" "}\n" - - "\nExamples:\n" - + HelpExampleCli("getblocktemplate", "{\"rules\": [\"segwit\"]}") + }, + RPCExamples{ + HelpExampleCli("getblocktemplate", "{\"rules\": [\"segwit\"]}") + HelpExampleRpc("getblocktemplate", "{\"rules\": [\"segwit\"]}") - ); + }, + }.ToString()); LOCK(cs_main); @@ -713,13 +718,13 @@ static UniValue submitblock(const JSONRPCRequest& request) { {"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."}, - }} - .ToString() + - "\nResult:\n" - "\nExamples:\n" - + HelpExampleCli("submitblock", "\"mydata\"") + }, + RPCResults{}, + RPCExamples{ + HelpExampleCli("submitblock", "\"mydata\"") + HelpExampleRpc("submitblock", "\"mydata\"") - ); + }, + }.ToString()); } std::shared_ptr<CBlock> blockptr = std::make_shared<CBlock>(); @@ -777,13 +782,15 @@ static UniValue submitheader(const JSONRPCRequest& request) "\nThrows when the header is invalid.\n", { {"hexdata", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "the hex-encoded block header data"}, - }} - .ToString() + - "\nResult:\n" + }, + RPCResult{ "None" - "\nExamples:\n" + - HelpExampleCli("submitheader", "\"aabbcc\"") + - HelpExampleRpc("submitheader", "\"aabbcc\"")); + }, + RPCExamples{ + HelpExampleCli("submitheader", "\"aabbcc\"") + + HelpExampleRpc("submitheader", "\"aabbcc\"") + }, + }.ToString()); } CBlockHeader h; @@ -826,9 +833,8 @@ static UniValue estimatesmartfee(const JSONRPCRequest& request) " \"UNSET\"\n" " \"ECONOMICAL\"\n" " \"CONSERVATIVE\""}, - }} - .ToString() + - "\nResult:\n" + }, + RPCResult{ "{\n" " \"feerate\" : x.x, (numeric, optional) estimate fee rate in " + CURRENCY_UNIT + "/kB\n" " \"errors\": [ str... ] (json array of strings, optional) Errors encountered during processing\n" @@ -839,9 +845,11 @@ static UniValue estimatesmartfee(const JSONRPCRequest& request) "fee estimation is able to return based on how long it has been running.\n" "An error is returned if not enough transactions and blocks\n" "have been observed to make an estimate for any number of blocks.\n" - "\nExample:\n" - + HelpExampleCli("estimatesmartfee", "6") - ); + }, + RPCExamples{ + HelpExampleCli("estimatesmartfee", "6") + }, + }.ToString()); RPCTypeCheck(request.params, {UniValue::VNUM, UniValue::VSTR}); RPCTypeCheckArgument(request.params[0], UniValue::VNUM); @@ -886,9 +894,8 @@ static UniValue estimaterawfee(const JSONRPCRequest& request) {"threshold", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "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."}, - }} - .ToString() + - "\nResult:\n" + }, + RPCResult{ "{\n" " \"short\" : { (json object, optional) estimate for short time horizon\n" " \"feerate\" : x.x, (numeric, optional) estimate fee rate in " + CURRENCY_UNIT + "/kB\n" @@ -910,9 +917,11 @@ static UniValue estimaterawfee(const JSONRPCRequest& request) "}\n" "\n" "Results are returned for any horizon which tracks blocks up to the confirmation target.\n" - "\nExample:\n" - + HelpExampleCli("estimaterawfee", "6 0.9") - ); + }, + RPCExamples{ + HelpExampleCli("estimaterawfee", "6 0.9") + }, + }.ToString()); RPCTypeCheck(request.params, {UniValue::VNUM, UniValue::VNUM}, true); RPCTypeCheckArgument(request.params[0], UniValue::VNUM); diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index 18c867bff3..8850cf066b 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -40,9 +40,8 @@ static UniValue validateaddress(const JSONRPCRequest& request) "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"}, - }} - .ToString() + - "\nResult:\n" + }, + RPCResult{ "{\n" " \"isvalid\" : true|false, (boolean) If the address is valid or not. If not, this is the only property returned.\n" " \"address\" : \"address\", (string) The bitcoin address validated\n" @@ -52,10 +51,12 @@ static UniValue validateaddress(const JSONRPCRequest& request) " \"witness_version\" : version (numeric, optional) The version number of the witness program\n" " \"witness_program\" : \"hex\" (string, optional) The hex value of the witness program\n" "}\n" - "\nExamples:\n" - + HelpExampleCli("validateaddress", "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"") + }, + RPCExamples{ + HelpExampleCli("validateaddress", "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"") + HelpExampleRpc("validateaddress", "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"") - ); + }, + }.ToString()); CTxDestination dest = DecodeDestination(request.params[0].get_str()); bool isValid = IsValidDestination(dest); @@ -91,20 +92,20 @@ static UniValue createmultisig(const JSONRPCRequest& request) {"key", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "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\"."}, - }} - .ToString() + - "\nResult:\n" + }, + RPCResult{ "{\n" " \"address\":\"multisigaddress\", (string) The value of the new multisig address.\n" " \"redeemScript\":\"script\" (string) The string value of the hex-encoded redemption script.\n" "}\n" - - "\nExamples:\n" + }, + RPCExamples{ "\nCreate a multisig address from 2 public keys\n" + HelpExampleCli("createmultisig", "2 \"[\\\"03789ed0bb717d88f7d321a368d905e7430207ebbd82bd342cf11ae157a7ace5fd\\\",\\\"03dbc6764b8884a92e871274b87583e6d5c2a58819473e17e107ef3f6aa5a61626\\\"]\"") + "\nAs a JSON-RPC call\n" + HelpExampleRpc("createmultisig", "2, \"[\\\"03789ed0bb717d88f7d321a368d905e7430207ebbd82bd342cf11ae157a7ace5fd\\\",\\\"03dbc6764b8884a92e871274b87583e6d5c2a58819473e17e107ef3f6aa5a61626\\\"]\"") - ; + }, + }.ToString(); throw std::runtime_error(msg); } @@ -151,11 +152,11 @@ static UniValue verifymessage(const JSONRPCRequest& request) {"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."}, - }} - .ToString() + - "\nResult:\n" + }, + RPCResult{ "true|false (boolean) If the signature is verified or not.\n" - "\nExamples:\n" + }, + RPCExamples{ "\nUnlock the wallet for 30 seconds\n" + HelpExampleCli("walletpassphrase", "\"mypassphrase\" 30") + "\nCreate the signature\n" @@ -164,7 +165,8 @@ static UniValue verifymessage(const JSONRPCRequest& request) + HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"signature\" \"my message\"") + "\nAs a JSON-RPC call\n" + HelpExampleRpc("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\", \"signature\", \"my message\"") - ); + }, + }.ToString()); LOCK(cs_main); @@ -208,18 +210,19 @@ static UniValue signmessagewithprivkey(const JSONRPCRequest& request) { {"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."}, - }} - .ToString() + - "\nResult:\n" + }, + RPCResult{ "\"signature\" (string) The signature of the message encoded in base 64\n" - "\nExamples:\n" + }, + RPCExamples{ "\nCreate the signature\n" + HelpExampleCli("signmessagewithprivkey", "\"privkey\" \"my message\"") + "\nVerify the signature\n" + HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"signature\" \"my message\"") + "\nAs a JSON-RPC call\n" + HelpExampleRpc("signmessagewithprivkey", "\"privkey\", \"my message\"") - ); + }, + }.ToString()); std::string strPrivkey = request.params[0].get_str(); std::string strMessage = request.params[1].get_str(); @@ -249,8 +252,10 @@ static UniValue setmocktime(const JSONRPCRequest& request) { {"timestamp", RPCArg::Type::NUM, /* opt */ false, /* default_val */ "", "Unix seconds-since-epoch timestamp\n" " Pass 0 to go back to using the system time."}, - }} - .ToString() + }, + RPCResults{}, + RPCExamples{""}, + }.ToString() ); if (!Params().MineBlocksOnDemand()) @@ -314,9 +319,9 @@ static UniValue getmemoryinfo(const JSONRPCRequest& request) {"mode", RPCArg::Type::STR, /* opt */ true, /* default_val */ "\"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+)."}, - }} - .ToString() + - "\nResult (mode \"stats\"):\n" + }, + { + RPCResult{"mode \"stats\"", "{\n" " \"locked\": { (json object) Information about locked memory manager\n" " \"used\": xxxxx, (numeric) Number of bytes used\n" @@ -327,12 +332,16 @@ static UniValue getmemoryinfo(const JSONRPCRequest& request) " \"chunks_free\": xxxxx, (numeric) Number unused chunks\n" " }\n" "}\n" - "\nResult (mode \"mallocinfo\"):\n" + }, + RPCResult{"mode \"mallocinfo\"", "\"<malloc version=\"1\">...\"\n" - "\nExamples:\n" - + HelpExampleCli("getmemoryinfo", "") + }, + }, + RPCExamples{ + HelpExampleCli("getmemoryinfo", "") + HelpExampleRpc("getmemoryinfo", "") - ); + }, + }.ToString()); std::string mode = request.params[0].isNull() ? "stats" : request.params[0].get_str(); if (mode == "stats") { @@ -357,9 +366,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) { @@ -392,27 +401,28 @@ UniValue logging(const JSONRPCRequest& request) { {"exclude_category", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "the valid logging category"}, }}, - }} - .ToString() + - "\nResult:\n" + }, + RPCResult{ "{ (json object where keys are the logging categories, and values indicates its status\n" - " \"category\": 0|1, (numeric) if being debug logged or not. 0:inactive, 1:active\n" + " \"category\": true|false, (bool) if being debug logged or not. false:inactive, true:active\n" " ...\n" "}\n" - "\nExamples:\n" - + HelpExampleCli("logging", "\"[\\\"all\\\"]\" \"[\\\"http\\\"]\"") - + HelpExampleRpc("logging", "[\"all\"], \"[libevent]\"") - ); + }, + RPCExamples{ + HelpExampleCli("logging", "\"[\\\"all\\\"]\" \"[\\\"http\\\"]\"") + + HelpExampleRpc("logging", "[\"all\"], [\"libevent\"]") + }, + }.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. @@ -421,8 +431,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."); } @@ -446,9 +456,11 @@ static UniValue echo(const JSONRPCRequest& request) "\nSimply echo back the input arguments. This command is for testing.\n" "\nThe difference between echo and echojson is that echojson has argument conversion enabled in the client-side table in " "bitcoin-cli and the GUI. There is no server-side difference.", - {}} - .ToString() + - ""); + {}, + RPCResults{}, + RPCExamples{""}, + }.ToString() + ); return request.params; } diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index 4d6b260cc7..b50038b085 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -1,9 +1,10 @@ -// 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 <rpc/server.h> +#include <banman.h> #include <chainparams.h> #include <clientversion.h> #include <core_io.h> @@ -29,14 +30,16 @@ static UniValue getconnectioncount(const JSONRPCRequest& request) if (request.fHelp || request.params.size() != 0) throw std::runtime_error( RPCHelpMan{"getconnectioncount", - "\nReturns the number of connections to other nodes.\n", {}} - .ToString() + - "\nResult:\n" + "\nReturns the number of connections to other nodes.\n", + {}, + RPCResult{ "n (numeric) The connection count\n" - "\nExamples:\n" - + HelpExampleCli("getconnectioncount", "") + }, + RPCExamples{ + HelpExampleCli("getconnectioncount", "") + HelpExampleRpc("getconnectioncount", "") - ); + }, + }.ToString()); if(!g_connman) throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); @@ -52,12 +55,13 @@ static UniValue ping(const JSONRPCRequest& request) "\nRequests that a ping be sent to all other nodes, to measure ping time.\n" "Results provided in getpeerinfo, pingtime and pingwait fields are decimal seconds.\n" "Ping command is handled in queue with all other commands, so it measures processing backlog, not just network ping.\n", - {}} - .ToString() + - "\nExamples:\n" - + HelpExampleCli("ping", "") + {}, + RPCResults{}, + RPCExamples{ + HelpExampleCli("ping", "") + HelpExampleRpc("ping", "") - ); + }, + }.ToString()); if(!g_connman) throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); @@ -74,9 +78,9 @@ static UniValue getpeerinfo(const JSONRPCRequest& request) if (request.fHelp || request.params.size() != 0) throw std::runtime_error( RPCHelpMan{"getpeerinfo", - "\nReturns data about each connected network node as a json array of objects.\n", {}} - .ToString() + - "\nResult:\n" + "\nReturns data about each connected network node as a json array of objects.\n", + {}, + RPCResult{ "[\n" " {\n" " \"id\": n, (numeric) Peer index\n" @@ -109,20 +113,26 @@ static UniValue getpeerinfo(const JSONRPCRequest& request) " \"whitelisted\": true|false, (boolean) Whether the peer is whitelisted\n" " \"minfeefilter\": n, (numeric) The minimum fee rate for transactions this peer accepts\n" " \"bytessent_per_msg\": {\n" - " \"addr\": n, (numeric) The total bytes sent aggregated by message type\n" + " \"msg\": n, (numeric) The total bytes sent aggregated by message type\n" + " When a message type is not listed in this json object, the bytes sent are 0.\n" + " Only known message types can appear as keys in the object.\n" " ...\n" " },\n" " \"bytesrecv_per_msg\": {\n" - " \"addr\": n, (numeric) The total bytes received aggregated by message type\n" + " \"msg\": n, (numeric) The total bytes received aggregated by message type\n" + " When a message type is not listed in this json object, the bytes received are 0.\n" + " Only known message types can appear as keys in the object and all bytes received of unknown message types are listed under '"+NET_MESSAGE_COMMAND_OTHER+"'.\n" " ...\n" " }\n" " }\n" " ,...\n" "]\n" - "\nExamples:\n" - + HelpExampleCli("getpeerinfo", "") + }, + RPCExamples{ + HelpExampleCli("getpeerinfo", "") + HelpExampleRpc("getpeerinfo", "") - ); + }, + }.ToString()); if(!g_connman) throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); @@ -178,14 +188,14 @@ static UniValue getpeerinfo(const JSONRPCRequest& request) obj.pushKV("minfeefilter", ValueFromAmount(stats.minFeeFilter)); UniValue sendPerMsgCmd(UniValue::VOBJ); - for (const mapMsgCmdSize::value_type &i : stats.mapSendBytesPerMsgCmd) { + for (const auto& i : stats.mapSendBytesPerMsgCmd) { if (i.second > 0) sendPerMsgCmd.pushKV(i.first, i.second); } obj.pushKV("bytessent_per_msg", sendPerMsgCmd); UniValue recvPerMsgCmd(UniValue::VOBJ); - for (const mapMsgCmdSize::value_type &i : stats.mapRecvBytesPerMsgCmd) { + for (const auto& i : stats.mapRecvBytesPerMsgCmd) { if (i.second > 0) recvPerMsgCmd.pushKV(i.first, i.second); } @@ -213,12 +223,13 @@ static UniValue addnode(const JSONRPCRequest& request) { {"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"}, - }} - .ToString() + - "\nExamples:\n" - + HelpExampleCli("addnode", "\"192.168.0.6:8333\" \"onetry\"") + }, + RPCResults{}, + RPCExamples{ + HelpExampleCli("addnode", "\"192.168.0.6:8333\" \"onetry\"") + HelpExampleRpc("addnode", "\"192.168.0.6:8333\", \"onetry\"") - ); + }, + }.ToString()); if(!g_connman) throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); @@ -257,14 +268,15 @@ static UniValue disconnectnode(const JSONRPCRequest& request) { {"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)"}, - }} - .ToString() + - "\nExamples:\n" - + HelpExampleCli("disconnectnode", "\"192.168.0.6:8333\"") + }, + RPCResults{}, + RPCExamples{ + HelpExampleCli("disconnectnode", "\"192.168.0.6:8333\"") + HelpExampleCli("disconnectnode", "\"\" 1") + HelpExampleRpc("disconnectnode", "\"192.168.0.6:8333\"") + HelpExampleRpc("disconnectnode", "\"\", 1") - ); + }, + }.ToString()); if(!g_connman) throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); @@ -300,9 +312,8 @@ static UniValue getaddednodeinfo(const JSONRPCRequest& request) "(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."}, - }} - .ToString() + - "\nResult:\n" + }, + RPCResult{ "[\n" " {\n" " \"addednode\" : \"192.168.0.201\", (string) The node IP address or name (as provided to addnode)\n" @@ -316,10 +327,12 @@ static UniValue getaddednodeinfo(const JSONRPCRequest& request) " }\n" " ,...\n" "]\n" - "\nExamples:\n" - + HelpExampleCli("getaddednodeinfo", "\"192.168.0.201\"") + }, + RPCExamples{ + HelpExampleCli("getaddednodeinfo", "\"192.168.0.201\"") + HelpExampleRpc("getaddednodeinfo", "\"192.168.0.201\"") - ); + }, + }.ToString()); if(!g_connman) throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); @@ -367,9 +380,8 @@ static UniValue getnettotals(const JSONRPCRequest& request) RPCHelpMan{"getnettotals", "\nReturns information about network traffic, including bytes in, bytes out,\n" "and current time.\n", - {}} - .ToString() + - "\nResult:\n" + {}, + RPCResult{ "{\n" " \"totalbytesrecv\": n, (numeric) Total bytes received\n" " \"totalbytessent\": n, (numeric) Total bytes sent\n" @@ -384,10 +396,12 @@ static UniValue getnettotals(const JSONRPCRequest& request) " \"time_left_in_cycle\": t (numeric) Seconds left in current time cycle\n" " }\n" "}\n" - "\nExamples:\n" - + HelpExampleCli("getnettotals", "") + }, + RPCExamples{ + HelpExampleCli("getnettotals", "") + HelpExampleRpc("getnettotals", "") - ); + }, + }.ToString()); if(!g_connman) throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); @@ -419,7 +433,7 @@ static UniValue GetNetworksInfo() UniValue obj(UniValue::VOBJ); GetProxy(network, proxy); obj.pushKV("name", GetNetworkName(network)); - obj.pushKV("limited", IsLimited(network)); + obj.pushKV("limited", !IsReachable(network)); obj.pushKV("reachable", IsReachable(network)); obj.pushKV("proxy", proxy.IsValid() ? proxy.proxy.ToStringIPPort() : std::string()); obj.pushKV("proxy_randomize_credentials", proxy.randomize_credentials); @@ -433,9 +447,9 @@ static UniValue getnetworkinfo(const JSONRPCRequest& request) if (request.fHelp || request.params.size() != 0) throw std::runtime_error( RPCHelpMan{"getnetworkinfo", - "Returns an object containing various state info regarding P2P networking.\n", {}} - .ToString() + - "\nResult:\n" + "Returns an object containing various state info regarding P2P networking.\n", + {}, + RPCResult{ "{\n" " \"version\": xxxxx, (numeric) the server version\n" " \"subversion\": \"/Satoshi:x.x.x/\", (string) the server subversion string\n" @@ -467,10 +481,12 @@ static UniValue getnetworkinfo(const JSONRPCRequest& request) " ]\n" " \"warnings\": \"...\" (string) any network and blockchain warnings\n" "}\n" - "\nExamples:\n" - + HelpExampleCli("getnetworkinfo", "") + }, + RPCExamples{ + HelpExampleCli("getnetworkinfo", "") + HelpExampleRpc("getnetworkinfo", "") - ); + }, + }.ToString()); LOCK(cs_main); UniValue obj(UniValue::VOBJ); @@ -520,15 +536,17 @@ static UniValue setban(const JSONRPCRequest& request) {"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)"}, - }} - .ToString() + - "\nExamples:\n" - + HelpExampleCli("setban", "\"192.168.0.6\" \"add\" 86400") + }, + RPCResults{}, + RPCExamples{ + HelpExampleCli("setban", "\"192.168.0.6\" \"add\" 86400") + HelpExampleCli("setban", "\"192.168.0.0/24\" \"add\"") + HelpExampleRpc("setban", "\"192.168.0.6\", \"add\", 86400") - ); - if(!g_connman) - throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); + }, + }.ToString()); + if (!g_banman) { + throw JSONRPCError(RPC_DATABASE_ERROR, "Error: Ban database not loaded"); + } CSubNet subNet; CNetAddr netAddr; @@ -550,8 +568,9 @@ static UniValue setban(const JSONRPCRequest& request) if (strCommand == "add") { - if (isSubnet ? g_connman->IsBanned(subNet) : g_connman->IsBanned(netAddr)) + if (isSubnet ? g_banman->IsBanned(subNet) : g_banman->IsBanned(netAddr)) { throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, "Error: IP/Subnet already banned"); + } int64_t banTime = 0; //use standard bantime if not specified if (!request.params[2].isNull()) @@ -561,12 +580,23 @@ static UniValue setban(const JSONRPCRequest& request) if (request.params[3].isTrue()) absolute = true; - isSubnet ? g_connman->Ban(subNet, BanReasonManuallyAdded, banTime, absolute) : g_connman->Ban(netAddr, BanReasonManuallyAdded, banTime, absolute); + if (isSubnet) { + g_banman->Ban(subNet, BanReasonManuallyAdded, banTime, absolute); + if (g_connman) { + g_connman->DisconnectNode(subNet); + } + } else { + g_banman->Ban(netAddr, BanReasonManuallyAdded, banTime, absolute); + if (g_connman) { + g_connman->DisconnectNode(netAddr); + } + } } else if(strCommand == "remove") { - if (!( isSubnet ? g_connman->Unban(subNet) : g_connman->Unban(netAddr) )) + if (!( isSubnet ? g_banman->Unban(subNet) : g_banman->Unban(netAddr) )) { throw JSONRPCError(RPC_CLIENT_INVALID_IP_OR_SUBNET, "Error: Unban failed. Requested address/subnet was not previously banned."); + } } return NullUniValue; } @@ -576,18 +606,21 @@ static UniValue listbanned(const JSONRPCRequest& request) if (request.fHelp || request.params.size() != 0) throw std::runtime_error( RPCHelpMan{"listbanned", - "\nList all banned IPs/Subnets.\n", {}} - .ToString() + - "\nExamples:\n" - + HelpExampleCli("listbanned", "") + "\nList all banned IPs/Subnets.\n", + {}, + RPCResults{}, + RPCExamples{ + HelpExampleCli("listbanned", "") + HelpExampleRpc("listbanned", "") - ); + }, + }.ToString()); - if(!g_connman) - throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); + if(!g_banman) { + throw JSONRPCError(RPC_DATABASE_ERROR, "Error: Ban database not loaded"); + } banmap_t banMap; - g_connman->GetBanned(banMap); + g_banman->GetBanned(banMap); UniValue bannedAddresses(UniValue::VARR); for (const auto& entry : banMap) @@ -610,16 +643,19 @@ static UniValue clearbanned(const JSONRPCRequest& request) if (request.fHelp || request.params.size() != 0) throw std::runtime_error( RPCHelpMan{"clearbanned", - "\nClear all banned IPs.\n", {}} - .ToString() + - "\nExamples:\n" - + HelpExampleCli("clearbanned", "") + "\nClear all banned IPs.\n", + {}, + RPCResults{}, + RPCExamples{ + HelpExampleCli("clearbanned", "") + HelpExampleRpc("clearbanned", "") - ); - if(!g_connman) - throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); + }, + }.ToString()); + if (!g_banman) { + throw JSONRPCError(RPC_DATABASE_ERROR, "Error: Ban database not loaded"); + } - g_connman->ClearBanned(); + g_banman->ClearBanned(); return NullUniValue; } @@ -632,8 +668,10 @@ static UniValue setnetworkactive(const JSONRPCRequest& request) "\nDisable/enable all p2p network activity.\n", { {"state", RPCArg::Type::BOOL, /* opt */ false, /* default_val */ "", "true to enable networking, false to disable"}, - }} - .ToString() + }, + RPCResults{}, + RPCExamples{""}, + }.ToString() ); } @@ -654,9 +692,8 @@ static UniValue getnodeaddresses(const JSONRPCRequest& request) "\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."}, - }} - .ToString() + - "\nResult:\n" + }, + RPCResult{ "[\n" " {\n" " \"time\": ttt, (numeric) Timestamp in seconds since epoch (Jan 1 1970 GMT) keeping track of when the node was last seen\n" @@ -666,10 +703,12 @@ static UniValue getnodeaddresses(const JSONRPCRequest& request) " }\n" " ,....\n" "]\n" - "\nExamples:\n" - + HelpExampleCli("getnodeaddresses", "8") + }, + RPCExamples{ + HelpExampleCli("getnodeaddresses", "8") + HelpExampleRpc("getnodeaddresses", "8") - ); + }, + }.ToString()); } if (!g_connman) { throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index bf00870107..b3b9d8af09 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.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. @@ -66,28 +66,31 @@ static UniValue getrawtransaction(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() < 1 || request.params.size() > 3) throw std::runtime_error( - RPCHelpMan{"getrawtransaction", - "\nNOTE: By default this function only works for mempool transactions. If the -txindex option is\n" - "enabled, it also works for blockchain transactions. If the block which contains the transaction\n" - "is known, its hash can be provided even for nodes without -txindex. Note that if a blockhash is\n" - "provided, only that block will be searched and if the transaction is in the mempool or other\n" - "blocks, or if this node does not have the given block available, the transaction will not be found.\n" - "DEPRECATED: for now, it also works for transactions with unspent outputs.\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" - , + RPCHelpMan{ + "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" + + "\nHint: use getmempoolentry to fetch a specific transaction from the mempool.\n" + "Or 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"}, - }} - .ToString() + - "\nResult (if verbose is not set or set to false):\n" + }, + { + RPCResult{"if verbose is not set or set to false", "\"data\" (string) The serialized, hex-encoded data for 'txid'\n" - - "\nResult (if verbose is set to true):\n" + }, + RPCResult{"if verbose is set to true", "{\n" " \"in_active_chain\": b, (bool) Whether specified block is in the active chain or not (only present with explicit \"blockhash\" argument)\n" " \"hex\" : \"data\", (string) The serialized, hex-encoded data for 'txid'\n" @@ -133,14 +136,16 @@ static UniValue getrawtransaction(const JSONRPCRequest& request) " \"blocktime\" : ttt (numeric) The block time in seconds since epoch (Jan 1 1970 GMT)\n" " \"time\" : ttt, (numeric) Same as \"blocktime\"\n" "}\n" - - "\nExamples:\n" - + HelpExampleCli("getrawtransaction", "\"mytxid\"") + }, + }, + RPCExamples{ + HelpExampleCli("getrawtransaction", "\"mytxid\"") + HelpExampleCli("getrawtransaction", "\"mytxid\" true") + HelpExampleRpc("getrawtransaction", "\"mytxid\", true") + HelpExampleCli("getrawtransaction", "\"mytxid\" false \"myblockhash\"") + HelpExampleCli("getrawtransaction", "\"mytxid\" true \"myblockhash\"") - ); + }, + }.ToString()); bool in_active_chain = true; uint256 hash = ParseHashV(request.params[0], "parameter 1"); @@ -175,7 +180,7 @@ static UniValue getrawtransaction(const JSONRPCRequest& request) CTransactionRef tx; uint256 hash_block; - if (!GetTransaction(hash, tx, Params().GetConsensus(), hash_block, true, blockindex)) { + if (!GetTransaction(hash, tx, Params().GetConsensus(), hash_block, blockindex)) { std::string errmsg; if (blockindex) { if (!(blockindex->nStatus & BLOCK_HAVE_DATA)) { @@ -219,10 +224,12 @@ static UniValue gettxoutproof(const JSONRPCRequest& request) }, }, {"blockhash", RPCArg::Type::STR_HEX, /* opt */ true, /* default_val */ "null", "If specified, looks for txid in the block with this hash"}, - }} - .ToString() + - "\nResult:\n" + }, + RPCResult{ "\"data\" (string) A string that is a serialized, hex-encoded data for the proof.\n" + }, + RPCExamples{""}, + }.ToString() ); std::set<uint256> setTxids; @@ -270,7 +277,7 @@ static UniValue gettxoutproof(const JSONRPCRequest& request) if (pblockindex == nullptr) { CTransactionRef tx; - if (!GetTransaction(oneTxid, tx, Params().GetConsensus(), hashBlock, false) || hashBlock.IsNull()) + if (!GetTransaction(oneTxid, tx, Params().GetConsensus(), hashBlock) || hashBlock.IsNull()) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not yet in block"); pblockindex = LookupBlockIndex(hashBlock); if (!pblockindex) { @@ -305,10 +312,12 @@ static UniValue verifytxoutproof(const JSONRPCRequest& request) "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"}, - }} - .ToString() + - "\nResult:\n" + }, + RPCResult{ "[\"txid\"] (array, strings) The txid(s) which the proof commits to, or empty array if the proof can not be validated.\n" + }, + RPCExamples{""}, + }.ToString() ); CDataStream ssMB(ParseHexV(request.params[0], "proof"), SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS); @@ -445,7 +454,7 @@ CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniVal } } - if (!rbf.isNull() && rawTx.vin.size() > 0 && rbfOptIn != SignalsOptInRBF(rawTx)) { + if (!rbf.isNull() && rawTx.vin.size() > 0 && rbfOptIn != SignalsOptInRBF(CTransaction(rawTx))) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter combination: Sequence number(s) contradict replaceable option"); } @@ -494,17 +503,17 @@ static UniValue createrawtransaction(const JSONRPCRequest& request) {"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" " Allows this transaction to be replaced by a transaction with higher fees. If provided, it is an error if explicit sequence numbers are incompatible."}, - }} - .ToString() + - "\nResult:\n" + }, + RPCResult{ "\"transaction\" (string) hex string of the transaction\n" - - "\nExamples:\n" - + HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"[{\\\"address\\\":0.01}]\"") + }, + RPCExamples{ + HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"[{\\\"address\\\":0.01}]\"") + HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"[{\\\"data\\\":\\\"00010203\\\"}]\"") + HelpExampleRpc("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\", \"[{\\\"address\\\":0.01}]\"") + HelpExampleRpc("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\", \"[{\\\"data\\\":\\\"00010203\\\"}]\"") - ); + }, + }.ToString()); } RPCTypeCheck(request.params, { @@ -517,7 +526,7 @@ static UniValue createrawtransaction(const JSONRPCRequest& request) CMutableTransaction rawTx = ConstructTransaction(request.params[0], request.params[1], request.params[2], request.params[3]); - return EncodeHexTx(rawTx); + return EncodeHexTx(CTransaction(rawTx)); } static UniValue decoderawtransaction(const JSONRPCRequest& request) @@ -530,9 +539,8 @@ static UniValue decoderawtransaction(const JSONRPCRequest& request) {"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" " If iswitness is not present, heuristic tests will be used in decoding"}, - }} - .ToString() + - "\nResult:\n" + }, + RPCResult{ "{\n" " \"txid\" : \"id\", (string) The transaction id\n" " \"hash\" : \"id\", (string) The transaction hash (differs from txid for witness transactions)\n" @@ -572,11 +580,12 @@ static UniValue decoderawtransaction(const JSONRPCRequest& request) " ,...\n" " ],\n" "}\n" - - "\nExamples:\n" - + HelpExampleCli("decoderawtransaction", "\"hexstring\"") + }, + RPCExamples{ + HelpExampleCli("decoderawtransaction", "\"hexstring\"") + HelpExampleRpc("decoderawtransaction", "\"hexstring\"") - ); + }, + }.ToString()); RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL}); @@ -603,9 +612,8 @@ static UniValue decodescript(const JSONRPCRequest& request) "\nDecode a hex-encoded script.\n", { {"hexstring", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "the hex-encoded script"}, - }} - .ToString() + - "\nResult:\n" + }, + RPCResult{ "{\n" " \"asm\":\"asm\", (string) Script public key\n" " \"hex\":\"hex\", (string) hex-encoded public key\n" @@ -617,10 +625,12 @@ static UniValue decodescript(const JSONRPCRequest& request) " ],\n" " \"p2sh\",\"address\" (string) address of P2SH script wrapping this redeem script (not returned if the script is already a P2SH).\n" "}\n" - "\nExamples:\n" - + HelpExampleCli("decodescript", "\"hexstring\"") + }, + RPCExamples{ + HelpExampleCli("decodescript", "\"hexstring\"") + HelpExampleRpc("decodescript", "\"hexstring\"") - ); + }, + }.ToString()); RPCTypeCheck(request.params, {UniValue::VSTR}); @@ -706,14 +716,14 @@ static UniValue combinerawtransaction(const JSONRPCRequest& request) {"hexstring", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "A transaction hash"}, }, }, - }} - .ToString() + - "\nResult:\n" + }, + RPCResult{ "\"hex\" (string) The hex-encoded raw transaction with signature(s)\n" - - "\nExamples:\n" - + HelpExampleCli("combinerawtransaction", "[\"myhex1\", \"myhex2\", \"myhex3\"]") - ); + }, + RPCExamples{ + HelpExampleCli("combinerawtransaction", "[\"myhex1\", \"myhex2\", \"myhex3\"]") + }, + }.ToString()); UniValue txs = request.params[0].get_array(); @@ -773,7 +783,7 @@ static UniValue combinerawtransaction(const JSONRPCRequest& request) UpdateInput(txin, sigdata); } - return EncodeHexTx(mergedTx); + return EncodeHexTx(CTransaction(mergedTx)); } UniValue SignTransaction(interfaces::Chain& chain, CMutableTransaction& mtx, const UniValue& prevTxsUnival, CBasicKeyStore *keystore, bool is_temp_keystore, const UniValue& hashType) @@ -906,7 +916,7 @@ UniValue SignTransaction(interfaces::Chain& chain, CMutableTransaction& mtx, con bool fComplete = vErrors.empty(); UniValue result(UniValue::VOBJ); - result.pushKV("hex", EncodeHexTx(mtx)); + result.pushKV("hex", EncodeHexTx(CTransaction(mtx))); result.pushKV("complete", fComplete); if (!vErrors.empty()) { result.pushKV("errors", vErrors); @@ -953,9 +963,8 @@ static UniValue signrawtransactionwithkey(const JSONRPCRequest& request) " \"NONE|ANYONECANPAY\"\n" " \"SINGLE|ANYONECANPAY\"\n" }, - }} - .ToString() + - "\nResult:\n" + }, + RPCResult{ "{\n" " \"hex\" : \"value\", (string) The hex-encoded raw transaction with signature(s)\n" " \"complete\" : true|false, (boolean) If the transaction has a complete set of signatures\n" @@ -970,11 +979,12 @@ static UniValue signrawtransactionwithkey(const JSONRPCRequest& request) " ,...\n" " ]\n" "}\n" - - "\nExamples:\n" - + HelpExampleCli("signrawtransactionwithkey", "\"myhex\"") + }, + RPCExamples{ + HelpExampleCli("signrawtransactionwithkey", "\"myhex\"") + HelpExampleRpc("signrawtransactionwithkey", "\"myhex\"") - ); + }, + }.ToString()); RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VARR, UniValue::VARR, UniValue::VSTR}, true); @@ -1015,11 +1025,11 @@ static UniValue sendrawtransaction(const JSONRPCRequest& request) { {"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"}, - }} - .ToString() + - "\nResult:\n" + }, + RPCResult{ "\"hex\" (string) The transaction hash in hex\n" - "\nExamples:\n" + }, + RPCExamples{ "\nCreate a transaction\n" + HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\" : \\\"mytxid\\\",\\\"vout\\\":0}]\" \"{\\\"myaddress\\\":0.01}\"") + "Sign the transaction, and get back the hex\n" @@ -1028,7 +1038,8 @@ static UniValue sendrawtransaction(const JSONRPCRequest& request) + HelpExampleCli("sendrawtransaction", "\"signedhex\"") + "\nAs a JSON-RPC call\n" + HelpExampleRpc("sendrawtransaction", "\"signedhex\"") - ); + }, + }.ToString()); std::promise<void> promise; @@ -1118,9 +1129,8 @@ static UniValue testmempoolaccept(const JSONRPCRequest& request) }, }, {"allowhighfees", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "Allow high fees"}, - }} - .ToString() + - "\nResult:\n" + }, + RPCResult{ "[ (array) The result of the mempool acceptance test for each raw transaction in the input array.\n" " Length is exactly one for now.\n" " {\n" @@ -1129,7 +1139,8 @@ static UniValue testmempoolaccept(const JSONRPCRequest& request) " \"reject-reason\" (string) Rejection string (only present when 'allowed' is false)\n" " }\n" "]\n" - "\nExamples:\n" + }, + RPCExamples{ "\nCreate a transaction\n" + HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\" : \\\"mytxid\\\",\\\"vout\\\":0}]\" \"{\\\"myaddress\\\":0.01}\"") + "Sign the transaction, and get back the hex\n" @@ -1138,7 +1149,8 @@ static UniValue testmempoolaccept(const JSONRPCRequest& request) + HelpExampleCli("testmempoolaccept", "[\"signedhex\"]") + "\nAs a JSON-RPC call\n" + HelpExampleRpc("testmempoolaccept", "[\"signedhex\"]") - ); + }, + }.ToString()); } RPCTypeCheck(request.params, {UniValue::VARR, UniValue::VBOOL}); @@ -1212,9 +1224,8 @@ UniValue decodepsbt(const JSONRPCRequest& request) "\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"}, - }} - .ToString() + - "\nResult:\n" + }, + RPCResult{ "{\n" " \"tx\" : { (json object) The decoded network-serialized unsigned transaction.\n" " ... The layout is the same as the output of decoderawtransaction.\n" @@ -1301,10 +1312,11 @@ UniValue decodepsbt(const JSONRPCRequest& request) " ]\n" " \"fee\" : fee (numeric, optional) The transaction fee paid if all UTXOs slots in the PSBT have been filled.\n" "}\n" - - "\nExamples:\n" - + HelpExampleCli("decodepsbt", "\"psbt\"") - ); + }, + RPCExamples{ + HelpExampleCli("decodepsbt", "\"psbt\"") + }, + }.ToString()); RPCTypeCheck(request.params, {UniValue::VSTR}); @@ -1492,13 +1504,14 @@ UniValue combinepsbt(const JSONRPCRequest& request) {"psbt", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "A base64 string of a PSBT"}, }, }, - }} - .ToString() + - "\nResult:\n" + }, + RPCResult{ " \"psbt\" (string) The base64-encoded partially signed transaction\n" - "\nExamples:\n" - + HelpExampleCli("combinepsbt", "[\"mybase64_1\", \"mybase64_2\", \"mybase64_3\"]") - ); + }, + RPCExamples{ + HelpExampleCli("combinepsbt", "[\"mybase64_1\", \"mybase64_2\", \"mybase64_3\"]") + }, + }.ToString()); RPCTypeCheck(request.params, {UniValue::VARR}, true); @@ -1546,19 +1559,19 @@ UniValue finalizepsbt(const JSONRPCRequest& request) {"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" " extract and return the complete transaction in normal network serialization instead of the PSBT."}, - }} - .ToString() + - "\nResult:\n" + }, + RPCResult{ "{\n" " \"psbt\" : \"value\", (string) The base64-encoded partially signed transaction if not extracted\n" " \"hex\" : \"value\", (string) The hex-encoded network transaction if extracted\n" " \"complete\" : true|false, (boolean) If the transaction has a complete set of signatures\n" " ]\n" "}\n" - - "\nExamples:\n" - + HelpExampleCli("finalizepsbt", "\"psbt\"") - ); + }, + RPCExamples{ + HelpExampleCli("finalizepsbt", "\"psbt\"") + }, + }.ToString()); RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL}, true); @@ -1637,13 +1650,14 @@ UniValue createpsbt(const JSONRPCRequest& request) {"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" " Allows this transaction to be replaced by a transaction with higher fees. If provided, it is an error if explicit sequence numbers are incompatible."}, - }} - .ToString() + - "\nResult:\n" + }, + RPCResult{ " \"psbt\" (string) The resulting raw transaction (base64-encoded string)\n" - "\nExamples:\n" - + HelpExampleCli("createpsbt", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"[{\\\"data\\\":\\\"00010203\\\"}]\"") - ); + }, + RPCExamples{ + HelpExampleCli("createpsbt", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"[{\\\"data\\\":\\\"00010203\\\"}]\"") + }, + }.ToString()); RPCTypeCheck(request.params, { @@ -1688,16 +1702,17 @@ UniValue converttopsbt(const JSONRPCRequest& request) " 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."}, - }} - .ToString() + - "\nResult:\n" + }, + RPCResult{ " \"psbt\" (string) The resulting raw transaction (base64-encoded string)\n" - "\nExamples:\n" + }, + RPCExamples{ "\nCreate a transaction\n" + HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"[{\\\"data\\\":\\\"00010203\\\"}]\"") + "\nConvert the transaction to a PSBT\n" + HelpExampleCli("converttopsbt", "\"rawtransaction\"") - ); + }, + }.ToString()); RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL, UniValue::VBOOL}, true); diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index e7e047334e..2ed74547b9 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.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. @@ -31,11 +31,39 @@ static RPCTimerInterface* timerInterface = nullptr; /* Map of name to timer. */ static std::map<std::string, std::unique_ptr<RPCTimerBase> > deadlineTimers; +struct RPCCommandExecutionInfo +{ + std::string method; + int64_t start; +}; + +struct RPCServerInfo +{ + Mutex mutex; + std::list<RPCCommandExecutionInfo> active_commands GUARDED_BY(mutex); +}; + +static RPCServerInfo g_rpc_server_info; + +struct RPCCommandExecution +{ + std::list<RPCCommandExecutionInfo>::iterator it; + explicit RPCCommandExecution(const std::string& method) + { + LOCK(g_rpc_server_info.mutex); + it = g_rpc_server_info.active_commands.insert(g_rpc_server_info.active_commands.end(), {method, GetTimeMicros()}); + } + ~RPCCommandExecution() + { + LOCK(g_rpc_server_info.mutex); + g_rpc_server_info.active_commands.erase(it); + } +}; + static struct CRPCSignals { boost::signals2::signal<void ()> Started; boost::signals2::signal<void ()> Stopped; - boost::signals2::signal<void (const CRPCCommand&)> PreCommand; } g_rpcSignals; void RPCServer::OnStarted(std::function<void ()> slot) @@ -203,10 +231,12 @@ UniValue help(const JSONRPCRequest& jsonRequest) "\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"}, - }} - .ToString() + - "\nResult:\n" + }, + RPCResult{ "\"text\" (string) The help text\n" + }, + RPCExamples{""}, + }.ToString() ); std::string strCommand; @@ -226,8 +256,11 @@ UniValue stop(const JSONRPCRequest& jsonRequest) if (jsonRequest.fHelp || jsonRequest.params.size() > 1) throw std::runtime_error( RPCHelpMan{"stop", - "\nStop Bitcoin server.", {}} - .ToString()); + "\nStop Bitcoin server.", + {}, + RPCResults{}, + RPCExamples{""}, + }.ToString()); // Event loop will exit after current HTTP requests have been handled, so // this reply will get back to the client. StartShutdown(); @@ -242,23 +275,54 @@ static UniValue uptime(const JSONRPCRequest& jsonRequest) if (jsonRequest.fHelp || jsonRequest.params.size() > 0) throw std::runtime_error( RPCHelpMan{"uptime", - "\nReturns the total uptime of the server.\n", {}} - .ToString() + - "\nResult:\n" + "\nReturns the total uptime of the server.\n", + {}, + RPCResult{ "ttt (numeric) The number of seconds that the server has been running\n" - "\nExamples:\n" - + HelpExampleCli("uptime", "") + }, + RPCExamples{ + HelpExampleCli("uptime", "") + HelpExampleRpc("uptime", "") - ); + }, + }.ToString()); return GetTime() - GetStartupTime(); } +static UniValue getrpcinfo(const JSONRPCRequest& request) +{ + if (request.fHelp || request.params.size() > 0) { + throw std::runtime_error( + RPCHelpMan{"getrpcinfo", + "\nReturns details of the RPC server.\n", + {}, + RPCResults{}, + RPCExamples{""}, + }.ToString() + ); + } + + LOCK(g_rpc_server_info.mutex); + UniValue active_commands(UniValue::VARR); + for (const RPCCommandExecutionInfo& info : g_rpc_server_info.active_commands) { + UniValue entry(UniValue::VOBJ); + entry.pushKV("method", info.method); + entry.pushKV("duration", GetTimeMicros() - info.start); + active_commands.push_back(entry); + } + + UniValue result(UniValue::VOBJ); + result.pushKV("active_commands", active_commands); + + return result; +} + // clang-format off static const CRPCCommand vRPCCommands[] = { // category name actor (function) argNames // --------------------- ------------------------ ----------------------- ---------- /* Overall control/query calls */ + { "control", "getrpcinfo", &getrpcinfo, {} }, { "control", "help", &help, {"command"} }, { "control", "stop", &stop, {"wait"} }, { "control", "uptime", &uptime, {} }, @@ -483,10 +547,9 @@ UniValue CRPCTable::execute(const JSONRPCRequest &request) const if (!pcmd) throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found"); - g_rpcSignals.PreCommand(*pcmd); - try { + RPCCommandExecution execution(request.strMethod); // Execute, convert arguments to array if necessary if (request.params.isObject()) { return pcmd->actor(transformNamedArguments(request, pcmd->argNames)); diff --git a/src/rpc/util.cpp b/src/rpc/util.cpp index b91baee4ac..4275cc09a8 100644 --- a/src/rpc/util.cpp +++ b/src/rpc/util.cpp @@ -242,8 +242,12 @@ struct Sections { } }; -RPCHelpMan::RPCHelpMan(const std::string& name, const std::string& description, const std::vector<RPCArg>& args) - : m_name{name}, m_description{description}, m_args{args} +RPCHelpMan::RPCHelpMan(std::string name, std::string description, std::vector<RPCArg> args, RPCResults results, RPCExamples examples) + : m_name{std::move(name)}, + m_description{std::move(description)}, + m_args{std::move(args)}, + m_results{std::move(results)}, + m_examples{std::move(examples)} { std::set<std::string> named_args; for (const auto& arg : m_args) { @@ -252,6 +256,25 @@ RPCHelpMan::RPCHelpMan(const std::string& name, const std::string& description, } } +std::string RPCResults::ToDescriptionString() const +{ + std::string result; + for (const auto& r : m_results) { + if (r.m_cond.empty()) { + result += "\nResult:\n"; + } else { + result += "\nResult (" + r.m_cond + "):\n"; + } + result += r.m_result; + } + return result; +} + +std::string RPCExamples::ToDescriptionString() const +{ + return m_examples.empty() ? m_examples : "\nExamples:\n" + m_examples; +} + std::string RPCHelpMan::ToString() const { std::string ret; @@ -292,6 +315,12 @@ std::string RPCHelpMan::ToString() const } ret += sections.ToString(); + // Result + ret += m_results.ToDescriptionString(); + + // Examples + ret += m_examples.ToDescriptionString(); + return ret; } diff --git a/src/rpc/util.h b/src/rpc/util.h index 9e97b3ae0b..4a9d4be787 100644 --- a/src/rpc/util.h +++ b/src/rpc/util.h @@ -106,10 +106,62 @@ struct RPCArg { std::string ToDescriptionString(bool implicitly_required = false) const; }; +struct RPCResult { + const std::string m_cond; + const std::string m_result; + + explicit RPCResult(std::string result) + : m_cond{}, m_result{std::move(result)} + { + assert(!m_result.empty()); + } + + RPCResult(std::string cond, std::string result) + : m_cond{std::move(cond)}, m_result{std::move(result)} + { + assert(!m_cond.empty()); + assert(!m_result.empty()); + } +}; + +struct RPCResults { + const std::vector<RPCResult> m_results; + + RPCResults() + : m_results{} + { + } + + RPCResults(RPCResult result) + : m_results{{result}} + { + } + + RPCResults(std::initializer_list<RPCResult> results) + : m_results{results} + { + } + + /** + * Return the description string. + */ + std::string ToDescriptionString() const; +}; + +struct RPCExamples { + const std::string m_examples; + RPCExamples( + std::string examples) + : m_examples(std::move(examples)) + { + } + std::string ToDescriptionString() const; +}; + class RPCHelpMan { public: - RPCHelpMan(const std::string& name, const std::string& description, const std::vector<RPCArg>& args); + RPCHelpMan(std::string name, std::string description, std::vector<RPCArg> args, RPCResults results, RPCExamples examples); std::string ToString() const; @@ -117,6 +169,8 @@ private: const std::string m_name; const std::string m_description; const std::vector<RPCArg> m_args; + const RPCResults m_results; + const RPCExamples m_examples; }; #endif // BITCOIN_RPC_UTIL_H diff --git a/src/scheduler.cpp b/src/scheduler.cpp index b2da62fc75..fdc859b3a0 100644 --- a/src/scheduler.cpp +++ b/src/scheduler.cpp @@ -41,7 +41,7 @@ void CScheduler::serviceQueue() try { if (!shouldStop() && taskQueue.empty()) { reverse_lock<boost::unique_lock<boost::mutex> > rlock(lock); - // Use this chance to get a tiny bit more entropy + // Use this chance to get more entropy RandAddSeedSleep(); } while (!shouldStop() && taskQueue.empty()) { diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp index a702be5b78..41e0f2e117 100644 --- a/src/script/descriptor.cpp +++ b/src/script/descriptor.cpp @@ -226,7 +226,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; @@ -322,7 +322,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 +395,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 +409,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 +427,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()) { diff --git a/src/script/sign.cpp b/src/script/sign.cpp index 635e4fa3d2..792fb2997f 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -509,7 +509,7 @@ bool IsSolvable(const SigningProvider& provider, const CScript& script) return false; } -PartiallySignedTransaction::PartiallySignedTransaction(const CTransaction& tx) : tx(tx) +PartiallySignedTransaction::PartiallySignedTransaction(const CMutableTransaction& tx) : tx(tx) { inputs.resize(tx.vin.size()); outputs.resize(tx.vout.size()); diff --git a/src/script/sign.h b/src/script/sign.h index 20c7203b26..e884f4c480 100644 --- a/src/script/sign.h +++ b/src/script/sign.h @@ -574,7 +574,7 @@ struct PartiallySignedTransaction 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 CTransaction& tx); + explicit PartiallySignedTransaction(const CMutableTransaction& tx); // Only checks if they refer to the same transaction friend bool operator==(const PartiallySignedTransaction& a, const PartiallySignedTransaction &b) diff --git a/src/streams.h b/src/streams.h index d5565fe61f..4e600f1826 100644 --- a/src/streams.h +++ b/src/streams.h @@ -64,12 +64,6 @@ public: size_t size() const { return stream->size(); } }; -template<typename S> -OverrideStream<S> WithOrVersion(S* s, int nVersionFlag) -{ - return OverrideStream<S>(s, s->GetType(), s->GetVersion() | nVersionFlag); -} - /* Minimal stream for overwriting and/or appending to an existing byte vector * * The referenced vector will grow as necessary @@ -126,12 +120,6 @@ class CVectorWriter { return nType; } - void seek(size_t nSize) - { - nPos += nSize; - if(nPos > vchData.size()) - vchData.resize(nPos); - } private: const int nType; const int nVersion; @@ -151,19 +139,21 @@ private: public: - /* + /** * @param[in] type Serialization Type * @param[in] version Serialization Version (including any flags) * @param[in] data Referenced byte vector to overwrite/append * @param[in] pos Starting position. Vector index where reads should start. */ VectorReader(int type, int version, const std::vector<unsigned char>& data, size_t pos) - : m_type(type), m_version(version), m_data(data) + : m_type(type), m_version(version), m_data(data), m_pos(pos) { - seek(pos); + if (m_pos > m_data.size()) { + throw std::ios_base::failure("VectorReader(...): end of data (m_pos > m_data.size())"); + } } - /* + /** * (other params same as above) * @param[in] args A list of items to deserialize starting at pos. */ @@ -203,14 +193,6 @@ public: memcpy(dst, m_data.data() + m_pos, n); m_pos = pos_next; } - - void seek(size_t n) - { - m_pos += n; - if (m_pos > m_data.size()) { - throw std::ios_base::failure("VectorReader::seek(): end of data"); - } - } }; /** Double ended buffer combining vector and stream-like interfaces. @@ -733,15 +715,15 @@ private: const int nType; const int nVersion; - FILE *src; // source file - uint64_t nSrcPos; // how many bytes have been read from source - uint64_t nReadPos; // how many bytes have been read from this - uint64_t nReadLimit; // up to which position we're allowed to read - uint64_t nRewind; // how many bytes we guarantee to rewind - std::vector<char> vchBuf; // the buffer + FILE *src; //!< source file + uint64_t nSrcPos; //!< how many bytes have been read from source + uint64_t nReadPos; //!< how many bytes have been read from this + uint64_t nReadLimit; //!< up to which position we're allowed to read + uint64_t nRewind; //!< how many bytes we guarantee to rewind + std::vector<char> vchBuf; //!< the buffer protected: - // read data from the source to fill the buffer + //! read data from the source to fill the buffer bool Fill() { unsigned int pos = nSrcPos % vchBuf.size(); unsigned int readNow = vchBuf.size() - pos; @@ -786,12 +768,12 @@ public: } } - // check whether we're at the end of the source file + //! check whether we're at the end of the source file bool eof() const { return nReadPos == nSrcPos && feof(src); } - // read a number of bytes + //! read a number of bytes void read(char *pch, size_t nSize) { if (nSize + nReadPos > nReadLimit) throw std::ios_base::failure("Read attempted past buffer limit"); @@ -813,12 +795,12 @@ public: } } - // return the current reading position + //! return the current reading position uint64_t GetPos() const { return nReadPos; } - // rewind to a given reading position + //! rewind to a given reading position bool SetPos(uint64_t nPos) { nReadPos = nPos; if (nReadPos + nRewind < nSrcPos) { @@ -844,8 +826,8 @@ public: return true; } - // prevent reading beyond a certain position - // no argument removes the limit + //! prevent reading beyond a certain position + //! no argument removes the limit bool SetLimit(uint64_t nPos = std::numeric_limits<uint64_t>::max()) { if (nPos < nReadPos) return false; @@ -860,7 +842,7 @@ public: return (*this); } - // search for a given byte in the stream, and remain positioned on it + //! search for a given byte in the stream, and remain positioned on it void FindByte(char ch) { while (true) { if (nReadPos == nSrcPos) diff --git a/src/support/allocators/secure.h b/src/support/allocators/secure.h index 7cd0df135d..57f5b1f733 100644 --- a/src/support/allocators/secure.h +++ b/src/support/allocators/secure.h @@ -40,7 +40,11 @@ struct secure_allocator : public std::allocator<T> { T* allocate(std::size_t n, const void* hint = 0) { - return static_cast<T*>(LockedPoolManager::Instance().alloc(sizeof(T) * n)); + T* allocation = static_cast<T*>(LockedPoolManager::Instance().alloc(sizeof(T) * n)); + if (!allocation) { + throw std::bad_alloc(); + } + return allocation; } void deallocate(T* p, std::size_t n) diff --git a/src/support/lockedpool.cpp b/src/support/lockedpool.cpp index 8d577cf521..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 @@ -248,6 +244,9 @@ void *PosixLockedPageAllocator::AllocateLocked(size_t len, bool *lockingSuccess) void *addr; len = align_up(len, page_size); addr = mmap(nullptr, len, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); + if (addr == MAP_FAILED) { + return nullptr; + } if (addr) { *lockingSuccess = mlock(addr, len) == 0; } diff --git a/src/support/lockedpool.h b/src/support/lockedpool.h index 48ffd7b307..b420c909fc 100644 --- a/src/support/lockedpool.h +++ b/src/support/lockedpool.h @@ -22,7 +22,7 @@ public: virtual ~LockedPageAllocator() {} /** Allocate and lock memory pages. * If len is not a multiple of the system page size, it is rounded up. - * Returns 0 in case of allocation failure. + * Returns nullptr in case of allocation failure. * * If locking the memory pages could not be accomplished it will still * return the memory, however the lockingSuccess flag will be false. diff --git a/src/sync.cpp b/src/sync.cpp index 30811f5f89..23ca866e53 100644 --- a/src/sync.cpp +++ b/src/sync.cpp @@ -73,7 +73,11 @@ struct LockData { LockOrders lockorders; InvLockOrders invlockorders; std::mutex dd_mutex; -} static lockdata; +}; +LockData& GetLockData() { + static LockData lockdata; + return lockdata; +} static thread_local LockStack g_lockstack; @@ -109,6 +113,7 @@ static void potential_deadlock_detected(const std::pair<void*, void*>& mismatch, static void push_lock(void* c, const CLockLocation& locklocation) { + LockData& lockdata = GetLockData(); std::lock_guard<std::mutex> lock(lockdata.dd_mutex); g_lockstack.push_back(std::make_pair(c, locklocation)); @@ -173,6 +178,7 @@ void AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLi void DeleteLock(void* cs) { + LockData& lockdata = GetLockData(); if (!lockdata.available) { // We're already shutting down. return; diff --git a/src/sync.h b/src/sync.h index 40709bdd7f..3857eda56b 100644 --- a/src/sync.h +++ b/src/sync.h @@ -20,7 +20,7 @@ //////////////////////////////////////////////// /* -CCriticalSection mutex; +RecursiveMutex mutex; std::recursive_mutex mutex; LOCK(mutex); @@ -104,6 +104,7 @@ public: * Wrapped mutex: supports recursive locking, but no waiting * TODO: We should move away from using the recursive lock by default. */ +using RecursiveMutex = AnnotatedMixin<std::recursive_mutex>; typedef AnnotatedMixin<std::recursive_mutex> CCriticalSection; /** Wrapped mutex: supports waiting but not recursive locking */ diff --git a/src/test/addrman_tests.cpp b/src/test/addrman_tests.cpp index 234da5ae4d..22347fbc57 100644 --- a/src/test/addrman_tests.cpp +++ b/src/test/addrman_tests.cpp @@ -12,13 +12,9 @@ class CAddrManTest : public CAddrMan { - uint64_t state; - public: explicit CAddrManTest(bool makeDeterministic = true) { - state = 1; - if (makeDeterministic) { // Set addrman addr placement to be deterministic. MakeDeterministic(); diff --git a/src/test/allocator_tests.cpp b/src/test/allocator_tests.cpp index 5a108dcdad..9eded4f5b2 100644 --- a/src/test/allocator_tests.cpp +++ b/src/test/allocator_tests.cpp @@ -105,13 +105,13 @@ BOOST_AUTO_TEST_CASE(arena_tests) // Go entirely wild: free and alloc interleaved, // generate targets and sizes using pseudo-randomness. for (int x=0; x<2048; ++x) - addr.push_back(0); + addr.push_back(nullptr); uint32_t s = 0x12345678; for (int x=0; x<5000; ++x) { int idx = s & (addr.size()-1); if (s & 0x80000000) { b.free(addr[idx]); - addr[idx] = 0; + addr[idx] = nullptr; } else if(!addr[idx]) { addr[idx] = b.alloc((s >> 16) & 2047); } @@ -144,9 +144,9 @@ public: *lockingSuccess = true; } - return reinterpret_cast<void*>(0x08000000 + (count<<24)); // Fake address, do not actually use this memory + return reinterpret_cast<void*>(uint64_t{static_cast<uint64_t>(0x08000000) + (count << 24)}); // Fake address, do not actually use this memory } - return 0; + return nullptr; } void FreeLocked(void* addr, size_t len) override { diff --git a/src/test/blockchain_tests.cpp b/src/test/blockchain_tests.cpp index 7d8ae46fb8..b61152985f 100644 --- a/src/test/blockchain_tests.cpp +++ b/src/test/blockchain_tests.cpp @@ -68,11 +68,4 @@ BOOST_AUTO_TEST_CASE(get_difficulty_for_very_high_target) TestDifficulty(0x12345678, 5913134931067755359633408.0); } -// Verify that difficulty is 1.0 for an empty chain. -BOOST_AUTO_TEST_CASE(get_difficulty_for_null_tip) -{ - double difficulty = GetDifficulty(nullptr); - RejectDifficultyMismatch(difficulty, 1.0); -} - BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/blockencodings_tests.cpp b/src/test/blockencodings_tests.cpp index 309b8d2d06..607af8a32a 100644 --- a/src/test/blockencodings_tests.cpp +++ b/src/test/blockencodings_tests.cpp @@ -62,7 +62,7 @@ BOOST_AUTO_TEST_CASE(SimpleRoundTripTest) TestMemPoolEntryHelper entry; CBlock block(BuildBlockTestCase()); - LOCK(pool.cs); + LOCK2(cs_main, pool.cs); pool.addUnchecked(entry.FromTx(block.vtx[2])); BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[2]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0); @@ -162,7 +162,7 @@ BOOST_AUTO_TEST_CASE(NonCoinbasePreforwardRTTest) TestMemPoolEntryHelper entry; CBlock block(BuildBlockTestCase()); - LOCK(pool.cs); + LOCK2(cs_main, pool.cs); pool.addUnchecked(entry.FromTx(block.vtx[2])); BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[2]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0); @@ -232,7 +232,7 @@ BOOST_AUTO_TEST_CASE(SufficientPreforwardRTTest) TestMemPoolEntryHelper entry; CBlock block(BuildBlockTestCase()); - LOCK(pool.cs); + LOCK2(cs_main, pool.cs); pool.addUnchecked(entry.FromTx(block.vtx[1])); BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[1]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0); 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/crypto_tests.cpp b/src/test/crypto_tests.cpp index f3fd83a0cc..86cb00a78f 100644 --- a/src/test/crypto_tests.cpp +++ b/src/test/crypto_tests.cpp @@ -532,7 +532,7 @@ BOOST_AUTO_TEST_CASE(countbits_tests) // Check handling of zero. BOOST_CHECK_EQUAL(CountBits(0), 0U); } else if (i < 10) { - for (uint64_t j = 1 << (i - 1); (j >> i) == 0; ++j) { + for (uint64_t j = (uint64_t)1 << (i - 1); (j >> i) == 0; ++j) { // Exhaustively test up to 10 bits BOOST_CHECK_EQUAL(CountBits(j), i); } diff --git a/src/test/denialofservice_tests.cpp b/src/test/denialofservice_tests.cpp index 8cf614bc8d..e5d62a3ab2 100644 --- a/src/test/denialofservice_tests.cpp +++ b/src/test/denialofservice_tests.cpp @@ -4,6 +4,7 @@ // Unit tests for denial-of-service detection/prevention code +#include <banman.h> #include <chainparams.h> #include <keystore.h> #include <net.h> @@ -20,6 +21,23 @@ #include <boost/test/unit_test.hpp> +struct CConnmanTest : public CConnman { + using CConnman::CConnman; + void AddNode(CNode& node) + { + LOCK(cs_vNodes); + vNodes.push_back(&node); + } + void ClearNodes() + { + LOCK(cs_vNodes); + for (CNode* node : vNodes) { + delete node; + } + vNodes.clear(); + } +}; + // Tests these internal-to-net_processing.cpp methods: extern bool AddOrphanTx(const CTransactionRef& tx, NodeId peer); extern void EraseOrphansFor(NodeId peer); @@ -57,6 +75,8 @@ BOOST_FIXTURE_TEST_SUITE(denialofservice_tests, TestingSetup) // work. BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction) { + auto connman = MakeUnique<CConnman>(0x1337, 0x1337); + auto peerLogic = MakeUnique<PeerLogicValidation>(connman.get(), nullptr, scheduler, false); // Mock an outbound peer CAddress addr1(ip(0xa0b0c001), NODE_NONE); @@ -109,7 +129,7 @@ BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction) peerLogic->FinalizeNode(dummyNode1.GetId(), dummy); } -static void AddRandomOutboundPeer(std::vector<CNode *> &vNodes, PeerLogicValidation &peerLogic) +static void AddRandomOutboundPeer(std::vector<CNode *> &vNodes, PeerLogicValidation &peerLogic, CConnmanTest* connman) { CAddress addr(ip(g_insecure_rand_ctx.randbits(32)), NODE_NONE); vNodes.emplace_back(new CNode(id++, ServiceFlags(NODE_NETWORK|NODE_WITNESS), 0, INVALID_SOCKET, addr, 0, 0, CAddress(), "", /*fInboundIn=*/ false)); @@ -120,11 +140,14 @@ static void AddRandomOutboundPeer(std::vector<CNode *> &vNodes, PeerLogicValidat node.nVersion = 1; node.fSuccessfullyConnected = true; - CConnmanTest::AddNode(node); + connman->AddNode(node); } BOOST_AUTO_TEST_CASE(stale_tip_peer_management) { + auto connman = MakeUnique<CConnmanTest>(0x1337, 0x1337); + auto peerLogic = MakeUnique<PeerLogicValidation>(connman.get(), nullptr, scheduler, false); + const Consensus::Params& consensusParams = Params().GetConsensus(); constexpr int nMaxOutbound = 8; CConnman::Options options; @@ -137,7 +160,7 @@ BOOST_AUTO_TEST_CASE(stale_tip_peer_management) // Mock some outbound peers for (int i=0; i<nMaxOutbound; ++i) { - AddRandomOutboundPeer(vNodes, *peerLogic); + AddRandomOutboundPeer(vNodes, *peerLogic, connman.get()); } peerLogic->CheckForStaleTipAndEvictPeers(consensusParams); @@ -162,7 +185,7 @@ BOOST_AUTO_TEST_CASE(stale_tip_peer_management) // If we add one more peer, something should get marked for eviction // on the next check (since we're mocking the time to be in the future, the // required time connected check should be satisfied). - AddRandomOutboundPeer(vNodes, *peerLogic); + AddRandomOutboundPeer(vNodes, *peerLogic, connman.get()); peerLogic->CheckForStaleTipAndEvictPeers(consensusParams); for (int i=0; i<nMaxOutbound; ++i) { @@ -189,13 +212,16 @@ BOOST_AUTO_TEST_CASE(stale_tip_peer_management) peerLogic->FinalizeNode(node->GetId(), dummy); } - CConnmanTest::ClearNodes(); + connman->ClearNodes(); } BOOST_AUTO_TEST_CASE(DoS_banning) { + auto banman = MakeUnique<BanMan>(GetDataDir() / "banlist.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME); + auto connman = MakeUnique<CConnman>(0x1337, 0x1337); + auto peerLogic = MakeUnique<PeerLogicValidation>(connman.get(), banman.get(), scheduler, false); - connman->ClearBanned(); + banman->ClearBanned(); CAddress addr1(ip(0xa0b0c001), NODE_NONE); CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, 0, 0, CAddress(), "", true); dummyNode1.SetSendVersion(PROTOCOL_VERSION); @@ -210,8 +236,8 @@ BOOST_AUTO_TEST_CASE(DoS_banning) LOCK2(cs_main, dummyNode1.cs_sendProcessing); BOOST_CHECK(peerLogic->SendMessages(&dummyNode1)); } - BOOST_CHECK(connman->IsBanned(addr1)); - BOOST_CHECK(!connman->IsBanned(ip(0xa0b0c001|0x0000ff00))); // Different IP, not banned + BOOST_CHECK(banman->IsBanned(addr1)); + BOOST_CHECK(!banman->IsBanned(ip(0xa0b0c001|0x0000ff00))); // Different IP, not banned CAddress addr2(ip(0xa0b0c002), NODE_NONE); CNode dummyNode2(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr2, 1, 1, CAddress(), "", true); @@ -227,8 +253,8 @@ BOOST_AUTO_TEST_CASE(DoS_banning) LOCK2(cs_main, dummyNode2.cs_sendProcessing); BOOST_CHECK(peerLogic->SendMessages(&dummyNode2)); } - BOOST_CHECK(!connman->IsBanned(addr2)); // 2 not banned yet... - BOOST_CHECK(connman->IsBanned(addr1)); // ... but 1 still should be + BOOST_CHECK(!banman->IsBanned(addr2)); // 2 not banned yet... + BOOST_CHECK(banman->IsBanned(addr1)); // ... but 1 still should be { LOCK(cs_main); Misbehaving(dummyNode2.GetId(), 50); @@ -237,7 +263,7 @@ BOOST_AUTO_TEST_CASE(DoS_banning) LOCK2(cs_main, dummyNode2.cs_sendProcessing); BOOST_CHECK(peerLogic->SendMessages(&dummyNode2)); } - BOOST_CHECK(connman->IsBanned(addr2)); + BOOST_CHECK(banman->IsBanned(addr2)); bool dummy; peerLogic->FinalizeNode(dummyNode1.GetId(), dummy); @@ -246,8 +272,11 @@ BOOST_AUTO_TEST_CASE(DoS_banning) BOOST_AUTO_TEST_CASE(DoS_banscore) { + auto banman = MakeUnique<BanMan>(GetDataDir() / "banlist.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME); + auto connman = MakeUnique<CConnman>(0x1337, 0x1337); + auto peerLogic = MakeUnique<PeerLogicValidation>(connman.get(), banman.get(), scheduler, false); - connman->ClearBanned(); + banman->ClearBanned(); gArgs.ForceSetArg("-banscore", "111"); // because 11 is my favorite number CAddress addr1(ip(0xa0b0c001), NODE_NONE); CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, 3, 1, CAddress(), "", true); @@ -263,7 +292,7 @@ BOOST_AUTO_TEST_CASE(DoS_banscore) LOCK2(cs_main, dummyNode1.cs_sendProcessing); BOOST_CHECK(peerLogic->SendMessages(&dummyNode1)); } - BOOST_CHECK(!connman->IsBanned(addr1)); + BOOST_CHECK(!banman->IsBanned(addr1)); { LOCK(cs_main); Misbehaving(dummyNode1.GetId(), 10); @@ -272,7 +301,7 @@ BOOST_AUTO_TEST_CASE(DoS_banscore) LOCK2(cs_main, dummyNode1.cs_sendProcessing); BOOST_CHECK(peerLogic->SendMessages(&dummyNode1)); } - BOOST_CHECK(!connman->IsBanned(addr1)); + BOOST_CHECK(!banman->IsBanned(addr1)); { LOCK(cs_main); Misbehaving(dummyNode1.GetId(), 1); @@ -281,7 +310,7 @@ BOOST_AUTO_TEST_CASE(DoS_banscore) LOCK2(cs_main, dummyNode1.cs_sendProcessing); BOOST_CHECK(peerLogic->SendMessages(&dummyNode1)); } - BOOST_CHECK(connman->IsBanned(addr1)); + BOOST_CHECK(banman->IsBanned(addr1)); gArgs.ForceSetArg("-banscore", std::to_string(DEFAULT_BANSCORE_THRESHOLD)); bool dummy; @@ -290,8 +319,11 @@ BOOST_AUTO_TEST_CASE(DoS_banscore) BOOST_AUTO_TEST_CASE(DoS_bantime) { + auto banman = MakeUnique<BanMan>(GetDataDir() / "banlist.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME); + auto connman = MakeUnique<CConnman>(0x1337, 0x1337); + auto peerLogic = MakeUnique<PeerLogicValidation>(connman.get(), banman.get(), scheduler, false); - connman->ClearBanned(); + banman->ClearBanned(); int64_t nStartTime = GetTime(); SetMockTime(nStartTime); // Overrides future calls to GetTime() @@ -310,13 +342,13 @@ BOOST_AUTO_TEST_CASE(DoS_bantime) LOCK2(cs_main, dummyNode.cs_sendProcessing); BOOST_CHECK(peerLogic->SendMessages(&dummyNode)); } - BOOST_CHECK(connman->IsBanned(addr)); + BOOST_CHECK(banman->IsBanned(addr)); SetMockTime(nStartTime+60*60); - BOOST_CHECK(connman->IsBanned(addr)); + BOOST_CHECK(banman->IsBanned(addr)); SetMockTime(nStartTime+60*60*24+1); - BOOST_CHECK(!connman->IsBanned(addr)); + BOOST_CHECK(!banman->IsBanned(addr)); bool dummy; peerLogic->FinalizeNode(dummyNode.GetId(), dummy); diff --git a/src/test/fuzz/fuzz.cpp b/src/test/fuzz/fuzz.cpp new file mode 100644 index 0000000000..0709da5563 --- /dev/null +++ b/src/test/fuzz/fuzz.cpp @@ -0,0 +1,77 @@ +// 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 <test/fuzz/fuzz.h> + +#include <unistd.h> + +#include <pubkey.h> +#include <util/memory.h> + + +static bool read_stdin(std::vector<uint8_t>& data) +{ + uint8_t buffer[1024]; + ssize_t length = 0; + while ((length = read(STDIN_FILENO, buffer, 1024)) > 0) { + data.insert(data.end(), buffer, buffer + length); + + if (data.size() > (1 << 20)) return false; + } + return length == 0; +} + +static void initialize() +{ + const static auto verify_handle = MakeUnique<ECCVerifyHandle>(); +} + +// This function is used by libFuzzer +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) +{ + test_one_input(std::vector<uint8_t>(data, data + size)); + return 0; +} + +// This function is used by libFuzzer +extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) +{ + initialize(); + return 0; +} + +// Disabled under WIN32 due to clash with Cygwin's WinMain. +#ifndef WIN32 +// Declare main(...) "weak" to allow for libFuzzer linking. libFuzzer provides +// the main(...) function. +__attribute__((weak)) +#endif +int main(int argc, char **argv) +{ + initialize(); +#ifdef __AFL_INIT + // Enable AFL deferred forkserver mode. Requires compilation using + // afl-clang-fast++. See fuzzing.md for details. + __AFL_INIT(); +#endif + +#ifdef __AFL_LOOP + // Enable AFL persistent mode. Requires compilation using afl-clang-fast++. + // See fuzzing.md for details. + while (__AFL_LOOP(1000)) { + std::vector<uint8_t> buffer; + if (!read_stdin(buffer)) { + continue; + } + test_one_input(buffer); + } +#else + std::vector<uint8_t> buffer; + if (!read_stdin(buffer)) { + return 0; + } + test_one_input(buffer); +#endif + return 0; +} diff --git a/src/test/fuzz/fuzz.h b/src/test/fuzz/fuzz.h new file mode 100644 index 0000000000..ad62a5faf0 --- /dev/null +++ b/src/test/fuzz/fuzz.h @@ -0,0 +1,17 @@ +// 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_TEST_FUZZ_FUZZ_H +#define BITCOIN_TEST_FUZZ_FUZZ_H + +#include <functional> +#include <stdint.h> +#include <vector> + + +const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr; + +void test_one_input(std::vector<uint8_t> buffer); + +#endif // BITCOIN_TEST_FUZZ_FUZZ_H diff --git a/src/test/getarg_tests.cpp b/src/test/getarg_tests.cpp index 14ddf4d10e..8048238028 100644 --- a/src/test/getarg_tests.cpp +++ b/src/test/getarg_tests.cpp @@ -2,6 +2,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include <util/strencodings.h> #include <util/system.h> #include <test/test_bitcoin.h> @@ -17,7 +18,7 @@ static void ResetArgs(const std::string& strArg) { std::vector<std::string> vecArg; if (strArg.size()) - boost::split(vecArg, strArg, boost::is_space(), boost::token_compress_on); + boost::split(vecArg, strArg, IsSpace, boost::token_compress_on); // Insert dummy executable name: vecArg.insert(vecArg.begin(), "testbitcoin"); diff --git a/src/test/mempool_tests.cpp b/src/test/mempool_tests.cpp index 2396aba0f1..23ca9d89ae 100644 --- a/src/test/mempool_tests.cpp +++ b/src/test/mempool_tests.cpp @@ -55,7 +55,7 @@ BOOST_AUTO_TEST_CASE(MempoolRemoveTest) CTxMemPool testPool; - LOCK(testPool.cs); + LOCK2(cs_main, testPool.cs); // Nothing in pool, remove should do nothing: unsigned int poolSize = testPool.size(); @@ -120,7 +120,7 @@ static void CheckSort(CTxMemPool &pool, std::vector<std::string> &sortedOrder) E BOOST_AUTO_TEST_CASE(MempoolIndexingTest) { CTxMemPool pool; - LOCK(pool.cs); + LOCK2(cs_main, pool.cs); TestMemPoolEntryHelper entry; /* 3rd highest fee */ @@ -293,7 +293,7 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest) BOOST_AUTO_TEST_CASE(MempoolAncestorIndexingTest) { CTxMemPool pool; - LOCK(pool.cs); + LOCK2(cs_main, pool.cs); TestMemPoolEntryHelper entry; /* 3rd highest fee */ @@ -422,7 +422,7 @@ BOOST_AUTO_TEST_CASE(MempoolAncestorIndexingTest) BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest) { CTxMemPool pool; - LOCK(pool.cs); + LOCK2(cs_main, pool.cs); TestMemPoolEntryHelper entry; CMutableTransaction tx1 = CMutableTransaction(); @@ -595,7 +595,7 @@ BOOST_AUTO_TEST_CASE(MempoolAncestryTests) size_t ancestors, descendants; CTxMemPool pool; - LOCK(pool.cs); + LOCK2(cs_main, pool.cs); TestMemPoolEntryHelper entry; /* Base transaction */ diff --git a/src/test/merkle_tests.cpp b/src/test/merkle_tests.cpp index 5e55ad6622..4cdf0f003e 100644 --- a/src/test/merkle_tests.cpp +++ b/src/test/merkle_tests.cpp @@ -13,9 +13,9 @@ static uint256 ComputeMerkleRootFromBranch(const uint256& leaf, const std::vecto uint256 hash = leaf; for (std::vector<uint256>::const_iterator it = vMerkleBranch.begin(); it != vMerkleBranch.end(); ++it) { if (nIndex & 1) { - hash = Hash(BEGIN(*it), END(*it), BEGIN(hash), END(hash)); + hash = Hash(it->begin(), it->end(), hash.begin(), hash.end()); } else { - hash = Hash(BEGIN(hash), END(hash), BEGIN(*it), END(*it)); + hash = Hash(hash.begin(), hash.end(), it->begin(), it->end()); } nIndex >>= 1; } diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index f3648e2eee..5ba1df2ec2 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -99,7 +99,7 @@ static bool TestSequenceLocks(const CTransaction &tx, int flags) EXCLUSIVE_LOCKS // Test suite for ancestor feerate transaction selection. // Implemented as an additional function, rather than a separate test case, // to allow reusing the blockchain created in CreateNewBlock_validity. -static void TestPackageSelection(const CChainParams& chainparams, const CScript& scriptPubKey, const std::vector<CTransactionRef>& txFirst) EXCLUSIVE_LOCKS_REQUIRED(::mempool.cs) +static void TestPackageSelection(const CChainParams& chainparams, const CScript& scriptPubKey, const std::vector<CTransactionRef>& txFirst) EXCLUSIVE_LOCKS_REQUIRED(cs_main, ::mempool.cs) { // Test the ancestor feerate transaction selection. TestMemPoolEntryHelper entry; diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp index e7a3c96343..b4ae8e9765 100644 --- a/src/test/net_tests.cpp +++ b/src/test/net_tests.cpp @@ -227,4 +227,80 @@ BOOST_AUTO_TEST_CASE(ipv4_peer_with_ipv6_addrMe_test) BOOST_CHECK(1); } + +BOOST_AUTO_TEST_CASE(LimitedAndReachable_Network) +{ + BOOST_CHECK_EQUAL(IsReachable(NET_IPV4), true); + BOOST_CHECK_EQUAL(IsReachable(NET_IPV6), true); + BOOST_CHECK_EQUAL(IsReachable(NET_ONION), true); + + SetReachable(NET_IPV4, false); + SetReachable(NET_IPV6, false); + SetReachable(NET_ONION, false); + + BOOST_CHECK_EQUAL(IsReachable(NET_IPV4), false); + BOOST_CHECK_EQUAL(IsReachable(NET_IPV6), false); + BOOST_CHECK_EQUAL(IsReachable(NET_ONION), false); + + SetReachable(NET_IPV4, true); + SetReachable(NET_IPV6, true); + SetReachable(NET_ONION, true); + + BOOST_CHECK_EQUAL(IsReachable(NET_IPV4), true); + BOOST_CHECK_EQUAL(IsReachable(NET_IPV6), true); + BOOST_CHECK_EQUAL(IsReachable(NET_ONION), true); +} + +BOOST_AUTO_TEST_CASE(LimitedAndReachable_NetworkCaseUnroutableAndInternal) +{ + BOOST_CHECK_EQUAL(IsReachable(NET_UNROUTABLE), true); + BOOST_CHECK_EQUAL(IsReachable(NET_INTERNAL), true); + + SetReachable(NET_UNROUTABLE, false); + SetReachable(NET_INTERNAL, false); + + BOOST_CHECK_EQUAL(IsReachable(NET_UNROUTABLE), true); // Ignored for both networks + BOOST_CHECK_EQUAL(IsReachable(NET_INTERNAL), true); +} + +CNetAddr UtilBuildAddress(unsigned char p1, unsigned char p2, unsigned char p3, unsigned char p4) +{ + unsigned char ip[] = {p1, p2, p3, p4}; + + struct sockaddr_in sa; + memset(&sa, 0, sizeof(sockaddr_in)); // initialize the memory block + memcpy(&(sa.sin_addr), &ip, sizeof(ip)); + return CNetAddr(sa.sin_addr); +} + + +BOOST_AUTO_TEST_CASE(LimitedAndReachable_CNetAddr) +{ + CNetAddr addr = UtilBuildAddress(0x001, 0x001, 0x001, 0x001); // 1.1.1.1 + + SetReachable(NET_IPV4, true); + BOOST_CHECK_EQUAL(IsReachable(addr), true); + + SetReachable(NET_IPV4, false); + BOOST_CHECK_EQUAL(IsReachable(addr), false); + + SetReachable(NET_IPV4, true); // have to reset this, because this is stateful. +} + + +BOOST_AUTO_TEST_CASE(LocalAddress_BasicLifecycle) +{ + CService addr = CService(UtilBuildAddress(0x002, 0x001, 0x001, 0x001), 1000); // 2.1.1.1:1000 + + SetReachable(NET_IPV4, true); + + BOOST_CHECK_EQUAL(IsLocal(addr), false); + BOOST_CHECK_EQUAL(AddLocal(addr, 1000), true); + BOOST_CHECK_EQUAL(IsLocal(addr), true); + + RemoveLocal(addr); + BOOST_CHECK_EQUAL(IsLocal(addr), false); +} + + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/policyestimator_tests.cpp b/src/test/policyestimator_tests.cpp index 431b16cfc2..7b274a1658 100644 --- a/src/test/policyestimator_tests.cpp +++ b/src/test/policyestimator_tests.cpp @@ -18,7 +18,7 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates) { CBlockPolicyEstimator feeEst; CTxMemPool mpool(&feeEst); - LOCK(mpool.cs); + LOCK2(cs_main, mpool.cs); TestMemPoolEntryHelper entry; CAmount basefee(2000); CAmount deltaFee(100); 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/script_p2sh_tests.cpp b/src/test/script_p2sh_tests.cpp index 1556b2f667..3a2a11ef98 100644 --- a/src/test/script_p2sh_tests.cpp +++ b/src/test/script_p2sh_tests.cpp @@ -213,14 +213,22 @@ BOOST_AUTO_TEST_CASE(is) BOOST_CHECK(p2sh.IsPayToScriptHash()); // Not considered pay-to-script-hash if using one of the OP_PUSHDATA opcodes: - static const unsigned char direct[] = { OP_HASH160, 20, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, OP_EQUAL }; - BOOST_CHECK(CScript(direct, direct+sizeof(direct)).IsPayToScriptHash()); - static const unsigned char pushdata1[] = { OP_HASH160, OP_PUSHDATA1, 20, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, OP_EQUAL }; - BOOST_CHECK(!CScript(pushdata1, pushdata1+sizeof(pushdata1)).IsPayToScriptHash()); - static const unsigned char pushdata2[] = { OP_HASH160, OP_PUSHDATA2, 20,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, OP_EQUAL }; - BOOST_CHECK(!CScript(pushdata2, pushdata2+sizeof(pushdata2)).IsPayToScriptHash()); - static const unsigned char pushdata4[] = { OP_HASH160, OP_PUSHDATA4, 20,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, OP_EQUAL }; - BOOST_CHECK(!CScript(pushdata4, pushdata4+sizeof(pushdata4)).IsPayToScriptHash()); + std::vector<unsigned char> direct = {OP_HASH160, 20}; + direct.insert(direct.end(), 20, 0); + direct.push_back(OP_EQUAL); + BOOST_CHECK(CScript(direct.begin(), direct.end()).IsPayToScriptHash()); + std::vector<unsigned char> pushdata1 = {OP_HASH160, OP_PUSHDATA1, 20}; + pushdata1.insert(pushdata1.end(), 20, 0); + pushdata1.push_back(OP_EQUAL); + BOOST_CHECK(!CScript(pushdata1.begin(), pushdata1.end()).IsPayToScriptHash()); + std::vector<unsigned char> pushdata2 = {OP_HASH160, 20, 0}; + pushdata2.insert(pushdata2.end(), 20, 0); + pushdata2.push_back(OP_EQUAL); + BOOST_CHECK(!CScript(pushdata2.begin(), pushdata2.end()).IsPayToScriptHash()); + std::vector<unsigned char> pushdata4 = {OP_HASH160, 20, 0, 0, 0}; + pushdata4.insert(pushdata4.end(), 20, 0); + pushdata4.push_back(OP_EQUAL); + BOOST_CHECK(!CScript(pushdata4.begin(), pushdata4.end()).IsPayToScriptHash()); CScript not_p2sh; BOOST_CHECK(!not_p2sh.IsPayToScriptHash()); diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp index 1b394753ef..87c3e74df0 100644 --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -184,11 +184,12 @@ void DoTest(const CScript& scriptPubKey, const CScript& scriptSig, const CScript stream << tx2; int libconsensus_flags = flags & bitcoinconsensus_SCRIPT_FLAGS_VERIFY_ALL; if (libconsensus_flags == flags) { + int expectedSuccessCode = expect ? 1 : 0; if (flags & bitcoinconsensus_SCRIPT_FLAGS_VERIFY_WITNESS) { - BOOST_CHECK_MESSAGE(bitcoinconsensus_verify_script_with_amount(scriptPubKey.data(), scriptPubKey.size(), txCredit.vout[0].nValue, (const unsigned char*)&stream[0], stream.size(), 0, libconsensus_flags, nullptr) == expect, message); + BOOST_CHECK_MESSAGE(bitcoinconsensus_verify_script_with_amount(scriptPubKey.data(), scriptPubKey.size(), txCredit.vout[0].nValue, (const unsigned char*)&stream[0], stream.size(), 0, libconsensus_flags, nullptr) == expectedSuccessCode, message); } else { - BOOST_CHECK_MESSAGE(bitcoinconsensus_verify_script_with_amount(scriptPubKey.data(), scriptPubKey.size(), 0, (const unsigned char*)&stream[0], stream.size(), 0, libconsensus_flags, nullptr) == expect, message); - BOOST_CHECK_MESSAGE(bitcoinconsensus_verify_script(scriptPubKey.data(), scriptPubKey.size(), (const unsigned char*)&stream[0], stream.size(), 0, libconsensus_flags, nullptr) == expect,message); + BOOST_CHECK_MESSAGE(bitcoinconsensus_verify_script_with_amount(scriptPubKey.data(), scriptPubKey.size(), 0, (const unsigned char*)&stream[0], stream.size(), 0, libconsensus_flags, nullptr) == expectedSuccessCode, message); + BOOST_CHECK_MESSAGE(bitcoinconsensus_verify_script(scriptPubKey.data(), scriptPubKey.size(), (const unsigned char*)&stream[0], stream.size(), 0, libconsensus_flags, nullptr) == expectedSuccessCode, message); } } #endif diff --git a/src/test/streams_tests.cpp b/src/test/streams_tests.cpp index 26cf74830d..a1940eb80e 100644 --- a/src/test/streams_tests.cpp +++ b/src/test/streams_tests.cpp @@ -102,15 +102,15 @@ BOOST_AUTO_TEST_CASE(streams_vector_reader) BOOST_CHECK_THROW(reader >> d, std::ios_base::failure); // Read a 4 bytes as a signed int from the beginning of the buffer. - reader.seek(-6); - reader >> d; + VectorReader new_reader(SER_NETWORK, INIT_PROTO_VERSION, vch, 0); + new_reader >> d; BOOST_CHECK_EQUAL(d, 67370753); // 1,255,3,4 in little-endian base-256 - BOOST_CHECK_EQUAL(reader.size(), 2); - BOOST_CHECK(!reader.empty()); + BOOST_CHECK_EQUAL(new_reader.size(), 2); + BOOST_CHECK(!new_reader.empty()); // Reading after end of byte vector throws an error even if the reader is // not totally empty. - BOOST_CHECK_THROW(reader >> d, std::ios_base::failure); + BOOST_CHECK_THROW(new_reader >> d, std::ios_base::failure); } BOOST_AUTO_TEST_CASE(bitstream_reader_writer) diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp index 858bb512fc..0c3fb7c398 100644 --- a/src/test/test_bitcoin.cpp +++ b/src/test/test_bitcoin.cpp @@ -4,6 +4,7 @@ #include <test/test_bitcoin.h> +#include <banman.h> #include <chainparams.h> #include <consensus/consensus.h> #include <consensus/params.h> @@ -24,21 +25,6 @@ const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr; FastRandomContext g_insecure_rand_ctx; -void CConnmanTest::AddNode(CNode& node) -{ - LOCK(g_connman->cs_vNodes); - g_connman->vNodes.push_back(&node); -} - -void CConnmanTest::ClearNodes() -{ - LOCK(g_connman->cs_vNodes); - for (const CNode* node : g_connman->vNodes) { - delete node; - } - g_connman->vNodes.clear(); -} - std::ostream& operator<<(std::ostream& os, const uint256& num) { os << num.ToString(); @@ -49,7 +35,6 @@ BasicTestingSetup::BasicTestingSetup(const std::string& chainName) : m_path_root(fs::temp_directory_path() / "test_bitcoin" / strprintf("%lu_%i", (unsigned long)GetTime(), (int)(InsecureRandRange(1 << 30)))) { SHA256AutoDetect(); - RandomInit(); ECC_Start(); SetupEnvironment(); SetupNetworking(); @@ -108,9 +93,9 @@ TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(cha nScriptCheckThreads = 3; for (int i=0; i < nScriptCheckThreads-1; i++) threadGroup.create_thread(&ThreadScriptCheck); + + g_banman = MakeUnique<BanMan>(GetDataDir() / "banlist.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME); g_connman = MakeUnique<CConnman>(0x1337, 0x1337); // Deterministic randomness for tests. - connman = g_connman.get(); - peerLogic.reset(new PeerLogicValidation(connman, scheduler, /*enable_bip61=*/true)); } TestingSetup::~TestingSetup() @@ -120,7 +105,7 @@ TestingSetup::~TestingSetup() GetMainSignals().FlushBackgroundCallbacks(); GetMainSignals().UnregisterBackgroundSignalScheduler(); g_connman.reset(); - peerLogic.reset(); + g_banman.reset(); UnloadBlockIndex(); pcoinsTip.reset(); pcoinsdbview.reset(); diff --git a/src/test/test_bitcoin.h b/src/test/test_bitcoin.h index 31d90c0151..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); @@ -68,17 +73,11 @@ private: */ class CConnman; class CNode; -struct CConnmanTest { - static void AddNode(CNode& node); - static void ClearNodes(); -}; class PeerLogicValidation; struct TestingSetup : public BasicTestingSetup { boost::thread_group threadGroup; - CConnman* connman; CScheduler scheduler; - std::unique_ptr<PeerLogicValidation> peerLogic; explicit TestingSetup(const std::string& chainName = CBaseChainParams::MAIN); ~TestingSetup(); diff --git a/src/test/test_bitcoin_fuzzy.cpp b/src/test/test_bitcoin_fuzzy.cpp index 88c082ff66..859fba0bdc 100644 --- a/src/test/test_bitcoin_fuzzy.cpp +++ b/src/test/test_bitcoin_fuzzy.cpp @@ -2,10 +2,6 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#if defined(HAVE_CONFIG_H) -#include <config/bitcoin-config.h> -#endif - #include <addrman.h> #include <blockencodings.h> #include <chain.h> @@ -28,304 +24,144 @@ #include <memory> #include <vector> -const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr; - -enum TEST_ID { - CBLOCK_DESERIALIZE=0, - CTRANSACTION_DESERIALIZE, - CBLOCKLOCATOR_DESERIALIZE, - CBLOCKMERKLEROOT, - CADDRMAN_DESERIALIZE, - CBLOCKHEADER_DESERIALIZE, - CBANENTRY_DESERIALIZE, - CTXUNDO_DESERIALIZE, - CBLOCKUNDO_DESERIALIZE, - CCOINS_DESERIALIZE, - CNETADDR_DESERIALIZE, - CSERVICE_DESERIALIZE, - CMESSAGEHEADER_DESERIALIZE, - CADDRESS_DESERIALIZE, - CINV_DESERIALIZE, - CBLOOMFILTER_DESERIALIZE, - CDISKBLOCKINDEX_DESERIALIZE, - CTXOUTCOMPRESSOR_DESERIALIZE, - BLOCKTRANSACTIONS_DESERIALIZE, - BLOCKTRANSACTIONSREQUEST_DESERIALIZE, - TEST_ID_END -}; - -static bool read_stdin(std::vector<uint8_t> &data) { - uint8_t buffer[1024]; - ssize_t length=0; - while((length = read(STDIN_FILENO, buffer, 1024)) > 0) { - data.insert(data.end(), buffer, buffer+length); - - if (data.size() > (1<<20)) return false; - } - return length==0; -} - -static int test_one_input(std::vector<uint8_t> buffer) { - if (buffer.size() < sizeof(uint32_t)) return 0; - - uint32_t test_id = 0xffffffff; - memcpy(&test_id, buffer.data(), sizeof(uint32_t)); - buffer.erase(buffer.begin(), buffer.begin() + sizeof(uint32_t)); - - if (test_id >= TEST_ID_END) return 0; +#include <test/fuzz/fuzz.h> +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& e) { - return 0; + return; } - switch(test_id) { - case CBLOCK_DESERIALIZE: - { +#if BLOCK_DESERIALIZE try { CBlock block; ds >> block; - } catch (const std::ios_base::failure& e) {return 0;} - break; - } - case CTRANSACTION_DESERIALIZE: - { + } catch (const std::ios_base::failure& e) {return;} +#elif TRANSACTION_DESERIALIZE try { CTransaction tx(deserialize, ds); - } catch (const std::ios_base::failure& e) {return 0;} - break; - } - case CBLOCKLOCATOR_DESERIALIZE: - { + } catch (const std::ios_base::failure& e) {return;} +#elif BLOCKLOCATOR_DESERIALIZE try { CBlockLocator bl; ds >> bl; - } catch (const std::ios_base::failure& e) {return 0;} - break; - } - case CBLOCKMERKLEROOT: - { + } catch (const std::ios_base::failure& e) {return;} +#elif BLOCKMERKLEROOT try { CBlock block; ds >> block; bool mutated; BlockMerkleRoot(block, &mutated); - } catch (const std::ios_base::failure& e) {return 0;} - break; - } - case CADDRMAN_DESERIALIZE: - { + } catch (const std::ios_base::failure& e) {return;} +#elif ADDRMAN_DESERIALIZE try { CAddrMan am; ds >> am; - } catch (const std::ios_base::failure& e) {return 0;} - break; - } - case CBLOCKHEADER_DESERIALIZE: - { + } catch (const std::ios_base::failure& e) {return;} +#elif BLOCKHEADER_DESERIALIZE try { CBlockHeader bh; ds >> bh; - } catch (const std::ios_base::failure& e) {return 0;} - break; - } - case CBANENTRY_DESERIALIZE: - { + } catch (const std::ios_base::failure& e) {return;} +#elif BANENTRY_DESERIALIZE try { CBanEntry be; ds >> be; - } catch (const std::ios_base::failure& e) {return 0;} - break; - } - case CTXUNDO_DESERIALIZE: - { + } catch (const std::ios_base::failure& e) {return;} +#elif TXUNDO_DESERIALIZE try { CTxUndo tu; ds >> tu; - } catch (const std::ios_base::failure& e) {return 0;} - break; - } - case CBLOCKUNDO_DESERIALIZE: - { + } catch (const std::ios_base::failure& e) {return;} +#elif BLOCKUNDO_DESERIALIZE try { CBlockUndo bu; ds >> bu; - } catch (const std::ios_base::failure& e) {return 0;} - break; - } - case CCOINS_DESERIALIZE: - { + } catch (const std::ios_base::failure& e) {return;} +#elif COINS_DESERIALIZE try { Coin coin; ds >> coin; - } catch (const std::ios_base::failure& e) {return 0;} - break; - } - case CNETADDR_DESERIALIZE: - { + } catch (const std::ios_base::failure& e) {return;} +#elif NETADDR_DESERIALIZE try { CNetAddr na; ds >> na; - } catch (const std::ios_base::failure& e) {return 0;} - break; - } - case CSERVICE_DESERIALIZE: - { + } catch (const std::ios_base::failure& e) {return;} +#elif SERVICE_DESERIALIZE try { CService s; ds >> s; - } catch (const std::ios_base::failure& e) {return 0;} - break; - } - case CMESSAGEHEADER_DESERIALIZE: - { + } catch (const std::ios_base::failure& e) {return;} +#elif MESSAGEHEADER_DESERIALIZE CMessageHeader::MessageStartChars pchMessageStart = {0x00, 0x00, 0x00, 0x00}; try { CMessageHeader mh(pchMessageStart); ds >> mh; - if (!mh.IsValid(pchMessageStart)) {return 0;} - } catch (const std::ios_base::failure& e) {return 0;} - break; - } - case CADDRESS_DESERIALIZE: - { + if (!mh.IsValid(pchMessageStart)) {return;} + } catch (const std::ios_base::failure& e) {return;} +#elif ADDRESS_DESERIALIZE try { CAddress a; ds >> a; - } catch (const std::ios_base::failure& e) {return 0;} - break; - } - case CINV_DESERIALIZE: - { + } catch (const std::ios_base::failure& e) {return;} +#elif INV_DESERIALIZE try { CInv i; ds >> i; - } catch (const std::ios_base::failure& e) {return 0;} - break; - } - case CBLOOMFILTER_DESERIALIZE: - { + } catch (const std::ios_base::failure& e) {return;} +#elif BLOOMFILTER_DESERIALIZE try { CBloomFilter bf; ds >> bf; - } catch (const std::ios_base::failure& e) {return 0;} - break; - } - case CDISKBLOCKINDEX_DESERIALIZE: - { + } catch (const std::ios_base::failure& e) {return;} +#elif DISKBLOCKINDEX_DESERIALIZE try { CDiskBlockIndex dbi; ds >> dbi; - } catch (const std::ios_base::failure& e) {return 0;} - break; - } - case CTXOUTCOMPRESSOR_DESERIALIZE: - { + } catch (const std::ios_base::failure& e) {return;} +#elif TXOUTCOMPRESSOR_DESERIALIZE CTxOut to; CTxOutCompressor toc(to); try { ds >> toc; - } catch (const std::ios_base::failure& e) {return 0;} - - break; - } - case BLOCKTRANSACTIONS_DESERIALIZE: - { + } catch (const std::ios_base::failure& e) {return;} +#elif BLOCKTRANSACTIONS_DESERIALIZE try { BlockTransactions bt; ds >> bt; - } catch (const std::ios_base::failure& e) {return 0;} - - break; - } - case BLOCKTRANSACTIONSREQUEST_DESERIALIZE: - { + } catch (const std::ios_base::failure& e) {return;} +#elif BLOCKTRANSACTIONSREQUEST_DESERIALIZE try { BlockTransactionsRequest btr; ds >> btr; - } catch (const std::ios_base::failure& e) {return 0;} - - break; - } - default: - return 0; - } - return 0; -} - -static std::unique_ptr<ECCVerifyHandle> globalVerifyHandle; -void initialize() { - globalVerifyHandle = MakeUnique<ECCVerifyHandle>(); -} - -// This function is used by libFuzzer -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { - test_one_input(std::vector<uint8_t>(data, data + size)); - return 0; -} - -// This function is used by libFuzzer -extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) { - initialize(); - return 0; -} - -// Disabled under WIN32 due to clash with Cygwin's WinMain. -#ifndef WIN32 -// Declare main(...) "weak" to allow for libFuzzer linking. libFuzzer provides -// the main(...) function. -__attribute__((weak)) -#endif -int main(int argc, char **argv) -{ - initialize(); -#ifdef __AFL_INIT - // Enable AFL deferred forkserver mode. Requires compilation using - // afl-clang-fast++. See fuzzing.md for details. - __AFL_INIT(); -#endif - -#ifdef __AFL_LOOP - // Enable AFL persistent mode. Requires compilation using afl-clang-fast++. - // See fuzzing.md for details. - int ret = 0; - while (__AFL_LOOP(1000)) { - std::vector<uint8_t> buffer; - if (!read_stdin(buffer)) { - continue; - } - ret = test_one_input(buffer); - } - return ret; + } catch (const std::ios_base::failure& e) {return;} #else - std::vector<uint8_t> buffer; - if (!read_stdin(buffer)) { - return 0; - } - return test_one_input(buffer); +#error Need at least one fuzz target to compile #endif } diff --git a/src/test/test_bitcoin_main.cpp b/src/test/test_bitcoin_main.cpp index 6c066d3fea..46b63b93b4 100644 --- a/src/test/test_bitcoin_main.cpp +++ b/src/test/test_bitcoin_main.cpp @@ -4,6 +4,7 @@ #define BOOST_TEST_MODULE Bitcoin Test Suite +#include <banman.h> #include <net.h> #include <memory> @@ -11,6 +12,7 @@ #include <boost/test/unit_test.hpp> std::unique_ptr<CConnman> g_connman; +std::unique_ptr<BanMan> g_banman; [[noreturn]] void Shutdown(void* parg) { diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index d952054483..39cff3f463 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -414,7 +414,8 @@ static void ReplaceRedeemScript(CScript& script, const CScript& redeemScript) script = PushAll(stack); } -BOOST_AUTO_TEST_CASE(test_big_witness_transaction) { +BOOST_AUTO_TEST_CASE(test_big_witness_transaction) +{ CMutableTransaction mtx; mtx.nVersion = 1; @@ -456,9 +457,8 @@ BOOST_AUTO_TEST_CASE(test_big_witness_transaction) { } CDataStream ssout(SER_NETWORK, PROTOCOL_VERSION); - auto vstream = WithOrVersion(&ssout, 0); - vstream << mtx; - CTransaction tx(deserialize, vstream); + ssout << mtx; + CTransaction tx(deserialize, ssout); // check all inputs concurrently, with the cache PrecomputedTransactionData txdata(tx); diff --git a/src/test/txindex_tests.cpp b/src/test/txindex_tests.cpp index 43e025c58f..0301901bf0 100644 --- a/src/test/txindex_tests.cpp +++ b/src/test/txindex_tests.cpp @@ -2,6 +2,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include <chainparams.h> #include <index/txindex.h> #include <script/standard.h> #include <test/test_bitcoin.h> @@ -38,6 +39,12 @@ BOOST_FIXTURE_TEST_CASE(txindex_initial_sync, TestChain100Setup) MilliSleep(100); } + // Check that txindex excludes genesis block transactions. + const CBlock& genesis_block = Params().GenesisBlock(); + for (const auto& txn : genesis_block.vtx) { + BOOST_CHECK(!txindex.FindTx(txn->GetHash(), block_hash, tx_disk)); + } + // Check that txindex has all txs that were in the chain before it started. for (const auto& txn : m_coinbase_txns) { if (!txindex.FindTx(txn->GetHash(), block_hash, tx_disk)) { diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index 9acebdd820..71b6ec7425 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -1224,7 +1224,7 @@ BOOST_AUTO_TEST_CASE(test_ToLower) BOOST_CHECK_EQUAL(ToLower('Z'), 'z'); BOOST_CHECK_EQUAL(ToLower('['), '['); BOOST_CHECK_EQUAL(ToLower(0), 0); - BOOST_CHECK_EQUAL(ToLower(255), 255); + BOOST_CHECK_EQUAL(ToLower('\xff'), '\xff'); std::string testVector; Downcase(testVector); @@ -1246,7 +1246,7 @@ BOOST_AUTO_TEST_CASE(test_ToUpper) BOOST_CHECK_EQUAL(ToUpper('z'), 'Z'); BOOST_CHECK_EQUAL(ToUpper('{'), '{'); BOOST_CHECK_EQUAL(ToUpper(0), 0); - BOOST_CHECK_EQUAL(ToUpper(255), 255); + BOOST_CHECK_EQUAL(ToUpper('\xff'), '\xff'); } BOOST_AUTO_TEST_CASE(test_Capitalize) diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp index c9ee6f9f81..550e23b222 100644 --- a/src/torcontrol.cpp +++ b/src/torcontrol.cpp @@ -527,7 +527,7 @@ void TorController::auth_cb(TorControlConnection& _conn, const TorControlReply& CService resolved(LookupNumeric("127.0.0.1", 9050)); proxyType addrOnion = proxyType(resolved, true); SetProxy(NET_ONION, addrOnion); - SetLimited(NET_ONION, false); + SetReachable(NET_ONION, true); } // Finally - now create the service diff --git a/src/txmempool.h b/src/txmempool.h index fadb554723..f7afaec8fc 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -485,7 +485,43 @@ public: > > indexed_transaction_set; - mutable CCriticalSection cs; + /** + * This mutex needs to be locked when accessing `mapTx` or other members + * that are guarded by it. + * + * @par Consistency guarantees + * + * By design, it is guaranteed that: + * + * 1. Locking both `cs_main` and `mempool.cs` will give a view of mempool + * that is consistent with current chain tip (`chainActive` and + * `pcoinsTip`) and is fully populated. Fully populated means that if the + * current active chain is missing transactions that were present in a + * previously active chain, all the missing transactions will have been + * re-added to the mempool and should be present if they meet size and + * consistency constraints. + * + * 2. Locking `mempool.cs` without `cs_main` will give a view of a mempool + * consistent with some chain that was active since `cs_main` was last + * locked, and that is fully populated as described above. It is ok for + * code that only needs to query or remove transactions from the mempool + * to lock just `mempool.cs` without `cs_main`. + * + * To provide these guarantees, it is necessary to lock both `cs_main` and + * `mempool.cs` whenever adding transactions to the mempool and whenever + * changing the chain tip. It's necessary to keep both mutexes locked until + * the mempool is consistent with the new chain tip and fully populated. + * + * @par Consistency bug + * + * The second guarantee above is not currently enforced, but + * https://github.com/bitcoin/bitcoin/pull/14193 will fix it. No known code + * in bitcoin currently depends on second guarantee, but it is important to + * fix for third party code that needs be able to frequently poll the + * mempool without locking `cs_main` and without encountering missing + * transactions during reorgs. + */ + mutable RecursiveMutex cs; indexed_transaction_set mapTx GUARDED_BY(cs); using txiter = indexed_transaction_set::nth_index<0>::type::const_iterator; @@ -541,8 +577,8 @@ public: // Note that addUnchecked is ONLY called from ATMP outside of tests // and any other callers may break wallet's in-mempool tracking (due to // lack of CValidationInterface::TransactionAddedToMempool callbacks). - void addUnchecked(const CTxMemPoolEntry& entry, bool validFeeEstimate = true) EXCLUSIVE_LOCKS_REQUIRED(cs); - void addUnchecked(const CTxMemPoolEntry& entry, setEntries& setAncestors, bool validFeeEstimate = true) EXCLUSIVE_LOCKS_REQUIRED(cs); + void addUnchecked(const CTxMemPoolEntry& entry, bool validFeeEstimate = true) EXCLUSIVE_LOCKS_REQUIRED(cs, cs_main); + void addUnchecked(const CTxMemPoolEntry& entry, setEntries& setAncestors, bool validFeeEstimate = true) EXCLUSIVE_LOCKS_REQUIRED(cs, cs_main); void removeRecursive(const CTransaction &tx, MemPoolRemovalReason reason = MemPoolRemovalReason::UNKNOWN); void removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMemPoolHeight, int flags) EXCLUSIVE_LOCKS_REQUIRED(cs_main); @@ -594,7 +630,7 @@ public: * for). Note: vHashesToUpdate should be the set of transactions from the * disconnected block that have been accepted back into the mempool. */ - void UpdateTransactionsFromBlock(const std::vector<uint256> &vHashesToUpdate); + void UpdateTransactionsFromBlock(const std::vector<uint256>& vHashesToUpdate) EXCLUSIVE_LOCKS_REQUIRED(cs_main); /** Try to calculate all in-mempool ancestors of entry. * (these are all calculated including the tx itself) @@ -636,7 +672,7 @@ public: */ void GetTransactionAncestry(const uint256& txid, size_t& ancestors, size_t& descendants) const; - unsigned long size() + unsigned long size() const { LOCK(cs); return mapTx.size(); @@ -710,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/uint256.cpp b/src/uint256.cpp index d9da668036..e3bc9712e8 100644 --- a/src/uint256.cpp +++ b/src/uint256.cpp @@ -33,7 +33,7 @@ void base_blob<BITS>::SetHex(const char* psz) psz++; // skip 0x - if (psz[0] == '0' && tolower(psz[1]) == 'x') + if (psz[0] == '0' && ToLower(psz[1]) == 'x') psz += 2; // hex string to uint diff --git a/src/util/moneystr.cpp b/src/util/moneystr.cpp index 4c4de7b729..f4e41eea4f 100644 --- a/src/util/moneystr.cpp +++ b/src/util/moneystr.cpp @@ -20,7 +20,7 @@ std::string FormatMoney(const CAmount& n) // Right-trim excess zeros before the decimal point: int nTrim = 0; - for (int i = str.size()-1; (str[i] == '0' && isdigit(str[i-2])); --i) + for (int i = str.size()-1; (str[i] == '0' && IsDigit(str[i-2])); --i) ++nTrim; if (nTrim) str.erase(str.size()-nTrim, nTrim); @@ -49,7 +49,7 @@ bool ParseMoney(const char* pszIn, CAmount& nRet) { p++; int64_t nMult = COIN / 10; - while (isdigit(*p) && (nMult > 0)) + while (IsDigit(*p) && (nMult > 0)) { nUnits += nMult * (*p++ - '0'); nMult /= 10; @@ -58,7 +58,7 @@ bool ParseMoney(const char* pszIn, CAmount& nRet) } if (IsSpace(*p)) break; - if (!isdigit(*p)) + if (!IsDigit(*p)) return false; strWhole.insert(strWhole.end(), *p); } diff --git a/src/util/strencodings.cpp b/src/util/strencodings.cpp index 46146be66f..fedeeac39b 100644 --- a/src/util/strencodings.cpp +++ b/src/util/strencodings.cpp @@ -589,7 +589,7 @@ bool ParseHDKeypath(const std::string& keypath_str, std::vector<uint32_t>& keypa void Downcase(std::string& str) { - std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c){return ToLower(c);}); + std::transform(str.begin(), str.end(), str.begin(), [](char c){return ToLower(c);}); } std::string Capitalize(std::string str) diff --git a/src/util/strencodings.h b/src/util/strencodings.h index 7d16d7dcfd..e392055f27 100644 --- a/src/util/strencodings.h +++ b/src/util/strencodings.h @@ -15,10 +15,6 @@ #include <string> #include <vector> -#define BEGIN(a) ((char*)&(a)) -#define END(a) ((char*)&((&(a))[1])) -#define UBEGIN(a) ((unsigned char*)&(a)) -#define UEND(a) ((unsigned char*)&((&(a))[1])) #define ARRAYLEN(array) (sizeof(array)/sizeof((array)[0])) /** Used by SanitizeString() */ @@ -212,7 +208,7 @@ NODISCARD bool ParseHDKeypath(const std::string& keypath_str, std::vector<uint32 * @return the lowercase equivalent of c; or the argument * if no conversion is possible. */ -constexpr unsigned char ToLower(unsigned char c) +constexpr char ToLower(char c) { return (c >= 'A' && c <= 'Z' ? (c - 'A') + 'a' : c); } @@ -233,7 +229,7 @@ void Downcase(std::string& str); * @return the uppercase equivalent of c; or the argument * if no conversion is possible. */ -constexpr unsigned char ToUpper(unsigned char c) +constexpr char ToUpper(char c) { return (c >= 'a' && c <= 'z' ? (c - 'a') + 'A' : c); } diff --git a/src/util/system.cpp b/src/util/system.cpp index 8e201ec590..bb9fcab59e 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 @@ -73,9 +68,6 @@ #include <malloc.h> #endif -#include <openssl/crypto.h> -#include <openssl/rand.h> -#include <openssl/conf.h> #include <thread> // Application startup time (used for uptime calculation) @@ -86,54 +78,6 @@ const char * const BITCOIN_PID_FILENAME = "bitcoind.pid"; ArgsManager gArgs; -/** Init OpenSSL library multithreading support */ -static std::unique_ptr<CCriticalSection[]> ppmutexOpenSSL; -void locking_callback(int mode, int i, const char* file, int line) NO_THREAD_SAFETY_ANALYSIS -{ - if (mode & CRYPTO_LOCK) { - ENTER_CRITICAL_SECTION(ppmutexOpenSSL[i]); - } else { - LEAVE_CRITICAL_SECTION(ppmutexOpenSSL[i]); - } -} - -// Singleton for wrapping OpenSSL setup/teardown. -class CInit -{ -public: - CInit() - { - // Init OpenSSL library multithreading support - ppmutexOpenSSL.reset(new CCriticalSection[CRYPTO_num_locks()]); - CRYPTO_set_locking_callback(locking_callback); - - // OpenSSL can optionally load a config file which lists optional loadable modules and engines. - // We don't use them so we don't require the config. However some of our libs may call functions - // which attempt to load the config file, possibly resulting in an exit() or crash if it is missing - // or corrupt. Explicitly tell OpenSSL not to try to load the file. The result for our libs will be - // that the config appears to have been loaded and there are no modules/engines available. - OPENSSL_no_config(); - -#ifdef WIN32 - // Seed OpenSSL PRNG with current contents of the screen - RAND_screen(); -#endif - - // Seed OpenSSL PRNG with performance counter - RandAddSeed(); - } - ~CInit() - { - // Securely erase the memory used by the PRNG - RAND_cleanup(); - // Shutdown OpenSSL library multithreading support - CRYPTO_set_locking_callback(nullptr); - // Clear the set of locks now to maintain symmetry with the constructor. - ppmutexOpenSSL.reset(); - } -} -instance_of_cinit; - /** A map that contains all the currently held directory locks. After * successful locking, these will be held here until the global destructor * cleans them up and thus automatically unlocks them, or ReleaseDirectoryLocks @@ -167,6 +111,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); @@ -443,7 +393,7 @@ bool ArgsManager::ParseParameters(int argc, const char* const argv[], std::strin key.erase(is_index); } #ifdef WIN32 - std::transform(key.begin(), key.end(), key.begin(), ::tolower); + std::transform(key.begin(), key.end(), key.begin(), ToLower); if (key[0] == '/') key[0] = '-'; #endif @@ -749,18 +699,17 @@ fs::path GetDefaultDataDir() #endif } -static fs::path g_blocks_path_cached; static fs::path g_blocks_path_cache_net_specific; static fs::path pathCached; static fs::path pathCachedNetSpecific; static CCriticalSection csPathCached; -const fs::path &GetBlocksDir(bool fNetSpecific) +const fs::path &GetBlocksDir() { LOCK(csPathCached); - fs::path &path = fNetSpecific ? g_blocks_path_cache_net_specific : g_blocks_path_cached; + fs::path &path = g_blocks_path_cache_net_specific; // This can be called during exceptions by LogPrintf(), so we cache the // value so we don't have to do memory allocations after that. @@ -776,9 +725,8 @@ const fs::path &GetBlocksDir(bool fNetSpecific) } else { path = GetDataDir(false); } - if (fNetSpecific) - path /= BaseParams().DataDir(); + path /= BaseParams().DataDir(); path /= "blocks"; fs::create_directories(path); return path; @@ -822,7 +770,6 @@ void ClearDatadirCache() pathCached = fs::path(); pathCachedNetSpecific = fs::path(); - g_blocks_path_cached = fs::path(); g_blocks_path_cache_net_specific = fs::path(); } @@ -865,7 +812,7 @@ static bool GetConfigOptions(std::istream& stream, std::string& error, std::vect } else if ((pos = str.find('=')) != std::string::npos) { std::string name = prefix + TrimString(str.substr(0, pos), pattern); std::string value = TrimString(str.substr(pos + 1), pattern); - if (used_hash && name == "rpcpassword") { + if (used_hash && name.find("rpcpassword") != std::string::npos) { error = strprintf("parse error on line %i, using # in rpcpassword can be ambiguous and should be avoided", linenr); return false; } @@ -1293,7 +1240,7 @@ fs::path AbsPathForConfigVal(const fs::path& path, bool net_specific) int ScheduleBatchPriority() { #ifdef SCHED_BATCH - const static sched_param param{0}; + const static sched_param param{}; if (int ret = pthread_setschedparam(pthread_self(), SCHED_BATCH, ¶m)) { LogPrintf("Failed to pthread_setschedparam: %s\n", strerror(errno)); return ret; diff --git a/src/util/system.h b/src/util/system.h index dca32cc6fc..17723d427d 100644 --- a/src/util/system.h +++ b/src/util/system.h @@ -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 @@ -79,7 +80,8 @@ void ReleaseDirectoryLocks(); bool TryCreateDirectories(const fs::path& p); fs::path GetDefaultDataDir(); -const fs::path &GetBlocksDir(bool fNetSpecific = true); +// The blocks directory is always net specific. +const fs::path &GetBlocksDir(); const fs::path &GetDataDir(bool fNetSpecific = true); void ClearDatadirCache(); fs::path GetConfigFile(const std::string& confPath); diff --git a/src/validation.cpp b/src/validation.cpp index 00d7a60cb7..de9c0d96db 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -173,7 +173,7 @@ public: CCoinsViewCache& view, const CChainParams& chainparams, bool fJustCheck = false) EXCLUSIVE_LOCKS_REQUIRED(cs_main); // Block disconnection on our pcoinsTip: - bool DisconnectTip(CValidationState& state, const CChainParams& chainparams, DisconnectedBlockTransactions *disconnectpool); + bool DisconnectTip(CValidationState& state, const CChainParams& chainparams, DisconnectedBlockTransactions* disconnectpool) EXCLUSIVE_LOCKS_REQUIRED(cs_main); // Manual block validity manipulation: bool PreciousBlock(CValidationState& state, const CChainParams& params, CBlockIndex* pindex) LOCKS_EXCLUDED(cs_main); @@ -210,9 +210,17 @@ private: bool RollforwardBlock(const CBlockIndex* pindex, CCoinsViewCache& inputs, const CChainParams& params) EXCLUSIVE_LOCKS_REQUIRED(cs_main); } g_chainstate; - - -CCriticalSection cs_main; +/** + * Mutex to guard access to validation specific variables, such as reading + * or changing the chainstate. + * + * This may also need to be locked when updating the transaction pool, e.g. on + * AcceptToMemoryPool. See CTxMemPool::cs comment for details. + * + * The transaction pool has a separate lock to allow reading from it and the + * chainstate at the same time. + */ +RecursiveMutex cs_main; BlockMap& mapBlockIndex = g_chainstate.mapBlockIndex; CChain& chainActive = g_chainstate.chainActive; @@ -994,13 +1002,11 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa * Return transaction in txOut, and if it was found inside a block, its hash is placed in hashBlock. * If blockIndex is provided, the transaction is fetched from the corresponding block. */ -bool GetTransaction(const uint256& hash, CTransactionRef& txOut, const Consensus::Params& consensusParams, uint256& hashBlock, bool fAllowSlow, CBlockIndex* blockIndex) +bool GetTransaction(const uint256& hash, CTransactionRef& txOut, const Consensus::Params& consensusParams, uint256& hashBlock, const CBlockIndex* const block_index) { - CBlockIndex* pindexSlow = blockIndex; - LOCK(cs_main); - if (!blockIndex) { + if (!block_index) { CTransactionRef ptx = mempool.get(hash); if (ptx) { txOut = ptx; @@ -1010,20 +1016,13 @@ bool GetTransaction(const uint256& hash, CTransactionRef& txOut, const Consensus if (g_txindex) { return g_txindex->FindTx(hash, hashBlock, txOut); } - - if (fAllowSlow) { // use coin database to locate block that contains transaction, and scan it - const Coin& coin = AccessByTxid(*pcoinsTip, hash); - if (!coin.IsSpent()) pindexSlow = chainActive[coin.nHeight]; - } - } - - if (pindexSlow) { + } else { CBlock block; - if (ReadBlockFromDisk(block, pindexSlow, consensusParams)) { + if (ReadBlockFromDisk(block, block_index, consensusParams)) { for (const auto& tx : block.vtx) { if (tx->GetHash() == hash) { txOut = tx; - hashBlock = pindexSlow->GetBlockHash(); + hashBlock = block_index->GetBlockHash(); return true; } } @@ -3998,7 +3997,7 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview, LogPrintf("[0%%]..."); /* Continued */ for (pindex = chainActive.Tip(); pindex && pindex->pprev; pindex = pindex->pprev) { boost::this_thread::interruption_point(); - int percentageDone = std::max(1, std::min(99, (int)(((double)(chainActive.Height() - pindex->nHeight)) / (double)nCheckDepth * (nCheckLevel >= 4 ? 50 : 100)))); + const int percentageDone = std::max(1, std::min(99, (int)(((double)(chainActive.Height() - pindex->nHeight)) / (double)nCheckDepth * (nCheckLevel >= 4 ? 50 : 100)))); if (reportDone < percentageDone/10) { // report every 10% step LogPrintf("[%d%%]...", percentageDone); /* Continued */ @@ -4056,7 +4055,13 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview, if (nCheckLevel >= 4) { while (pindex != chainActive.Tip()) { boost::this_thread::interruption_point(); - uiInterface.ShowProgress(_("Verifying blocks..."), std::max(1, std::min(99, 100 - (int)(((double)(chainActive.Height() - pindex->nHeight)) / (double)nCheckDepth * 50))), false); + const int percentageDone = std::max(1, std::min(99, 100 - (int)(((double)(chainActive.Height() - pindex->nHeight)) / (double)nCheckDepth * 50))); + if (reportDone < percentageDone/10) { + // report every 10% step + LogPrintf("[%d%%]...", percentageDone); /* Continued */ + reportDone = percentageDone/10; + } + uiInterface.ShowProgress(_("Verifying blocks..."), percentageDone, false); pindex = chainActive.Next(pindex); CBlock block; if (!ReadBlockFromDisk(block, pindex, chainparams.GetConsensus())) diff --git a/src/validation.h b/src/validation.h index b5548a9293..b16d8438d7 100644 --- a/src/validation.h +++ b/src/validation.h @@ -50,7 +50,7 @@ struct LockPoints; /** Default for -whitelistrelay. */ static const bool DEFAULT_WHITELISTRELAY = true; /** Default for -whitelistforcerelay. */ -static const bool DEFAULT_WHITELISTFORCERELAY = true; +static const bool DEFAULT_WHITELISTFORCERELAY = false; /** Default for -minrelaytxfee, minimum relay fee for transactions */ static const unsigned int DEFAULT_MIN_RELAY_TX_FEE = 1000; //! -maxtxfee default @@ -201,14 +201,14 @@ static const unsigned int NODE_NETWORK_LIMITED_MIN_BLOCKS = 288; static const signed int DEFAULT_CHECKBLOCKS = 6; static const unsigned int DEFAULT_CHECKLEVEL = 3; -// Require that user allocate at least 550MB for block & undo files (blk???.dat and rev???.dat) +// Require that user allocate at least 550 MiB for block & undo files (blk???.dat and rev???.dat) // At 1MB per block, 288 blocks = 288MB. // Add 15% for Undo data = 331MB // Add 20% for Orphan block rate = 397MB // We want the low water mark after pruning to be at least 397 MB and since we prune in // full block file chunks, we need the high water mark which triggers the prune to be // one 128MB block file + added 15% undo data = 147MB greater for a total of 545MB -// Setting the target to > than 550MB will make it likely we can respect the target. +// Setting the target to >= 550 MiB will make it likely we can respect the target. static const uint64_t MIN_DISK_SPACE_FOR_BLOCK_FILES = 550 * 1024 * 1024; /** @@ -269,7 +269,7 @@ void ThreadScriptCheck(); /** Check whether we are doing an initial block download (synchronizing from disk or network) */ bool IsInitialBlockDownload(); /** Retrieve a transaction (from memory pool, or from disk, if possible) */ -bool GetTransaction(const uint256& hash, CTransactionRef& tx, const Consensus::Params& params, uint256& hashBlock, bool fAllowSlow = false, CBlockIndex* blockIndex = nullptr); +bool GetTransaction(const uint256& hash, CTransactionRef& tx, const Consensus::Params& params, uint256& hashBlock, const CBlockIndex* const blockIndex = nullptr); /** * Find the best known block, and make it the tip of the block chain * 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 f5ac6e98b2..1dc78255f6 100644 --- a/src/wallet/crypter.cpp +++ b/src/wallet/crypter.cpp @@ -175,7 +175,7 @@ bool CCryptoKeyStore::Lock() return true; } -bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn) +bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn, bool accept_no_keys) { { LOCK(cs_KeyStore); @@ -204,7 +204,7 @@ bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn) LogPrintf("The wallet is probably corrupted: Some keys decrypt but not all.\n"); throw std::runtime_error("Error unlocking wallet: some keys decrypt but not all. Your wallet file may be corrupt."); } - if (keyFail || !keyPass) + if (keyFail || (!keyPass && !accept_no_keys)) return false; vMasterKey = vMasterKeyIn; fDecryptionThoroughlyChecked = true; diff --git a/src/wallet/crypter.h b/src/wallet/crypter.h index 418316c398..8e195ca8fa 100644 --- a/src/wallet/crypter.h +++ b/src/wallet/crypter.h @@ -133,7 +133,7 @@ protected: //! will encrypt previously unencrypted keys bool EncryptKeys(CKeyingMaterial& vMasterKeyIn); - bool Unlock(const CKeyingMaterial& vMasterKeyIn); + bool Unlock(const CKeyingMaterial& vMasterKeyIn, bool accept_no_keys = false); CryptedKeyMap mapCryptedKeys GUARDED_BY(cs_KeyStore); public: diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp index 98e2abbd18..c64a85c910 100644 --- a/src/wallet/db.cpp +++ b/src/wallet/db.cpp @@ -48,7 +48,7 @@ void CheckUniqueFileid(const BerkeleyEnvironment& env, const std::string& filena } CCriticalSection cs_db; -std::map<std::string, BerkeleyEnvironment> g_dbenvs GUARDED_BY(cs_db); //!< Map from directory name to open db environment. +std::map<std::string, std::weak_ptr<BerkeleyEnvironment>> g_dbenvs GUARDED_BY(cs_db); //!< Map from directory name to db environment. } // namespace bool WalletDatabaseFileId::operator==(const WalletDatabaseFileId& rhs) const @@ -80,19 +80,29 @@ bool IsWalletLoaded(const fs::path& wallet_path) LOCK(cs_db); auto env = g_dbenvs.find(env_directory.string()); if (env == g_dbenvs.end()) return false; - return env->second.IsDatabaseLoaded(database_filename); + auto database = env->second.lock(); + return database && database->IsDatabaseLoaded(database_filename); } -BerkeleyEnvironment* GetWalletEnv(const fs::path& wallet_path, std::string& database_filename) +/** + * @param[in] wallet_path Path to wallet directory. Or (for backwards compatibility only) a path to a berkeley btree data file inside a wallet directory. + * @param[out] database_filename Filename of berkeley btree data file inside the wallet directory. + * @return A shared pointer to the BerkeleyEnvironment object for the wallet directory, never empty because ~BerkeleyEnvironment + * erases the weak pointer from the g_dbenvs map. + * @post A new BerkeleyEnvironment weak pointer is inserted into g_dbenvs if the directory path key was not already in the map. + */ +std::shared_ptr<BerkeleyEnvironment> GetWalletEnv(const fs::path& wallet_path, std::string& database_filename) { fs::path env_directory; SplitWalletPath(wallet_path, env_directory, database_filename); LOCK(cs_db); - // Note: An unused temporary BerkeleyEnvironment object may be created inside the - // emplace function if the key already exists. This is a little inefficient, - // but not a big concern since the map will be changed in the future to hold - // pointers instead of objects, anyway. - return &g_dbenvs.emplace(std::piecewise_construct, std::forward_as_tuple(env_directory.string()), std::forward_as_tuple(env_directory)).first->second; + auto inserted = g_dbenvs.emplace(env_directory.string(), std::weak_ptr<BerkeleyEnvironment>()); + if (inserted.second) { + auto env = std::make_shared<BerkeleyEnvironment>(env_directory.string()); + inserted.first->second = env; + return env; + } + return inserted.first->second.lock(); } // @@ -116,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() @@ -137,6 +154,8 @@ BerkeleyEnvironment::BerkeleyEnvironment(const fs::path& dir_path) : strPath(dir BerkeleyEnvironment::~BerkeleyEnvironment() { + LOCK(cs_db); + g_dbenvs.erase(strPath); Close(); } @@ -214,10 +233,10 @@ bool BerkeleyEnvironment::Open(bool retry) return true; } -void BerkeleyEnvironment::MakeMock() +//! Construct an in-memory mock Berkeley environment for testing and as a place-holder for g_dbenvs emplace +BerkeleyEnvironment::BerkeleyEnvironment() { - if (fDbEnvInit) - throw std::runtime_error("BerkeleyEnvironment::MakeMock: Already initialized"); + Reset(); boost::this_thread::interruption_point(); @@ -263,10 +282,49 @@ BerkeleyEnvironment::VerifyResult BerkeleyEnvironment::Verify(const std::string& return (fRecovered ? VerifyResult::RECOVER_OK : VerifyResult::RECOVER_FAIL); } +BerkeleyBatch::SafeDbt::SafeDbt() +{ + m_dbt.set_flags(DB_DBT_MALLOC); +} + +BerkeleyBatch::SafeDbt::SafeDbt(void* data, size_t size) + : m_dbt(data, size) +{ +} + +BerkeleyBatch::SafeDbt::~SafeDbt() +{ + if (m_dbt.get_data() != nullptr) { + // Clear memory, e.g. in case it was a private key + memory_cleanse(m_dbt.get_data(), m_dbt.get_size()); + // under DB_DBT_MALLOC, data is malloced by the Dbt, but must be + // freed by the caller. + // https://docs.oracle.com/cd/E17275_01/html/api_reference/C/dbt.html + if (m_dbt.get_flags() & DB_DBT_MALLOC) { + free(m_dbt.get_data()); + } + } +} + +const void* BerkeleyBatch::SafeDbt::get_data() const +{ + return m_dbt.get_data(); +} + +u_int32_t BerkeleyBatch::SafeDbt::get_size() const +{ + return m_dbt.get_size(); +} + +BerkeleyBatch::SafeDbt::operator Dbt*() +{ + return &m_dbt; +} + bool BerkeleyBatch::Recover(const fs::path& file_path, void *callbackDataIn, bool (*recoverKVcallback)(void* callbackData, CDataStream ssKey, CDataStream ssValue), std::string& newFilename) { std::string filename; - BerkeleyEnvironment* env = GetWalletEnv(file_path, filename); + std::shared_ptr<BerkeleyEnvironment> env = GetWalletEnv(file_path, filename); // Recovery procedure: // move wallet file to walletfilename.timestamp.bak @@ -335,10 +393,10 @@ bool BerkeleyBatch::Recover(const fs::path& file_path, void *callbackDataIn, boo bool BerkeleyBatch::VerifyEnvironment(const fs::path& file_path, std::string& errorStr) { std::string walletFile; - BerkeleyEnvironment* env = GetWalletEnv(file_path, walletFile); + std::shared_ptr<BerkeleyEnvironment> env = GetWalletEnv(file_path, walletFile); fs::path walletDir = env->Directory(); - LogPrintf("Using BerkeleyDB version %s\n", DbEnv::version(0, 0, 0)); + LogPrintf("Using BerkeleyDB version %s\n", DbEnv::version(nullptr, nullptr, nullptr)); LogPrintf("Using wallet %s\n", walletFile); // Wallet file must be a plain filename without a directory @@ -359,7 +417,7 @@ bool BerkeleyBatch::VerifyEnvironment(const fs::path& file_path, std::string& er bool BerkeleyBatch::VerifyDatabaseFile(const fs::path& file_path, std::string& warningStr, std::string& errorStr, BerkeleyEnvironment::recoverFunc_type recoverFunc) { std::string walletFile; - BerkeleyEnvironment* env = GetWalletEnv(file_path, walletFile); + std::shared_ptr<BerkeleyEnvironment> env = GetWalletEnv(file_path, walletFile); fs::path walletDir = env->Directory(); if (fs::exists(walletDir / walletFile)) @@ -463,7 +521,7 @@ BerkeleyBatch::BerkeleyBatch(BerkeleyDatabase& database, const char* pszMode, bo { fReadOnly = (!strchr(pszMode, '+') && !strchr(pszMode, 'w')); fFlushOnClose = fFlushOnCloseIn; - env = database.env; + env = database.env.get(); if (database.IsDummy()) { return; } @@ -520,7 +578,7 @@ BerkeleyBatch::BerkeleyBatch(BerkeleyDatabase& database, const char* pszMode, bo // versions of BDB have an set_lk_exclusive method for this // purpose, but the older version we use does not.) for (const auto& env : g_dbenvs) { - CheckUniqueFileid(env.second, strFilename, *pdb_temp, this->env->m_fileids[strFilename]); + CheckUniqueFileid(*env.second.lock().get(), strFilename, *pdb_temp, this->env->m_fileids[strFilename]); } pdb = pdb_temp.release(); @@ -621,7 +679,7 @@ bool BerkeleyBatch::Rewrite(BerkeleyDatabase& database, const char* pszSkip) if (database.IsDummy()) { return true; } - BerkeleyEnvironment *env = database.env; + BerkeleyEnvironment *env = database.env.get(); const std::string& strFile = database.strFile; while (true) { { @@ -752,7 +810,7 @@ bool BerkeleyBatch::PeriodicFlush(BerkeleyDatabase& database) return true; } bool ret = false; - BerkeleyEnvironment *env = database.env; + BerkeleyEnvironment *env = database.env.get(); const std::string& strFile = database.strFile; TRY_LOCK(cs_db, lockDb); if (lockDb) diff --git a/src/wallet/db.h b/src/wallet/db.h index e453d441d7..9df965305a 100644 --- a/src/wallet/db.h +++ b/src/wallet/db.h @@ -50,10 +50,10 @@ public: std::condition_variable_any m_db_in_use; BerkeleyEnvironment(const fs::path& env_directory); + BerkeleyEnvironment(); ~BerkeleyEnvironment(); void Reset(); - void MakeMock(); bool IsMock() const { return fMockDb; } bool IsInitialized() const { return fDbEnvInit; } bool IsDatabaseLoaded(const std::string& db_filename) const { return m_databases.find(db_filename) != m_databases.end(); } @@ -102,7 +102,7 @@ public: bool IsWalletLoaded(const fs::path& wallet_path); /** Get BerkeleyEnvironment and database filename given a wallet path. */ -BerkeleyEnvironment* GetWalletEnv(const fs::path& wallet_path, std::string& database_filename); +std::shared_ptr<BerkeleyEnvironment> GetWalletEnv(const fs::path& wallet_path, std::string& database_filename); /** An instance of this class represents one database. * For BerkeleyDB this is just a (env, strFile) tuple. @@ -117,17 +117,11 @@ public: } /** Create DB handle to real database */ - BerkeleyDatabase(const fs::path& wallet_path, bool mock = false) : - nUpdateCounter(0), nLastSeen(0), nLastFlushed(0), nLastWalletUpdate(0) + BerkeleyDatabase(std::shared_ptr<BerkeleyEnvironment> env, std::string filename) : + nUpdateCounter(0), nLastSeen(0), nLastFlushed(0), nLastWalletUpdate(0), env(std::move(env)), strFile(std::move(filename)) { - env = GetWalletEnv(wallet_path, strFile); - auto inserted = env->m_databases.emplace(strFile, std::ref(*this)); + auto inserted = this->env->m_databases.emplace(strFile, std::ref(*this)); assert(inserted.second); - if (mock) { - env->Close(); - env->Reset(); - env->MakeMock(); - } } ~BerkeleyDatabase() { @@ -140,7 +134,8 @@ public: /** Return object for accessing database at specified path. */ static std::unique_ptr<BerkeleyDatabase> Create(const fs::path& path) { - return MakeUnique<BerkeleyDatabase>(path); + std::string filename; + return MakeUnique<BerkeleyDatabase>(GetWalletEnv(path, filename), std::move(filename)); } /** Return object for accessing dummy database with no read/write capabilities. */ @@ -152,7 +147,7 @@ public: /** Return object for accessing temporary in-memory database. */ static std::unique_ptr<BerkeleyDatabase> CreateMock() { - return MakeUnique<BerkeleyDatabase>("", true /* mock */); + return MakeUnique<BerkeleyDatabase>(std::make_shared<BerkeleyEnvironment>(), ""); } /** Rewrite the entire database on disk, with the exception of key pszSkip if non-zero @@ -176,12 +171,21 @@ public: unsigned int nLastFlushed; int64_t nLastWalletUpdate; + /** + * Pointer to shared database environment. + * + * Normally there is only one BerkeleyDatabase object per + * BerkeleyEnvivonment, but in the special, backwards compatible case where + * multiple wallet BDB data files are loaded from the same directory, this + * will point to a shared instance that gets freed when the last data file + * is closed. + */ + std::shared_ptr<BerkeleyEnvironment> env; + /** Database pointer. This is initialized lazily and reset during flushes, so it can be null. */ std::unique_ptr<Db> m_db; private: - /** BerkeleyDB specific */ - BerkeleyEnvironment *env; std::string strFile; /** Return whether this database handle is a dummy for testing. @@ -191,10 +195,29 @@ private: bool IsDummy() { return env == nullptr; } }; - /** RAII class that provides access to a Berkeley database */ class BerkeleyBatch { + /** RAII class that automatically cleanses its data on destruction */ + class SafeDbt final + { + Dbt m_dbt; + + public: + // construct Dbt with internally-managed data + SafeDbt(); + // construct Dbt with provided data + SafeDbt(void* data, size_t size); + ~SafeDbt(); + + // delegate to Dbt + const void* get_data() const; + u_int32_t get_size() const; + + // conversion operator to access the underlying Dbt + operator Dbt*(); + }; + protected: Db* pdb; std::string strFile; @@ -222,7 +245,6 @@ public: /* verifies the database file */ static bool VerifyDatabaseFile(const fs::path& file_path, std::string& warningStr, std::string& errorStr, BerkeleyEnvironment::recoverFunc_type recoverFunc); -public: template <typename K, typename T> bool Read(const K& key, T& value) { @@ -233,13 +255,11 @@ public: CDataStream ssKey(SER_DISK, CLIENT_VERSION); ssKey.reserve(1000); ssKey << key; - Dbt datKey(ssKey.data(), ssKey.size()); + SafeDbt datKey(ssKey.data(), ssKey.size()); // Read - Dbt datValue; - datValue.set_flags(DB_DBT_MALLOC); - int ret = pdb->get(activeTxn, &datKey, &datValue, 0); - memory_cleanse(datKey.get_data(), datKey.get_size()); + SafeDbt datValue; + int ret = pdb->get(activeTxn, datKey, datValue, 0); bool success = false; if (datValue.get_data() != nullptr) { // Unserialize value @@ -250,10 +270,6 @@ public: } catch (const std::exception&) { // In this case success remains 'false' } - - // Clear and free memory - memory_cleanse(datValue.get_data(), datValue.get_size()); - free(datValue.get_data()); } return ret == 0 && success; } @@ -270,20 +286,16 @@ public: CDataStream ssKey(SER_DISK, CLIENT_VERSION); ssKey.reserve(1000); ssKey << key; - Dbt datKey(ssKey.data(), ssKey.size()); + SafeDbt datKey(ssKey.data(), ssKey.size()); // Value CDataStream ssValue(SER_DISK, CLIENT_VERSION); ssValue.reserve(10000); ssValue << value; - Dbt datValue(ssValue.data(), ssValue.size()); + SafeDbt datValue(ssValue.data(), ssValue.size()); // Write - int ret = pdb->put(activeTxn, &datKey, &datValue, (fOverwrite ? 0 : DB_NOOVERWRITE)); - - // Clear memory in case it was a private key - memory_cleanse(datKey.get_data(), datKey.get_size()); - memory_cleanse(datValue.get_data(), datValue.get_size()); + int ret = pdb->put(activeTxn, datKey, datValue, (fOverwrite ? 0 : DB_NOOVERWRITE)); return (ret == 0); } @@ -299,13 +311,10 @@ public: CDataStream ssKey(SER_DISK, CLIENT_VERSION); ssKey.reserve(1000); ssKey << key; - Dbt datKey(ssKey.data(), ssKey.size()); + SafeDbt datKey(ssKey.data(), ssKey.size()); // Erase - int ret = pdb->del(activeTxn, &datKey, 0); - - // Clear memory - memory_cleanse(datKey.get_data(), datKey.get_size()); + int ret = pdb->del(activeTxn, datKey, 0); return (ret == 0 || ret == DB_NOTFOUND); } @@ -319,13 +328,10 @@ public: CDataStream ssKey(SER_DISK, CLIENT_VERSION); ssKey.reserve(1000); ssKey << key; - Dbt datKey(ssKey.data(), ssKey.size()); + SafeDbt datKey(ssKey.data(), ssKey.size()); // Exists - int ret = pdb->exists(activeTxn, &datKey, 0); - - // Clear memory - memory_cleanse(datKey.get_data(), datKey.get_size()); + int ret = pdb->exists(activeTxn, datKey, 0); return (ret == 0); } @@ -340,20 +346,12 @@ public: return pcursor; } - int ReadAtCursor(Dbc* pcursor, CDataStream& ssKey, CDataStream& ssValue, bool setRange = false) + int ReadAtCursor(Dbc* pcursor, CDataStream& ssKey, CDataStream& ssValue) { // Read at cursor - Dbt datKey; - unsigned int fFlags = DB_NEXT; - if (setRange) { - datKey.set_data(ssKey.data()); - datKey.set_size(ssKey.size()); - fFlags = DB_SET_RANGE; - } - Dbt datValue; - datKey.set_flags(DB_DBT_MALLOC); - datValue.set_flags(DB_DBT_MALLOC); - int ret = pcursor->get(&datKey, &datValue, fFlags); + SafeDbt datKey; + SafeDbt datValue; + int ret = pcursor->get(datKey, datValue, DB_NEXT); if (ret != 0) return ret; else if (datKey.get_data() == nullptr || datValue.get_data() == nullptr) @@ -366,16 +364,9 @@ public: ssValue.SetType(SER_DISK); ssValue.clear(); ssValue.write((char*)datValue.get_data(), datValue.get_size()); - - // Clear and free memory - memory_cleanse(datKey.get_data(), datKey.get_size()); - memory_cleanse(datValue.get_data(), datValue.get_size()); - free(datKey.get_data()); - free(datValue.get_data()); return 0; } -public: bool TxnBegin() { if (!pdb || activeTxn) diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp index 14d811c6cd..87cd264c3d 100644 --- a/src/wallet/init.cpp +++ b/src/wallet/init.cpp @@ -242,7 +242,11 @@ void StopWallets() void UnloadWallets() { - for (const std::shared_ptr<CWallet>& pwallet : GetWallets()) { - RemoveWallet(pwallet); + auto wallets = GetWallets(); + while (!wallets.empty()) { + auto wallet = wallets.back(); + wallets.pop_back(); + RemoveWallet(wallet); + UnloadWallet(std::move(wallet)); } } diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index ed1e2d3940..32c36ceaeb 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -111,16 +111,16 @@ UniValue importprivkey(const JSONRPCRequest& request) throw std::runtime_error( RPCHelpMan{"importprivkey", "\nAdds a private key (as returned by dumpprivkey) to your wallet. Requires a new wallet backup.\n" - "Hint: use importmulti to import more than one private key.\n", + "Hint: use importmulti to import more than one private key.\n" + "\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"}, - }} - .ToString() + - "\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" - "\nExamples:\n" + }, + RPCResults{}, + RPCExamples{ "\nDump a private key\n" + HelpExampleCli("dumpprivkey", "\"myaddress\"") + "\nImport the private key with rescan\n" @@ -131,8 +131,12 @@ UniValue importprivkey(const JSONRPCRequest& request) + HelpExampleCli("importprivkey", "\"mykey\" \"\" false") + "\nAs a JSON-RPC call\n" + HelpExampleRpc("importprivkey", "\"mykey\", \"testing\", false") - ); + }, + }.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; @@ -209,16 +213,18 @@ UniValue abortrescan(const JSONRPCRequest& request) if (request.fHelp || request.params.size() > 0) throw std::runtime_error( RPCHelpMan{"abortrescan", - "\nStops current wallet rescan triggered by an RPC call, e.g. by an importprivkey call.\n", {}} - .ToString() + - "\nExamples:\n" + "\nStops current wallet rescan triggered by an RPC call, e.g. by an importprivkey call.\n", + {}, + RPCResults{}, + RPCExamples{ "\nImport a private key\n" + HelpExampleCli("importprivkey", "\"mykey\"") + "\nAbort the running wallet rescan\n" + HelpExampleCli("abortrescan", "") + "\nAs a JSON-RPC call\n" + HelpExampleRpc("abortrescan", "") - ); + }, + }.ToString()); if (!pwallet->IsScanning() || pwallet->IsAbortingRescan()) return false; pwallet->AbortRescan(); @@ -272,27 +278,28 @@ UniValue importaddress(const JSONRPCRequest& request) if (request.fHelp || request.params.size() < 1 || request.params.size() > 4) throw std::runtime_error( RPCHelpMan{"importaddress", - "\nAdds an address or script (in hex) that can be watched as if it were in your wallet but cannot be used to spend. Requires a new wallet backup.\n", + "\nAdds an address or script (in hex) that can be watched as if it were in your wallet but cannot be used to spend. Requires a new wallet backup.\n" + "\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 address exists but related transactions are still missing, leading to temporarily incorrect/bogus balances and unspent outputs until rescan completes.\n" + "If you have the full public key, you should call importpubkey instead of this.\n" + "\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"}, - }} - .ToString() + - "\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 address exists but related transactions are still missing, leading to temporarily incorrect/bogus balances and unspent outputs until rescan completes.\n" - "If you have the full public key, you should call importpubkey instead of this.\n" - "\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" - "\nExamples:\n" + }, + RPCResults{}, + RPCExamples{ "\nImport an address with rescan\n" + HelpExampleCli("importaddress", "\"myaddress\"") + "\nImport using a label without rescan\n" + HelpExampleCli("importaddress", "\"myaddress\" \"testing\" false") + "\nAs a JSON-RPC call\n" + HelpExampleRpc("importaddress", "\"myaddress\", \"testing\", false") - ); + }, + }.ToString()); std::string strLabel; @@ -358,8 +365,10 @@ UniValue importprunedfunds(const JSONRPCRequest& request) { {"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"}, - }} - .ToString() + }, + RPCResults{}, + RPCExamples{""}, + }.ToString() ); CMutableTransaction tx; @@ -379,8 +388,7 @@ UniValue importprunedfunds(const JSONRPCRequest& request) if (merkleBlock.txn.ExtractMatches(vMatch, vIndex) == merkleBlock.header.hashMerkleRoot) { auto locked_chain = pwallet->chain().lock(); - const CBlockIndex* pindex = LookupBlockIndex(merkleBlock.header.GetHash()); - if (!pindex || !chainActive.Contains(pindex)) { + if (locked_chain->getBlockHeight(merkleBlock.header.GetHash()) == nullopt) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found in chain"); } @@ -423,13 +431,14 @@ UniValue removeprunedfunds(const JSONRPCRequest& request) "\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"}, - }} - .ToString() + - "\nExamples:\n" - + HelpExampleCli("removeprunedfunds", "\"a8d0c0184dde994a09ec054286f1ce581bebf46446a512166eae7628734ea0a5\"") + + }, + RPCResults{}, + RPCExamples{ + HelpExampleCli("removeprunedfunds", "\"a8d0c0184dde994a09ec054286f1ce581bebf46446a512166eae7628734ea0a5\"") + "\nAs a JSON-RPC call\n" + HelpExampleRpc("removeprunedfunds", "\"a8d0c0184dde994a09ec054286f1ce581bebf46446a512166eae7628734ea0a5\"") - ); + }, + }.ToString()); auto locked_chain = pwallet->chain().lock(); LOCK(pwallet->cs_wallet); @@ -461,23 +470,24 @@ UniValue importpubkey(const JSONRPCRequest& request) if (request.fHelp || request.params.size() < 1 || request.params.size() > 3) throw std::runtime_error( RPCHelpMan{"importpubkey", - "\nAdds a public key (in hex) that can be watched as if it were in your wallet but cannot be used to spend. Requires a new wallet backup.\n", + "\nAdds a public key (in hex) that can be watched as if it were in your wallet but cannot be used to spend. Requires a new wallet backup.\n" + "\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"}, - }} - .ToString() + - "\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" - "\nExamples:\n" + }, + RPCResults{}, + RPCExamples{ "\nImport a public key with rescan\n" + HelpExampleCli("importpubkey", "\"mypubkey\"") + "\nImport using a label without rescan\n" + HelpExampleCli("importpubkey", "\"mypubkey\" \"testing\" false") + "\nAs a JSON-RPC call\n" + HelpExampleRpc("importpubkey", "\"mypubkey\", \"testing\", false") - ); + }, + }.ToString()); std::string strLabel; @@ -538,16 +548,17 @@ UniValue importwallet(const JSONRPCRequest& request) "\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"}, - }} - .ToString() + - "\nExamples:\n" + }, + RPCResults{}, + RPCExamples{ "\nDump the wallet\n" + HelpExampleCli("dumpwallet", "\"test\"") + "\nImport the wallet\n" + HelpExampleCli("importwallet", "\"test\"") + "\nImport using the json rpc call\n" + HelpExampleRpc("importwallet", "\"test\"") - ); + }, + }.ToString()); if (fPruneMode) throw JSONRPCError(RPC_WALLET_ERROR, "Importing wallets is disabled in pruned mode"); @@ -570,7 +581,8 @@ UniValue importwallet(const JSONRPCRequest& request) if (!file.is_open()) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file"); } - nTimeBegin = chainActive.Tip()->GetBlockTime(); + Optional<int> tip_height = locked_chain->getHeight(); + nTimeBegin = tip_height ? locked_chain->getBlockTime(*tip_height) : 0; int64_t nFilesize = std::max((int64_t)1, (int64_t)file.tellg()); file.seekg(0, file.beg); @@ -578,8 +590,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] == '#') @@ -591,13 +605,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; @@ -613,36 +620,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); } @@ -671,15 +709,16 @@ UniValue dumpprivkey(const JSONRPCRequest& request) "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"}, - }} - .ToString() + - "\nResult:\n" + }, + RPCResult{ "\"key\" (string) The private key\n" - "\nExamples:\n" - + HelpExampleCli("dumpprivkey", "\"myaddress\"") + }, + RPCExamples{ + HelpExampleCli("dumpprivkey", "\"myaddress\"") + HelpExampleCli("importprivkey", "\"mykey\"") + HelpExampleRpc("dumpprivkey", "\"myaddress\"") - ); + }, + }.ToString()); auto locked_chain = pwallet->chain().lock(); LOCK(pwallet->cs_wallet); @@ -720,16 +759,17 @@ UniValue dumpwallet(const JSONRPCRequest& request) "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)"}, - }} - .ToString() + - "\nResult:\n" + }, + RPCResult{ "{ (json object)\n" " \"filename\" : { (string) The filename with full absolute path\n" "}\n" - "\nExamples:\n" - + HelpExampleCli("dumpwallet", "\"test\"") + }, + RPCExamples{ + HelpExampleCli("dumpwallet", "\"test\"") + HelpExampleRpc("dumpwallet", "\"test\"") - ); + }, + }.ToString()); auto locked_chain = pwallet->chain().lock(); LOCK(pwallet->cs_wallet); @@ -773,8 +813,9 @@ UniValue dumpwallet(const JSONRPCRequest& request) // produce output file << strprintf("# Wallet dump created by Bitcoin %s\n", CLIENT_BUILD); file << strprintf("# * Created on %s\n", FormatISO8601DateTime(GetTime())); - file << strprintf("# * Best block at time of backup was %i (%s),\n", chainActive.Height(), chainActive.Tip()->GetBlockHash().ToString()); - file << strprintf("# mined on %s\n", FormatISO8601DateTime(chainActive.Tip()->GetBlockTime())); + const Optional<int> tip_height = locked_chain->getHeight(); + 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"; // add the base58check encoded extended master if the wallet uses HD @@ -849,9 +890,9 @@ struct ImportData enum class ScriptContext { - TOP, //! Top-level scriptPubKey - P2SH, //! P2SH redeemScript - WITNESS_V0, //! P2WSH witnessScript + TOP, //!< Top-level scriptPubKey + P2SH, //!< P2SH redeemScript + WITNESS_V0, //!< P2WSH witnessScript }; // Analyse the provided scriptPubKey, determining which keys and which redeem scripts from the ImportData struct are needed to spend it, and mark them as used. @@ -946,6 +987,11 @@ static UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, con const bool watchOnly = data.exists("watchonly") ? data["watchonly"].get_bool() : false; const std::string& label = data.exists("label") ? data["label"].get_str() : ""; + // If private keys are disabled, abort if private keys are being imported + if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) && !keys.isNull()) { + throw JSONRPCError(RPC_WALLET_ERROR, "Cannot import private keys to a wallet with private keys disabled"); + } + // Generate the script and destination for the scriptPubKey provided CScript script; CTxDestination dest; @@ -1148,7 +1194,11 @@ UniValue importmulti(const JSONRPCRequest& mainRequest) if (mainRequest.fHelp || mainRequest.params.size() < 1 || mainRequest.params.size() > 2) throw std::runtime_error( RPCHelpMan{"importmulti", - "\nImport addresses/scripts (with private or public keys, redeem script (P2SH)), rescanning all addresses in one-shot-only (rescan can be disabled via options). Requires a new wallet backup.\n", + "\nImport addresses/scripts (with private or public keys, redeem script (P2SH)), optionally rescanning the blockchain from the earliest creation time of the imported scripts. Requires a new wallet backup.\n" + "If an address/script is imported without all of the private keys required to spend from that address, it will be watchonly. The 'watchonly' option must be set to true in this case or a warning will be returned.\n" + "Conversely, if all the private keys are provided and the address/script is spendable, the watchonly option must be set to false, or a warning will be returned.\n" + "\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", { @@ -1178,7 +1228,7 @@ UniValue importmulti(const JSONRPCRequest& mainRequest) } }, {"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 watched even when not all private keys are provided."}, + {"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"}, }, }, @@ -1189,17 +1239,18 @@ UniValue importmulti(const JSONRPCRequest& mainRequest) {"rescan", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "true", "Stating if should rescan the blockchain after all imports"}, }, "\"options\""}, - }} - .ToString() + - "\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" - "\nExamples:\n" + - HelpExampleCli("importmulti", "'[{ \"scriptPubKey\": { \"address\": \"<my address>\" }, \"timestamp\":1455191478 }, " - "{ \"scriptPubKey\": { \"address\": \"<my 2nd address>\" }, \"label\": \"example 2\", \"timestamp\": 1455191480 }]'") + - HelpExampleCli("importmulti", "'[{ \"scriptPubKey\": { \"address\": \"<my address>\" }, \"timestamp\":1455191478 }]' '{ \"rescan\": false}'") + - + }, + RPCResult{ "\nResponse is an array with the same size as the input that has the execution result :\n" - " [{\"success\": true}, {\"success\": true, \"warnings\": [\"Ignoring irrelevant private key\"]}, {\"success\": false, \"error\": {\"code\": -1, \"message\": \"Internal Server Error\"}}, ...]\n"); + " [{\"success\": true}, {\"success\": true, \"warnings\": [\"Ignoring irrelevant private key\"]}, {\"success\": false, \"error\": {\"code\": -1, \"message\": \"Internal Server Error\"}}, ...]\n" + }, + RPCExamples{ + HelpExampleCli("importmulti", "'[{ \"scriptPubKey\": { \"address\": \"<my address>\" }, \"timestamp\":1455191478 }, " + "{ \"scriptPubKey\": { \"address\": \"<my 2nd address>\" }, \"label\": \"example 2\", \"timestamp\": 1455191480 }]'") + + HelpExampleCli("importmulti", "'[{ \"scriptPubKey\": { \"address\": \"<my address>\" }, \"timestamp\":1455191478 }]' '{ \"rescan\": false}'") + }, + }.ToString() + ); RPCTypeCheck(mainRequest.params, {UniValue::VARR, UniValue::VOBJ}); @@ -1232,15 +1283,16 @@ UniValue importmulti(const JSONRPCRequest& mainRequest) EnsureWalletIsUnlocked(pwallet); // Verify all timestamps are present before importing any keys. - now = chainActive.Tip() ? chainActive.Tip()->GetMedianTimePast() : 0; + const Optional<int> tip_height = locked_chain->getHeight(); + now = tip_height ? locked_chain->getBlockMedianTimePast(*tip_height) : 0; for (const UniValue& data : requests.getValues()) { GetImportTimestamp(data, now); } const int64_t minimumTimestamp = 1; - if (fRescan && chainActive.Tip()) { - nLowestTimestamp = chainActive.Tip()->GetBlockTime(); + if (fRescan && tip_height) { + nLowestTimestamp = locked_chain->getBlockTime(*tip_height); } else { fRescan = false; } diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index c1cdd0b2ee..e38ad3a0ba 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -102,7 +102,10 @@ static void WalletTxToJSON(interfaces::Chain& chain, interfaces::Chain::Lock& lo { entry.pushKV("blockhash", wtx.hashBlock.GetHex()); entry.pushKV("blockindex", wtx.nIndex); - entry.pushKV("blocktime", LookupBlockIndex(wtx.hashBlock)->GetBlockTime()); + int64_t block_time; + bool found_block = chain.findBlock(wtx.hashBlock, nullptr /* block */, &block_time); + assert(found_block); + entry.pushKV("blocktime", block_time); } else { entry.pushKV("trusted", wtx.IsTrusted(locked_chain)); } @@ -157,14 +160,15 @@ static UniValue getnewaddress(const JSONRPCRequest& request) { {"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\"."}, - }} - .ToString() + - "\nResult:\n" + }, + RPCResult{ "\"address\" (string) The new bitcoin address\n" - "\nExamples:\n" - + HelpExampleCli("getnewaddress", "") + }, + RPCExamples{ + HelpExampleCli("getnewaddress", "") + HelpExampleRpc("getnewaddress", "") - ); + }, + }.ToString()); if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) { throw JSONRPCError(RPC_WALLET_ERROR, "Error: Private keys are disabled for this wallet"); @@ -217,14 +221,15 @@ static UniValue getrawchangeaddress(const JSONRPCRequest& request) "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\"."}, - }} - .ToString() + - "\nResult:\n" + }, + RPCResult{ "\"address\" (string) The address\n" - "\nExamples:\n" - + HelpExampleCli("getrawchangeaddress", "") + }, + RPCExamples{ + HelpExampleCli("getrawchangeaddress", "") + HelpExampleRpc("getrawchangeaddress", "") - ); + }, + }.ToString()); if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) { throw JSONRPCError(RPC_WALLET_ERROR, "Error: Private keys are disabled for this wallet"); @@ -273,12 +278,13 @@ static UniValue setlabel(const JSONRPCRequest& request) { {"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."}, - }} - .ToString() + - "\nExamples:\n" - + HelpExampleCli("setlabel", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"tabby\"") + }, + RPCResults{}, + RPCExamples{ + HelpExampleCli("setlabel", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"tabby\"") + HelpExampleRpc("setlabel", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\", \"tabby\"") - ); + }, + }.ToString()); LOCK(pwallet->cs_wallet); @@ -369,16 +375,17 @@ static UniValue sendtoaddress(const JSONRPCRequest& request) " \"UNSET\"\n" " \"ECONOMICAL\"\n" " \"CONSERVATIVE\""}, - }} - .ToString() + - "\nResult:\n" + }, + RPCResult{ "\"txid\" (string) The transaction id.\n" - "\nExamples:\n" - + HelpExampleCli("sendtoaddress", "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1") + }, + RPCExamples{ + HelpExampleCli("sendtoaddress", "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1") + HelpExampleCli("sendtoaddress", "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1 \"donation\" \"seans outpost\"") + HelpExampleCli("sendtoaddress", "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1 \"\" \"\" true") + HelpExampleRpc("sendtoaddress", "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\", 0.1, \"donation\", \"seans outpost\"") - ); + }, + }.ToString()); // Make sure the results are valid at least up to the most recent block // the user could have gotten from another RPC command prior to now @@ -446,9 +453,8 @@ static UniValue listaddressgroupings(const JSONRPCRequest& request) "\nLists groups of addresses which have had their common ownership\n" "made public by common use as inputs or as the resulting change\n" "in past transactions\n", - {}} - .ToString() + - "\nResult:\n" + {}, + RPCResult{ "[\n" " [\n" " [\n" @@ -460,10 +466,12 @@ static UniValue listaddressgroupings(const JSONRPCRequest& request) " ]\n" " ,...\n" "]\n" - "\nExamples:\n" - + HelpExampleCli("listaddressgroupings", "") + }, + RPCExamples{ + HelpExampleCli("listaddressgroupings", "") + HelpExampleRpc("listaddressgroupings", "") - ); + }, + }.ToString()); // Make sure the results are valid at least up to the most recent block // the user could have gotten from another RPC command prior to now @@ -510,11 +518,11 @@ static UniValue signmessage(const JSONRPCRequest& request) { {"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."}, - }} - .ToString() + - "\nResult:\n" + }, + RPCResult{ "\"signature\" (string) The signature of the message encoded in base 64\n" - "\nExamples:\n" + }, + RPCExamples{ "\nUnlock the wallet for 30 seconds\n" + HelpExampleCli("walletpassphrase", "\"mypassphrase\" 30") + "\nCreate the signature\n" @@ -523,7 +531,8 @@ static UniValue signmessage(const JSONRPCRequest& request) + HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"signature\" \"my message\"") + "\nAs a JSON-RPC call\n" + HelpExampleRpc("signmessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\", \"my message\"") - ); + }, + }.ToString()); auto locked_chain = pwallet->chain().lock(); LOCK(pwallet->cs_wallet); @@ -575,11 +584,11 @@ static UniValue getreceivedbyaddress(const JSONRPCRequest& request) { {"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."}, - }} - .ToString() + - "\nResult:\n" + }, + RPCResult{ "amount (numeric) The total amount in " + CURRENCY_UNIT + " received at this address.\n" - "\nExamples:\n" + }, + RPCExamples{ "\nThe amount from transactions with at least 1 confirmation\n" + HelpExampleCli("getreceivedbyaddress", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\"") + "\nThe amount including unconfirmed transactions, zero confirmations\n" @@ -588,7 +597,8 @@ static UniValue getreceivedbyaddress(const JSONRPCRequest& request) + HelpExampleCli("getreceivedbyaddress", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" 6") + "\nAs a JSON-RPC call\n" + HelpExampleRpc("getreceivedbyaddress", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\", 6") - ); + }, + }.ToString()); // Make sure the results are valid at least up to the most recent block // the user could have gotten from another RPC command prior to now @@ -646,11 +656,11 @@ static UniValue getreceivedbylabel(const JSONRPCRequest& request) { {"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."}, - }} - .ToString() + - "\nResult:\n" + }, + RPCResult{ "amount (numeric) The total amount in " + CURRENCY_UNIT + " received for this label.\n" - "\nExamples:\n" + }, + RPCExamples{ "\nAmount received by the default label with at least 1 confirmation\n" + HelpExampleCli("getreceivedbylabel", "\"\"") + "\nAmount received at the tabby label including unconfirmed amounts with zero confirmations\n" @@ -659,7 +669,8 @@ static UniValue getreceivedbylabel(const JSONRPCRequest& request) + HelpExampleCli("getreceivedbylabel", "\"tabby\" 6") + "\nAs a JSON-RPC call\n" + HelpExampleRpc("getreceivedbylabel", "\"tabby\", 6") - ); + }, + }.ToString()); // Make sure the results are valid at least up to the most recent block // the user could have gotten from another RPC command prior to now @@ -718,18 +729,19 @@ static UniValue getbalance(const JSONRPCRequest& request) {"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')"}, - }} - .ToString() + - "\nResult:\n" + }, + RPCResult{ "amount (numeric) The total amount in " + CURRENCY_UNIT + " received for this wallet.\n" - "\nExamples:\n" + }, + RPCExamples{ "\nThe total amount in the wallet with 1 or more confirmations\n" + HelpExampleCli("getbalance", "") + "\nThe total amount in the wallet at least 6 blocks confirmed\n" + HelpExampleCli("getbalance", "\"*\" 6") + "\nAs a JSON-RPC call\n" + HelpExampleRpc("getbalance", "\"*\", 6") - ); + }, + }.ToString()); // Make sure the results are valid at least up to the most recent block // the user could have gotten from another RPC command prior to now @@ -768,8 +780,11 @@ static UniValue getunconfirmedbalance(const JSONRPCRequest &request) if (request.fHelp || request.params.size() > 0) throw std::runtime_error( RPCHelpMan{"getunconfirmedbalance", - "Returns the server's total unconfirmed balance\n", {}} - .ToString()); + "Returns the server's total unconfirmed balance\n", + {}, + RPCResults{}, + RPCExamples{""}, + }.ToString()); // Make sure the results are valid at least up to the most recent block // the user could have gotten from another RPC command prior to now @@ -819,12 +834,12 @@ static UniValue sendmany(const JSONRPCRequest& request) " \"UNSET\"\n" " \"ECONOMICAL\"\n" " \"CONSERVATIVE\""}, - }} - .ToString() + - "\nResult:\n" + }, + RPCResult{ "\"txid\" (string) The transaction id for the send. Only 1 transaction is created regardless of \n" " the number of addresses.\n" - "\nExamples:\n" + }, + RPCExamples{ "\nSend two amounts to two different addresses:\n" + HelpExampleCli("sendmany", "\"\" \"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\"") + "\nSend two amounts to two different addresses setting the confirmation and comment:\n" @@ -833,7 +848,8 @@ static UniValue sendmany(const JSONRPCRequest& request) + HelpExampleCli("sendmany", "\"\" \"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\" 1 \"\" \"[\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\\\",\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\"]\"") + "\nAs a JSON-RPC call\n" + HelpExampleRpc("sendmany", "\"\", {\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\":0.01,\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\":0.02}, 6, \"testing\"") - ); + }, + }.ToString()); // Make sure the results are valid at least up to the most recent block // the user could have gotten from another RPC command prior to now @@ -964,19 +980,20 @@ static UniValue addmultisigaddress(const JSONRPCRequest& request) }, {"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\"."}, - }} - .ToString() + - "\nResult:\n" + }, + RPCResult{ "{\n" " \"address\":\"multisigaddress\", (string) The value of the new multisig address.\n" " \"redeemScript\":\"script\" (string) The string value of the hex-encoded redemption script.\n" "}\n" - "\nExamples:\n" + }, + RPCExamples{ "\nAdd a multisig address from 2 addresses\n" + HelpExampleCli("addmultisigaddress", "2 \"[\\\"16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"") + "\nAs a JSON-RPC call\n" + HelpExampleRpc("addmultisigaddress", "2, \"[\\\"16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"") - ; + }, + }.ToString(); throw std::runtime_error(msg); } @@ -1020,15 +1037,12 @@ static UniValue addmultisigaddress(const JSONRPCRequest& request) struct tallyitem { - CAmount nAmount; - int nConf; + CAmount nAmount{0}; + int nConf{std::numeric_limits<int>::max()}; std::vector<uint256> txids; - bool fIsWatchonly; + bool fIsWatchonly{false}; tallyitem() { - nAmount = 0; - nConf = std::numeric_limits<int>::max(); - fIsWatchonly = false; } }; @@ -1196,9 +1210,8 @@ static UniValue listreceivedbyaddress(const JSONRPCRequest& request) {"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."}, - }} - .ToString() + - "\nResult:\n" + }, + RPCResult{ "[\n" " {\n" " \"involvesWatchonly\" : true, (bool) Only returned if imported addresses were involved in transaction\n" @@ -1213,13 +1226,14 @@ static UniValue listreceivedbyaddress(const JSONRPCRequest& request) " }\n" " ,...\n" "]\n" - - "\nExamples:\n" - + HelpExampleCli("listreceivedbyaddress", "") + }, + RPCExamples{ + HelpExampleCli("listreceivedbyaddress", "") + HelpExampleCli("listreceivedbyaddress", "6 true") + HelpExampleRpc("listreceivedbyaddress", "6, true, true") + HelpExampleRpc("listreceivedbyaddress", "6, true, true, \"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\"") - ); + }, + }.ToString()); // Make sure the results are valid at least up to the most recent block // the user could have gotten from another RPC command prior to now @@ -1248,9 +1262,8 @@ static UniValue listreceivedbylabel(const JSONRPCRequest& request) {"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')."}, - }} - .ToString() + - "\nResult:\n" + }, + RPCResult{ "[\n" " {\n" " \"involvesWatchonly\" : true, (bool) Only returned if imported addresses were involved in transaction\n" @@ -1260,12 +1273,13 @@ static UniValue listreceivedbylabel(const JSONRPCRequest& request) " }\n" " ,...\n" "]\n" - - "\nExamples:\n" - + HelpExampleCli("listreceivedbylabel", "") + }, + RPCExamples{ + HelpExampleCli("listreceivedbylabel", "") + HelpExampleCli("listreceivedbylabel", "6 true") + HelpExampleRpc("listreceivedbylabel", "6, true, true") - ); + }, + }.ToString()); // Make sure the results are valid at least up to the most recent block // the user could have gotten from another RPC command prior to now @@ -1391,9 +1405,8 @@ UniValue listtransactions(const JSONRPCRequest& request) {"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')"}, - }} - .ToString() + - "\nResult:\n" + }, + RPCResult{ "[\n" " {\n" " \"address\":\"address\", (string) The bitcoin address of the transaction.\n" @@ -1425,15 +1438,16 @@ UniValue listtransactions(const JSONRPCRequest& request) " 'send' category of transactions.\n" " }\n" "]\n" - - "\nExamples:\n" + }, + RPCExamples{ "\nList the most recent 10 transactions in the systems\n" + HelpExampleCli("listtransactions", "") + "\nList transactions 100 to 120\n" + HelpExampleCli("listtransactions", "\"*\" 20 100") + "\nAs a JSON-RPC call\n" + HelpExampleRpc("listtransactions", "\"*\", 20, 100") - ); + }, + }.ToString()); // Make sure the results are valid at least up to the most recent block // the user could have gotten from another RPC command prior to now @@ -1526,9 +1540,8 @@ static UniValue listsinceblock(const JSONRPCRequest& request) {"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" " (not guaranteed to work on pruned nodes)"}, - }} - .ToString() + - "\nResult:\n" + }, + RPCResult{ "{\n" " \"transactions\": [\n" " \"address\":\"address\", (string) The bitcoin address of the transaction.\n" @@ -1563,11 +1576,13 @@ static UniValue listsinceblock(const JSONRPCRequest& request) " ],\n" " \"lastblock\": \"lastblockhash\" (string) The hash of the block (target_confirmations-1) from the best block on the main chain. This is typically used to feed back into listsinceblock the next time you call it. So you would generally use a target_confirmations of say 6, so you will be continually re-notified of transactions until they've reached 6 confirmations plus any new ones\n" "}\n" - "\nExamples:\n" - + HelpExampleCli("listsinceblock", "") + }, + RPCExamples{ + HelpExampleCli("listsinceblock", "") + HelpExampleCli("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\" 6") + HelpExampleRpc("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\", 6") - ); + }, + }.ToString()); // Make sure the results are valid at least up to the most recent block // the user could have gotten from another RPC command prior to now @@ -1576,24 +1591,19 @@ static UniValue listsinceblock(const JSONRPCRequest& request) auto locked_chain = pwallet->chain().lock(); LOCK(pwallet->cs_wallet); - const CBlockIndex* pindex = nullptr; // Block index of the specified block or the common ancestor, if the block provided was in a deactivated chain. - const CBlockIndex* paltindex = nullptr; // Block index of the specified block, even if it's in a deactivated chain. + // The way the 'height' is initialized is just a workaround for the gcc bug #47679 since version 4.6.0. + Optional<int> height = MakeOptional(false, int()); // Height of the specified block or the common ancestor, if the block provided was in a deactivated chain. + Optional<int> altheight; // Height of the specified block, even if it's in a deactivated chain. int target_confirms = 1; isminefilter filter = ISMINE_SPENDABLE; + uint256 blockId; if (!request.params[0].isNull() && !request.params[0].get_str().empty()) { - uint256 blockId(ParseHashV(request.params[0], "blockhash")); - - paltindex = pindex = LookupBlockIndex(blockId); - if (!pindex) { + blockId = ParseHashV(request.params[0], "blockhash"); + height = locked_chain->findFork(blockId, &altheight); + if (!height) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); } - if (chainActive[pindex->nHeight] != pindex) { - // the block being asked for is a part of a deactivated chain; - // we don't want to depend on its perceived height in the block - // chain, we want to instead use the last common ancestor - pindex = chainActive.FindFork(pindex); - } } if (!request.params[1].isNull()) { @@ -1610,7 +1620,8 @@ static UniValue listsinceblock(const JSONRPCRequest& request) bool include_removed = (request.params[3].isNull() || request.params[3].get_bool()); - int depth = pindex ? (1 + chainActive.Height() - pindex->nHeight) : -1; + const Optional<int> tip_height = locked_chain->getHeight(); + int depth = tip_height && height ? (1 + *tip_height - *height) : -1; UniValue transactions(UniValue::VARR); @@ -1625,9 +1636,9 @@ static UniValue listsinceblock(const JSONRPCRequest& request) // when a reorg'd block is requested, we also list any relevant transactions // in the blocks of the chain that was detached UniValue removed(UniValue::VARR); - while (include_removed && paltindex && paltindex != pindex) { + while (include_removed && altheight && *altheight > *height) { CBlock block; - if (!ReadBlockFromDisk(block, paltindex, Params().GetConsensus())) { + if (!pwallet->chain().findBlock(blockId, &block) || block.IsNull()) { throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk"); } for (const CTransactionRef& tx : block.vtx) { @@ -1638,11 +1649,12 @@ static UniValue listsinceblock(const JSONRPCRequest& request) ListTransactions(*locked_chain, pwallet, it->second, -100000000, true, removed, filter, nullptr /* filter_label */); } } - paltindex = paltindex->pprev; + blockId = block.hashPrevBlock; + --*altheight; } - CBlockIndex *pblockLast = chainActive[chainActive.Height() + 1 - target_confirms]; - uint256 lastblock = pblockLast ? pblockLast->GetBlockHash() : uint256(); + int last_height = tip_height ? *tip_height + 1 - target_confirms : -1; + uint256 lastblock = last_height >= 0 ? locked_chain->getBlockHash(last_height) : uint256(); UniValue ret(UniValue::VOBJ); ret.pushKV("transactions", transactions); @@ -1668,9 +1680,8 @@ static UniValue gettransaction(const JSONRPCRequest& request) { {"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[]"}, - }} - .ToString() + - "\nResult:\n" + }, + RPCResult{ "{\n" " \"amount\" : x.xxx, (numeric) The transaction amount in " + CURRENCY_UNIT + "\n" " \"fee\": x.xxx, (numeric) The amount of the fee in " + CURRENCY_UNIT + ". This is negative and only available for the \n" @@ -1705,12 +1716,13 @@ static UniValue gettransaction(const JSONRPCRequest& request) " ],\n" " \"hex\" : \"data\" (string) Raw data for transaction\n" "}\n" - - "\nExamples:\n" - + HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"") + }, + RPCExamples{ + HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"") + HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\" true") + HelpExampleRpc("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"") - ); + }, + }.ToString()); // Make sure the results are valid at least up to the most recent block // the user could have gotten from another RPC command prior to now @@ -1773,13 +1785,13 @@ static UniValue abandontransaction(const JSONRPCRequest& request) "It has no effect on transactions which are already abandoned.\n", { {"txid", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "The transaction id"}, - }} - .ToString() + - "\nResult:\n" - "\nExamples:\n" - + HelpExampleCli("abandontransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"") + }, + RPCResults{}, + RPCExamples{ + HelpExampleCli("abandontransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"") + HelpExampleRpc("abandontransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"") - ); + }, + }.ToString()); } // Make sure the results are valid at least up to the most recent block @@ -1817,12 +1829,13 @@ static UniValue backupwallet(const JSONRPCRequest& request) "\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"}, - }} - .ToString() + - "\nExamples:\n" - + HelpExampleCli("backupwallet", "\"backup.dat\"") + }, + RPCResults{}, + RPCExamples{ + HelpExampleCli("backupwallet", "\"backup.dat\"") + HelpExampleRpc("backupwallet", "\"backup.dat\"") - ); + }, + }.ToString()); // Make sure the results are valid at least up to the most recent block // the user could have gotten from another RPC command prior to now @@ -1856,12 +1869,13 @@ static UniValue keypoolrefill(const JSONRPCRequest& request) HelpRequiringPassphrase(pwallet) + "\n", { {"newsize", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "100", "The new keypool size"}, - }} - .ToString() + - "\nExamples:\n" - + HelpExampleCli("keypoolrefill", "") + }, + RPCResults{}, + RPCExamples{ + HelpExampleCli("keypoolrefill", "") + HelpExampleRpc("keypoolrefill", "") - ); + }, + }.ToString()); if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) { throw JSONRPCError(RPC_WALLET_ERROR, "Error: Private keys are disabled for this wallet"); @@ -1902,23 +1916,24 @@ static UniValue walletpassphrase(const JSONRPCRequest& request) throw std::runtime_error( RPCHelpMan{"walletpassphrase", "\nStores the wallet decryption key in memory for 'timeout' seconds.\n" - "This is needed prior to performing transactions related to private keys such as sending bitcoins\n", + "This is needed prior to performing transactions related to private keys such as sending bitcoins\n" + "\nNote:\n" + "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)."}, - }} - .ToString() + - "\nNote:\n" - "Issuing the walletpassphrase command while the wallet is already unlocked will set a new unlock\n" - "time that overrides the old one.\n" - "\nExamples:\n" + }, + RPCResults{}, + RPCExamples{ "\nUnlock the wallet for 60 seconds\n" + HelpExampleCli("walletpassphrase", "\"my pass phrase\" 60") + "\nLock the wallet again (before 60 seconds)\n" + HelpExampleCli("walletlock", "") + "\nAs a JSON-RPC call\n" + HelpExampleRpc("walletpassphrase", "\"my pass phrase\", 60") - ); + }, + }.ToString()); } auto locked_chain = pwallet->chain().lock(); @@ -1991,12 +2006,13 @@ static UniValue walletpassphrasechange(const JSONRPCRequest& request) { {"oldpassphrase", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The current passphrase"}, {"newpassphrase", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The new passphrase"}, - }} - .ToString() + - "\nExamples:\n" - + HelpExampleCli("walletpassphrasechange", "\"old one\" \"new one\"") + }, + RPCResults{}, + RPCExamples{ + HelpExampleCli("walletpassphrasechange", "\"old one\" \"new one\"") + HelpExampleRpc("walletpassphrasechange", "\"old one\", \"new one\"") - ); + }, + }.ToString()); } auto locked_chain = pwallet->chain().lock(); @@ -2043,9 +2059,9 @@ static UniValue walletlock(const JSONRPCRequest& request) "\nRemoves the wallet encryption key from memory, locking the wallet.\n" "After calling this method, you will need to call walletpassphrase again\n" "before being able to call any methods which require the wallet to be unlocked.\n", - {}} - .ToString() + - "\nExamples:\n" + {}, + RPCResults{}, + RPCExamples{ "\nSet the passphrase for 2 minutes to perform a transaction\n" + HelpExampleCli("walletpassphrase", "\"my pass phrase\" 120") + "\nPerform a send (requires passphrase set)\n" @@ -2054,7 +2070,8 @@ static UniValue walletlock(const JSONRPCRequest& request) + HelpExampleCli("walletlock", "") + "\nAs a JSON-RPC call\n" + HelpExampleRpc("walletlock", "") - ); + }, + }.ToString()); } auto locked_chain = pwallet->chain().lock(); @@ -2090,9 +2107,9 @@ static UniValue encryptwallet(const JSONRPCRequest& request) "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."}, - }} - .ToString() + - "\nExamples:\n" + }, + RPCResults{}, + RPCExamples{ "\nEncrypt your wallet\n" + HelpExampleCli("encryptwallet", "\"my pass phrase\"") + "\nNow set the passphrase to use the wallet, such as for signing or sending bitcoin\n" @@ -2103,7 +2120,8 @@ static UniValue encryptwallet(const JSONRPCRequest& request) + HelpExampleCli("walletlock", "") + "\nAs a JSON-RPC call\n" + HelpExampleRpc("encryptwallet", "\"my pass phrase\"") - ); + }, + }.ToString()); } auto locked_chain = pwallet->chain().lock(); @@ -2161,12 +2179,11 @@ static UniValue lockunspent(const JSONRPCRequest& request) }, }, }, - }} - .ToString() + - "\nResult:\n" + }, + RPCResult{ "true|false (boolean) Whether the command was successful or not\n" - - "\nExamples:\n" + }, + RPCExamples{ "\nList the unspent transactions\n" + HelpExampleCli("listunspent", "") + "\nLock an unspent transaction\n" @@ -2177,7 +2194,8 @@ static UniValue lockunspent(const JSONRPCRequest& request) + HelpExampleCli("lockunspent", "true \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") + "\nAs a JSON-RPC call\n" + HelpExampleRpc("lockunspent", "false, \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") - ); + }, + }.ToString()); // Make sure the results are valid at least up to the most recent block // the user could have gotten from another RPC command prior to now @@ -2273,9 +2291,8 @@ static UniValue listlockunspent(const JSONRPCRequest& request) RPCHelpMan{"listlockunspent", "\nReturns list of temporarily unspendable outputs.\n" "See the lockunspent call to lock and unlock transactions for spending.\n", - {}} - .ToString() + - "\nResult:\n" + {}, + RPCResult{ "[\n" " {\n" " \"txid\" : \"transactionid\", (string) The transaction id locked\n" @@ -2283,7 +2300,8 @@ static UniValue listlockunspent(const JSONRPCRequest& request) " }\n" " ,...\n" "]\n" - "\nExamples:\n" + }, + RPCExamples{ "\nList the unspent transactions\n" + HelpExampleCli("listunspent", "") + "\nLock an unspent transaction\n" @@ -2294,7 +2312,8 @@ static UniValue listlockunspent(const JSONRPCRequest& request) + HelpExampleCli("lockunspent", "true \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") + "\nAs a JSON-RPC call\n" + HelpExampleRpc("listlockunspent", "") - ); + }, + }.ToString()); auto locked_chain = pwallet->chain().lock(); LOCK(pwallet->cs_wallet); @@ -2330,14 +2349,15 @@ static UniValue settxfee(const JSONRPCRequest& request) "\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"}, - }} - .ToString() + - "\nResult\n" + }, + RPCResult{ "true|false (boolean) Returns true if successful\n" - "\nExamples:\n" - + HelpExampleCli("settxfee", "0.00001") + }, + RPCExamples{ + HelpExampleCli("settxfee", "0.00001") + HelpExampleRpc("settxfee", "0.00001") - ); + }, + }.ToString()); } auto locked_chain = pwallet->chain().lock(); @@ -2369,9 +2389,9 @@ static UniValue getwalletinfo(const JSONRPCRequest& request) if (request.fHelp || request.params.size() != 0) throw std::runtime_error( RPCHelpMan{"getwalletinfo", - "Returns an object containing various wallet state info.\n", {}} - .ToString() + - "\nResult:\n" + "Returns an object containing various wallet state info.\n", + {}, + RPCResult{ "{\n" " \"walletname\": xxxxx, (string) the wallet name\n" " \"walletversion\": xxxxx, (numeric) the wallet version\n" @@ -2388,10 +2408,12 @@ static UniValue getwalletinfo(const JSONRPCRequest& request) " \"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" - "\nExamples:\n" - + HelpExampleCli("getwalletinfo", "") + }, + RPCExamples{ + HelpExampleCli("getwalletinfo", "") + HelpExampleRpc("getwalletinfo", "") - ); + }, + }.ToString()); // Make sure the results are valid at least up to the most recent block // the user could have gotten from another RPC command prior to now @@ -2432,8 +2454,9 @@ static UniValue listwalletdir(const JSONRPCRequest& request) if (request.fHelp || request.params.size() != 0) { throw std::runtime_error( RPCHelpMan{"listwalletdir", - "Returns a list of wallets in the wallet directory.\n", {}} - .ToString() + + "Returns a list of wallets in the wallet directory.\n", + {}, + RPCResult{ "{\n" " \"wallets\" : [ (json array of objects)\n" " {\n" @@ -2442,10 +2465,12 @@ static UniValue listwalletdir(const JSONRPCRequest& request) " ,...\n" " ]\n" "}\n" - "\nExamples:\n" - + HelpExampleCli("listwalletdir", "") + }, + RPCExamples{ + HelpExampleCli("listwalletdir", "") + HelpExampleRpc("listwalletdir", "") - ); + }, + }.ToString()); } UniValue wallets(UniValue::VARR); @@ -2467,17 +2492,18 @@ static UniValue listwallets(const JSONRPCRequest& request) RPCHelpMan{"listwallets", "Returns a list of currently loaded wallets.\n" "For full information on the wallet, use \"getwalletinfo\"\n", - {}} - .ToString() + - "\nResult:\n" + {}, + RPCResult{ "[ (json array of strings)\n" " \"walletname\" (string) the wallet name\n" " ...\n" "]\n" - "\nExamples:\n" - + HelpExampleCli("listwallets", "") + }, + RPCExamples{ + HelpExampleCli("listwallets", "") + HelpExampleRpc("listwallets", "") - ); + }, + }.ToString()); UniValue obj(UniValue::VARR); @@ -2504,17 +2530,18 @@ static UniValue loadwallet(const JSONRPCRequest& request) "\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."}, - }} - .ToString() + - "\nResult:\n" + }, + RPCResult{ "{\n" " \"name\" : <wallet_name>, (string) The wallet name if loaded successfully.\n" " \"warning\" : <warning>, (string) Warning message if wallet was not loaded cleanly.\n" "}\n" - "\nExamples:\n" - + HelpExampleCli("loadwallet", "\"test.dat\"") + }, + RPCExamples{ + HelpExampleCli("loadwallet", "\"test.dat\"") + HelpExampleRpc("loadwallet", "\"test.dat\"") - ); + }, + }.ToString()); WalletLocation location(request.params[0].get_str()); std::string error; @@ -2558,17 +2585,18 @@ static UniValue createwallet(const JSONRPCRequest& request) { {"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)."}, - }} - .ToString() + - "\nResult:\n" + }, + RPCResult{ "{\n" " \"name\" : <wallet_name>, (string) The wallet name if created successfully. If the wallet was created using a full path, the wallet_name will be the full path.\n" " \"warning\" : <warning>, (string) Warning message if wallet was not loaded cleanly.\n" "}\n" - "\nExamples:\n" - + HelpExampleCli("createwallet", "\"testwallet\"") + }, + RPCExamples{ + HelpExampleCli("createwallet", "\"testwallet\"") + HelpExampleRpc("createwallet", "\"testwallet\"") - ); + }, + }.ToString()); } std::string error; std::string warning; @@ -2612,12 +2640,13 @@ static UniValue unloadwallet(const JSONRPCRequest& request) "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."}, - }} - .ToString() + - "\nExamples:\n" - + HelpExampleCli("unloadwallet", "wallet_name") + }, + RPCResults{}, + RPCExamples{ + HelpExampleCli("unloadwallet", "wallet_name") + HelpExampleRpc("unloadwallet", "wallet_name") - ); + }, + }.ToString()); } std::string wallet_name; @@ -2640,16 +2669,8 @@ static UniValue unloadwallet(const JSONRPCRequest& request) if (!RemoveWallet(wallet)) { throw JSONRPCError(RPC_MISC_ERROR, "Requested wallet already unloaded"); } - UnregisterValidationInterface(wallet.get()); - // The wallet can be in use so it's not possible to explicitly unload here. - // Just notify the unload intent so that all shared pointers are released. - // The wallet will be destroyed once the last shared pointer is released. - wallet->NotifyUnload(); - - // There's no point in waiting for the wallet to unload. - // At this point this method should never fail. The unloading could only - // fail due to an unexpected error which would cause a process termination. + UnloadWallet(std::move(wallet)); return NullUniValue; } @@ -2667,12 +2688,15 @@ static UniValue resendwallettransactions(const JSONRPCRequest& request) throw std::runtime_error( RPCHelpMan{"resendwallettransactions", "Immediately re-broadcast unconfirmed wallet transactions to all peers.\n" - "Intended only for testing; the wallet code periodically re-broadcasts\n", - {}} - .ToString() + - "automatically.\n" + "Intended only for testing; the wallet code periodically re-broadcasts\n" + "automatically.\n", + {}, + RPCResult{ "Returns an RPC error if -walletbroadcast is set to false.\n" "Returns array of transaction ids that were re-broadcast.\n" + }, + RPCExamples{""}, + }.ToString() ); if (!g_connman) @@ -2727,9 +2751,8 @@ static UniValue listunspent(const JSONRPCRequest& request) {"minimumSumAmount", RPCArg::Type::AMOUNT, /* opt */ true, /* default_val */ "unlimited", "Minimum sum value of all UTXOs in " + CURRENCY_UNIT + ""}, }, "query_options"}, - }} - .ToString() + - "\nResult\n" + }, + RPCResult{ "[ (array of json object)\n" " {\n" " \"txid\" : \"txid\", (string) the transaction id \n" @@ -2749,14 +2772,15 @@ static UniValue listunspent(const JSONRPCRequest& request) " }\n" " ,...\n" "]\n" - - "\nExamples\n" - + HelpExampleCli("listunspent", "") + }, + RPCExamples{ + HelpExampleCli("listunspent", "") + HelpExampleCli("listunspent", "6 9999999 \"[\\\"1PGFqEzfmQch1gKD3ra4k18PNj3tTUUSqg\\\",\\\"1LtvqCaApEdUGFkpKMM4MstjcaL4dKg8SP\\\"]\"") + HelpExampleRpc("listunspent", "6, 9999999 \"[\\\"1PGFqEzfmQch1gKD3ra4k18PNj3tTUUSqg\\\",\\\"1LtvqCaApEdUGFkpKMM4MstjcaL4dKg8SP\\\"]\"") + HelpExampleCli("listunspent", "6 9999999 '[]' true '{ \"minimumAmount\": 0.005 }'") + HelpExampleRpc("listunspent", "6, 9999999, [] , true, { \"minimumAmount\": 0.005 } ") - ); + }, + }.ToString()); int nMinDepth = 1; if (!request.params[0].isNull()) { @@ -3004,7 +3028,8 @@ 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" @@ -3039,24 +3064,25 @@ static UniValue fundrawtransaction(const JSONRPCRequest& request) "options"}, {"iswitness", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "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"}, - }} - .ToString() + - "\nResult:\n" + }, + RPCResult{ "{\n" " \"hex\": \"value\", (string) The resulting raw transaction (hex-encoded string)\n" " \"fee\": n, (numeric) Fee in " + CURRENCY_UNIT + " the resulting transaction pays\n" " \"changepos\": n (numeric) The position of the added change output, or -1\n" "}\n" - "\nExamples:\n" + }, + RPCExamples{ "\nCreate a transaction with no inputs\n" + HelpExampleCli("createrawtransaction", "\"[]\" \"{\\\"myaddress\\\":0.01}\"") + "\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\"") - ); + }, + }.ToString()); RPCTypeCheck(request.params, {UniValue::VSTR, UniValueType(), UniValue::VBOOL}); @@ -3073,7 +3099,7 @@ static UniValue fundrawtransaction(const JSONRPCRequest& request) FundTransaction(pwallet, tx, fee, change_position, request.params[1]); UniValue result(UniValue::VOBJ); - result.pushKV("hex", EncodeHexTx(tx)); + result.pushKV("hex", EncodeHexTx(CTransaction(tx))); result.pushKV("fee", ValueFromAmount(fee)); result.pushKV("changepos", change_position); @@ -3118,9 +3144,8 @@ UniValue signrawtransactionwithwallet(const JSONRPCRequest& request) " \"ALL|ANYONECANPAY\"\n" " \"NONE|ANYONECANPAY\"\n" " \"SINGLE|ANYONECANPAY\""}, - }} - .ToString() + - "\nResult:\n" + }, + RPCResult{ "{\n" " \"hex\" : \"value\", (string) The hex-encoded raw transaction with signature(s)\n" " \"complete\" : true|false, (boolean) If the transaction has a complete set of signatures\n" @@ -3135,11 +3160,12 @@ UniValue signrawtransactionwithwallet(const JSONRPCRequest& request) " ,...\n" " ]\n" "}\n" - - "\nExamples:\n" - + HelpExampleCli("signrawtransactionwithwallet", "\"myhex\"") + }, + RPCExamples{ + HelpExampleCli("signrawtransactionwithwallet", "\"myhex\"") + HelpExampleRpc("signrawtransactionwithwallet", "\"myhex\"") - ); + }, + }.ToString()); RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VARR, UniValue::VSTR}, true); @@ -3201,18 +3227,20 @@ static UniValue bumpfee(const JSONRPCRequest& request) " \"CONSERVATIVE\""}, }, "options"}, - }} - .ToString() + - "\nResult:\n" + }, + RPCResult{ "{\n" " \"txid\": \"value\", (string) The id of the new transaction\n" " \"origfee\": n, (numeric) Fee of the replaced transaction\n" " \"fee\": n, (numeric) Fee of the new transaction\n" " \"errors\": [ str... ] (json array of strings) Errors encountered during processing (may be empty)\n" "}\n" - "\nExamples:\n" + }, + RPCExamples{ "\nBump the fee, get the new transaction\'s txid\n" + - HelpExampleCli("bumpfee", "<txid>")); + HelpExampleCli("bumpfee", "<txid>") + }, + }.ToString()); } RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VOBJ}); @@ -3327,14 +3355,15 @@ UniValue generate(const JSONRPCRequest& request) { {"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."}, - }} - .ToString() + - "\nResult:\n" + }, + RPCResult{ "[ blockhashes ] (array) hashes of blocks generated\n" - "\nExamples:\n" + }, + RPCExamples{ "\nGenerate 11 blocks\n" + HelpExampleCli("generate", "11") - ); + }, + }.ToString()); } if (!IsDeprecatedRPCEnabled("generate")) { @@ -3380,18 +3409,19 @@ UniValue rescanblockchain(const JSONRPCRequest& request) "\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 */ "tip height", "the last block height that should be scanned"}, - }} - .ToString() + - "\nResult:\n" + {"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."}, + }, + RPCResult{ "{\n" - " \"start_height\" (numeric) The block height where the rescan has started. If omitted, rescan started from the genesis block.\n" - " \"stop_height\" (numeric) The height of the last rescanned block. If omitted, rescan stopped at the chain tip.\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" - "\nExamples:\n" - + HelpExampleCli("rescanblockchain", "100000 120000") + }, + RPCExamples{ + HelpExampleCli("rescanblockchain", "100000 120000") + HelpExampleRpc("rescanblockchain", "100000, 120000") - ); + }, + }.ToString()); } WalletRescanReserver reserver(pwallet); @@ -3399,50 +3429,53 @@ UniValue rescanblockchain(const JSONRPCRequest& request) throw JSONRPCError(RPC_WALLET_ERROR, "Wallet is currently rescanning. Abort existing rescan or wait."); } - CBlockIndex *pindexStart = nullptr; - CBlockIndex *pindexStop = nullptr; - CBlockIndex *pChainTip = nullptr; + int start_height = 0; + uint256 start_block, stop_block; { auto locked_chain = pwallet->chain().lock(); - pindexStart = chainActive.Genesis(); - pChainTip = chainActive.Tip(); + Optional<int> tip_height = locked_chain->getHeight(); if (!request.params[0].isNull()) { - pindexStart = chainActive[request.params[0].get_int()]; - if (!pindexStart) { + start_height = request.params[0].get_int(); + if (start_height < 0 || !tip_height || start_height > *tip_height) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid start_height"); } } + Optional<int> stop_height; if (!request.params[1].isNull()) { - pindexStop = chainActive[request.params[1].get_int()]; - if (!pindexStop) { + stop_height = request.params[1].get_int(); + if (*stop_height < 0 || !tip_height || *stop_height > *tip_height) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid stop_height"); } - else if (pindexStop->nHeight < pindexStart->nHeight) { + else if (*stop_height < start_height) { throw JSONRPCError(RPC_INVALID_PARAMETER, "stop_height must be greater than start_height"); } } - } - // We can't rescan beyond non-pruned blocks, stop and throw an error - if (fPruneMode) { - auto locked_chain = pwallet->chain().lock(); - CBlockIndex *block = pindexStop ? pindexStop : pChainTip; - while (block && block->nHeight >= pindexStart->nHeight) { - if (!(block->nStatus & BLOCK_HAVE_DATA)) { - throw JSONRPCError(RPC_MISC_ERROR, "Can't rescan beyond pruned data. Use RPC call getblockchaininfo to determine your pruned height."); + // We can't rescan beyond non-pruned blocks, stop and throw an error + if (locked_chain->findPruned(start_height, stop_height)) { + throw JSONRPCError(RPC_MISC_ERROR, "Can't rescan beyond pruned data. Use RPC call getblockchaininfo to determine your pruned height."); + } + + 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); } - block = block->pprev; } } - const CBlockIndex *failed_block, *stopBlock; CWallet::ScanResult result = - pwallet->ScanForWalletTransactions(pindexStart, pindexStop, reserver, failed_block, stopBlock, true); - switch (result) { + pwallet->ScanForWalletTransactions(start_block, stop_block, reserver, true /* fUpdate */); + switch (result.status) { case CWallet::ScanResult::SUCCESS: - break; // stopBlock set by ScanForWalletTransactions + break; case CWallet::ScanResult::FAILURE: throw JSONRPCError(RPC_MISC_ERROR, "Rescan failed. Potentially corrupted data files."); case CWallet::ScanResult::USER_ABORT: @@ -3450,8 +3483,8 @@ UniValue rescanblockchain(const JSONRPCRequest& request) // no default case, so the compiler can warn about missing cases } UniValue response(UniValue::VOBJ); - response.pushKV("start_height", pindexStart->nHeight); - response.pushKV("stop_height", stopBlock->nHeight); + response.pushKV("start_height", start_height); + response.pushKV("stop_height", result.last_scanned_height ? *result.last_scanned_height : UniValue()); return response; } @@ -3590,14 +3623,12 @@ UniValue getaddressinfo(const JSONRPCRequest& request) "to be in the wallet.\n", { {"address", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The bitcoin address to get the information of."}, - }} - .ToString() + - "\nResult:\n" + }, + RPCResult{ "{\n" " \"address\" : \"address\", (string) The bitcoin address validated\n" " \"scriptPubKey\" : \"hex\", (string) The hex-encoded scriptPubKey generated by the address\n" " \"ismine\" : true|false, (boolean) If the address is yours or not\n" - " \"solvable\" : true|false, (boolean) If the address is solvable by the wallet\n" " \"iswatchonly\" : true|false, (boolean) If the address is watchonly\n" " \"solvable\" : true|false, (boolean) Whether we know how to spend coins sent to this address, ignoring the possible lack of private keys\n" " \"desc\" : \"desc\", (string, optional) A descriptor for spending coins sent to this address (only when solvable)\n" @@ -3616,7 +3647,7 @@ UniValue getaddressinfo(const JSONRPCRequest& request) " \"sigsrequired\" : xxxxx (numeric, optional) Number of signatures required to spend multisig output (only if \"script\" is \"multisig\")\n" " \"pubkey\" : \"publickeyhex\", (string, optional) The hex value of the raw public key, for single-key addresses (possibly embedded in P2SH or P2WSH)\n" " \"embedded\" : {...}, (object, optional) Information about the address embedded in P2SH or P2WSH, if relevant and known. It includes all getaddressinfo output fields for the embedded address, excluding metadata (\"timestamp\", \"hdkeypath\", \"hdseedid\") and relation to the wallet (\"ismine\", \"iswatchonly\").\n" - " \"iscompressed\" : true|false, (boolean) If the address is compressed\n" + " \"iscompressed\" : true|false, (boolean, optional) If the pubkey is compressed\n" " \"label\" : \"label\" (string) The label associated with the address, \"\" is the default label\n" " \"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" @@ -3630,10 +3661,12 @@ UniValue getaddressinfo(const JSONRPCRequest& request) " },...\n" " ]\n" "}\n" - "\nExamples:\n" - + HelpExampleCli("getaddressinfo", "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"") + }, + RPCExamples{ + HelpExampleCli("getaddressinfo", "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"") + HelpExampleRpc("getaddressinfo", "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"") - ); + }, + }.ToString()); } LOCK(pwallet->cs_wallet); @@ -3660,7 +3693,6 @@ UniValue getaddressinfo(const JSONRPCRequest& request) ret.pushKV("desc", InferDescriptor(scriptPubKey, *pwallet)->ToString()); } ret.pushKV("iswatchonly", bool(mine & ISMINE_WATCH_ONLY)); - ret.pushKV("solvable", IsSolvable(*pwallet, scriptPubKey)); UniValue detail = DescribeWalletAddress(pwallet, dest); ret.pushKVs(detail); if (pwallet->mapAddressBook.count(dest)) { @@ -3718,18 +3750,19 @@ static UniValue getaddressesbylabel(const JSONRPCRequest& request) "\nReturns the list of addresses assigned the specified label.\n", { {"label", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The label."}, - }} - .ToString() + - "\nResult:\n" + }, + RPCResult{ "{ (json object with addresses as keys)\n" " \"address\": { (json object with information about address)\n" " \"purpose\": \"string\" (string) Purpose of address (\"send\" for sending address, \"receive\" for receiving address)\n" " },...\n" "}\n" - "\nExamples:\n" - + HelpExampleCli("getaddressesbylabel", "\"tabby\"") + }, + RPCExamples{ + HelpExampleCli("getaddressesbylabel", "\"tabby\"") + HelpExampleRpc("getaddressesbylabel", "\"tabby\"") - ); + }, + }.ToString()); LOCK(pwallet->cs_wallet); @@ -3765,14 +3798,14 @@ static UniValue listlabels(const JSONRPCRequest& request) "\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."}, - }} - .ToString() + - "\nResult:\n" + }, + RPCResult{ "[ (json array of string)\n" " \"label\", (string) Label name\n" " ...\n" "]\n" - "\nExamples:\n" + }, + RPCExamples{ "\nList all labels\n" + HelpExampleCli("listlabels", "") + "\nList labels that have receiving addresses\n" @@ -3781,7 +3814,8 @@ static UniValue listlabels(const JSONRPCRequest& request) + HelpExampleCli("listlabels", "send") + "\nAs a JSON-RPC call\n" + HelpExampleRpc("listlabels", "receive") - ); + }, + }.ToString()); LOCK(pwallet->cs_wallet); @@ -3829,20 +3863,25 @@ UniValue sethdseed(const JSONRPCRequest& request) " 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" " The seed value can be retrieved using the dumpwallet command. It is the private key marked hdseed=1"}, - }} - .ToString() + - "\nExamples:\n" - + HelpExampleCli("sethdseed", "") + }, + RPCResults{}, + RPCExamples{ + HelpExampleCli("sethdseed", "") + HelpExampleCli("sethdseed", "false") + HelpExampleCli("sethdseed", "true \"wifkey\"") + HelpExampleRpc("sethdseed", "true, \"wifkey\"") - ); + }, + }.ToString()); } if (IsInitialBlockDownload()) { 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); @@ -3973,18 +4012,18 @@ UniValue walletprocesspsbt(const JSONRPCRequest& request) " \"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"}, - }} - .ToString() + - "\nResult:\n" + }, + RPCResult{ "{\n" " \"psbt\" : \"value\", (string) The base64-encoded partially signed transaction\n" " \"complete\" : true|false, (boolean) If the transaction has a complete set of signatures\n" " ]\n" "}\n" - - "\nExamples:\n" - + HelpExampleCli("walletprocesspsbt", "\"psbt\"") - ); + }, + RPCExamples{ + HelpExampleCli("walletprocesspsbt", "\"psbt\"") + }, + }.ToString()); RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL, UniValue::VSTR}); @@ -4055,8 +4094,7 @@ UniValue walletcreatefundedpsbt(const JSONRPCRequest& request) }, }, }, - {"locktime", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "0", "Raw locktime. Non-0 value also locktime-activates inputs\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."}, + {"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", "", { {"changeAddress", RPCArg::Type::STR_HEX, /* opt */ true, /* default_val */ "pool address", "The bitcoin address to receive the change"}, @@ -4083,18 +4121,19 @@ UniValue walletcreatefundedpsbt(const JSONRPCRequest& request) }, "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"}, - }} - .ToString() + - "\nResult:\n" + }, + RPCResult{ "{\n" " \"psbt\": \"value\", (string) The resulting raw transaction (base64-encoded string)\n" " \"fee\": n, (numeric) Fee in " + CURRENCY_UNIT + " the resulting transaction pays\n" " \"changepos\": n (numeric) The position of the added change output, or -1\n" "}\n" - "\nExamples:\n" + }, + RPCExamples{ "\nCreate a transaction with no inputs\n" + HelpExampleCli("walletcreatefundedpsbt", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"[{\\\"data\\\":\\\"00010203\\\"}]\"") - ); + }, + }.ToString()); RPCTypeCheck(request.params, { UniValue::VARR, diff --git a/src/wallet/test/db_tests.cpp b/src/wallet/test/db_tests.cpp new file mode 100644 index 0000000000..2a64749379 --- /dev/null +++ b/src/wallet/test/db_tests.cpp @@ -0,0 +1,72 @@ +// 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. + +#include <memory> + +#include <boost/test/unit_test.hpp> + +#include <fs.h> +#include <test/test_bitcoin.h> +#include <wallet/db.h> + + +BOOST_FIXTURE_TEST_SUITE(db_tests, BasicTestingSetup) + +BOOST_AUTO_TEST_CASE(getwalletenv_file) +{ + std::string test_name = "test_name.dat"; + fs::path datadir = SetDataDir("tempdir"); + fs::path file_path = datadir / test_name; + std::ofstream f(file_path.BOOST_FILESYSTEM_C_STR); + f.close(); + + std::string filename; + std::shared_ptr<BerkeleyEnvironment> env = GetWalletEnv(file_path, filename); + BOOST_CHECK(filename == test_name); + BOOST_CHECK(env->Directory() == datadir); +} + +BOOST_AUTO_TEST_CASE(getwalletenv_directory) +{ + std::string expected_name = "wallet.dat"; + fs::path datadir = SetDataDir("tempdir"); + + std::string filename; + std::shared_ptr<BerkeleyEnvironment> env = GetWalletEnv(datadir, filename); + BOOST_CHECK(filename == expected_name); + BOOST_CHECK(env->Directory() == datadir); +} + +BOOST_AUTO_TEST_CASE(getwalletenv_g_dbenvs_multiple) +{ + fs::path datadir = SetDataDir("tempdir"); + fs::path datadir_2 = SetDataDir("tempdir_2"); + std::string filename; + + std::shared_ptr<BerkeleyEnvironment> env_1 = GetWalletEnv(datadir, filename); + std::shared_ptr<BerkeleyEnvironment> env_2 = GetWalletEnv(datadir, filename); + std::shared_ptr<BerkeleyEnvironment> env_3 = GetWalletEnv(datadir_2, filename); + + BOOST_CHECK(env_1 == env_2); + BOOST_CHECK(env_2 != env_3); +} + +BOOST_AUTO_TEST_CASE(getwalletenv_g_dbenvs_free_instance) +{ + fs::path datadir = SetDataDir("tempdir"); + fs::path datadir_2 = SetDataDir("tempdir_2"); + std::string filename; + + std::shared_ptr <BerkeleyEnvironment> env_1_a = GetWalletEnv(datadir, filename); + std::shared_ptr <BerkeleyEnvironment> env_2_a = GetWalletEnv(datadir_2, filename); + env_1_a.reset(); + + std::shared_ptr<BerkeleyEnvironment> env_1_b = GetWalletEnv(datadir, filename); + std::shared_ptr<BerkeleyEnvironment> env_2_b = GetWalletEnv(datadir_2, filename); + + BOOST_CHECK(env_1_a != env_1_b); + BOOST_CHECK(env_2_a == env_2_b); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp index 1ed1926af2..fcb34c3706 100644 --- a/src/wallet/test/wallet_tests.cpp +++ b/src/wallet/test/wallet_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2018 The Bitcoin Core developers +// Copyright (c) 2012-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. @@ -39,7 +39,6 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup) auto chain = interfaces::MakeChain(); // Cap last block file size, and mine new block in a new block file. - const CBlockIndex* const null_block = nullptr; CBlockIndex* oldTip = chainActive.Tip(); GetBlockFileInfo(oldTip->GetBlockPos().nFile)->nSize = MAX_BLOCKFILE_SIZE; CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())); @@ -47,16 +46,17 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup) auto locked_chain = chain->lock(); - // Verify ScanForWalletTransactions accomodates a null start block. + // Verify ScanForWalletTransactions accommodates a null start block. { CWallet wallet(*chain, WalletLocation(), WalletDatabase::CreateDummy()); AddKey(wallet, coinbaseKey); WalletRescanReserver reserver(&wallet); reserver.reserve(); - const CBlockIndex *stop_block = null_block + 1, *failed_block = null_block + 1; - BOOST_CHECK_EQUAL(wallet.ScanForWalletTransactions(nullptr, nullptr, reserver, failed_block, stop_block), CWallet::ScanResult::SUCCESS); - BOOST_CHECK_EQUAL(failed_block, null_block); - BOOST_CHECK_EQUAL(stop_block, null_block); + CWallet::ScanResult result = wallet.ScanForWalletTransactions({} /* start_block */, {} /* stop_block */, reserver, false /* update */); + BOOST_CHECK_EQUAL(result.status, CWallet::ScanResult::SUCCESS); + 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); } @@ -67,10 +67,11 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup) AddKey(wallet, coinbaseKey); WalletRescanReserver reserver(&wallet); reserver.reserve(); - const CBlockIndex *stop_block = null_block + 1, *failed_block = null_block + 1; - BOOST_CHECK_EQUAL(wallet.ScanForWalletTransactions(oldTip, nullptr, reserver, failed_block, stop_block), CWallet::ScanResult::SUCCESS); - BOOST_CHECK_EQUAL(failed_block, null_block); - BOOST_CHECK_EQUAL(stop_block, newTip); + CWallet::ScanResult result = wallet.ScanForWalletTransactions(oldTip->GetBlockHash(), {} /* stop_block */, reserver, false /* update */); + BOOST_CHECK_EQUAL(result.status, CWallet::ScanResult::SUCCESS); + 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); } @@ -85,10 +86,11 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup) AddKey(wallet, coinbaseKey); WalletRescanReserver reserver(&wallet); reserver.reserve(); - const CBlockIndex *stop_block = null_block + 1, *failed_block = null_block + 1; - BOOST_CHECK_EQUAL(wallet.ScanForWalletTransactions(oldTip, nullptr, reserver, failed_block, stop_block), CWallet::ScanResult::FAILURE); - BOOST_CHECK_EQUAL(failed_block, oldTip); - BOOST_CHECK_EQUAL(stop_block, newTip); + CWallet::ScanResult result = wallet.ScanForWalletTransactions(oldTip->GetBlockHash(), {} /* stop_block */, reserver, false /* update */); + BOOST_CHECK_EQUAL(result.status, CWallet::ScanResult::FAILURE); + 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); } @@ -102,10 +104,11 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup) AddKey(wallet, coinbaseKey); WalletRescanReserver reserver(&wallet); reserver.reserve(); - const CBlockIndex *stop_block = null_block + 1, *failed_block = null_block + 1; - BOOST_CHECK_EQUAL(wallet.ScanForWalletTransactions(oldTip, nullptr, reserver, failed_block, stop_block), CWallet::ScanResult::FAILURE); - BOOST_CHECK_EQUAL(failed_block, newTip); - BOOST_CHECK_EQUAL(stop_block, null_block); + CWallet::ScanResult result = wallet.ScanForWalletTransactions(oldTip->GetBlockHash(), {} /* stop_block */, reserver, false /* update */); + BOOST_CHECK_EQUAL(result.status, CWallet::ScanResult::FAILURE); + 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); } } @@ -276,7 +279,7 @@ static int64_t AddTx(CWallet& wallet, uint32_t lockTime, int64_t mockTime, int64 CWalletTx wtx(&wallet, MakeTransactionRef(tx)); if (block) { - wtx.SetMerkleBranch(block, 0); + wtx.SetMerkleBranch(block->GetBlockHash(), 0); } { LOCK(cs_main); @@ -340,11 +343,11 @@ public: AddKey(*wallet, coinbaseKey); WalletRescanReserver reserver(wallet.get()); reserver.reserve(); - const CBlockIndex* const null_block = nullptr; - const CBlockIndex *stop_block = null_block + 1, *failed_block = null_block + 1; - BOOST_CHECK_EQUAL(wallet->ScanForWalletTransactions(chainActive.Genesis(), nullptr, reserver, failed_block, stop_block), CWallet::ScanResult::SUCCESS); - BOOST_CHECK_EQUAL(stop_block, chainActive.Tip()); - BOOST_CHECK_EQUAL(failed_block, null_block); + 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.last_scanned_block, chainActive.Tip()->GetBlockHash()); + BOOST_CHECK_EQUAL(*result.last_scanned_height, chainActive.Height()); + BOOST_CHECK(result.last_failed_block.IsNull()); } ~ListCoinsTestingSetup() @@ -372,7 +375,7 @@ public: LOCK(wallet->cs_wallet); auto it = wallet->mapWallet.find(tx->GetHash()); BOOST_CHECK(it != wallet->mapWallet.end()); - it->second.SetMerkleBranch(chainActive.Tip(), 1); + it->second.SetMerkleBranch(chainActive.Tip()->GetBlockHash(), 1); return it->second; } diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 109f8e6da0..bdddcd718b 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -82,13 +82,52 @@ std::shared_ptr<CWallet> GetWallet(const std::string& name) return nullptr; } +static Mutex g_wallet_release_mutex; +static std::condition_variable g_wallet_release_cv; +static std::set<CWallet*> g_unloading_wallet_set; + // Custom deleter for shared_ptr<CWallet>. static void ReleaseWallet(CWallet* wallet) { + // Unregister and delete the wallet right after BlockUntilSyncedToCurrentChain + // so that it's in sync with the current chainstate. wallet->WalletLogPrintf("Releasing wallet\n"); wallet->BlockUntilSyncedToCurrentChain(); wallet->Flush(); + UnregisterValidationInterface(wallet); delete wallet; + // Wallet is now released, notify UnloadWallet, if any. + { + LOCK(g_wallet_release_mutex); + if (g_unloading_wallet_set.erase(wallet) == 0) { + // UnloadWallet was not called for this wallet, all done. + return; + } + } + g_wallet_release_cv.notify_all(); +} + +void UnloadWallet(std::shared_ptr<CWallet>&& wallet) +{ + // Mark wallet for unloading. + CWallet* pwallet = wallet.get(); + { + LOCK(g_wallet_release_mutex); + auto it = g_unloading_wallet_set.insert(pwallet); + assert(it.second); + } + // The wallet can be in use so it's not possible to explicitly unload here. + // Notify the unload intent so that all remaining shared pointers are + // released. + pwallet->NotifyUnload(); + // Time to ditch our shared_ptr and wait for ReleaseWallet call. + wallet.reset(); + { + WAIT_LOCK(g_wallet_release_mutex, lock); + while (g_unloading_wallet_set.count(pwallet) == 1) { + g_wallet_release_cv.wait(lock); + } + } } const uint32_t BIP32_HARDENED_KEY_LIMIT = 0x80000000; @@ -212,6 +251,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. @@ -359,7 +401,7 @@ bool CWallet::LoadWatchOnly(const CScript &dest) return CCryptoKeyStore::AddWatchOnly(dest); } -bool CWallet::Unlock(const SecureString& strWalletPassphrase) +bool CWallet::Unlock(const SecureString& strWalletPassphrase, bool accept_no_keys) { CCrypter crypter; CKeyingMaterial _vMasterKey; @@ -372,7 +414,7 @@ bool CWallet::Unlock(const SecureString& strWalletPassphrase) return false; if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, _vMasterKey)) continue; // try another master key - if (CCryptoKeyStore::Unlock(_vMasterKey)) + if (CCryptoKeyStore::Unlock(_vMasterKey, accept_no_keys)) return true; } } @@ -896,19 +938,19 @@ void CWallet::LoadToWallet(const CWalletTx& wtxIn) } } -bool CWallet::AddToWalletIfInvolvingMe(const CTransactionRef& ptx, const CBlockIndex* pIndex, int posInBlock, bool fUpdate) +bool CWallet::AddToWalletIfInvolvingMe(const CTransactionRef& ptx, const uint256& block_hash, int posInBlock, bool fUpdate) { const CTransaction& tx = *ptx; { AssertLockHeld(cs_wallet); - if (pIndex != nullptr) { + if (!block_hash.IsNull()) { for (const CTxIn& txin : tx.vin) { std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(txin.prevout); while (range.first != range.second) { if (range.first->second != tx.GetHash()) { - WalletLogPrintf("Transaction %s (in block %s) conflicts with wallet transaction %s (both spend %s:%i)\n", tx.GetHash().ToString(), pIndex->GetBlockHash().ToString(), range.first->second.ToString(), range.first->first.hash.ToString(), range.first->first.n); - MarkConflicted(pIndex->GetBlockHash(), range.first->second); + WalletLogPrintf("Transaction %s (in block %s) conflicts with wallet transaction %s (both spend %s:%i)\n", tx.GetHash().ToString(), block_hash.ToString(), range.first->second.ToString(), range.first->first.hash.ToString(), range.first->first.n); + MarkConflicted(block_hash, range.first->second); } range.first++; } @@ -944,8 +986,8 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransactionRef& ptx, const CBlockI CWalletTx wtx(this, ptx); // Get merkle branch if transaction was found in a block - if (pIndex != nullptr) - wtx.SetMerkleBranch(pIndex, posInBlock); + if (!block_hash.IsNull()) + wtx.SetMerkleBranch(block_hash, posInBlock); return AddToWallet(wtx, false); } @@ -1032,11 +1074,7 @@ void CWallet::MarkConflicted(const uint256& hashBlock, const uint256& hashTx) auto locked_chain = chain().lock(); LOCK(cs_wallet); - int conflictconfirms = 0; - CBlockIndex* pindex = LookupBlockIndex(hashBlock); - if (pindex && chainActive.Contains(pindex)) { - conflictconfirms = -(chainActive.Height() - pindex->nHeight + 1); - } + int conflictconfirms = -locked_chain->getBlockDepth(hashBlock); // If number of conflict confirms cannot be determined, this means // that the block is still unknown or not yet part of the main chain, // for example when loading the wallet during a reindex. Do nothing in that @@ -1082,8 +1120,8 @@ void CWallet::MarkConflicted(const uint256& hashBlock, const uint256& hashTx) } } -void CWallet::SyncTransaction(const CTransactionRef& ptx, const CBlockIndex *pindex, int posInBlock, bool update_tx) { - if (!AddToWalletIfInvolvingMe(ptx, pindex, posInBlock, update_tx)) +void CWallet::SyncTransaction(const CTransactionRef& ptx, const uint256& block_hash, int posInBlock, bool update_tx) { + if (!AddToWalletIfInvolvingMe(ptx, block_hash, posInBlock, update_tx)) return; // Not one of ours // If a transaction changes 'conflicted' state, that changes the balance @@ -1095,7 +1133,7 @@ void CWallet::SyncTransaction(const CTransactionRef& ptx, const CBlockIndex *pin void CWallet::TransactionAddedToMempool(const CTransactionRef& ptx) { auto locked_chain = chain().lock(); LOCK(cs_wallet); - SyncTransaction(ptx); + SyncTransaction(ptx, {} /* block hash */, 0 /* position in block */); auto it = mapWallet.find(ptx->GetHash()); if (it != mapWallet.end()) { @@ -1123,15 +1161,15 @@ void CWallet::BlockConnected(const std::shared_ptr<const CBlock>& pblock, const // the notification that the conflicted transaction was evicted. for (const CTransactionRef& ptx : vtxConflicted) { - SyncTransaction(ptx); + SyncTransaction(ptx, {} /* block hash */, 0 /* position in block */); TransactionRemovedFromMempool(ptx); } for (size_t i = 0; i < pblock->vtx.size(); i++) { - SyncTransaction(pblock->vtx[i], pindex, i); + SyncTransaction(pblock->vtx[i], pindex->GetBlockHash(), i); TransactionRemovedFromMempool(pblock->vtx[i]); } - m_last_block_processed = pindex; + m_last_block_processed = pindex->GetBlockHash(); } void CWallet::BlockDisconnected(const std::shared_ptr<const CBlock>& pblock) { @@ -1139,7 +1177,7 @@ void CWallet::BlockDisconnected(const std::shared_ptr<const CBlock>& pblock) { LOCK(cs_wallet); for (const CTransactionRef& ptx : pblock->vtx) { - SyncTransaction(ptx); + SyncTransaction(ptx, {} /* block hash */, 0 /* position in block */); } } @@ -1156,9 +1194,8 @@ void CWallet::BlockUntilSyncedToCurrentChain() { // protected by cs_wallet instead of cs_main, but as long as we need // cs_main here anyway, it's easier to just call it cs_main-protected. auto locked_chain = chain().lock(); - const CBlockIndex* initialChainTip = chainActive.Tip(); - if (m_last_block_processed && m_last_block_processed->GetAncestor(initialChainTip->nHeight) == initialChainTip) { + if (!m_last_block_processed.IsNull() && locked_chain->isPotentialTip(m_last_block_processed)) { return; } } @@ -1364,6 +1401,7 @@ void CWallet::SetHDSeed(const CPubKey& seed) newHdChain.nVersion = CanSupportFeature(FEATURE_HD_SPLIT) ? CHDChain::VERSION_HD_CHAIN_SPLIT : CHDChain::VERSION_HD_BASE; newHdChain.seed_id = seed.GetID(); SetHDChain(newHdChain, false); + NotifyCanGetAddressesChanged(); } void CWallet::SetHDChain(const CHDChain& chain, bool memonly) @@ -1471,7 +1509,7 @@ int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *wall // implies that we can sign for every input. return -1; } - return GetVirtualTransactionSize(txNew); + return GetVirtualTransactionSize(CTransaction(txNew)); } int CalculateMaximumSignedInputSize(const CTxOut& txout, const CWallet* wallet, bool use_max_sig) @@ -1552,132 +1590,146 @@ int64_t CWallet::RescanFromTime(int64_t startTime, const WalletRescanReserver& r // Find starting block. May be null if nCreateTime is greater than the // highest blockchain timestamp, in which case there is nothing that needs // to be scanned. - CBlockIndex* startBlock = nullptr; + uint256 start_block; { auto locked_chain = chain().lock(); - startBlock = chainActive.FindEarliestAtLeast(startTime - TIMESTAMP_WINDOW); - WalletLogPrintf("%s: Rescanning last %i blocks\n", __func__, startBlock ? chainActive.Height() - startBlock->nHeight + 1 : 0); + const Optional<int> start_height = locked_chain->findFirstBlockWithTime(startTime - TIMESTAMP_WINDOW, &start_block); + const Optional<int> tip_height = locked_chain->getHeight(); + WalletLogPrintf("%s: Rescanning last %i blocks\n", __func__, tip_height && start_height ? *tip_height - *start_height + 1 : 0); } - if (startBlock) { - const CBlockIndex *failedBlock, *stop_block; + if (!start_block.IsNull()) { // TODO: this should take into account failure by ScanResult::USER_ABORT - if (ScanResult::FAILURE == ScanForWalletTransactions(startBlock, nullptr, reserver, failedBlock, stop_block, update)) { - return failedBlock->GetBlockTimeMax() + TIMESTAMP_WINDOW + 1; + ScanResult result = ScanForWalletTransactions(start_block, {} /* stop_block */, reserver, update); + if (result.status == ScanResult::FAILURE) { + int64_t 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; } } return startTime; } /** - * Scan the block chain (starting in pindexStart) for transactions + * Scan the block chain (starting in start_block) for transactions * from or to us. If fUpdate is true, found transactions that already * exist in the wallet will be updated. * - * @param[in] pindexStop if not a nullptr, the scan will stop at this block-index - * @param[out] failed_block if FAILURE is returned, the most recent block - * that could not be scanned, otherwise nullptr - * @param[out] stop_block the most recent block that could be scanned, - * otherwise nullptr if no block could be scanned + * @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 pindexStop (and the optional pindexStart) are on + * @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 * transactions for. */ -CWallet::ScanResult CWallet::ScanForWalletTransactions(const CBlockIndex* const pindexStart, const CBlockIndex* const pindexStop, const WalletRescanReserver& reserver, const CBlockIndex*& failed_block, const CBlockIndex*& stop_block, bool fUpdate) +CWallet::ScanResult CWallet::ScanForWalletTransactions(const uint256& start_block, const uint256& stop_block, const WalletRescanReserver& reserver, bool fUpdate) { int64_t nNow = GetTime(); - const CChainParams& chainParams = Params(); assert(reserver.isReserved()); - if (pindexStop) { - assert(pindexStop->nHeight >= pindexStart->nHeight); - } - const CBlockIndex* pindex = pindexStart; - failed_block = nullptr; - stop_block = nullptr; + uint256 block_hash = start_block; + ScanResult result; - if (pindex) WalletLogPrintf("Rescan started from block %d...\n", pindex->nHeight); + WalletLogPrintf("Rescan started from block %s...\n", start_block.ToString()); { fAbortRescan = false; ShowProgress(strprintf("%s " + _("Rescanning..."), GetDisplayName()), 0); // show rescan progress in GUI as dialog or on splashscreen, if -rescan on startup - CBlockIndex* tip = nullptr; + uint256 tip_hash; + // The way the 'block_height' is initialized is just a workaround for the gcc bug #47679 since version 4.6.0. + Optional<int> block_height = MakeOptional(false, int()); double progress_begin; double progress_end; { auto locked_chain = chain().lock(); - progress_begin = GuessVerificationProgress(chainParams.TxData(), pindex); - if (pindexStop == nullptr) { - tip = chainActive.Tip(); - progress_end = GuessVerificationProgress(chainParams.TxData(), tip); - } else { - progress_end = GuessVerificationProgress(chainParams.TxData(), pindexStop); + if (Optional<int> tip_height = locked_chain->getHeight()) { + tip_hash = locked_chain->getBlockHash(*tip_height); } + block_height = locked_chain->getBlockHeight(block_hash); + progress_begin = chain().guessVerificationProgress(block_hash); + progress_end = chain().guessVerificationProgress(stop_block.IsNull() ? tip_hash : stop_block); } double progress_current = progress_begin; - while (pindex && !fAbortRescan && !ShutdownRequested()) { - if (pindex->nHeight % 100 == 0 && progress_end - progress_begin > 0.0) { + while (block_height && !fAbortRescan && !ShutdownRequested()) { + if (*block_height % 100 == 0 && progress_end - progress_begin > 0.0) { ShowProgress(strprintf("%s " + _("Rescanning..."), GetDisplayName()), std::max(1, std::min(99, (int)((progress_current - progress_begin) / (progress_end - progress_begin) * 100)))); } if (GetTime() >= nNow + 60) { nNow = GetTime(); - WalletLogPrintf("Still rescanning. At block %d. Progress=%f\n", pindex->nHeight, progress_current); + WalletLogPrintf("Still rescanning. At block %d. Progress=%f\n", *block_height, progress_current); } CBlock block; - if (ReadBlockFromDisk(block, pindex, Params().GetConsensus())) { + if (chain().findBlock(block_hash, &block) && !block.IsNull()) { auto locked_chain = chain().lock(); LOCK(cs_wallet); - if (pindex && !chainActive.Contains(pindex)) { + if (!locked_chain->getBlockHeight(block_hash)) { // Abort scan if current block is no longer active, to prevent // marking transactions as coming from the wrong block. - failed_block = pindex; + // TODO: This should return success instead of failure, see + // https://github.com/bitcoin/bitcoin/pull/14711#issuecomment-458342518 + result.last_failed_block = block_hash; + result.status = ScanResult::FAILURE; break; } for (size_t posInBlock = 0; posInBlock < block.vtx.size(); ++posInBlock) { - SyncTransaction(block.vtx[posInBlock], pindex, posInBlock, fUpdate); + SyncTransaction(block.vtx[posInBlock], block_hash, posInBlock, fUpdate); } // scan succeeded, record block as most recent successfully scanned - stop_block = pindex; + 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 - failed_block = pindex; + result.last_failed_block = block_hash; + result.status = ScanResult::FAILURE; } - if (pindex == pindexStop) { + if (block_hash == stop_block) { break; } { auto locked_chain = chain().lock(); - pindex = chainActive.Next(pindex); - progress_current = GuessVerificationProgress(chainParams.TxData(), pindex); - if (pindexStop == nullptr && tip != chainActive.Tip()) { - tip = chainActive.Tip(); + Optional<int> tip_height = locked_chain->getHeight(); + if (!tip_height || *tip_height <= block_height || !locked_chain->getBlockHeight(block_hash)) { + // break successfully when rescan has reached the tip, or + // previous block is no longer on the chain due to a reorg + break; + } + + // increment block and verification progress + block_hash = locked_chain->getBlockHash(++*block_height); + progress_current = chain().guessVerificationProgress(block_hash); + + // handle updated tip hash + const uint256 prev_tip_hash = tip_hash; + tip_hash = locked_chain->getBlockHash(*tip_height); + if (stop_block.IsNull() && prev_tip_hash != tip_hash) { // in case the tip has changed, update progress max - progress_end = GuessVerificationProgress(chainParams.TxData(), tip); + progress_end = chain().guessVerificationProgress(tip_hash); } } } ShowProgress(strprintf("%s " + _("Rescanning..."), GetDisplayName()), 100); // hide progress dialog in GUI - if (pindex && fAbortRescan) { - WalletLogPrintf("Rescan aborted at block %d. Progress=%f\n", pindex->nHeight, progress_current); - return ScanResult::USER_ABORT; - } else if (pindex && ShutdownRequested()) { - WalletLogPrintf("Rescan interrupted by shutdown request at block %d. Progress=%f\n", pindex->nHeight, progress_current); - return ScanResult::USER_ABORT; + if (block_height && fAbortRescan) { + 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, progress_current); + result.status = ScanResult::USER_ABORT; } } - if (failed_block) { - return ScanResult::FAILURE; - } else { - return ScanResult::SUCCESS; - } + return result; } void CWallet::ReacceptWalletTransactions() @@ -2516,6 +2568,66 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nC return true; } +static bool IsCurrentForAntiFeeSniping(interfaces::Chain::Lock& locked_chain) +{ + if (IsInitialBlockDownload()) { + return false; + } + constexpr int64_t MAX_ANTI_FEE_SNIPING_TIP_AGE = 8 * 60 * 60; // in seconds + if (chainActive.Tip()->GetBlockTime() < (GetTime() - MAX_ANTI_FEE_SNIPING_TIP_AGE)) { + return false; + } + return true; +} + +/** + * Return a height-based locktime for new transactions (uses the height of the + * current chain tip unless we are not synced with the current chain + */ +static uint32_t GetLocktimeForNewTransaction(interfaces::Chain::Lock& locked_chain) +{ + uint32_t const height = locked_chain.getHeight().get_value_or(-1); + uint32_t locktime; + // Discourage fee sniping. + // + // For a large miner the value of the transactions in the best block and + // the mempool can exceed the cost of deliberately attempting to mine two + // blocks to orphan the current best block. By setting nLockTime such that + // only the next block can include the transaction, we discourage this + // practice as the height restricted and limited blocksize gives miners + // considering fee sniping fewer options for pulling off this attack. + // + // A simple way to think about this is from the wallet's point of view we + // always want the blockchain to move forward. By setting nLockTime this + // way we're basically making the statement that we only want this + // transaction to appear in the next block; we don't want to potentially + // encourage reorgs by allowing transactions to appear at lower heights + // than the next block in forks of the best chain. + // + // Of course, the subsidy is high enough, and transaction volume low + // enough, that fee sniping isn't a problem yet, but by implementing a fix + // now we ensure code won't be written that makes assumptions about + // nLockTime that preclude a fix later. + if (IsCurrentForAntiFeeSniping(locked_chain)) { + locktime = height; + + // Secondly occasionally randomly pick a nLockTime even further back, so + // that transactions that are delayed after signing for whatever reason, + // e.g. high-latency mix networks and some CoinJoin implementations, have + // better privacy. + if (GetRandInt(10) == 0) + locktime = std::max(0, (int)locktime - GetRandInt(100)); + } else { + // If our chain is lagging behind, we can't discourage fee sniping nor help + // the privacy of high-latency transactions. To avoid leaking a potentially + // unique "nLockTime fingerprint", set nLockTime to a constant. + locktime = 0; + } + assert(locktime <= height); + assert(locktime < LOCKTIME_THRESHOLD); + return locktime; +} + OutputType CWallet::TransactionChangeType(OutputType change_type, const std::vector<CRecipient>& vecSend) { // If -changetype is specified, always use that change type. @@ -2570,37 +2682,8 @@ bool CWallet::CreateTransaction(interfaces::Chain::Lock& locked_chain, const std CMutableTransaction txNew; - // Discourage fee sniping. - // - // For a large miner the value of the transactions in the best block and - // the mempool can exceed the cost of deliberately attempting to mine two - // blocks to orphan the current best block. By setting nLockTime such that - // only the next block can include the transaction, we discourage this - // practice as the height restricted and limited blocksize gives miners - // considering fee sniping fewer options for pulling off this attack. - // - // A simple way to think about this is from the wallet's point of view we - // always want the blockchain to move forward. By setting nLockTime this - // way we're basically making the statement that we only want this - // transaction to appear in the next block; we don't want to potentially - // encourage reorgs by allowing transactions to appear at lower heights - // than the next block in forks of the best chain. - // - // Of course, the subsidy is high enough, and transaction volume low - // enough, that fee sniping isn't a problem yet, but by implementing a fix - // now we ensure code won't be written that makes assumptions about - // nLockTime that preclude a fix later. - txNew.nLockTime = chainActive.Height(); - - // Secondly occasionally randomly pick a nLockTime even further back, so - // that transactions that are delayed after signing for whatever reason, - // e.g. high-latency mix networks and some CoinJoin implementations, have - // better privacy. - if (GetRandInt(10) == 0) - txNew.nLockTime = std::max(0, (int)txNew.nLockTime - GetRandInt(100)); + txNew.nLockTime = GetLocktimeForNewTransaction(locked_chain); - assert(txNew.nLockTime <= (unsigned int)chainActive.Height()); - assert(txNew.nLockTime < LOCKTIME_THRESHOLD); FeeCalculation feeCalc; CAmount nFeeNeeded; int nBytes; @@ -2781,7 +2864,7 @@ bool CWallet::CreateTransaction(interfaces::Chain::Lock& locked_chain, const std txNew.vin.push_back(CTxIn(coin.outpoint,CScript())); } - nBytes = CalculateMaximumSignedTxSize(txNew, this, coin_control.fAllowWatchOnly); + nBytes = CalculateMaximumSignedTxSize(CTransaction(txNew), this, coin_control.fAllowWatchOnly); if (nBytes < 0) { strFailReason = _("Signing transaction failed"); return false; @@ -3258,6 +3341,7 @@ bool CWallet::TopUpKeyPool(unsigned int kpSize) 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()); } } + NotifyCanGetAddressesChanged(); return true; } @@ -3302,6 +3386,7 @@ bool CWallet::ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool, bool fRe m_pool_key_to_index.erase(keypool.vchPubKey.GetID()); WalletLogPrintf("keypool reserve %d\n", nIndex); } + NotifyCanGetAddressesChanged(); return true; } @@ -3326,6 +3411,7 @@ void CWallet::ReturnKey(int64_t nIndex, bool fInternal, const CPubKey& pubkey) setExternalKeyPool.insert(nIndex); } m_pool_key_to_index[pubkey.GetID()] = nIndex; + NotifyCanGetAddressesChanged(); } WalletLogPrintf("keypool return %d\n", nIndex); } @@ -3649,11 +3735,12 @@ void CWallet::GetKeyBirthTimes(interfaces::Chain::Lock& locked_chain, std::map<C } // map in which we'll infer heights of other keys - CBlockIndex *pindexMax = chainActive[std::max(0, chainActive.Height() - 144)]; // the tip can be reorganized; use a 144-block safety margin - std::map<CKeyID, CBlockIndex*> mapKeyFirstBlock; + const Optional<int> tip_height = locked_chain.getHeight(); + const int max_height = tip_height && *tip_height > 144 ? *tip_height - 144 : 0; // the tip can be reorganized; use a 144-block safety margin + std::map<CKeyID, int> mapKeyFirstBlock; for (const CKeyID &keyid : GetKeys()) { if (mapKeyBirth.count(keyid) == 0) - mapKeyFirstBlock[keyid] = pindexMax; + mapKeyFirstBlock[keyid] = max_height; } // if there are no such keys, we're done @@ -3664,17 +3751,15 @@ void CWallet::GetKeyBirthTimes(interfaces::Chain::Lock& locked_chain, std::map<C for (const auto& entry : mapWallet) { // iterate over all wallet transactions... const CWalletTx &wtx = entry.second; - CBlockIndex* pindex = LookupBlockIndex(wtx.hashBlock); - if (pindex && chainActive.Contains(pindex)) { + if (Optional<int> height = locked_chain.getBlockHeight(wtx.hashBlock)) { // ... which are already in a block - int nHeight = pindex->nHeight; for (const CTxOut &txout : wtx.tx->vout) { // iterate over all their outputs for (const auto &keyid : GetAffectedKeys(txout.scriptPubKey, *this)) { // ... and all their affected keys - std::map<CKeyID, CBlockIndex*>::iterator rit = mapKeyFirstBlock.find(keyid); - if (rit != mapKeyFirstBlock.end() && nHeight < rit->second->nHeight) - rit->second = pindex; + std::map<CKeyID, int>::iterator rit = mapKeyFirstBlock.find(keyid); + if (rit != mapKeyFirstBlock.end() && *height < rit->second) + rit->second = *height; } } } @@ -3682,7 +3767,7 @@ void CWallet::GetKeyBirthTimes(interfaces::Chain::Lock& locked_chain, std::map<C // Extract block timestamps for those keys for (const auto& entry : mapKeyFirstBlock) - mapKeyBirth[entry.first] = entry.second->GetBlockTime() - TIMESTAMP_WINDOW; // block times can be 2h off + mapKeyBirth[entry.first] = locked_chain.getBlockTime(entry.second) - TIMESTAMP_WINDOW; // block times can be 2h off } /** @@ -3710,7 +3795,8 @@ unsigned int CWallet::ComputeTimeSmart(const CWalletTx& wtx) const { unsigned int nTimeSmart = wtx.nTimeReceived; if (!wtx.hashUnset()) { - if (const CBlockIndex* pindex = LookupBlockIndex(wtx.hashBlock)) { + int64_t blocktime; + if (chain().findBlock(wtx.hashBlock, nullptr /* block */, &blocktime)) { int64_t latestNow = wtx.nTimeReceived; int64_t latestEntry = 0; @@ -3736,7 +3822,6 @@ unsigned int CWallet::ComputeTimeSmart(const CWalletTx& wtx) const } } - int64_t blocktime = pindex->GetBlockTime(); nTimeSmart = std::max(latestEntry, std::min(blocktime, latestNow)); } else { WalletLogPrintf("%s: found %s in block %s not in index\n", __func__, wtx.GetHash().ToString(), wtx.hashBlock.ToString()); @@ -3842,6 +3927,9 @@ bool CWallet::Verify(interfaces::Chain& chain, const WalletLocation& location, b return false; } + // Keep same database environment instance across Verify/Recover calls below. + std::unique_ptr<WalletDatabase> database = WalletDatabase::Create(wallet_path); + try { if (!WalletBatch::VerifyEnvironment(wallet_path, error_string)) { return false; @@ -3998,7 +4086,7 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain, } auto locked_chain = chain.assumeLocked(); // Temporary. Removed in upcoming lock cleanup - walletInstance->ChainStateFlushed(chainActive.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)); @@ -4085,58 +4173,67 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain, // Try to top up keypool. No-op if the wallet is locked. walletInstance->TopUpKeyPool(); - LockAnnotation lock(::cs_main); // Temporary, for FindForkInGlobalIndex below. Removed in upcoming commit. auto locked_chain = chain.lock(); LOCK(walletInstance->cs_wallet); - CBlockIndex *pindexRescan = chainActive.Genesis(); + int rescan_height = 0; if (!gArgs.GetBoolArg("-rescan", false)) { WalletBatch batch(*walletInstance->database); CBlockLocator locator; - if (batch.ReadBestBlock(locator)) - pindexRescan = FindForkInGlobalIndex(chainActive, locator); + if (batch.ReadBestBlock(locator)) { + if (const Optional<int> fork_height = locked_chain->findLocatorFork(locator)) { + rescan_height = *fork_height; + } + } } - walletInstance->m_last_block_processed = chainActive.Tip(); + const Optional<int> tip_height = locked_chain->getHeight(); + if (tip_height) { + walletInstance->m_last_block_processed = locked_chain->getBlockHash(*tip_height); + } else { + walletInstance->m_last_block_processed.SetNull(); + } - if (chainActive.Tip() && chainActive.Tip() != pindexRescan) + if (tip_height && *tip_height != rescan_height) { //We can't rescan beyond non-pruned blocks, stop and throw an error //this might happen if a user uses an old wallet within a pruned node // or if he ran -disablewallet for a longer time, then decided to re-enable if (fPruneMode) { - CBlockIndex *block = chainActive.Tip(); - while (block && block->pprev && (block->pprev->nStatus & BLOCK_HAVE_DATA) && block->pprev->nTx > 0 && pindexRescan != block) - block = block->pprev; + int block_height = *tip_height; + while (block_height > 0 && locked_chain->haveBlockOnDisk(block_height - 1) && rescan_height != block_height) { + --block_height; + } - if (pindexRescan != block) { + if (rescan_height != block_height) { InitError(_("Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)")); return nullptr; } } uiInterface.InitMessage(_("Rescanning...")); - walletInstance->WalletLogPrintf("Rescanning last %i blocks (from block %i)...\n", chainActive.Height() - pindexRescan->nHeight, pindexRescan->nHeight); + walletInstance->WalletLogPrintf("Rescanning last %i blocks (from block %i)...\n", *tip_height - rescan_height, rescan_height); // No need to read and scan block if block was created before // our wallet birthday (as adjusted for block time variability) - while (pindexRescan && walletInstance->nTimeFirstKey && (pindexRescan->GetBlockTime() < (walletInstance->nTimeFirstKey - TIMESTAMP_WINDOW))) { - pindexRescan = chainActive.Next(pindexRescan); + if (walletInstance->nTimeFirstKey) { + if (Optional<int> first_block = locked_chain->findFirstBlockWithTimeAndHeight(walletInstance->nTimeFirstKey - TIMESTAMP_WINDOW, rescan_height)) { + rescan_height = *first_block; + } } nStart = GetTimeMillis(); { WalletRescanReserver reserver(walletInstance.get()); - const CBlockIndex *stop_block, *failed_block; - if (!reserver.reserve() || (ScanResult::SUCCESS != walletInstance->ScanForWalletTransactions(pindexRescan, nullptr, reserver, failed_block, stop_block, true))) { + if (!reserver.reserve() || (ScanResult::SUCCESS != walletInstance->ScanForWalletTransactions(locked_chain->getBlockHash(rescan_height), {} /* stop block */, reserver, true /* update */).status)) { InitError(_("Failed to rescan the wallet during initialization")); return nullptr; } } walletInstance->WalletLogPrintf("Rescan completed in %15dms\n", GetTimeMillis() - nStart); - walletInstance->ChainStateFlushed(chainActive.GetLocator()); + walletInstance->ChainStateFlushed(locked_chain->getTipLocator()); walletInstance->database->IncrementUpdateCounter(); // Restore wallet transaction metadata after -zapwallettxes=1 @@ -4213,10 +4310,10 @@ CWalletKey::CWalletKey(int64_t nExpires) nTimeExpires = nExpires; } -void CMerkleTx::SetMerkleBranch(const CBlockIndex* pindex, int posInBlock) +void CMerkleTx::SetMerkleBranch(const uint256& block_hash, int posInBlock) { // Update the tx's hashBlock - hashBlock = pindex->GetBlockHash(); + hashBlock = block_hash; // set the position of the transaction in the block nIndex = posInBlock; @@ -4229,12 +4326,7 @@ int CMerkleTx::GetDepthInMainChain(interfaces::Chain::Lock& locked_chain) const AssertLockHeld(cs_main); - // Find the block it claims to be in - CBlockIndex* pindex = LookupBlockIndex(hashBlock); - if (!pindex || !chainActive.Contains(pindex)) - return 0; - - return ((nIndex == -1) ? (-1) : 1) * (chainActive.Height() - pindex->nHeight + 1); + return locked_chain.getBlockDepth(hashBlock) * (nIndex == -1 ? -1 : 1); } int CMerkleTx::GetBlocksToMaturity(interfaces::Chain::Lock& locked_chain) const diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 95a2c833f8..cf3fa0aced 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -35,8 +35,8 @@ #include <vector> //! Responsible for reading and validating the -wallet arguments and verifying the wallet database. -// This function will perform salvage on the wallet if requested, as long as only one wallet is -// being loaded (WalletParameterInteraction forbids -salvagewallet, -zapwallettxes or -upgradewallet with multiwallet). +//! This function will perform salvage on the wallet if requested, as long as only one wallet is +//! being loaded (WalletParameterInteraction forbids -salvagewallet, -zapwallettxes or -upgradewallet with multiwallet). bool VerifyWallets(interfaces::Chain& chain, const std::vector<std::string>& wallet_files); //! Load wallet databases. @@ -54,6 +54,13 @@ void StopWallets(); //! Close all wallets. void UnloadWallets(); +//! Explicitly unload and delete the wallet. +//! Blocks the current thread after signaling the unload intent so that all +//! wallet clients release the wallet. +//! Note that, when blocking is not required, the wallet is implicitly unloaded +//! by the shared pointer deleter. +void UnloadWallet(std::shared_ptr<CWallet>&& wallet); + bool AddWallet(const std::shared_ptr<CWallet>& wallet); bool RemoveWallet(const std::shared_ptr<CWallet>& wallet); bool HasWallets(); @@ -88,7 +95,6 @@ static const bool DEFAULT_DISABLE_WALLET = false; //! Pre-calculated constants for input size estimation in *virtual size* static constexpr size_t DUMMY_NESTED_P2WPKH_INPUT_SIZE = 91; -class CBlockIndex; class CCoinControl; class COutput; class CReserveKey; @@ -280,7 +286,7 @@ public: READWRITE(nIndex); } - void SetMerkleBranch(const CBlockIndex* pIndex, int posInBlock); + void SetMerkleBranch(const uint256& block_hash, int posInBlock); /** * Return depth of transaction in blockchain: @@ -581,8 +587,8 @@ public: int64_t nTimeCreated; int64_t nTimeExpires; std::string strComment; - //! todo: add something to note what created it (user, getnewaddress, change) - //! maybe should have a map<string, string> property map + // todo: add something to note what created it (user, getnewaddress, change) + // maybe should have a map<string, string> property map explicit CWalletKey(int64_t nExpires=0); @@ -660,7 +666,7 @@ private: * Abandoned state should probably be more carefully tracked via different * posInBlock signals or by checking mempool presence when necessary. */ - bool AddToWalletIfInvolvingMe(const CTransactionRef& tx, const CBlockIndex* pIndex, int posInBlock, bool fUpdate) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); + bool AddToWalletIfInvolvingMe(const CTransactionRef& tx, const uint256& block_hash, int posInBlock, bool fUpdate) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); /* Mark a transaction (and its in-wallet descendants) as conflicting with a particular block. */ void MarkConflicted(const uint256& hashBlock, const uint256& hashTx); @@ -671,8 +677,8 @@ private: void SyncMetaData(std::pair<TxSpends::iterator, TxSpends::iterator>) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); /* Used by TransactionAddedToMemorypool/BlockConnected/Disconnected/ScanForWalletTransactions. - * Should be called with pindexBlock and posInBlock if this is for a transaction that is included in a block. */ - void SyncTransaction(const CTransactionRef& tx, const CBlockIndex *pindex = nullptr, int posInBlock = 0, bool update_tx = true) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); + * Should be called with non-zero block_hash and posInBlock if this is for a transaction that is included in a block. */ + void SyncTransaction(const CTransactionRef& tx, const uint256& block_hash, int posInBlock = 0, bool update_tx = true) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); /* the HD chain data model (external chain counters) */ CHDChain hdChain; @@ -716,10 +722,8 @@ private: * Note that this is *not* how far we've processed, we may need some rescan * to have seen all transactions in the chain, but is only used to track * live BlockConnected callbacks. - * - * Protected by cs_main (see BlockUntilSyncedToCurrentChain) */ - const CBlockIndex* m_last_block_processed = nullptr; + uint256 m_last_block_processed; public: /* @@ -770,6 +774,8 @@ public: ~CWallet() { + // Should not have slots connected at this point. + assert(NotifyUnload.empty()); delete encrypted_batch; encrypted_batch = nullptr; } @@ -878,7 +884,7 @@ public: //! Holds a timestamp at which point the wallet is scheduled (externally) to be relocked. Caller must arrange for actual relocking to occur via Lock(). int64_t nRelockTime = 0; - bool Unlock(const SecureString& strWalletPassphrase); + bool Unlock(const SecureString& strWalletPassphrase, bool accept_no_keys = false); bool ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase); bool EncryptWallet(const SecureString& strWalletPassphrase); @@ -900,12 +906,22 @@ public: void BlockDisconnected(const std::shared_ptr<const CBlock>& pblock) override; int64_t RescanFromTime(int64_t startTime, const WalletRescanReserver& reserver, bool update); - enum class ScanResult { - SUCCESS, - FAILURE, - USER_ABORT + struct ScanResult { + enum { SUCCESS, FAILURE, USER_ABORT } status = SUCCESS; + + //! 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 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 last_failed_block; }; - ScanResult ScanForWalletTransactions(const CBlockIndex* const pindexStart, const CBlockIndex* const pindexStop, const WalletRescanReserver& reserver, const CBlockIndex*& failed_block, const CBlockIndex*& stop_block, bool fUpdate = false); + ScanResult ScanForWalletTransactions(const uint256& first_block, const uint256& last_block, const WalletRescanReserver& reserver, bool fUpdate); void TransactionRemovedFromMempool(const CTransactionRef &ptx) override; void ReacceptWalletTransactions(); void ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman) override EXCLUSIVE_LOCKS_REQUIRED(cs_main); @@ -1078,6 +1094,9 @@ public: /** Watch-only address added */ boost::signals2::signal<void (bool fHaveWatchOnly)> NotifyWatchonlyChanged; + /** Keypool has new keys */ + boost::signals2::signal<void ()> NotifyCanGetAddressesChanged; + /** Inquire whether this wallet broadcasts transactions. */ bool GetBroadcastTransactions() const { return fBroadcastTransactions; } /** Set whether this wallet broadcasts transactions. */ @@ -1178,18 +1197,16 @@ class CReserveKey final : public CReserveScript { protected: CWallet* pwallet; - int64_t nIndex; + int64_t nIndex{-1}; CPubKey vchPubKey; - bool fInternal; + bool fInternal{false}; + public: explicit CReserveKey(CWallet* pwalletIn) { - nIndex = -1; pwallet = pwalletIn; - fInternal = false; } - CReserveKey() = default; CReserveKey(const CReserveKey&) = delete; CReserveKey& operator=(const CReserveKey&) = delete; diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index 09a33f252c..6e037808e3 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -153,21 +153,17 @@ bool WalletBatch::WriteMinVersion(int nVersion) class CWalletScanState { public: - unsigned int nKeys; - unsigned int nCKeys; - unsigned int nWatchKeys; - unsigned int nKeyMeta; - unsigned int m_unknown_records; - bool fIsEncrypted; - bool fAnyUnordered; - int nFileVersion; + unsigned int nKeys{0}; + unsigned int nCKeys{0}; + unsigned int nWatchKeys{0}; + unsigned int nKeyMeta{0}; + unsigned int m_unknown_records{0}; + bool fIsEncrypted{false}; + bool fAnyUnordered{false}; + int nFileVersion{0}; std::vector<uint256> vWalletUpgrade; CWalletScanState() { - nKeys = nCKeys = nWatchKeys = nKeyMeta = m_unknown_records = 0; - fIsEncrypted = false; - fAnyUnordered = false; - nFileVersion = 0; } }; diff --git a/src/wallet/wallettool.cpp b/src/wallet/wallettool.cpp new file mode 100644 index 0000000000..30b0c48eef --- /dev/null +++ b/src/wallet/wallettool.cpp @@ -0,0 +1,139 @@ +// Copyright (c) 2016-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 <base58.h> +#include <fs.h> +#include <interfaces/chain.h> +#include <util/system.h> +#include <wallet/wallet.h> +#include <wallet/walletutil.h> + +namespace WalletTool { + +// The standard wallet deleter function blocks on the validation interface +// queue, which doesn't exist for the bitcoin-wallet. Define our own +// deleter here. +static void WalletToolReleaseWallet(CWallet* wallet) +{ + wallet->WalletLogPrintf("Releasing wallet\n"); + wallet->Flush(); + delete wallet; +} + +static std::shared_ptr<CWallet> CreateWallet(const std::string& name, const fs::path& path) +{ + if (fs::exists(path)) { + fprintf(stderr, "Error: File exists already\n"); + return nullptr; + } + // dummy chain interface + auto chain = interfaces::MakeChain(); + std::shared_ptr<CWallet> wallet_instance(new CWallet(*chain, WalletLocation(name), WalletDatabase::Create(path)), WalletToolReleaseWallet); + bool first_run = true; + DBErrors load_wallet_ret = wallet_instance->LoadWallet(first_run); + if (load_wallet_ret != DBErrors::LOAD_OK) { + fprintf(stderr, "Error creating %s", name.c_str()); + return nullptr; + } + + wallet_instance->SetMinVersion(FEATURE_HD_SPLIT); + + // generate a new HD seed + CPubKey seed = wallet_instance->GenerateNewSeed(); + wallet_instance->SetHDSeed(seed); + + fprintf(stdout, "Topping up keypool...\n"); + wallet_instance->TopUpKeyPool(); + return wallet_instance; +} + +static std::shared_ptr<CWallet> LoadWallet(const std::string& name, const fs::path& path) +{ + if (!fs::exists(path)) { + fprintf(stderr, "Error: Wallet files does not exist\n"); + return nullptr; + } + + // dummy chain interface + auto chain = interfaces::MakeChain(); + std::shared_ptr<CWallet> wallet_instance(new CWallet(*chain, WalletLocation(name), WalletDatabase::Create(path)), WalletToolReleaseWallet); + DBErrors load_wallet_ret; + try { + bool first_run; + load_wallet_ret = wallet_instance->LoadWallet(first_run); + } catch (const std::runtime_error) { + fprintf(stderr, "Error loading %s. Is wallet being used by another process?\n", name.c_str()); + return nullptr; + } + + if (load_wallet_ret != DBErrors::LOAD_OK) { + wallet_instance = nullptr; + if (load_wallet_ret == DBErrors::CORRUPT) { + fprintf(stderr, "Error loading %s: Wallet corrupted", name.c_str()); + return nullptr; + } else if (load_wallet_ret == DBErrors::NONCRITICAL_ERROR) { + fprintf(stderr, "Error reading %s! All keys read correctly, but transaction data" + " or address book entries might be missing or incorrect.", + name.c_str()); + } else if (load_wallet_ret == DBErrors::TOO_NEW) { + fprintf(stderr, "Error loading %s: Wallet requires newer version of %s", + name.c_str(), PACKAGE_NAME); + return nullptr; + } else if (load_wallet_ret == DBErrors::NEED_REWRITE) { + fprintf(stderr, "Wallet needed to be rewritten: restart %s to complete", PACKAGE_NAME); + return nullptr; + } else { + fprintf(stderr, "Error loading %s", name.c_str()); + return nullptr; + } + } + + return wallet_instance; +} + +static void WalletShowInfo(CWallet* wallet_instance) +{ + // lock required because of some AssertLockHeld() + LOCK(wallet_instance->cs_wallet); + + fprintf(stdout, "Wallet info\n===========\n"); + fprintf(stdout, "Encrypted: %s\n", wallet_instance->IsCrypted() ? "yes" : "no"); + fprintf(stdout, "HD (hd seed available): %s\n", wallet_instance->GetHDChain().seed_id.IsNull() ? "no" : "yes"); + fprintf(stdout, "Keypool Size: %u\n", wallet_instance->GetKeyPoolSize()); + fprintf(stdout, "Transactions: %zu\n", wallet_instance->mapWallet.size()); + fprintf(stdout, "Address Book: %zu\n", wallet_instance->mapAddressBook.size()); +} + +bool ExecuteWalletToolFunc(const std::string& command, const std::string& name) +{ + fs::path path = fs::absolute(name, GetWalletDir()); + + if (command == "create") { + std::shared_ptr<CWallet> wallet_instance = CreateWallet(name, path); + if (wallet_instance) { + WalletShowInfo(wallet_instance.get()); + wallet_instance->Flush(); + } + } else if (command == "info") { + if (!fs::exists(path)) { + fprintf(stderr, "Error: no wallet file at %s\n", name.c_str()); + return false; + } + std::string error; + if (!WalletBatch::VerifyEnvironment(path, error)) { + fprintf(stderr, "Error loading %s. Is wallet being used by other process?\n", name.c_str()); + return false; + } + std::shared_ptr<CWallet> wallet_instance = LoadWallet(name, path); + if (!wallet_instance) return false; + WalletShowInfo(wallet_instance.get()); + wallet_instance->Flush(); + } else { + fprintf(stderr, "Invalid command: %s\n", command.c_str()); + return false; + } + + return true; +} +} // namespace WalletTool diff --git a/src/wallet/wallettool.h b/src/wallet/wallettool.h new file mode 100644 index 0000000000..5b06fd1792 --- /dev/null +++ b/src/wallet/wallettool.h @@ -0,0 +1,20 @@ +// Copyright (c) 2016-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. + +#ifndef BITCOIN_WALLET_WALLETTOOL_H +#define BITCOIN_WALLET_WALLETTOOL_H + +#include <script/ismine.h> +#include <wallet/wallet.h> + +namespace WalletTool { + +std::shared_ptr<CWallet> CreateWallet(const std::string& name, const fs::path& path); +std::shared_ptr<CWallet> LoadWallet(const std::string& name, const fs::path& path); +void WalletShowInfo(CWallet* wallet_instance); +bool ExecuteWalletToolFunc(const std::string& command, const std::string& file); + +} // namespace WalletTool + +#endif // BITCOIN_WALLET_WALLETTOOL_H diff --git a/src/zmq/zmqpublishnotifier.cpp b/src/zmq/zmqpublishnotifier.cpp index 15d4ac1b89..ba89d1401d 100644 --- a/src/zmq/zmqpublishnotifier.cpp +++ b/src/zmq/zmqpublishnotifier.cpp @@ -101,6 +101,7 @@ bool CZMQAbstractPublishNotifier::Initialize(void *pcontext) else { LogPrint(BCLog::ZMQ, "zmq: Reusing socket for address %s\n", address); + LogPrint(BCLog::ZMQ, "zmq: Outbound message high water mark for %s at %s is %d\n", type, address, outbound_message_high_water_mark); psocket = i->second->psocket; mapPublishNotifiers.insert(std::make_pair(address, this)); diff --git a/src/zmq/zmqrpc.cpp b/src/zmq/zmqrpc.cpp index d3eab46e5f..a34968ef7d 100644 --- a/src/zmq/zmqrpc.cpp +++ b/src/zmq/zmqrpc.cpp @@ -18,9 +18,9 @@ UniValue getzmqnotifications(const JSONRPCRequest& request) if (request.fHelp || request.params.size() != 0) { throw std::runtime_error( RPCHelpMan{"getzmqnotifications", - "\nReturns information about the active ZeroMQ notifications.\n", {}} - .ToString() + - "\nResult:\n" + "\nReturns information about the active ZeroMQ notifications.\n", + {}, + RPCResult{ "[\n" " { (json object)\n" " \"type\": \"pubhashtx\", (string) Type of notification\n" @@ -29,10 +29,12 @@ UniValue getzmqnotifications(const JSONRPCRequest& request) " },\n" " ...\n" "]\n" - "\nExamples:\n" - + HelpExampleCli("getzmqnotifications", "") + }, + RPCExamples{ + HelpExampleCli("getzmqnotifications", "") + HelpExampleRpc("getzmqnotifications", "") - ); + }, + }.ToString()); } UniValue result(UniValue::VARR); diff --git a/test/README.md b/test/README.md index 1cf22cb64b..9d4351b1de 100644 --- a/test/README.md +++ b/test/README.md @@ -18,7 +18,8 @@ request is opened. All sets of tests can also be run locally. # Running tests locally -Build for your system first. Be sure to enable wallet, utils and daemon when you configure. Tests will not run otherwise. +Before tests can be run locally, Bitcoin Core must be built. See the [building instructions](/doc#building) for help. + ### Functional tests @@ -174,7 +175,8 @@ cat /tmp/user/1000/testo9vsdjo3/node1/regtest/bitcoind.pid gdb /home/example/bitcoind <pid> ``` -Note: gdb attach step may require `sudo` +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 diff --git a/test/functional/README.md b/test/functional/README.md index 711151d606..74f454b86c 100644 --- a/test/functional/README.md +++ b/test/functional/README.md @@ -20,9 +20,13 @@ don't have test cases for. - Where possible, try to adhere to [PEP-8 guidelines](https://www.python.org/dev/peps/pep-0008/) - Use a python linter like flake8 before submitting PRs to catch common style nits (eg trailing whitespace, unused imports, etc) +- The oldest supported Python version is specified in [doc/dependencies.md](/doc/dependencies.md). + Consider using [pyenv](https://github.com/pyenv/pyenv), which checks [.python-version](/.python-version), + to prevent accidentally introducing modern syntax from an unsupported Python version. + The Travis linter also checks this, but [possibly not in all cases](https://github.com/bitcoin/bitcoin/pull/14884#discussion_r239585126). - See [the python lint script](/test/lint/lint-python.sh) that checks for violations that could lead to bugs and issues in the test code. -- Avoid wildcard imports where possible +- Avoid wildcard imports - Use a module-level docstring to describe what the test is testing, and how it is testing it. - When subclassing the BitcoinTestFramwork, place overrides for the diff --git a/test/functional/example_test.py b/test/functional/example_test.py index be3544ee74..f367e4fca8 100755 --- a/test/functional/example_test.py +++ b/test/functional/example_test.py @@ -13,7 +13,7 @@ is testing and *how* it's being tested # libraries then local imports). from collections import defaultdict -# Avoid wildcard * imports if possible +# Avoid wildcard * imports from test_framework.blocktools import (create_block, create_coinbase) from test_framework.messages import CInv from test_framework.mininode import ( diff --git a/test/functional/feature_block.py b/test/functional/feature_block.py index 697a0b19ac..5253ff7aaa 100755 --- a/test/functional/feature_block.py +++ b/test/functional/feature_block.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 block processing.""" @@ -137,12 +137,6 @@ class FullBlockTest(BitcoinTestFramework): for TxTemplate in invalid_txs.iter_all_templates(): template = TxTemplate(spend_tx=attempt_spend_tx) - # Something about the serialization code for missing inputs creates - # a different hash in the test client than on bitcoind, resulting - # in a mismatching merkle root during block validation. - # Skip until we figure out what's going on. - if TxTemplate == invalid_txs.InputMissing: - continue if template.valid_in_block: continue @@ -150,7 +144,22 @@ class FullBlockTest(BitcoinTestFramework): blockname = "for_invalid.%s" % TxTemplate.__name__ badblock = self.next_block(blockname) badtx = template.get_tx() - self.sign_tx(badtx, attempt_spend_tx) + if TxTemplate != invalid_txs.InputMissing: + self.sign_tx(badtx, attempt_spend_tx) + else: + # Segwit is active in regtest at this point, so to deserialize a + # transaction without any inputs correctly, we set the outputs + # to an empty list. This is a hack, as the serialization of an + # empty list of outputs is deserialized as flags==0 and thus + # deserialization of the outputs is skipped. + # A policy check requires "loose" txs to be of a minimum size, + # so vtx is not set to be empty in the TxTemplate class and we + # only apply the workaround where txs are not "loose", i.e. in + # blocks. + # + # The workaround has the purpose that both sides calculate + # the same tx hash in the merkle tree + badtx.vout = [] badtx.rehash() badblock = self.update_block(blockname, [badtx]) self.sync_blocks( @@ -916,7 +925,7 @@ class FullBlockTest(BitcoinTestFramework): # \-> b67 (20) # # - self.log.info("Reject a block with a transaction double spending a transaction creted in the same block") + self.log.info("Reject a block with a transaction double spending a transaction created in the same block") self.move_tip(65) b67 = self.next_block(67) tx1 = self.create_and_sign_transaction(out[20], out[20].vout[0].nValue) @@ -1211,7 +1220,7 @@ class FullBlockTest(BitcoinTestFramework): blocks = [] spend = out[32] for i in range(89, LARGE_REORG_SIZE + 89): - b = self.next_block(i, spend) + b = self.next_block(i, spend, version=4) tx = CTransaction() script_length = MAX_BLOCK_BASE_SIZE - len(b.serialize()) - 69 script_output = CScript([b'\x00' * script_length]) @@ -1230,20 +1239,32 @@ class FullBlockTest(BitcoinTestFramework): self.move_tip(88) blocks2 = [] for i in range(89, LARGE_REORG_SIZE + 89): - blocks2.append(self.next_block("alt" + str(i))) + blocks2.append(self.next_block("alt" + str(i), version=4)) self.sync_blocks(blocks2, False, force_send=True) # extend alt chain to trigger re-org - block = self.next_block("alt" + str(chain1_tip + 1)) + block = self.next_block("alt" + str(chain1_tip + 1), version=4) self.sync_blocks([block], True, timeout=480) # ... and re-org back to the first chain self.move_tip(chain1_tip) - block = self.next_block(chain1_tip + 1) + block = self.next_block(chain1_tip + 1, version=4) self.sync_blocks([block], False, force_send=True) - block = self.next_block(chain1_tip + 2) + block = self.next_block(chain1_tip + 2, version=4) self.sync_blocks([block], True, timeout=480) + self.log.info("Reject a block with an invalid block header version") + b_v1 = self.next_block('b_v1', version=1) + self.sync_blocks([b_v1], success=False, force_send=True, reject_reason='bad-version(0x00000001)') + + self.move_tip(chain1_tip + 2) + b_cb34 = self.next_block('b_cb34', version=4) + b_cb34.vtx[0].vin[0].scriptSig = b_cb34.vtx[0].vin[0].scriptSig[:-1] + b_cb34.vtx[0].rehash() + b_cb34.hashMerkleRoot = b_cb34.calc_merkle_root() + b_cb34.solve() + self.sync_blocks([b_cb34], success=False, reject_reason='bad-cb-height', reconnect=True) + # Helper methods ################ @@ -1271,7 +1292,7 @@ class FullBlockTest(BitcoinTestFramework): tx.rehash() return tx - def next_block(self, number, spend=None, additional_coinbase_value=0, script=CScript([OP_TRUE]), solve=True): + def next_block(self, number, spend=None, additional_coinbase_value=0, script=CScript([OP_TRUE]), solve=True, *, version=1): if self.tip is None: base_block_hash = self.genesis_hash block_time = int(time.time()) + 1 @@ -1284,11 +1305,11 @@ class FullBlockTest(BitcoinTestFramework): coinbase.vout[0].nValue += additional_coinbase_value coinbase.rehash() if spend is None: - block = create_block(base_block_hash, coinbase, block_time) + block = create_block(base_block_hash, coinbase, block_time, version=version) else: coinbase.vout[0].nValue += spend.vout[0].nValue - 1 # all but one satoshi to fees coinbase.rehash() - block = create_block(base_block_hash, coinbase, block_time) + block = create_block(base_block_hash, coinbase, block_time, version=version) tx = self.create_tx(spend, 0, 1, script) # spend 1 satoshi self.sign_tx(tx, spend) self.add_transactions_to_block(block, [tx]) diff --git a/test/functional/feature_blocksdir.py b/test/functional/feature_blocksdir.py index c170f510c8..3a4889bbe9 100755 --- a/test/functional/feature_blocksdir.py +++ b/test/functional/feature_blocksdir.py @@ -18,6 +18,8 @@ class BlocksdirTest(BitcoinTestFramework): def run_test(self): self.stop_node(0) + assert os.path.isdir(os.path.join(self.nodes[0].datadir, "regtest", "blocks")) + assert not os.path.isdir(os.path.join(self.nodes[0].datadir, "blocks")) shutil.rmtree(self.nodes[0].datadir) initialize_datadir(self.options.tmpdir, 0) self.log.info("Starting with nonexistent blocksdir ...") diff --git a/test/functional/feature_config_args.py b/test/functional/feature_config_args.py index d87eabaa6d..4b3f6603a2 100755 --- a/test/functional/feature_config_args.py +++ b/test/functional/feature_config_args.py @@ -34,6 +34,14 @@ class ConfArgsTest(BitcoinTestFramework): self.nodes[0].assert_start_raises_init_error(expected_msg='Error reading configuration file: parse error on line 3, using # in rpcpassword can be ambiguous and should be avoided') with open(inc_conf_file_path, 'w', encoding='utf-8') as conf: + conf.write('server=1\nrpcuser=someuser\nmain.rpcpassword=some#pass') + self.nodes[0].assert_start_raises_init_error(expected_msg='Error reading configuration file: parse error on line 3, using # in rpcpassword can be ambiguous and should be avoided') + + with open(inc_conf_file_path, 'w', encoding='utf-8') as conf: + conf.write('server=1\nrpcuser=someuser\n[main]\nrpcpassword=some#pass') + self.nodes[0].assert_start_raises_init_error(expected_msg='Error reading configuration file: parse error on line 4, using # in rpcpassword can be ambiguous and should be avoided') + + with open(inc_conf_file_path, 'w', encoding='utf-8') as conf: conf.write('testnot.datadir=1\n[testnet]\n') self.restart_node(0) self.nodes[0].stop_node(expected_stderr='Warning: Section [testnet] is not recognized.' + os.linesep + 'Warning: Section [testnot] is not recognized.') diff --git a/test/functional/feature_pruning.py b/test/functional/feature_pruning.py index 9a3f4fae45..3e1ba88f0a 100755 --- a/test/functional/feature_pruning.py +++ b/test/functional/feature_pruning.py @@ -320,7 +320,7 @@ class PruneTest(BitcoinTestFramework): if has_block(3): raise AssertionError("blk00003.dat is still there, should be pruned by now") - # stop node, start back up with auto-prune at 550MB, make sure still runs + # stop node, start back up with auto-prune at 550 MiB, make sure still runs self.stop_node(node_number) self.start_node(node_number, extra_args=["-prune=550"]) diff --git a/test/functional/feature_segwit.py b/test/functional/feature_segwit.py index 4bcdf9af55..1efc50e71f 100755 --- a/test/functional/feature_segwit.py +++ b/test/functional/feature_segwit.py @@ -43,22 +43,26 @@ class SegWitTest(BitcoinTestFramework): 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" ], ] diff --git a/test/functional/feature_shutdown.py b/test/functional/feature_shutdown.py index b633fabb1f..5084cb1322 100755 --- a/test/functional/feature_shutdown.py +++ b/test/functional/feature_shutdown.py @@ -5,7 +5,7 @@ """Test bitcoind shutdown.""" from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import assert_equal, get_rpc_proxy +from test_framework.util import assert_equal, get_rpc_proxy, wait_until from threading import Thread def test_long_call(node): @@ -20,8 +20,14 @@ class ShutdownTest(BitcoinTestFramework): def run_test(self): node = get_rpc_proxy(self.nodes[0].url, 1, timeout=600, coveragedir=self.nodes[0].coverage_dir) + # Force connection establishment by executing a dummy command. + node.getblockcount() Thread(target=test_long_call, args=(node,)).start() - # wait 1 second to ensure event loop waits for current connections to close + # Wait until the server is executing the above `waitfornewblock`. + wait_until(lambda: len(self.nodes[0].getrpcinfo()['active_commands']) == 2) + # Wait 1 second after requesting shutdown but not before the `stop` call + # finishes. This is to ensure event loop waits for current connections + # to close. self.stop_node(0, wait=1000) if __name__ == '__main__': diff --git a/test/functional/interface_rest.py b/test/functional/interface_rest.py index afa9de580f..f850a54462 100755 --- a/test/functional/interface_rest.py +++ b/test/functional/interface_rest.py @@ -41,7 +41,8 @@ class RESTTest (BitcoinTestFramework): def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 2 - self.extra_args = [["-rest"], []] + # TODO: remove -txindex. Currently required for getrawtransaction call. + self.extra_args = [["-rest", "-txindex"], []] def skip_test_if_missing_module(self): self.skip_if_no_wallet() @@ -198,9 +199,19 @@ class RESTTest (BitcoinTestFramework): self.nodes[0].generate(1) # generate block to not affect upcoming tests self.sync_all() - self.log.info("Test the /block and /headers URIs") + self.log.info("Test the /block, /blockhashbyheight and /headers URIs") bb_hash = self.nodes[0].getbestblockhash() + # Check result if block does not exists + assert_equal(self.test_rest_request('/headers/1/0000000000000000000000000000000000000000000000000000000000000000'), []) + self.test_rest_request('/block/0000000000000000000000000000000000000000000000000000000000000000', status=404, ret_type=RetType.OBJ) + + # Check result if block is not in the active chain + self.nodes[0].invalidateblock(bb_hash) + assert_equal(self.test_rest_request('/headers/1/{}'.format(bb_hash)), []) + self.test_rest_request('/block/{}'.format(bb_hash)) + self.nodes[0].reconsiderblock(bb_hash) + # 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) @@ -227,6 +238,23 @@ class RESTTest (BitcoinTestFramework): # Check json format block_json_obj = self.test_rest_request("/block/{}".format(bb_hash)) assert_equal(block_json_obj['hash'], bb_hash) + assert_equal(self.test_rest_request("/blockhashbyheight/{}".format(block_json_obj['height']))['blockhash'], bb_hash) + + # Check hex/bin format + resp_hex = self.test_rest_request("/blockhashbyheight/{}".format(block_json_obj['height']), req_type=ReqType.HEX, ret_type=RetType.OBJ) + assert_equal(resp_hex.read().decode('utf-8').rstrip(), bb_hash) + resp_bytes = self.test_rest_request("/blockhashbyheight/{}".format(block_json_obj['height']), req_type=ReqType.BIN, ret_type=RetType.BYTES) + blockhash = binascii.hexlify(resp_bytes[::-1]).decode('utf-8') + assert_equal(blockhash, bb_hash) + + # Check invalid blockhashbyheight requests + resp = self.test_rest_request("/blockhashbyheight/abc", ret_type=RetType.OBJ, status=400) + assert_equal(resp.read().decode('utf-8').rstrip(), "Invalid height: abc") + resp = self.test_rest_request("/blockhashbyheight/1000000", ret_type=RetType.OBJ, status=404) + assert_equal(resp.read().decode('utf-8').rstrip(), "Block height out of range") + resp = self.test_rest_request("/blockhashbyheight/-1", ret_type=RetType.OBJ, status=400) + assert_equal(resp.read().decode('utf-8').rstrip(), "Invalid height: -1") + self.test_rest_request("/blockhashbyheight/", ret_type=RetType.OBJ, status=400) # Compare with json block header json_obj = self.test_rest_request("/headers/1/{}".format(bb_hash)) diff --git a/test/functional/interface_rpc.py b/test/functional/interface_rpc.py index e3d7b0655d..b6955d4492 100755 --- a/test/functional/interface_rpc.py +++ b/test/functional/interface_rpc.py @@ -5,13 +5,23 @@ """Tests some generic aspects of the RPC interface.""" from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import assert_equal +from test_framework.util import assert_equal, assert_greater_than_or_equal class RPCInterfaceTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 1 self.setup_clean_chain = True + def test_getrpcinfo(self): + self.log.info("Testing getrpcinfo...") + + info = self.nodes[0].getrpcinfo() + assert_equal(len(info['active_commands']), 1) + + command = info['active_commands'][0] + assert_equal(command['method'], 'getrpcinfo') + assert_greater_than_or_equal(command['duration'], 0) + def test_batch_request(self): self.log.info("Testing basic JSON-RPC batch request...") @@ -39,6 +49,7 @@ class RPCInterfaceTest(BitcoinTestFramework): assert result_by_id[3]['result'] is not None def run_test(self): + self.test_getrpcinfo() self.test_batch_request() diff --git a/test/functional/p2p_invalid_messages.py b/test/functional/p2p_invalid_messages.py index dbc5c5fff6..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.""" @@ -16,7 +16,7 @@ class msg_unrecognized: command = b'badmsg' - def __init__(self, str_data): + def __init__(self, *, str_data): self.str_data = str_data.encode() if not isinstance(str_data, bytes) else str_data def serialize(self): @@ -26,19 +26,14 @@ class msg_unrecognized: return "{}(data={})".format(self.command, self.str_data) -class msg_nametoolong(msg_unrecognized): - - command = b'thisnameiswayyyyyyyyytoolong' - - class InvalidMessagesTest(BitcoinTestFramework): - def set_test_params(self): self.num_nodes = 1 self.setup_clean_chain = True def run_test(self): """ + . Test msg header 0. Send a bunch of large (4MB) messages of an unrecognized type. Check to see that it isn't an effective DoS against the node. @@ -46,10 +41,12 @@ class InvalidMessagesTest(BitcoinTestFramework): 2. Send a few messages with an incorrect data size in the header, ensure the messages are ignored. - - 3. Send an unrecognized message with a command name longer than 12 characters. - """ + self.test_magic_bytes() + self.test_checksum() + self.test_size() + self.test_command() + node = self.nodes[0] self.node = node node.add_p2p_connection(P2PDataStore()) @@ -64,7 +61,7 @@ class InvalidMessagesTest(BitcoinTestFramework): # Send as large a message as is valid, ensure we aren't disconnected but # also can't exhaust resources. # - msg_at_size = msg_unrecognized("b" * valid_data_limit) + msg_at_size = msg_unrecognized(str_data="b" * valid_data_limit) assert len(msg_at_size.serialize()) == msg_limit increase_allowed = 0.5 @@ -94,10 +91,10 @@ class InvalidMessagesTest(BitcoinTestFramework): # # Send an oversized message, ensure we're disconnected. # - msg_over_size = msg_unrecognized("b" * (valid_data_limit + 1)) + msg_over_size = msg_unrecognized(str_data="b" * (valid_data_limit + 1)) assert len(msg_over_size.serialize()) == (msg_limit + 1) - with node.assert_debug_log(["Oversized message from peer=0, disconnecting"]): + with node.assert_debug_log(["Oversized message from peer=4, disconnecting"]): # An unknown message type (or *any* message type) over # MAX_PROTOCOL_MESSAGE_LENGTH should result in a disconnect. node.p2p.send_message(msg_over_size) @@ -113,7 +110,7 @@ class InvalidMessagesTest(BitcoinTestFramework): # Send messages with an incorrect data size in the header. # actual_size = 100 - msg = msg_unrecognized("b" * actual_size) + msg = msg_unrecognized(str_data="b" * actual_size) # TODO: handle larger-than cases. I haven't been able to pin down what behavior to expect. for wrong_size in (2, 77, 78, 79): @@ -140,18 +137,59 @@ class InvalidMessagesTest(BitcoinTestFramework): node.disconnect_p2ps() node.add_p2p_connection(P2PDataStore()) - # - # 3. - # - # Send a message with a too-long command name. - # - node.p2p.send_message(msg_nametoolong("foobar")) - node.p2p.wait_for_disconnect(timeout=4) - # Node is still up. conn = node.add_p2p_connection(P2PDataStore()) conn.sync_with_ping() + 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)) + conn.wait_for_disconnect(timeout=1) + self.nodes[0].disconnect_p2ps() + + def test_checksum(self): + conn = self.nodes[0].add_p2p_connection(P2PDataStore()) + with self.nodes[0].assert_debug_log(['ProcessMessages(badmsg, 2 bytes): CHECKSUM ERROR expected 78df0a04 was ffffffff']): + msg = conn.build_message(msg_unrecognized(str_data="d")) + cut_len = ( + 4 + # magic + 12 + # command + 4 #len + ) + # modify checksum + msg = msg[:cut_len] + b'\xff' * 4 + msg[cut_len + 4:] + self.nodes[0].p2p.send_raw_message(msg) + conn.sync_with_ping(timeout=1) + self.nodes[0].disconnect_p2ps() + + def test_size(self): + conn = self.nodes[0].add_p2p_connection(P2PDataStore()) + with self.nodes[0].assert_debug_log(['']): + msg = conn.build_message(msg_unrecognized(str_data="d")) + cut_len = ( + 4 + # magic + 12 # command + ) + # modify len to MAX_SIZE + 1 + msg = msg[:cut_len] + struct.pack("<I", 0x02000000 + 1) + msg[cut_len + 4:] + self.nodes[0].p2p.send_raw_message(msg) + conn.wait_for_disconnect(timeout=1) + self.nodes[0].disconnect_p2ps() + + def test_command(self): + conn = self.nodes[0].add_p2p_connection(P2PDataStore()) + with self.nodes[0].assert_debug_log(['PROCESSMESSAGE: ERRORS IN HEADER']): + msg = msg_unrecognized(str_data="d") + msg.command = b'\xff' * 12 + msg = conn.build_message(msg) + # Modify command + msg = msg[:7] + b'\x00' + msg[7 + 1:] + self.nodes[0].p2p.send_raw_message(msg) + conn.sync_with_ping(timeout=1) + self.nodes[0].disconnect_p2ps() def _tweak_msg_data_size(self, message, wrong_size): """ @@ -174,6 +212,5 @@ class InvalidMessagesTest(BitcoinTestFramework): return raw_msg_with_wrong_size - if __name__ == '__main__': InvalidMessagesTest().main() diff --git a/test/functional/p2p_segwit.py b/test/functional/p2p_segwit.py index d95da227e5..8f8e89cf15 100755 --- a/test/functional/p2p_segwit.py +++ b/test/functional/p2p_segwit.py @@ -755,7 +755,7 @@ class SegWitTest(BitcoinTestFramework): spend_tx.vin[0].scriptSig = CScript([p2wsh_pubkey, b'a']) spend_tx.rehash() with self.nodes[0].assert_debug_log( - expected_msgs=('Not relaying invalid transaction {}'.format(spend_tx.hash), 'was not accepted: mandatory-script-verify-flag-failed (Script evaluated without error but finished with a false/empty top stack element)')): + expected_msgs=(spend_tx.hash, 'was not accepted: mandatory-script-verify-flag-failed (Script evaluated without error but finished with a false/empty top stack element)')): test_transaction_acceptance(self.nodes[0], self.test_node, spend_tx, with_witness=False, accepted=False) # Now put the witness script in the witness, should succeed after diff --git a/test/functional/rpc_invalidateblock.py b/test/functional/rpc_invalidateblock.py index d8ecdd573a..d8a1deb2a3 100755 --- a/test/functional/rpc_invalidateblock.py +++ b/test/functional/rpc_invalidateblock.py @@ -4,10 +4,15 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test the invalidateblock RPC.""" -import time - from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import assert_equal, connect_nodes_bi, sync_blocks +from test_framework.address import ADDRESS_BCRT1_UNSPENDABLE +from test_framework.util import ( + assert_equal, + connect_nodes_bi, + sync_blocks, + wait_until, +) + class InvalidateTest(BitcoinTestFramework): def set_test_params(self): @@ -21,46 +26,66 @@ class InvalidateTest(BitcoinTestFramework): self.log.info("Make sure we repopulate setBlockIndexCandidates after InvalidateBlock:") self.log.info("Mine 4 blocks on Node 0") self.nodes[0].generatetoaddress(4, self.nodes[0].get_deterministic_priv_key().address) - assert(self.nodes[0].getblockcount() == 4) - besthash = self.nodes[0].getbestblockhash() + assert_equal(self.nodes[0].getblockcount(), 4) + besthash_n0 = self.nodes[0].getbestblockhash() self.log.info("Mine competing 6 blocks on Node 1") self.nodes[1].generatetoaddress(6, self.nodes[1].get_deterministic_priv_key().address) - assert(self.nodes[1].getblockcount() == 6) + assert_equal(self.nodes[1].getblockcount(), 6) self.log.info("Connect nodes to force a reorg") - connect_nodes_bi(self.nodes,0,1) + connect_nodes_bi(self.nodes, 0, 1) sync_blocks(self.nodes[0:2]) - assert(self.nodes[0].getblockcount() == 6) + assert_equal(self.nodes[0].getblockcount(), 6) badhash = self.nodes[1].getblockhash(2) self.log.info("Invalidate block 2 on node 0 and verify we reorg to node 0's original chain") self.nodes[0].invalidateblock(badhash) - newheight = self.nodes[0].getblockcount() - newhash = self.nodes[0].getbestblockhash() - if (newheight != 4 or newhash != besthash): - raise AssertionError("Wrong tip for node0, hash %s, height %d"%(newhash,newheight)) + assert_equal(self.nodes[0].getblockcount(), 4) + assert_equal(self.nodes[0].getbestblockhash(), besthash_n0) self.log.info("Make sure we won't reorg to a lower work chain:") - connect_nodes_bi(self.nodes,1,2) + connect_nodes_bi(self.nodes, 1, 2) self.log.info("Sync node 2 to node 1 so both have 6 blocks") sync_blocks(self.nodes[1:3]) - assert(self.nodes[2].getblockcount() == 6) + assert_equal(self.nodes[2].getblockcount(), 6) self.log.info("Invalidate block 5 on node 1 so its tip is now at 4") self.nodes[1].invalidateblock(self.nodes[1].getblockhash(5)) - assert(self.nodes[1].getblockcount() == 4) + assert_equal(self.nodes[1].getblockcount(), 4) self.log.info("Invalidate block 3 on node 2, so its tip is now 2") self.nodes[2].invalidateblock(self.nodes[2].getblockhash(3)) - assert(self.nodes[2].getblockcount() == 2) + assert_equal(self.nodes[2].getblockcount(), 2) self.log.info("..and then mine a block") self.nodes[2].generatetoaddress(1, self.nodes[2].get_deterministic_priv_key().address) self.log.info("Verify all nodes are at the right height") - time.sleep(5) - assert_equal(self.nodes[2].getblockcount(), 3) - assert_equal(self.nodes[0].getblockcount(), 4) - node1height = self.nodes[1].getblockcount() - if node1height < 4: - raise AssertionError("Node 1 reorged to a lower height: %d"%node1height) + wait_until(lambda: self.nodes[2].getblockcount() == 3, timeout=5) + wait_until(lambda: self.nodes[0].getblockcount() == 4, timeout=5) + wait_until(lambda: self.nodes[1].getblockcount() == 4, timeout=5) + + self.log.info("Verify that we reconsider all ancestors as well") + blocks = self.nodes[1].generatetoaddress(10, ADDRESS_BCRT1_UNSPENDABLE) + assert_equal(self.nodes[1].getbestblockhash(), blocks[-1]) + # Invalidate the two blocks at the tip + self.nodes[1].invalidateblock(blocks[-1]) + self.nodes[1].invalidateblock(blocks[-2]) + assert_equal(self.nodes[1].getbestblockhash(), blocks[-3]) + # Reconsider only the previous tip + self.nodes[1].reconsiderblock(blocks[-1]) + # Should be back at the tip by now + assert_equal(self.nodes[1].getbestblockhash(), blocks[-1]) + + self.log.info("Verify that we reconsider all descendants") + blocks = self.nodes[1].generatetoaddress(10, ADDRESS_BCRT1_UNSPENDABLE) + assert_equal(self.nodes[1].getbestblockhash(), blocks[-1]) + # Invalidate the two blocks at the tip + self.nodes[1].invalidateblock(blocks[-2]) + self.nodes[1].invalidateblock(blocks[-4]) + assert_equal(self.nodes[1].getbestblockhash(), blocks[-5]) + # Reconsider only the previous tip + self.nodes[1].reconsiderblock(blocks[-4]) + # Should be back at the tip by now + assert_equal(self.nodes[1].getbestblockhash(), blocks[-1]) + if __name__ == '__main__': InvalidateTest().main() diff --git a/test/functional/rpc_psbt.py b/test/functional/rpc_psbt.py index 272ebe65cb..1e10280e60 100755 --- a/test/functional/rpc_psbt.py +++ b/test/functional/rpc_psbt.py @@ -19,6 +19,8 @@ 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() diff --git a/test/functional/rpc_rawtransaction.py b/test/functional/rpc_rawtransaction.py index 5b9dbef68d..a97d753626 100755 --- a/test/functional/rpc_rawtransaction.py +++ b/test/functional/rpc_rawtransaction.py @@ -42,7 +42,8 @@ class RawTransactionsTest(BitcoinTestFramework): def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 3 - self.extra_args = [["-addresstype=legacy"], ["-addresstype=legacy"], ["-addresstype=legacy"]] + # 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): self.skip_if_no_wallet() diff --git a/test/functional/test_framework/blocktools.py b/test/functional/test_framework/blocktools.py index 7679ea5398..6b47cae4c3 100644 --- a/test/functional/test_framework/blocktools.py +++ b/test/functional/test_framework/blocktools.py @@ -46,9 +46,10 @@ MAX_BLOCK_SIGOPS = 20000 # From BIP141 WITNESS_COMMITMENT_HEADER = b"\xaa\x21\xa9\xed" -def create_block(hashprev, coinbase, ntime=None): +def create_block(hashprev, coinbase, ntime=None, *, version=1): """Create a block (with regtest difficulty).""" block = CBlock() + block.nVersion = version if ntime is None: import time block.nTime = int(time.time() + 600) diff --git a/test/functional/test_framework/mininode.py b/test/functional/test_framework/mininode.py index ca5734d67d..ac7cc068bd 100755 --- a/test/functional/test_framework/mininode.py +++ b/test/functional/test_framework/mininode.py @@ -118,7 +118,7 @@ class P2PConnection(asyncio.Protocol): # The initial message to send after the connection was made: self.on_connection_send_msg = None self.recvbuf = b"" - self.network = net + self.magic_bytes = MAGIC_BYTES[net] logger.debug('Connecting to Bitcoin Node: %s:%d' % (self.dstaddr, self.dstport)) loop = NetworkThread.network_event_loop @@ -170,7 +170,7 @@ class P2PConnection(asyncio.Protocol): while True: if len(self.recvbuf) < 4: return - if self.recvbuf[:4] != MAGIC_BYTES[self.network]: + if self.recvbuf[:4] != self.magic_bytes: raise ValueError("got garbage %s" % repr(self.recvbuf)) if len(self.recvbuf) < 4 + 12 + 4 + 4: return @@ -232,7 +232,7 @@ class P2PConnection(asyncio.Protocol): """Build a serialized P2P message""" command = message.command data = message.serialize() - tmsg = MAGIC_BYTES[self.network] + tmsg = self.magic_bytes tmsg += command tmsg += b"\x00" * (12 - len(command)) tmsg += struct.pack("<I", len(data)) diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py index 240d9ce87c..8c4c0d7226 100755 --- a/test/functional/test_framework/test_framework.py +++ b/test/functional/test_framework/test_framework.py @@ -141,6 +141,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass): config = configparser.ConfigParser() config.read_file(open(self.options.configfile)) + self.config = config self.options.bitcoind = os.getenv("BITCOIND", default=config["environment"]["BUILDDIR"] + '/src/bitcoind' + config["environment"]["EXEEXT"]) self.options.bitcoincli = os.getenv("BITCOINCLI", default=config["environment"]["BUILDDIR"] + '/src/bitcoin-cli' + config["environment"]["EXEEXT"]) diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py index 14d37e7220..d6e31457d1 100755 --- a/test/functional/test_framework/test_node.py +++ b/test/functional/test_framework/test_node.py @@ -498,6 +498,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""" @@ -529,8 +537,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/wallet_util.py b/test/functional/test_framework/wallet_util.py new file mode 100755 index 0000000000..c0dfa4c3f0 --- /dev/null +++ b/test/functional/test_framework/wallet_util.py @@ -0,0 +1,99 @@ +#!/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. +"""Useful util functions for testing the wallet""" +from collections import namedtuple + +from test_framework.address import ( + key_to_p2pkh, + key_to_p2sh_p2wpkh, + key_to_p2wpkh, + script_to_p2sh, + script_to_p2sh_p2wsh, + script_to_p2wsh, +) +from test_framework.script import ( + CScript, + OP_0, + OP_2, + OP_3, + OP_CHECKMULTISIG, + OP_CHECKSIG, + OP_DUP, + OP_EQUAL, + OP_EQUALVERIFY, + OP_HASH160, + hash160, + sha256, +) +from test_framework.util import hex_str_to_bytes + +Key = namedtuple('Key', ['privkey', + 'pubkey', + 'p2pkh_script', + 'p2pkh_addr', + 'p2wpkh_script', + 'p2wpkh_addr', + 'p2sh_p2wpkh_script', + 'p2sh_p2wpkh_redeem_script', + 'p2sh_p2wpkh_addr']) + +Multisig = namedtuple('Multisig', ['privkeys', + 'pubkeys', + 'p2sh_script', + 'p2sh_addr', + 'redeem_script', + 'p2wsh_script', + 'p2wsh_addr', + 'p2sh_p2wsh_script', + 'p2sh_p2wsh_addr']) + +def get_key(node): + """Generate a fresh key on node + + Returns a named tuple of privkey, pubkey and all address and scripts.""" + addr = node.getnewaddress() + pubkey = node.getaddressinfo(addr)['pubkey'] + pkh = hash160(hex_str_to_bytes(pubkey)) + return Key(privkey=node.dumpprivkey(addr), + pubkey=pubkey, + p2pkh_script=CScript([OP_DUP, OP_HASH160, pkh, OP_EQUALVERIFY, OP_CHECKSIG]).hex(), + p2pkh_addr=key_to_p2pkh(pubkey), + p2wpkh_script=CScript([OP_0, pkh]).hex(), + p2wpkh_addr=key_to_p2wpkh(pubkey), + p2sh_p2wpkh_script=CScript([OP_HASH160, hash160(CScript([OP_0, pkh])), OP_EQUAL]).hex(), + p2sh_p2wpkh_redeem_script=CScript([OP_0, pkh]).hex(), + p2sh_p2wpkh_addr=key_to_p2sh_p2wpkh(pubkey)) + +def get_multisig(node): + """Generate a fresh 2-of-3 multisig on node + + Returns a named tuple of privkeys, pubkeys and all address and scripts.""" + addrs = [] + pubkeys = [] + for _ in range(3): + addr = node.getaddressinfo(node.getnewaddress()) + addrs.append(addr['address']) + pubkeys.append(addr['pubkey']) + script_code = CScript([OP_2] + [hex_str_to_bytes(pubkey) for pubkey in pubkeys] + [OP_3, OP_CHECKMULTISIG]) + witness_script = CScript([OP_0, sha256(script_code)]) + return Multisig(privkeys=[node.dumpprivkey(addr) for addr in addrs], + pubkeys=pubkeys, + p2sh_script=CScript([OP_HASH160, hash160(script_code), OP_EQUAL]).hex(), + p2sh_addr=script_to_p2sh(script_code), + redeem_script=script_code.hex(), + p2wsh_script=witness_script.hex(), + p2wsh_addr=script_to_p2wsh(script_code), + p2sh_p2wsh_script=CScript([OP_HASH160, witness_script, OP_EQUAL]).hex(), + p2sh_p2wsh_addr=script_to_p2sh_p2wsh(script_code)) + +def test_address(node, address, **kwargs): + """Get address info for `address` and test whether the returned values are as expected.""" + addr_info = node.getaddressinfo(address) + for key, value in kwargs.items(): + if value is None: + if key in addr_info.keys(): + raise AssertionError("key {} unexpectedly returned in getaddressinfo.".format(key)) + elif addr_info[key] != value: + raise AssertionError("key {} value {} did not match expected value {}".format(key, addr_info[key], value)) diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index a094433942..5c92370b85 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -108,6 +108,7 @@ BASE_SCRIPTS = [ 'interface_bitcoin_cli.py', 'mempool_resurrect.py', 'wallet_txn_doublespend.py --mineblock', + 'tool_wallet.py', 'wallet_txn_clone.py', 'wallet_txn_clone.py --segwit', 'rpc_getchaintips.py', @@ -174,6 +175,7 @@ BASE_SCRIPTS = [ 'wallet_fallbackfee.py', 'feature_minchainwork.py', 'rpc_getblockstats.py', + 'wallet_create_tx.py', 'p2p_fingerprint.py', 'feature_uacomment.py', 'wallet_coinbase_category.py', @@ -561,7 +563,7 @@ class TestResult(): def check_script_prefixes(): """Check that test scripts start with one of the allowed name prefixes.""" - good_prefixes_re = re.compile("(example|feature|interface|mempool|mining|p2p|rpc|wallet)_") + good_prefixes_re = re.compile("(example|feature|interface|mempool|mining|p2p|rpc|wallet|tool)_") bad_script_names = [script for script in ALL_SCRIPTS if good_prefixes_re.match(script) is None] if bad_script_names: diff --git a/test/functional/tool_wallet.py b/test/functional/tool_wallet.py new file mode 100755 index 0000000000..fbcf21e729 --- /dev/null +++ b/test/functional/tool_wallet.py @@ -0,0 +1,101 @@ +#!/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 bitcoin-wallet.""" +import subprocess +import textwrap + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import assert_equal + +class ToolWalletTest(BitcoinTestFramework): + def set_test_params(self): + self.num_nodes = 1 + self.setup_clean_chain = True + + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + + def bitcoin_wallet_process(self, *args): + binary = self.config["environment"]["BUILDDIR"] + '/src/bitcoin-wallet' + self.config["environment"]["EXEEXT"] + args = ['-datadir={}'.format(self.nodes[0].datadir), '-regtest'] + list(args) + return subprocess.Popen([binary] + args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) + + def assert_raises_tool_error(self, error, *args): + p = self.bitcoin_wallet_process(*args) + stdout, stderr = p.communicate() + assert_equal(p.poll(), 1) + assert_equal(stdout, '') + assert_equal(stderr.strip(), error) + + def assert_tool_output(self, output, *args): + p = self.bitcoin_wallet_process(*args) + stdout, stderr = p.communicate() + assert_equal(p.poll(), 0) + assert_equal(stderr, '') + assert_equal(stdout, output) + + def run_test(self): + + self.assert_raises_tool_error('Invalid command: foo', 'foo') + # `bitcoin-wallet help` is an error. Use `bitcoin-wallet -help` + self.assert_raises_tool_error('Invalid command: help', 'help') + self.assert_raises_tool_error('Error: two methods provided (info and create). Only one method should be provided.', 'info', 'create') + self.assert_raises_tool_error('Error parsing command line arguments: Invalid parameter -foo', '-foo') + self.assert_raises_tool_error('Error loading wallet.dat. Is wallet being used by other process?', '-wallet=wallet.dat', 'info') + self.assert_raises_tool_error('Error: no wallet file at nonexistent.dat', '-wallet=nonexistent.dat', 'info') + + # stop the node to close the wallet to call info command + self.stop_node(0) + + out = textwrap.dedent('''\ + Wallet info + =========== + Encrypted: no + HD (hd seed available): yes + Keypool Size: 2 + Transactions: 0 + Address Book: 3 + ''') + self.assert_tool_output(out, '-wallet=wallet.dat', 'info') + + # mutate the wallet to check the info command output changes accordingly + self.start_node(0) + self.nodes[0].generate(1) + self.stop_node(0) + + out = textwrap.dedent('''\ + Wallet info + =========== + Encrypted: no + HD (hd seed available): yes + Keypool Size: 2 + Transactions: 1 + Address Book: 3 + ''') + self.assert_tool_output(out, '-wallet=wallet.dat', 'info') + + out = textwrap.dedent('''\ + Topping up keypool... + Wallet info + =========== + Encrypted: no + HD (hd seed available): yes + Keypool Size: 2000 + Transactions: 0 + Address Book: 0 + ''') + self.assert_tool_output(out, '-wallet=foo', 'create') + + self.start_node(0, ['-wallet=foo']) + out = self.nodes[0].getwalletinfo() + self.stop_node(0) + + assert_equal(0, out['txcount']) + assert_equal(1000, out['keypoolsize']) + assert_equal(1000, out['keypoolsize_hd_internal']) + assert_equal(True, 'hdseedid' in out) + +if __name__ == '__main__': + ToolWalletTest().main() diff --git a/test/functional/wallet_abandonconflict.py b/test/functional/wallet_abandonconflict.py index e5ac2c8bd4..0c3c247694 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,12 +13,21 @@ 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 - self.extra_args = [["-minrelaytxfee=0.00001"], []] + # TODO: remove -txindex. Currently required for getrawtransaction call. + self.extra_args = [["-minrelaytxfee=0.00001", "-txindex"], []] def skip_test_if_missing_module(self): self.skip_if_no_wallet() @@ -40,21 +49,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") @@ -63,12 +72,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)) @@ -76,8 +85,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"]) @@ -105,7 +114,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 @@ -145,8 +154,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) @@ -172,5 +181,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_basic.py b/test/functional/wallet_basic.py index 7184bb8cb6..673eb718e6 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.""" @@ -19,10 +19,13 @@ 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() @@ -194,7 +197,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 @@ -203,14 +206,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 @@ -219,7 +222,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 @@ -237,7 +240,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 @@ -264,7 +267,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() @@ -341,7 +344,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(), @@ -383,7 +386,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 @@ -442,8 +445,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)) @@ -480,7 +483,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: @@ -491,5 +494,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 new file mode 100755 index 0000000000..27dc0fb279 --- /dev/null +++ b/test/functional/wallet_create_tx.py @@ -0,0 +1,35 @@ +#!/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. + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import ( + assert_equal, +) + + +class CreateTxWalletTest(BitcoinTestFramework): + def set_test_params(self): + self.setup_clean_chain = False + self.num_nodes = 1 + + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + + def run_test(self): + 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) + tx = self.nodes[0].decoderawtransaction(self.nodes[0].gettransaction(txid)['hex']) + assert_equal(tx['locktime'], 0) + + self.log.info('Check that anti-fee-sniping is enabled when we mine a recent block') + self.nodes[0].generate(1) + txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1) + tx = self.nodes[0].decoderawtransaction(self.nodes[0].gettransaction(txid)['hex']) + assert 0 < tx['locktime'] <= 201 + + +if __name__ == '__main__': + CreateTxWalletTest().main() diff --git a/test/functional/wallet_disableprivatekeys.py b/test/functional/wallet_disableprivatekeys.py index 34ff525255..e55bb82e76 100755 --- a/test/functional/wallet_disableprivatekeys.py +++ b/test/functional/wallet_disableprivatekeys.py @@ -7,6 +7,7 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( + assert_equal, assert_raises_rpc_error, ) @@ -31,5 +32,15 @@ class DisablePrivateKeysTest(BitcoinTestFramework): assert_raises_rpc_error(-4,"Error: Private keys are disabled for this wallet", w1.getrawchangeaddress) w1.importpubkey(w2.getaddressinfo(w2.getnewaddress())['pubkey']) + self.log.info('Test that private keys cannot be imported') + addr = w2.getnewaddress('', 'legacy') + privkey = w2.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') + if __name__ == '__main__': DisablePrivateKeysTest().main() diff --git a/test/functional/wallet_import_with_label.py b/test/functional/wallet_import_with_label.py index 95acaa752e..a623b75606 100755 --- a/test/functional/wallet_import_with_label.py +++ b/test/functional/wallet_import_with_label.py @@ -11,7 +11,7 @@ with and without a label. """ from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import assert_equal +from test_framework.wallet_util import test_address class ImportWithLabel(BitcoinTestFramework): @@ -32,11 +32,11 @@ class ImportWithLabel(BitcoinTestFramework): address = self.nodes[0].getnewaddress() label = "Test Label" self.nodes[1].importaddress(address, label) - address_assert = self.nodes[1].getaddressinfo(address) - - assert_equal(address_assert["iswatchonly"], True) - assert_equal(address_assert["ismine"], False) - assert_equal(address_assert["label"], label) + test_address(self.nodes[1], + address, + iswatchonly=True, + ismine=False, + label=label) self.log.info( "Import the watch-only address's private key without a " @@ -45,7 +45,9 @@ class ImportWithLabel(BitcoinTestFramework): priv_key = self.nodes[0].dumpprivkey(address) self.nodes[1].importprivkey(priv_key) - assert_equal(label, self.nodes[1].getaddressinfo(address)["label"]) + test_address(self.nodes[1], + address, + label=label) self.log.info( "Test importaddress without label and importprivkey with label." @@ -53,11 +55,11 @@ class ImportWithLabel(BitcoinTestFramework): self.log.info("Import a watch-only address without a label.") address2 = self.nodes[0].getnewaddress() self.nodes[1].importaddress(address2) - address_assert2 = self.nodes[1].getaddressinfo(address2) - - assert_equal(address_assert2["iswatchonly"], True) - assert_equal(address_assert2["ismine"], False) - assert_equal(address_assert2["label"], "") + test_address(self.nodes[1], + address2, + iswatchonly=True, + ismine=False, + label="") self.log.info( "Import the watch-only address's private key with a " @@ -67,18 +69,20 @@ class ImportWithLabel(BitcoinTestFramework): label2 = "Test Label 2" self.nodes[1].importprivkey(priv_key2, label2) - assert_equal(label2, self.nodes[1].getaddressinfo(address2)["label"]) + test_address(self.nodes[1], + address2, + label=label2) self.log.info("Test importaddress with label and importprivkey with label.") self.log.info("Import a watch-only address with a label.") address3 = self.nodes[0].getnewaddress() label3_addr = "Test Label 3 for importaddress" self.nodes[1].importaddress(address3, label3_addr) - address_assert3 = self.nodes[1].getaddressinfo(address3) - - assert_equal(address_assert3["iswatchonly"], True) - assert_equal(address_assert3["ismine"], False) - assert_equal(address_assert3["label"], label3_addr) + test_address(self.nodes[1], + address3, + iswatchonly=True, + ismine=False, + label=label3_addr) self.log.info( "Import the watch-only address's private key with a " @@ -88,7 +92,9 @@ class ImportWithLabel(BitcoinTestFramework): label3_priv = "Test Label 3 for importprivkey" self.nodes[1].importprivkey(priv_key3, label3_priv) - assert_equal(label3_priv, self.nodes[1].getaddressinfo(address3)["label"]) + test_address(self.nodes[1], + address3, + label=label3_priv) self.log.info( "Test importprivkey won't label new dests with the same " @@ -98,15 +104,12 @@ class ImportWithLabel(BitcoinTestFramework): address4 = self.nodes[0].getnewaddress() label4_addr = "Test Label 4 for importaddress" self.nodes[1].importaddress(address4, label4_addr) - address_assert4 = self.nodes[1].getaddressinfo(address4) - - assert_equal(address_assert4["iswatchonly"], True) - assert_equal(address_assert4["ismine"], False) - assert_equal(address_assert4["label"], label4_addr) - - self.log.info("Asserts address has no embedded field with dests.") - - assert_equal(address_assert4.get("embedded"), None) + test_address(self.nodes[1], + address4, + iswatchonly=True, + ismine=False, + label=label4_addr, + embedded=None) self.log.info( "Import the watch-only address's private key without a " @@ -116,16 +119,14 @@ class ImportWithLabel(BitcoinTestFramework): ) priv_key4 = self.nodes[0].dumpprivkey(address4) self.nodes[1].importprivkey(priv_key4) - address_assert4 = self.nodes[1].getaddressinfo(address4) - - assert address_assert4.get("embedded") - - bcaddress_assert = self.nodes[1].getaddressinfo( - address_assert4["embedded"]["address"] - ) - - assert_equal(address_assert4["label"], label4_addr) - assert_equal(bcaddress_assert["label"], "") + embedded_addr = self.nodes[1].getaddressinfo(address4)['embedded']['address'] + + test_address(self.nodes[1], + embedded_addr, + label="") + test_address(self.nodes[1], + address4, + label=label4_addr) self.stop_nodes() diff --git a/test/functional/wallet_importmulti.py b/test/functional/wallet_importmulti.py index 3492075694..f122f19e3a 100755 --- a/test/functional/wallet_importmulti.py +++ b/test/functional/wallet_importmulti.py @@ -14,30 +14,10 @@ variants. success, and (if unsuccessful) test the error code and error message returned. - `test_address()` is called to call getaddressinfo for an address on node1 and test the values returned.""" -from collections import namedtuple - -from test_framework.address import ( - key_to_p2pkh, - key_to_p2sh_p2wpkh, - key_to_p2wpkh, - script_to_p2sh, - script_to_p2sh_p2wsh, - script_to_p2wsh, -) + from test_framework.script import ( CScript, - OP_0, - OP_2, - OP_3, - OP_CHECKMULTISIG, - OP_CHECKSIG, - OP_DUP, - OP_EQUAL, - OP_EQUALVERIFY, - OP_HASH160, OP_NOP, - hash160, - sha256, ) from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( @@ -45,28 +25,12 @@ from test_framework.util import ( assert_greater_than, assert_raises_rpc_error, bytes_to_hex_str, - hex_str_to_bytes ) - -Key = namedtuple('Key', ['privkey', - 'pubkey', - 'p2pkh_script', - 'p2pkh_addr', - 'p2wpkh_script', - 'p2wpkh_addr', - 'p2sh_p2wpkh_script', - 'p2sh_p2wpkh_redeem_script', - 'p2sh_p2wpkh_addr']) - -Multisig = namedtuple('Multisig', ['privkeys', - 'pubkeys', - 'p2sh_script', - 'p2sh_addr', - 'redeem_script', - 'p2wsh_script', - 'p2wsh_addr', - 'p2sh_p2wsh_script', - 'p2sh_p2wsh_addr']) +from test_framework.wallet_util import ( + get_key, + get_multisig, + test_address, +) class ImportMultiTest(BitcoinTestFramework): def set_test_params(self): @@ -80,45 +44,6 @@ class ImportMultiTest(BitcoinTestFramework): def setup_network(self): self.setup_nodes() - def get_key(self): - """Generate a fresh key on node0 - - Returns a named tuple of privkey, pubkey and all address and scripts.""" - addr = self.nodes[0].getnewaddress() - pubkey = self.nodes[0].getaddressinfo(addr)['pubkey'] - pkh = hash160(hex_str_to_bytes(pubkey)) - return Key(self.nodes[0].dumpprivkey(addr), - pubkey, - CScript([OP_DUP, OP_HASH160, pkh, OP_EQUALVERIFY, OP_CHECKSIG]).hex(), # p2pkh - key_to_p2pkh(pubkey), # p2pkh addr - CScript([OP_0, pkh]).hex(), # p2wpkh - key_to_p2wpkh(pubkey), # p2wpkh addr - CScript([OP_HASH160, hash160(CScript([OP_0, pkh])), OP_EQUAL]).hex(), # p2sh-p2wpkh - CScript([OP_0, pkh]).hex(), # p2sh-p2wpkh redeem script - key_to_p2sh_p2wpkh(pubkey)) # p2sh-p2wpkh addr - - def get_multisig(self): - """Generate a fresh multisig on node0 - - Returns a named tuple of privkeys, pubkeys and all address and scripts.""" - addrs = [] - pubkeys = [] - for _ in range(3): - addr = self.nodes[0].getaddressinfo(self.nodes[0].getnewaddress()) - addrs.append(addr['address']) - pubkeys.append(addr['pubkey']) - script_code = CScript([OP_2] + [hex_str_to_bytes(pubkey) for pubkey in pubkeys] + [OP_3, OP_CHECKMULTISIG]) - witness_script = CScript([OP_0, sha256(script_code)]) - return Multisig([self.nodes[0].dumpprivkey(addr) for addr in addrs], - pubkeys, - CScript([OP_HASH160, hash160(script_code), OP_EQUAL]).hex(), # p2sh - script_to_p2sh(script_code), # p2sh addr - script_code.hex(), # redeem script - witness_script.hex(), # p2wsh - script_to_p2wsh(script_code), # p2wsh addr - CScript([OP_HASH160, witness_script, OP_EQUAL]).hex(), # p2sh-p2wsh - script_to_p2sh_p2wsh(script_code)) # p2sh-p2wsh addr - def test_importmulti(self, req, success, error_code=None, error_message=None, warnings=[]): """Run importmulti and assert success""" result = self.nodes[1].importmulti([req]) @@ -131,16 +56,6 @@ class ImportMultiTest(BitcoinTestFramework): assert_equal(result[0]['error']['code'], error_code) assert_equal(result[0]['error']['message'], error_message) - def test_address(self, address, **kwargs): - """Get address info for `address` and test whether the returned values are as expected.""" - addr_info = self.nodes[1].getaddressinfo(address) - for key, value in kwargs.items(): - if value is None: - if key in addr_info.keys(): - raise AssertionError("key {} unexpectedly returned in getaddressinfo.".format(key)) - elif addr_info[key] != value: - raise AssertionError("key {} value {} did not match expected value {}".format(key, addr_info[key], value)) - def run_test(self): self.log.info("Mining blocks...") self.nodes[0].generate(1) @@ -164,177 +79,178 @@ class ImportMultiTest(BitcoinTestFramework): # Bitcoin Address (implicit non-internal) self.log.info("Should import an address") - key = self.get_key() - address = key.p2pkh_addr - self.test_importmulti({"scriptPubKey": {"address": address}, + key = get_key(self.nodes[0]) + self.test_importmulti({"scriptPubKey": {"address": key.p2pkh_addr}, "timestamp": "now"}, - True) - self.test_address(address, - iswatchonly=True, - ismine=False, - timestamp=timestamp, - ischange=False) - watchonly_address = address + success=True) + test_address(self.nodes[1], + key.p2pkh_addr, + iswatchonly=True, + ismine=False, + timestamp=timestamp, + ischange=False) + watchonly_address = key.p2pkh_addr watchonly_timestamp = timestamp self.log.info("Should not import an invalid address") self.test_importmulti({"scriptPubKey": {"address": "not valid address"}, "timestamp": "now"}, - False, + success=False, error_code=-5, error_message='Invalid address \"not valid address\"') # ScriptPubKey + internal self.log.info("Should import a scriptPubKey with internal flag") - key = self.get_key() + key = get_key(self.nodes[0]) self.test_importmulti({"scriptPubKey": key.p2pkh_script, "timestamp": "now", "internal": True}, - True) - self.test_address(key.p2pkh_addr, - iswatchonly=True, - ismine=False, - timestamp=timestamp, - ischange=True) + success=True) + test_address(self.nodes[1], + key.p2pkh_addr, + iswatchonly=True, + ismine=False, + timestamp=timestamp, + ischange=True) # ScriptPubKey + internal + label self.log.info("Should not allow a label to be specified when internal is true") - key = self.get_key() + key = get_key(self.nodes[0]) self.test_importmulti({"scriptPubKey": key.p2pkh_script, "timestamp": "now", "internal": True, "label": "Example label"}, - False, + success=False, error_code=-8, error_message='Internal addresses should not have a label') # Nonstandard scriptPubKey + !internal self.log.info("Should not import a nonstandard scriptPubKey without internal flag") nonstandardScriptPubKey = key.p2pkh_script + bytes_to_hex_str(CScript([OP_NOP])) - key = self.get_key() - address = key.p2pkh_addr + key = get_key(self.nodes[0]) self.test_importmulti({"scriptPubKey": nonstandardScriptPubKey, "timestamp": "now"}, - False, + success=False, error_code=-8, error_message='Internal must be set to true for nonstandard scriptPubKey imports.') - self.test_address(address, - iswatchonly=False, - ismine=False, - timestamp=None) + test_address(self.nodes[1], + key.p2pkh_addr, + iswatchonly=False, + ismine=False, + timestamp=None) # Address + Public key + !Internal(explicit) self.log.info("Should import an address with public key") - key = self.get_key() - address = key.p2pkh_addr - self.test_importmulti({"scriptPubKey": {"address": address}, + key = get_key(self.nodes[0]) + self.test_importmulti({"scriptPubKey": {"address": key.p2pkh_addr}, "timestamp": "now", "pubkeys": [key.pubkey], "internal": False}, - True, + success=True, warnings=["Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag."]) - self.test_address(address, - iswatchonly=True, - ismine=False, - timestamp=timestamp) + test_address(self.nodes[1], + key.p2pkh_addr, + iswatchonly=True, + ismine=False, + timestamp=timestamp) # ScriptPubKey + Public key + internal self.log.info("Should import a scriptPubKey with internal and with public key") - key = self.get_key() - address = key.p2pkh_addr + key = get_key(self.nodes[0]) self.test_importmulti({"scriptPubKey": key.p2pkh_script, "timestamp": "now", "pubkeys": [key.pubkey], "internal": True}, - True, + success=True, warnings=["Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag."]) - self.test_address(address, - iswatchonly=True, - ismine=False, - timestamp=timestamp) + test_address(self.nodes[1], + key.p2pkh_addr, + iswatchonly=True, + ismine=False, + timestamp=timestamp) # Nonstandard scriptPubKey + Public key + !internal self.log.info("Should not import a nonstandard scriptPubKey without internal and with public key") - key = self.get_key() - address = key.p2pkh_addr + key = get_key(self.nodes[0]) self.test_importmulti({"scriptPubKey": nonstandardScriptPubKey, "timestamp": "now", "pubkeys": [key.pubkey]}, - False, + success=False, error_code=-8, error_message='Internal must be set to true for nonstandard scriptPubKey imports.') - self.test_address(address, - iswatchonly=False, - ismine=False, - timestamp=None) + test_address(self.nodes[1], + key.p2pkh_addr, + iswatchonly=False, + ismine=False, + timestamp=None) # Address + Private key + !watchonly self.log.info("Should import an address with private key") - key = self.get_key() - address = key.p2pkh_addr - self.test_importmulti({"scriptPubKey": {"address": address}, + key = get_key(self.nodes[0]) + self.test_importmulti({"scriptPubKey": {"address": key.p2pkh_addr}, "timestamp": "now", "keys": [key.privkey]}, - True) - self.test_address(address, - iswatchonly=False, - ismine=True, - timestamp=timestamp) + success=True) + test_address(self.nodes[1], + key.p2pkh_addr, + iswatchonly=False, + ismine=True, + timestamp=timestamp) self.log.info("Should not import an address with private key if is already imported") - self.test_importmulti({"scriptPubKey": {"address": address}, + self.test_importmulti({"scriptPubKey": {"address": key.p2pkh_addr}, "timestamp": "now", "keys": [key.privkey]}, - False, + success=False, error_code=-4, error_message='The wallet already contains the private key for this address or script') # Address + Private key + watchonly self.log.info("Should import an address with private key and with watchonly") - key = self.get_key() - address = key.p2pkh_addr - self.test_importmulti({"scriptPubKey": {"address": address}, + key = get_key(self.nodes[0]) + self.test_importmulti({"scriptPubKey": {"address": key.p2pkh_addr}, "timestamp": "now", "keys": [key.privkey], "watchonly": True}, - True, + success=True, warnings=["All private keys are provided, outputs will be considered spendable. If this is intentional, do not specify the watchonly flag."]) - self.test_address(address, - iswatchonly=False, - ismine=True, - timestamp=timestamp) + test_address(self.nodes[1], + key.p2pkh_addr, + iswatchonly=False, + ismine=True, + timestamp=timestamp) # ScriptPubKey + Private key + internal self.log.info("Should import a scriptPubKey with internal and with private key") - key = self.get_key() - address = key.p2pkh_addr + key = get_key(self.nodes[0]) self.test_importmulti({"scriptPubKey": key.p2pkh_script, "timestamp": "now", "keys": [key.privkey], "internal": True}, - True) - self.test_address(address, - iswatchonly=False, - ismine=True, - timestamp=timestamp) + success=True) + test_address(self.nodes[1], + key.p2pkh_addr, + iswatchonly=False, + ismine=True, + timestamp=timestamp) # Nonstandard scriptPubKey + Private key + !internal self.log.info("Should not import a nonstandard scriptPubKey without internal and with private key") - key = self.get_key() - address = key.p2pkh_addr + key = get_key(self.nodes[0]) self.test_importmulti({"scriptPubKey": nonstandardScriptPubKey, "timestamp": "now", "keys": [key.privkey]}, - False, + success=False, error_code=-8, error_message='Internal must be set to true for nonstandard scriptPubKey imports.') - self.test_address(address, - iswatchonly=False, - ismine=False, - timestamp=None) + test_address(self.nodes[1], + key.p2pkh_addr, + iswatchonly=False, + ismine=False, + timestamp=None) # P2SH address - multisig = self.get_multisig() + multisig = get_multisig(self.nodes[0]) self.nodes[1].generate(100) self.nodes[1].sendtoaddress(multisig.p2sh_addr, 10.00) self.nodes[1].generate(1) @@ -343,17 +259,18 @@ class ImportMultiTest(BitcoinTestFramework): self.log.info("Should import a p2sh") self.test_importmulti({"scriptPubKey": {"address": multisig.p2sh_addr}, "timestamp": "now"}, - True) - self.test_address(multisig.p2sh_addr, - isscript=True, - iswatchonly=True, - timestamp=timestamp) + success=True) + test_address(self.nodes[1], + multisig.p2sh_addr, + isscript=True, + iswatchonly=True, + timestamp=timestamp) p2shunspent = self.nodes[1].listunspent(0, 999999, [multisig.p2sh_addr])[0] assert_equal(p2shunspent['spendable'], False) assert_equal(p2shunspent['solvable'], False) # P2SH + Redeem script - multisig = self.get_multisig() + multisig = get_multisig(self.nodes[0]) self.nodes[1].generate(100) self.nodes[1].sendtoaddress(multisig.p2sh_addr, 10.00) self.nodes[1].generate(1) @@ -363,16 +280,17 @@ class ImportMultiTest(BitcoinTestFramework): self.test_importmulti({"scriptPubKey": {"address": multisig.p2sh_addr}, "timestamp": "now", "redeemscript": multisig.redeem_script}, - True, + success=True, warnings=["Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag."]) - self.test_address(multisig.p2sh_addr, timestamp=timestamp, iswatchonly=True, ismine=False, solvable=True) + test_address(self.nodes[1], + multisig.p2sh_addr, timestamp=timestamp, iswatchonly=True, ismine=False, solvable=True) p2shunspent = self.nodes[1].listunspent(0, 999999, [multisig.p2sh_addr])[0] assert_equal(p2shunspent['spendable'], False) assert_equal(p2shunspent['solvable'], True) # P2SH + Redeem script + Private Keys + !Watchonly - multisig = self.get_multisig() + multisig = get_multisig(self.nodes[0]) self.nodes[1].generate(100) self.nodes[1].sendtoaddress(multisig.p2sh_addr, 10.00) self.nodes[1].generate(1) @@ -383,20 +301,21 @@ class ImportMultiTest(BitcoinTestFramework): "timestamp": "now", "redeemscript": multisig.redeem_script, "keys": multisig.privkeys[0:2]}, - True, + success=True, warnings=["Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag."]) - self.test_address(multisig.p2sh_addr, - timestamp=timestamp, - ismine=False, - iswatchonly=True, - solvable=True) + test_address(self.nodes[1], + multisig.p2sh_addr, + timestamp=timestamp, + ismine=False, + iswatchonly=True, + solvable=True) p2shunspent = self.nodes[1].listunspent(0, 999999, [multisig.p2sh_addr])[0] assert_equal(p2shunspent['spendable'], False) assert_equal(p2shunspent['solvable'], True) # P2SH + Redeem script + Private Keys + Watchonly - multisig = self.get_multisig() + multisig = get_multisig(self.nodes[0]) self.nodes[1].generate(100) self.nodes[1].sendtoaddress(multisig.p2sh_addr, 10.00) self.nodes[1].generate(1) @@ -408,98 +327,101 @@ class ImportMultiTest(BitcoinTestFramework): "redeemscript": multisig.redeem_script, "keys": multisig.privkeys[0:2], "watchonly": True}, - True) - self.test_address(multisig.p2sh_addr, - iswatchonly=True, - ismine=False, - solvable=True, - timestamp=timestamp) + success=True) + test_address(self.nodes[1], + multisig.p2sh_addr, + iswatchonly=True, + ismine=False, + solvable=True, + timestamp=timestamp) # Address + Public key + !Internal + Wrong pubkey self.log.info("Should not import an address with the wrong public key as non-solvable") - key = self.get_key() - address = key.p2pkh_addr - wrong_key = self.get_key().pubkey - self.test_importmulti({"scriptPubKey": {"address": address}, + key = get_key(self.nodes[0]) + wrong_key = get_key(self.nodes[0]).pubkey + self.test_importmulti({"scriptPubKey": {"address": key.p2pkh_addr}, "timestamp": "now", "pubkeys": [wrong_key]}, - True, + success=True, warnings=["Importing as non-solvable: some required keys are missing. If this is intentional, don't provide any keys, pubkeys, witnessscript, or redeemscript.", "Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag."]) - self.test_address(address, - iswatchonly=True, - ismine=False, - solvable=False, - timestamp=timestamp) + test_address(self.nodes[1], + key.p2pkh_addr, + iswatchonly=True, + ismine=False, + solvable=False, + timestamp=timestamp) # ScriptPubKey + Public key + internal + Wrong pubkey self.log.info("Should import a scriptPubKey with internal and with a wrong public key as non-solvable") - key = self.get_key() - address = key.p2pkh_addr - wrong_key = self.get_key().pubkey + key = get_key(self.nodes[0]) + wrong_key = get_key(self.nodes[0]).pubkey self.test_importmulti({"scriptPubKey": key.p2pkh_script, "timestamp": "now", "pubkeys": [wrong_key], "internal": True}, - True, + success=True, warnings=["Importing as non-solvable: some required keys are missing. If this is intentional, don't provide any keys, pubkeys, witnessscript, or redeemscript.", "Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag."]) - self.test_address(address, - iswatchonly=True, - ismine=False, - solvable=False, - timestamp=timestamp) + test_address(self.nodes[1], + key.p2pkh_addr, + iswatchonly=True, + ismine=False, + solvable=False, + timestamp=timestamp) # Address + Private key + !watchonly + Wrong private key self.log.info("Should import an address with a wrong private key as non-solvable") - key = self.get_key() - address = key.p2pkh_addr - wrong_privkey = self.get_key().privkey - self.test_importmulti({"scriptPubKey": {"address": address}, + key = get_key(self.nodes[0]) + wrong_privkey = get_key(self.nodes[0]).privkey + self.test_importmulti({"scriptPubKey": {"address": key.p2pkh_addr}, "timestamp": "now", "keys": [wrong_privkey]}, - True, + success=True, warnings=["Importing as non-solvable: some required keys are missing. If this is intentional, don't provide any keys, pubkeys, witnessscript, or redeemscript.", "Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag."]) - self.test_address(address, - iswatchonly=True, - ismine=False, - solvable=False, - timestamp=timestamp) + test_address(self.nodes[1], + key.p2pkh_addr, + iswatchonly=True, + ismine=False, + solvable=False, + timestamp=timestamp) # ScriptPubKey + Private key + internal + Wrong private key self.log.info("Should import a scriptPubKey with internal and with a wrong private key as non-solvable") - key = self.get_key() - address = key.p2pkh_addr - wrong_privkey = self.get_key().privkey + key = get_key(self.nodes[0]) + wrong_privkey = get_key(self.nodes[0]).privkey self.test_importmulti({"scriptPubKey": key.p2pkh_script, "timestamp": "now", "keys": [wrong_privkey], "internal": True}, - True, + success=True, warnings=["Importing as non-solvable: some required keys are missing. If this is intentional, don't provide any keys, pubkeys, witnessscript, or redeemscript.", "Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag."]) - self.test_address(address, - iswatchonly=True, - ismine=False, - solvable=False, - timestamp=timestamp) + test_address(self.nodes[1], + key.p2pkh_addr, + iswatchonly=True, + ismine=False, + solvable=False, + timestamp=timestamp) # Importing existing watch only address with new timestamp should replace saved timestamp. assert_greater_than(timestamp, watchonly_timestamp) self.log.info("Should replace previously saved watch only timestamp.") self.test_importmulti({"scriptPubKey": {"address": watchonly_address}, "timestamp": "now"}, - True) - self.test_address(watchonly_address, - iswatchonly=True, - ismine=False, - timestamp=timestamp) + success=True) + test_address(self.nodes[1], + watchonly_address, + iswatchonly=True, + ismine=False, + timestamp=timestamp) watchonly_timestamp = timestamp # restart nodes to check for proper serialization/deserialization of watch only address self.stop_nodes() self.start_nodes() - self.test_address(watchonly_address, - iswatchonly=True, - ismine=False, - timestamp=watchonly_timestamp) + test_address(self.nodes[1], + watchonly_address, + iswatchonly=True, + ismine=False, + timestamp=watchonly_timestamp) # Bad or missing timestamps self.log.info("Should throw on invalid or missing timestamp values") @@ -513,48 +435,49 @@ class ImportMultiTest(BitcoinTestFramework): # Import P2WPKH address as watch only self.log.info("Should import a P2WPKH address as watch only") - key = self.get_key() - address = key.p2wpkh_addr - self.test_importmulti({"scriptPubKey": {"address": address}, + key = get_key(self.nodes[0]) + self.test_importmulti({"scriptPubKey": {"address": key.p2wpkh_addr}, "timestamp": "now"}, - True) - self.test_address(address, - iswatchonly=True, - solvable=False) + success=True) + test_address(self.nodes[1], + key.p2wpkh_addr, + iswatchonly=True, + solvable=False) # Import P2WPKH address with public key but no private key self.log.info("Should import a P2WPKH address and public key as solvable but not spendable") - key = self.get_key() - address = key.p2wpkh_addr - self.test_importmulti({"scriptPubKey": {"address": address}, + key = get_key(self.nodes[0]) + self.test_importmulti({"scriptPubKey": {"address": key.p2wpkh_addr}, "timestamp": "now", "pubkeys": [key.pubkey]}, - True, + success=True, warnings=["Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag."]) - self.test_address(address, - ismine=False, - solvable=True) + test_address(self.nodes[1], + key.p2wpkh_addr, + ismine=False, + solvable=True) # Import P2WPKH address with key and check it is spendable self.log.info("Should import a P2WPKH address with key") - key = self.get_key() - address = key.p2wpkh_addr - self.test_importmulti({"scriptPubKey": {"address": address}, + key = get_key(self.nodes[0]) + self.test_importmulti({"scriptPubKey": {"address": key.p2wpkh_addr}, "timestamp": "now", "keys": [key.privkey]}, - True) - self.test_address(address, - iswatchonly=False, - ismine=True) + success=True) + test_address(self.nodes[1], + key.p2wpkh_addr, + iswatchonly=False, + ismine=True) # P2WSH multisig address without scripts or keys - multisig = self.get_multisig() + multisig = get_multisig(self.nodes[0]) self.log.info("Should import a p2wsh multisig as watch only without respective redeem script and private keys") self.test_importmulti({"scriptPubKey": {"address": multisig.p2wsh_addr}, "timestamp": "now"}, - True) - self.test_address(multisig.p2sh_addr, - solvable=False) + success=True) + test_address(self.nodes[1], + multisig.p2sh_addr, + solvable=False) # Same P2WSH multisig address as above, but now with witnessscript + private keys self.log.info("Should import a p2wsh with respective witness script and private keys") @@ -562,61 +485,63 @@ class ImportMultiTest(BitcoinTestFramework): "timestamp": "now", "witnessscript": multisig.redeem_script, "keys": multisig.privkeys}, - True) - self.test_address(multisig.p2sh_addr, - solvable=True, - ismine=True, - sigsrequired=2) + success=True) + test_address(self.nodes[1], + multisig.p2sh_addr, + solvable=True, + ismine=True, + sigsrequired=2) # P2SH-P2WPKH address with no redeemscript or public or private key - key = self.get_key() - address = key.p2sh_p2wpkh_addr + key = get_key(self.nodes[0]) self.log.info("Should import a p2sh-p2wpkh without redeem script or keys") - self.test_importmulti({"scriptPubKey": {"address": address}, + self.test_importmulti({"scriptPubKey": {"address": key.p2sh_p2wpkh_addr}, "timestamp": "now"}, - True) - self.test_address(address, - solvable=False, - ismine=False) + success=True) + test_address(self.nodes[1], + key.p2sh_p2wpkh_addr, + solvable=False, + ismine=False) # P2SH-P2WPKH address + redeemscript + public key with no private key self.log.info("Should import a p2sh-p2wpkh with respective redeem script and pubkey as solvable") - self.test_importmulti({"scriptPubKey": {"address": address}, + self.test_importmulti({"scriptPubKey": {"address": key.p2sh_p2wpkh_addr}, "timestamp": "now", "redeemscript": key.p2sh_p2wpkh_redeem_script, "pubkeys": [key.pubkey]}, - True, + success=True, warnings=["Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag."]) - self.test_address(address, - solvable=True, - ismine=False) + test_address(self.nodes[1], + key.p2sh_p2wpkh_addr, + solvable=True, + ismine=False) # P2SH-P2WPKH address + redeemscript + private key - key = self.get_key() - address = key.p2sh_p2wpkh_addr + key = get_key(self.nodes[0]) self.log.info("Should import a p2sh-p2wpkh with respective redeem script and private keys") - self.test_importmulti({"scriptPubKey": {"address": address}, + self.test_importmulti({"scriptPubKey": {"address": key.p2sh_p2wpkh_addr}, "timestamp": "now", "redeemscript": key.p2sh_p2wpkh_redeem_script, "keys": [key.privkey]}, - True) - self.test_address(address, - solvable=True, - ismine=True) + success=True) + test_address(self.nodes[1], + key.p2sh_p2wpkh_addr, + solvable=True, + ismine=True) # P2SH-P2WSH multisig + redeemscript with no private key - multisig = self.get_multisig() - address = multisig.p2sh_p2wsh_addr + multisig = get_multisig(self.nodes[0]) self.log.info("Should import a p2sh-p2wsh with respective redeem script but no private key") - self.test_importmulti({"scriptPubKey": {"address": address}, + self.test_importmulti({"scriptPubKey": {"address": multisig.p2sh_p2wsh_addr}, "timestamp": "now", "redeemscript": multisig.p2wsh_script, "witnessscript": multisig.redeem_script}, - True, + success=True, warnings=["Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag."]) - self.test_address(address, - solvable=True, - ismine=False) + test_address(self.nodes[1], + multisig.p2sh_p2wsh_addr, + solvable=True, + ismine=False) if __name__ == '__main__': ImportMultiTest().main() 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 d78c105c17..1c2e0a9cb7 100755 --- a/test/functional/wallet_txn_clone.py +++ b/test/functional/wallet_txn_clone.py @@ -65,7 +65,7 @@ class TxnMallTest(BitcoinTestFramework): # Construct a clone of tx1, to be malleated rawtx1 = self.nodes[0].getrawtransaction(txid1, 1) - clone_inputs = [{"txid": rawtx1["vin"][0]["txid"], "vout": rawtx1["vin"][0]["vout"]}] + clone_inputs = [{"txid": rawtx1["vin"][0]["txid"], "vout": rawtx1["vin"][0]["vout"], "sequence": rawtx1["vin"][0]["sequence"]}] clone_outputs = {rawtx1["vout"][0]["scriptPubKey"]["addresses"][0]: rawtx1["vout"][0]["value"], rawtx1["vout"][1]["scriptPubKey"]["addresses"][0]: rawtx1["vout"][1]["value"]} clone_locktime = rawtx1["locktime"] diff --git a/test/lint/check-doc.py b/test/lint/check-doc.py index 4facd6c334..c370ce0c04 100755 --- a/test/lint/check-doc.py +++ b/test/lint/check-doc.py @@ -30,8 +30,8 @@ def main(): used = check_output(CMD_GREP_ARGS, shell=True, universal_newlines=True, encoding='utf8') docd = check_output(CMD_GREP_DOCS, shell=True, universal_newlines=True, encoding='utf8') else: - used = check_output(CMD_GREP_ARGS, shell=True, universal_newlines=True) # encoding='utf8' - docd = check_output(CMD_GREP_DOCS, shell=True, universal_newlines=True) # encoding='utf8' + used = check_output(CMD_GREP_ARGS, shell=True).decode('utf8').strip() + docd = check_output(CMD_GREP_DOCS, shell=True).decode('utf8').strip() args_used = set(re.findall(re.compile(REGEX_ARG), used)) args_docd = set(re.findall(re.compile(REGEX_DOC), docd)).union(SET_DOC_OPTIONAL) diff --git a/test/lint/lint-format-strings.sh b/test/lint/lint-format-strings.sh index 2c443abf6b..c994ae3f4d 100755 --- a/test/lint/lint-format-strings.sh +++ b/test/lint/lint-format-strings.sh @@ -11,20 +11,20 @@ export LC_ALL=C FUNCTION_NAMES_AND_NUMBER_OF_LEADING_ARGUMENTS=( - FatalError,0 - fprintf,1 - LogConnectFailure,1 - LogPrint,1 - LogPrintf,0 - printf,0 - snprintf,2 - sprintf,1 - strprintf,0 - vfprintf,1 - vprintf,1 - vsnprintf,1 - vsprintf,1 - WalletLogPrintf,0 + "FatalError,0" + "fprintf,1" + "LogConnectFailure,1" + "LogPrint,1" + "LogPrintf,0" + "printf,0" + "snprintf,2" + "sprintf,1" + "strprintf,0" + "vfprintf,1" + "vprintf,1" + "vsnprintf,1" + "vsprintf,1" + "WalletLogPrintf,0" ) EXIT_CODE=0 diff --git a/test/lint/lint-locale-dependence.sh b/test/lint/lint-locale-dependence.sh index 44170a6b5a..1534d5ef68 100755 --- a/test/lint/lint-locale-dependence.sh +++ b/test/lint/lint-locale-dependence.sh @@ -4,30 +4,21 @@ export LC_ALL=C KNOWN_VIOLATIONS=( "src/bitcoin-tx.cpp.*stoul" "src/bitcoin-tx.cpp.*trim_right" - "src/bitcoin-tx.cpp:.*atoi" - "src/core_read.cpp.*is_digit" "src/dbwrapper.cpp.*stoul" "src/dbwrapper.cpp:.*vsnprintf" "src/httprpc.cpp.*trim" "src/init.cpp:.*atoi" "src/qt/rpcconsole.cpp:.*atoi" - "src/qt/rpcconsole.cpp:.*isdigit" "src/rest.cpp:.*strtol" "src/test/dbwrapper_tests.cpp:.*snprintf" - "src/test/getarg_tests.cpp.*split" "src/torcontrol.cpp:.*atoi" "src/torcontrol.cpp:.*strtol" - "src/uint256.cpp:.*tolower" - "src/util/system.cpp:.*atoi" - "src/util/system.cpp:.*fprintf" - "src/util/system.cpp:.*tolower" - "src/util/moneystr.cpp:.*isdigit" "src/util/strencodings.cpp:.*atoi" "src/util/strencodings.cpp:.*strtol" - "src/util/strencodings.cpp:.*strtoll" "src/util/strencodings.cpp:.*strtoul" - "src/util/strencodings.cpp:.*strtoull" "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.sh b/test/lint/lint-python.sh index 3dbb9fff28..f5b851aeab 100755 --- a/test/lint/lint-python.sh +++ b/test/lint/lint-python.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/usr/bin/env bash # # Copyright (c) 2017 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying @@ -8,77 +8,79 @@ export LC_ALL=C -# E101 indentation contains mixed spaces and tabs -# E112 expected an indented block -# E113 unexpected indentation -# E115 expected an indented block (comment) -# E116 unexpected indentation (comment) -# E125 continuation line with same indent as next logical line -# E129 visually indented line with same indent as next logical line -# E131 continuation line unaligned for hanging indent -# E133 closing bracket is missing indentation -# E223 tab before operator -# E224 tab after operator -# E242 tab after ',' -# E266 too many leading '#' for block comment -# E271 multiple spaces after keyword -# E272 multiple spaces before keyword -# E273 tab after keyword -# E274 tab before keyword -# E275 missing whitespace after keyword -# E304 blank lines found after function decorator -# E306 expected 1 blank line before a nested definition -# E401 multiple imports on one line -# E402 module level import not at top of file -# F403 'from foo_module import *' used; unable to detect undefined names -# F405 foo_function may be undefined, or defined from star imports: bar_module -# E502 the backslash is redundant between brackets -# E701 multiple statements on one line (colon) -# E702 multiple statements on one line (semicolon) -# E703 statement ends with a semicolon -# E711 comparison to None should be 'if cond is None:' -# E714 test for object identity should be "is not" -# E721 do not compare types, use "isinstance()" -# E741 do not use variables named "l", "O", or "I" -# E742 do not define classes named "l", "O", or "I" -# E743 do not define functions named "l", "O", or "I" -# E901 SyntaxError: invalid syntax -# E902 TokenError: EOF in multi-line string -# F401 module imported but unused -# F402 import module from line N shadowed by loop variable -# F404 future import(s) name after other statements -# F406 "from module import *" only allowed at module level -# F407 an undefined __future__ feature name was imported -# F601 dictionary key name repeated with different values -# F602 dictionary key variable name repeated with different values -# F621 too many expressions in an assignment with star-unpacking -# F622 two or more starred expressions in an assignment (a, *b, *c = d) -# F631 assertion test is a tuple, which are always True -# F701 a break statement outside of a while or for loop -# F702 a continue statement outside of a while or for loop -# F703 a continue statement in a finally block in a loop -# F704 a yield or yield from statement outside of a function -# F705 a return statement with arguments inside a generator -# F706 a return statement outside of a function/method -# F707 an except: block as not the last exception handler -# F811 redefinition of unused name from line N -# F812 list comprehension redefines 'foo' from line N -# F821 undefined name 'Foo' -# F822 undefined name name in __all__ -# F823 local variable name … referenced before assignment -# F831 duplicate argument name in function definition -# F841 local variable 'foo' is assigned to but never used -# W191 indentation contains tabs -# W291 trailing whitespace -# W292 no newline at end of file -# W293 blank line contains whitespace -# W504 line break after binary operator -# W601 .has_key() is deprecated, use "in" -# W602 deprecated form of raising exception -# W603 "<>" is deprecated, use "!=" -# W604 backticks are deprecated, use "repr()" -# W605 invalid escape sequence "x" -# W606 'async' and 'await' are reserved keywords starting with Python 3.7 +enabled=( + E101 # indentation contains mixed spaces and tabs + E112 # expected an indented block + E113 # unexpected indentation + E115 # expected an indented block (comment) + E116 # unexpected indentation (comment) + E125 # continuation line with same indent as next logical line + E129 # visually indented line with same indent as next logical line + E131 # continuation line unaligned for hanging indent + E133 # closing bracket is missing indentation + E223 # tab before operator + E224 # tab after operator + E242 # tab after ',' + E266 # too many leading '#' for block comment + E271 # multiple spaces after keyword + E272 # multiple spaces before keyword + E273 # tab after keyword + E274 # tab before keyword + E275 # missing whitespace after keyword + E304 # blank lines found after function decorator + E306 # expected 1 blank line before a nested definition + E401 # multiple imports on one line + E402 # module level import not at top of file + E502 # the backslash is redundant between brackets + E701 # multiple statements on one line (colon) + E702 # multiple statements on one line (semicolon) + E703 # statement ends with a semicolon + E711 # comparison to None should be 'if cond is None:' + E714 # test for object identity should be "is not" + E721 # do not compare types, use "isinstance()" + E741 # do not use variables named "l", "O", or "I" + E742 # do not define classes named "l", "O", or "I" + E743 # do not define functions named "l", "O", or "I" + E901 # SyntaxError: invalid syntax + E902 # TokenError: EOF in multi-line string + F401 # module imported but unused + F402 # import module from line N shadowed by loop variable + F403 # 'from foo_module import *' used; unable to detect undefined names + F404 # future import(s) name after other statements + F405 # foo_function may be undefined, or defined from star imports: bar_module + F406 # "from module import *" only allowed at module level + F407 # an undefined __future__ feature name was imported + F601 # dictionary key name repeated with different values + F602 # dictionary key variable name repeated with different values + F621 # too many expressions in an assignment with star-unpacking + F622 # two or more starred expressions in an assignment (a, *b, *c = d) + F631 # assertion test is a tuple, which are always True + F701 # a break statement outside of a while or for loop + F702 # a continue statement outside of a while or for loop + F703 # a continue statement in a finally block in a loop + F704 # a yield or yield from statement outside of a function + F705 # a return statement with arguments inside a generator + F706 # a return statement outside of a function/method + F707 # an except: block as not the last exception handler + F811 # redefinition of unused name from line N + F812 # list comprehension redefines 'foo' from line N + F821 # undefined name 'Foo' + F822 # undefined name name in __all__ + F823 # local variable name … referenced before assignment + F831 # duplicate argument name in function definition + F841 # local variable 'foo' is assigned to but never used + W191 # indentation contains tabs + W291 # trailing whitespace + W292 # no newline at end of file + W293 # blank line contains whitespace + W504 # line break after binary operator + W601 # .has_key() is deprecated, use "in" + W602 # deprecated form of raising exception + W603 # "<>" is deprecated, use "!=" + W604 # backticks are deprecated, use "repr()" + W605 # invalid escape sequence "x" + W606 # 'async' and 'await' are reserved keywords starting with Python 3.7 +) if ! command -v flake8 > /dev/null; then echo "Skipping Python linting since flake8 is not installed. Install by running \"pip3 install flake8\"" @@ -88,4 +90,4 @@ elif PYTHONWARNINGS="ignore" flake8 --version | grep -q "Python 2"; then exit 0 fi -PYTHONWARNINGS="ignore" flake8 --ignore=B,C,E,F,I,N,W --select=E101,E112,E113,E115,E116,E125,E129,E131,E133,E223,E224,E242,E266,E271,E272,E273,E274,E275,E304,E306,E401,E402,E502,E701,E702,E703,E711,E714,E721,E741,E742,E743,E901,E902,F401,F402,F403,F404,F405,F406,F407,F601,F602,F621,F622,F631,F701,F702,F703,F704,F705,F706,F707,F811,F812,F821,F822,F823,F831,F841,W191,W291,W292,W293,W504,W601,W602,W603,W604,W605,W606 "${@:-.}" +PYTHONWARNINGS="ignore" flake8 --ignore=B,C,E,F,I,N,W --select=$(IFS=","; echo "${enabled[*]}") "${@:-.}" diff --git a/test/lint/lint-shell.sh b/test/lint/lint-shell.sh index 9af3c10ed6..6f5e6546c5 100755 --- a/test/lint/lint-shell.sh +++ b/test/lint/lint-shell.sh @@ -13,7 +13,7 @@ export LC_ALL=C # respectively. So export LC_ALL=C is set as required by lint-shell-locale.sh # but unset here in case of running in Travis. if [ "$TRAVIS" = "true" ]; then - unset LC_ALL + unset LC_ALL fi if ! command -v shellcheck > /dev/null; then @@ -22,26 +22,26 @@ if ! command -v shellcheck > /dev/null; then fi # Disabled warnings: -# SC1087: Use braces when expanding arrays, e.g. ${array[idx]} (or ${var}[.. to quiet). -# SC1117: Backslash is literal in "\.". Prefer explicit escaping: "\\.". -# SC2001: See if you can use ${variable//search/replace} instead. -# SC2004: $/${} is unnecessary on arithmetic variables. -# SC2005: Useless echo? Instead of 'echo $(cmd)', just use 'cmd'. -# SC2006: Use $(..) instead of legacy `..`. -# SC2016: Expressions don't expand in single quotes, use double quotes for that. -# SC2028: echo won't expand escape sequences. Consider printf. -# SC2046: Quote this to prevent word splitting. -# SC2048: Use "$@" (with quotes) to prevent whitespace problems. -# SC2066: Since you double quoted this, it will not word split, and the loop will only run once. -# SC2086: Double quote to prevent globbing and word splitting. -# SC2116: Useless echo? Instead of 'cmd $(echo foo)', just use 'cmd foo'. -# SC2148: Tips depend on target shell and yours is unknown. Add a shebang. -# SC2162: read without -r will mangle backslashes. -# SC2166: Prefer [ p ] && [ q ] as [ p -a q ] is not well defined. -# SC2166: Prefer [ p ] || [ q ] as [ p -o q ] is not well defined. -# SC2181: Check exit code directly with e.g. 'if mycmd;', not indirectly with $?. -# SC2206: Quote to prevent word splitting, or split robustly with mapfile or read -a. -# SC2207: Prefer mapfile or read -a to split command output (or quote to avoid splitting). -# SC2230: which is non-standard. Use builtin 'command -v' instead. -shellcheck -e SC1087,SC1117,SC2001,SC2004,SC2005,SC2006,SC2016,SC2028,SC2046,SC2048,SC2066,SC2086,SC2116,SC2148,SC2162,SC2166,SC2181,SC2206,SC2207,SC2230 \ +disabled=( + SC1087 # Use braces when expanding arrays, e.g. ${array[idx]} (or ${var}[.. to quiet). + SC2001 # See if you can use ${variable//search/replace} instead. + SC2004 # $/${} is unnecessary on arithmetic variables. + SC2005 # Useless echo? Instead of 'echo $(cmd)', just use 'cmd'. + SC2006 # Use $(..) instead of legacy `..`. + SC2016 # Expressions don't expand in single quotes, use double quotes for that. + SC2028 # echo won't expand escape sequences. Consider printf. + SC2046 # Quote this to prevent word splitting. + SC2048 # Use "$@" (with quotes) to prevent whitespace problems. + SC2066 # Since you double quoted this, it will not word split, and the loop will only run once. + SC2086 # Double quote to prevent globbing and word splitting. + SC2116 # Useless echo? Instead of 'cmd $(echo foo)', just use 'cmd foo'. + SC2162 # read without -r will mangle backslashes. + SC2166 # Prefer [ p ] {&&,||} [ q ] as [ p -{a,o} q ] is not well defined. + SC2181 # Check exit code directly with e.g. 'if mycmd;', not indirectly with $?. + SC2206 # Quote to prevent word splitting, or split robustly with mapfile or read -a. + SC2207 # Prefer mapfile or read -a to split command output (or quote to avoid splitting). + SC2230 # which is non-standard. Use builtin 'command -v' instead. + SC2236 # Don't force -n instead of ! -z. +) +shellcheck -e "$(IFS=","; echo "${disabled[*]}")" \ $(git ls-files -- "*.sh" | grep -vE 'src/(secp256k1|univalue)/') diff --git a/test/lint/lint-whitespace.sh b/test/lint/lint-whitespace.sh index beb7ec42f4..f318e19071 100755 --- a/test/lint/lint-whitespace.sh +++ b/test/lint/lint-whitespace.sh @@ -23,7 +23,7 @@ while getopts "?" opt; do done if [ -z "${TRAVIS_COMMIT_RANGE}" ]; then - if [ "$1" ]; then + if [ -n "$1" ]; then TRAVIS_COMMIT_RANGE="HEAD~$1...HEAD" else TRAVIS_COMMIT_RANGE="HEAD" diff --git a/test/sanitizer_suppressions/ubsan b/test/sanitizer_suppressions/ubsan index e90d5c2ac0..f0107f1361 100644 --- a/test/sanitizer_suppressions/ubsan +++ b/test/sanitizer_suppressions/ubsan @@ -29,7 +29,6 @@ unsigned-integer-overflow:policy/fees.cpp unsigned-integer-overflow:prevector.h unsigned-integer-overflow:script/interpreter.cpp unsigned-integer-overflow:stl_bvector.h -unsigned-integer-overflow:streams.h unsigned-integer-overflow:txmempool.cpp unsigned-integer-overflow:util/strencodings.cpp unsigned-integer-overflow:validation.cpp |